File tree Expand file tree Collapse file tree 4 files changed +68
-54
lines changed Expand file tree Collapse file tree 4 files changed +68
-54
lines changed Original file line number Diff line number Diff line change 1+ import 'package:flutter/material.dart' hide Tooltip;
2+ import 'package:flutter/services.dart' ;
3+ import 'tooltip.dart' ;
4+
5+ class CopyableText extends StatefulWidget {
6+ final String text;
7+ final TextStyle ? style;
8+
9+ const CopyableText (this .text, {super .key, this .style});
10+
11+ @override
12+ State <CopyableText > createState () => _CopyableTextState ();
13+ }
14+
15+ class _CopyableTextState extends State <CopyableText > {
16+ bool _copied = false ;
17+
18+ void _copyToClipboard () async {
19+ await Clipboard .setData (ClipboardData (text: widget.text));
20+ setState (() => _copied = true );
21+ }
22+
23+ void _resetCopied () {
24+ if (_copied) {
25+ setState (() => _copied = false );
26+ }
27+ }
28+
29+ @override
30+ Widget build (BuildContext context) {
31+ return MouseRegion (
32+ cursor: SystemMouseCursors .click,
33+ onExit: (_) => _resetCopied (),
34+ child: GestureDetector (
35+ onTap: _copyToClipboard,
36+ child: Tooltip (
37+ message: _copied ? 'Copied' : 'Click to copy' ,
38+ child: Text (
39+ widget.text,
40+ style: widget.style,
41+ maxLines: 1 ,
42+ overflow: TextOverflow .ellipsis,
43+ ),
44+ ),
45+ ),
46+ );
47+ }
48+ }
Original file line number Diff line number Diff line change 11import 'package:flutter/material.dart' hide Tooltip;
2+ import '../copyable_text.dart' ;
23
34import '../extensions.dart' ;
45import '../tooltip.dart' ;
56
67class IpAddresses extends StatelessWidget {
78 final Iterable <String > ips;
9+ final bool copyable;
810
9- const IpAddresses (this .ips, {super .key});
11+ const IpAddresses (this .ips, {this .copyable = false , super .key});
1012
1113 @override
1214 Widget build (BuildContext context) {
@@ -15,10 +17,12 @@ class IpAddresses extends StatelessWidget {
1517
1618 return Row (children: [
1719 Expanded (
18- child: Tooltip (
19- message: firstIp,
20- child: Text (firstIp.nonBreaking, overflow: TextOverflow .ellipsis),
21- ),
20+ child: copyable
21+ ? CopyableText (firstIp)
22+ : Tooltip (
23+ message: firstIp,
24+ child: Text (firstIp.nonBreaking, overflow: TextOverflow .ellipsis),
25+ ),
2226 ),
2327 if (restIps.isNotEmpty)
2428 Badge .count (
Original file line number Diff line number Diff line change @@ -12,51 +12,7 @@ import 'vm_action_buttons.dart';
1212import 'vm_details.dart' ;
1313import 'vm_status_icon.dart' ;
1414import '../tooltip.dart' ;
15-
16- class CopyableText extends StatefulWidget {
17- final String text;
18- final TextStyle ? style;
19-
20- const CopyableText (this .text, {super .key, this .style});
21-
22- @override
23- State <CopyableText > createState () => _CopyableTextState ();
24- }
25-
26- class _CopyableTextState extends State <CopyableText > {
27- bool _copied = false ;
28-
29- void _copyToClipboard () async {
30- await Clipboard .setData (ClipboardData (text: widget.text));
31- setState (() => _copied = true );
32- }
33-
34- void _resetCopied () {
35- if (_copied) {
36- setState (() => _copied = false );
37- }
38- }
39-
40- @override
41- Widget build (BuildContext context) {
42- return MouseRegion (
43- cursor: SystemMouseCursors .click,
44- onExit: (_) => _resetCopied (),
45- child: GestureDetector (
46- onTap: _copyToClipboard,
47- child: Tooltip (
48- message: _copied ? 'Copied' : 'Click to copy' ,
49- child: Text (
50- widget.text,
51- style: widget.style,
52- maxLines: 1 ,
53- overflow: TextOverflow .ellipsis,
54- ),
55- ),
56- ),
57- );
58- }
59- }
15+ import '../copyable_text.dart' ;
6016
6117class VmDetailsHeader extends ConsumerWidget {
6218 final String name;
Original file line number Diff line number Diff line change @@ -14,6 +14,7 @@ import '../vm_details/vm_status_icon.dart';
1414import 'search_box.dart' ;
1515import 'table.dart' ;
1616import 'vms.dart' ;
17+ import '../copyable_text.dart' ;
1718
1819final headers = < TableHeader <VmInfo >> [
1920 TableHeader (
@@ -72,23 +73,28 @@ final headers = <TableHeader<VmInfo>>[
7273 minWidth: 70 ,
7374 cellBuilder: (info) {
7475 final image = info.instanceInfo.currentRelease;
75- return Text (
76+ return CopyableText (
7677 image.isNotBlank ? image.nonBreaking : '-' ,
77- overflow: TextOverflow .ellipsis,
7878 );
7979 },
8080 ),
8181 TableHeader (
8282 name: 'PRIVATE IP' ,
8383 width: 140 ,
8484 minWidth: 100 ,
85- cellBuilder: (info) => IpAddresses (info.instanceInfo.ipv4.take (1 )),
85+ cellBuilder: (info) => IpAddresses (
86+ info.instanceInfo.ipv4.take (1 ),
87+ copyable: true ,
88+ ),
8689 ),
8790 TableHeader (
8891 name: 'PUBLIC IP' ,
8992 width: 140 ,
9093 minWidth: 100 ,
91- cellBuilder: (info) => IpAddresses (info.instanceInfo.ipv4.skip (1 )),
94+ cellBuilder: (info) => IpAddresses (
95+ info.instanceInfo.ipv4.skip (1 ),
96+ copyable: true ,
97+ ),
9298 ),
9399];
94100
You can’t perform that action at this time.
0 commit comments