Skip to content

Commit

Permalink
implement click-to-copy in vm_table_headers
Browse files Browse the repository at this point in the history
  • Loading branch information
levkropp committed Jan 15, 2025
1 parent e43933c commit ddf482a
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 54 deletions.
48 changes: 48 additions & 0 deletions src/client/gui/lib/copyable_text.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'package:flutter/material.dart' hide Tooltip;
import 'package:flutter/services.dart';
import 'tooltip.dart';

class CopyableText extends StatefulWidget {
final String text;
final TextStyle? style;

const CopyableText(this.text, {super.key, this.style});

@override
State<CopyableText> createState() => _CopyableTextState();
}

class _CopyableTextState extends State<CopyableText> {
bool _copied = false;

void _copyToClipboard() async {
await Clipboard.setData(ClipboardData(text: widget.text));
setState(() => _copied = true);
}

void _resetCopied() {
if (_copied) {
setState(() => _copied = false);
}
}

@override
Widget build(BuildContext context) {
return MouseRegion(
cursor: SystemMouseCursors.click,
onExit: (_) => _resetCopied(),
child: GestureDetector(
onTap: _copyToClipboard,
child: Tooltip(
message: _copied ? 'Copied' : 'Click to copy',
child: Text(
widget.text,
style: widget.style,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
),
);
}
}
14 changes: 9 additions & 5 deletions src/client/gui/lib/vm_details/ip_addresses.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import 'package:flutter/material.dart' hide Tooltip;
import '../copyable_text.dart';

import '../extensions.dart';
import '../tooltip.dart';

class IpAddresses extends StatelessWidget {
final Iterable<String> ips;
final bool copyable;

const IpAddresses(this.ips, {super.key});
const IpAddresses(this.ips, {this.copyable = false, super.key});

@override
Widget build(BuildContext context) {
Expand All @@ -15,10 +17,12 @@ class IpAddresses extends StatelessWidget {

return Row(children: [
Expanded(
child: Tooltip(
message: firstIp,
child: Text(firstIp.nonBreaking, overflow: TextOverflow.ellipsis),
),
child: copyable
? CopyableText(firstIp)
: Tooltip(
message: firstIp,
child: Text(firstIp.nonBreaking, overflow: TextOverflow.ellipsis),
),
),
if (restIps.isNotEmpty)
Badge.count(
Expand Down
46 changes: 1 addition & 45 deletions src/client/gui/lib/vm_details/vm_details_general.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,51 +12,7 @@ import 'vm_action_buttons.dart';
import 'vm_details.dart';
import 'vm_status_icon.dart';
import '../tooltip.dart';

class CopyableText extends StatefulWidget {
final String text;
final TextStyle? style;

const CopyableText(this.text, {super.key, this.style});

@override
State<CopyableText> createState() => _CopyableTextState();
}

class _CopyableTextState extends State<CopyableText> {
bool _copied = false;

void _copyToClipboard() async {
await Clipboard.setData(ClipboardData(text: widget.text));
setState(() => _copied = true);
}

void _resetCopied() {
if (_copied) {
setState(() => _copied = false);
}
}

@override
Widget build(BuildContext context) {
return MouseRegion(
cursor: SystemMouseCursors.click,
onExit: (_) => _resetCopied(),
child: GestureDetector(
onTap: _copyToClipboard,
child: Tooltip(
message: _copied ? 'Copied' : 'Click to copy',
child: Text(
widget.text,
style: widget.style,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
),
);
}
}
import '../copyable_text.dart';

class VmDetailsHeader extends ConsumerWidget {
final String name;
Expand Down
14 changes: 10 additions & 4 deletions src/client/gui/lib/vm_table/vm_table_headers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import '../vm_details/vm_status_icon.dart';
import 'search_box.dart';
import 'table.dart';
import 'vms.dart';
import '../copyable_text.dart';

final headers = <TableHeader<VmInfo>>[
TableHeader(
Expand Down Expand Up @@ -72,23 +73,28 @@ final headers = <TableHeader<VmInfo>>[
minWidth: 70,
cellBuilder: (info) {
final image = info.instanceInfo.currentRelease;
return Text(
return CopyableText(
image.isNotBlank ? image.nonBreaking : '-',
overflow: TextOverflow.ellipsis,
);
},
),
TableHeader(
name: 'PRIVATE IP',
width: 140,
minWidth: 100,
cellBuilder: (info) => IpAddresses(info.instanceInfo.ipv4.take(1)),
cellBuilder: (info) => IpAddresses(
info.instanceInfo.ipv4.take(1),
copyable: true,
),
),
TableHeader(
name: 'PUBLIC IP',
width: 140,
minWidth: 100,
cellBuilder: (info) => IpAddresses(info.instanceInfo.ipv4.skip(1)),
cellBuilder: (info) => IpAddresses(
info.instanceInfo.ipv4.skip(1),
copyable: true,
),
),
];

Expand Down

0 comments on commit ddf482a

Please sign in to comment.