| 
									
										
										
										
											2022-11-14 15:41:43 +08:00
										 |  |  | import 'dart:io'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  | import 'package:flutter/services.dart'; | 
					
						
							| 
									
										
										
										
											2022-10-08 17:39:05 +09:00
										 |  |  | import 'package:flutter_hbb/common/widgets/address_book.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-23 15:12:50 +08:00
										 |  |  | import 'package:flutter_hbb/consts.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import '../../common.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-02 17:19:44 +08:00
										 |  |  | import '../../common/formatter/id_formatter.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | import '../../models/model.dart'; | 
					
						
							|  |  |  | import '../../models/peer_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  | import '../../models/platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu; | 
					
						
							|  |  |  | import '../../desktop/widgets/popup_menu.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef PopupMenuEntryBuilder = Future<List<mod_menu.PopupMenuEntry<String>>> | 
					
						
							|  |  |  |     Function(BuildContext); | 
					
						
							| 
									
										
										
										
											2022-07-28 14:06:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  | enum PeerUiType { grid, list } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | final peerCardUiType = PeerUiType.grid.obs; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | class _PeerCard extends StatefulWidget { | 
					
						
							|  |  |  |   final Peer peer; | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |   final Function(BuildContext, String) connect; | 
					
						
							|  |  |  |   final PopupMenuEntryBuilder popupMenuEntryBuilder; | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 00:35:19 -07:00
										 |  |  |   const _PeerCard( | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |       {required this.peer, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       required this.connect, | 
					
						
							|  |  |  |       required this.popupMenuEntryBuilder, | 
					
						
							|  |  |  |       Key? key}) | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |       : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   _PeerCardState createState() => _PeerCardState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /// State for the connection page.
 | 
					
						
							| 
									
										
										
										
											2022-07-29 16:47:24 +08:00
										 |  |  | class _PeerCardState extends State<_PeerCard> | 
					
						
							|  |  |  |     with AutomaticKeepAliveClientMixin { | 
					
						
							| 
									
										
										
										
											2022-09-01 22:36:40 -07:00
										 |  |  |   var _menuPos = RelativeRect.fill; | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  |   final double _cardRadius = 16; | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |   final double _borderWidth = 2; | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-07-29 16:47:24 +08:00
										 |  |  |     super.build(context); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |     if (isDesktop) { | 
					
						
							|  |  |  |       return _buildDesktop(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return _buildMobile(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildMobile() { | 
					
						
							|  |  |  |     final peer = super.widget.peer; | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |     final name = | 
					
						
							|  |  |  |         '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |     return Card( | 
					
						
							| 
									
										
										
										
											2022-09-21 17:16:09 +08:00
										 |  |  |         margin: EdgeInsets.symmetric(horizontal: 2), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |         child: GestureDetector( | 
					
						
							|  |  |  |             onTap: !isWebDesktop ? () => connect(context, peer.id) : null, | 
					
						
							|  |  |  |             onDoubleTap: isWebDesktop ? () => connect(context, peer.id) : null, | 
					
						
							|  |  |  |             onLongPressStart: (details) { | 
					
						
							|  |  |  |               final x = details.globalPosition.dx; | 
					
						
							|  |  |  |               final y = details.globalPosition.dy; | 
					
						
							|  |  |  |               _menuPos = RelativeRect.fromLTRB(x, y, x, y); | 
					
						
							|  |  |  |               _showPeerMenu(peer.id); | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2022-09-28 21:07:44 +08:00
										 |  |  |             child: Container( | 
					
						
							|  |  |  |               padding: EdgeInsets.only(left: 12, top: 8, bottom: 8), | 
					
						
							|  |  |  |               child: Row( | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Container( | 
					
						
							|  |  |  |                       width: 50, | 
					
						
							|  |  |  |                       height: 50, | 
					
						
							|  |  |  |                       decoration: BoxDecoration( | 
					
						
							|  |  |  |                         color: str2color('${peer.id}${peer.platform}', 0x7f), | 
					
						
							|  |  |  |                         borderRadius: BorderRadius.circular(4), | 
					
						
							|  |  |  |                       ), | 
					
						
							|  |  |  |                       padding: const EdgeInsets.all(6), | 
					
						
							|  |  |  |                       child: getPlatformImage(peer.platform)), | 
					
						
							|  |  |  |                   Expanded( | 
					
						
							|  |  |  |                     child: Column( | 
					
						
							|  |  |  |                       crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |                       children: [ | 
					
						
							|  |  |  |                         Row(children: [ | 
					
						
							|  |  |  |                           getOnline(4, peer.online), | 
					
						
							|  |  |  |                           Text(peer.alias.isEmpty | 
					
						
							|  |  |  |                               ? formatID(peer.id) | 
					
						
							|  |  |  |                               : peer.alias) | 
					
						
							|  |  |  |                         ]), | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |                         Text(name) | 
					
						
							| 
									
										
										
										
											2022-09-28 21:07:44 +08:00
										 |  |  |                       ], | 
					
						
							|  |  |  |                     ).paddingOnly(left: 8.0), | 
					
						
							| 
									
										
										
										
											2022-09-22 16:45:14 +08:00
										 |  |  |                   ), | 
					
						
							| 
									
										
										
										
											2022-09-28 21:07:44 +08:00
										 |  |  |                   InkWell( | 
					
						
							|  |  |  |                       child: const Padding( | 
					
						
							|  |  |  |                           padding: EdgeInsets.all(12), | 
					
						
							|  |  |  |                           child: Icon(Icons.more_vert)), | 
					
						
							|  |  |  |                       onTapDown: (e) { | 
					
						
							|  |  |  |                         final x = e.globalPosition.dx; | 
					
						
							|  |  |  |                         final y = e.globalPosition.dy; | 
					
						
							|  |  |  |                         _menuPos = RelativeRect.fromLTRB(x, y, x, y); | 
					
						
							|  |  |  |                       }, | 
					
						
							|  |  |  |                       onTap: () { | 
					
						
							|  |  |  |                         _showPeerMenu(peer.id); | 
					
						
							|  |  |  |                       }) | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               ), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |             ))); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildDesktop() { | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |     final peer = super.widget.peer; | 
					
						
							|  |  |  |     var deco = Rx<BoxDecoration?>(BoxDecoration( | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |         border: Border.all(color: Colors.transparent, width: _borderWidth), | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |         borderRadius: peerCardUiType.value == PeerUiType.grid | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  |             ? BorderRadius.circular(_cardRadius) | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |             : null)); | 
					
						
							|  |  |  |     return MouseRegion( | 
					
						
							|  |  |  |       onEnter: (evt) { | 
					
						
							|  |  |  |         deco.value = BoxDecoration( | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |             border: Border.all( | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  |                 color: Theme.of(context).colorScheme.primary, | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |                 width: _borderWidth), | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |             borderRadius: peerCardUiType.value == PeerUiType.grid | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  |                 ? BorderRadius.circular(_cardRadius) | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |                 : null); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       onExit: (evt) { | 
					
						
							|  |  |  |         deco.value = BoxDecoration( | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |             border: Border.all(color: Colors.transparent, width: _borderWidth), | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |             borderRadius: peerCardUiType.value == PeerUiType.grid | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  |                 ? BorderRadius.circular(_cardRadius) | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |                 : null); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       child: GestureDetector( | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |           onDoubleTap: () => widget.connect(context, peer.id), | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |           child: Obx(() => peerCardUiType.value == PeerUiType.grid | 
					
						
							|  |  |  |               ? _buildPeerCard(context, peer, deco) | 
					
						
							|  |  |  |               : _buildPeerTile(context, peer, deco))), | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |   Widget _buildPeerTile( | 
					
						
							|  |  |  |       BuildContext context, Peer peer, Rx<BoxDecoration?> deco) { | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |     final name = | 
					
						
							|  |  |  |         '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |     final greyStyle = TextStyle( | 
					
						
							|  |  |  |         fontSize: 11, | 
					
						
							|  |  |  |         color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6)); | 
					
						
							| 
									
										
										
										
											2022-09-22 15:59:51 +08:00
										 |  |  |     final alias = bind.mainGetPeerOptionSync(id: peer.id, key: 'alias'); | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |     return Obx( | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |       () => Container( | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |         foregroundDecoration: deco.value, | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |         child: Row( | 
					
						
							|  |  |  |           mainAxisSize: MainAxisSize.max, | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |           children: [ | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |             Container( | 
					
						
							|  |  |  |               decoration: BoxDecoration( | 
					
						
							|  |  |  |                 color: str2color('${peer.id}${peer.platform}', 0x7f), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |               alignment: Alignment.center, | 
					
						
							| 
									
										
										
										
											2022-09-27 18:34:05 +08:00
										 |  |  |               width: 42, | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |               child: getPlatformImage(peer.platform, size: 30).paddingAll(6), | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |             Expanded( | 
					
						
							|  |  |  |               child: Container( | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |                 decoration: | 
					
						
							|  |  |  |                     BoxDecoration(color: Theme.of(context).backgroundColor), | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |                 child: Row( | 
					
						
							|  |  |  |                   children: [ | 
					
						
							|  |  |  |                     Expanded( | 
					
						
							|  |  |  |                       child: Column( | 
					
						
							|  |  |  |                         children: [ | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |                           Row(children: [ | 
					
						
							| 
									
										
										
										
											2022-09-25 21:15:00 +08:00
										 |  |  |                             getOnline(8, peer.online), | 
					
						
							| 
									
										
										
										
											2022-09-22 15:59:51 +08:00
										 |  |  |                             Expanded( | 
					
						
							|  |  |  |                                 child: Text( | 
					
						
							|  |  |  |                               alias.isEmpty ? formatID(peer.id) : alias, | 
					
						
							|  |  |  |                               overflow: TextOverflow.ellipsis, | 
					
						
							| 
									
										
										
										
											2022-09-27 19:42:05 +08:00
										 |  |  |                               style: Theme.of(context).textTheme.titleSmall, | 
					
						
							| 
									
										
										
										
											2022-09-22 15:59:51 +08:00
										 |  |  |                             )), | 
					
						
							| 
									
										
										
										
											2022-09-23 23:04:34 +08:00
										 |  |  |                           ]).marginOnly(bottom: 2), | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |                           Align( | 
					
						
							|  |  |  |                             alignment: Alignment.centerLeft, | 
					
						
							| 
									
										
										
										
											2022-09-22 15:59:51 +08:00
										 |  |  |                             child: Text( | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |                               name, | 
					
						
							| 
									
										
										
										
											2022-09-22 15:59:51 +08:00
										 |  |  |                               style: greyStyle, | 
					
						
							|  |  |  |                               textAlign: TextAlign.start, | 
					
						
							|  |  |  |                               overflow: TextOverflow.ellipsis, | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |                             ), | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |                           ), | 
					
						
							|  |  |  |                         ], | 
					
						
							| 
									
										
										
										
											2022-09-23 23:04:34 +08:00
										 |  |  |                       ).marginOnly(top: 2), | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |                     ), | 
					
						
							| 
									
										
										
										
											2022-08-26 13:02:15 +08:00
										 |  |  |                     _actionMore(peer), | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |                   ], | 
					
						
							| 
									
										
										
										
											2022-09-22 15:59:51 +08:00
										 |  |  |                 ).paddingOnly(left: 10.0, top: 3.0), | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |               ), | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |   Widget _buildPeerCard( | 
					
						
							|  |  |  |       BuildContext context, Peer peer, Rx<BoxDecoration?> deco) { | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |     final name = | 
					
						
							|  |  |  |         '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |     return Card( | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |       color: Colors.transparent, | 
					
						
							|  |  |  |       elevation: 0, | 
					
						
							|  |  |  |       margin: EdgeInsets.zero, | 
					
						
							| 
									
										
										
										
											2022-08-24 14:57:41 +08:00
										 |  |  |       child: Obx( | 
					
						
							|  |  |  |         () => Container( | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |           foregroundDecoration: deco.value, | 
					
						
							|  |  |  |           child: ClipRRect( | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  |             borderRadius: BorderRadius.circular(_cardRadius - _borderWidth), | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |             child: Column( | 
					
						
							|  |  |  |               mainAxisSize: MainAxisSize.min, | 
					
						
							|  |  |  |               mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |               children: [ | 
					
						
							|  |  |  |                 Expanded( | 
					
						
							|  |  |  |                   child: Container( | 
					
						
							| 
									
										
										
										
											2022-08-24 14:57:41 +08:00
										 |  |  |                     color: str2color('${peer.id}${peer.platform}', 0x7f), | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |                     child: Row( | 
					
						
							|  |  |  |                       children: [ | 
					
						
							|  |  |  |                         Expanded( | 
					
						
							|  |  |  |                           child: Column( | 
					
						
							|  |  |  |                             crossAxisAlignment: CrossAxisAlignment.center, | 
					
						
							|  |  |  |                             children: [ | 
					
						
							|  |  |  |                               Container( | 
					
						
							|  |  |  |                                 padding: const EdgeInsets.all(6), | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |                                 child: | 
					
						
							|  |  |  |                                     getPlatformImage(peer.platform, size: 60), | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |                               ), | 
					
						
							|  |  |  |                               Row( | 
					
						
							|  |  |  |                                 children: [ | 
					
						
							|  |  |  |                                   Expanded( | 
					
						
							| 
									
										
										
										
											2022-09-21 21:20:19 +08:00
										 |  |  |                                     child: Tooltip( | 
					
						
							|  |  |  |                                       message: name, | 
					
						
							|  |  |  |                                       waitDuration: const Duration(seconds: 1), | 
					
						
							|  |  |  |                                       child: Text( | 
					
						
							|  |  |  |                                         name, | 
					
						
							|  |  |  |                                         style: const TextStyle( | 
					
						
							|  |  |  |                                             color: Colors.white70, | 
					
						
							|  |  |  |                                             fontSize: 12), | 
					
						
							|  |  |  |                                         textAlign: TextAlign.center, | 
					
						
							|  |  |  |                                         overflow: TextOverflow.ellipsis, | 
					
						
							|  |  |  |                                       ), | 
					
						
							|  |  |  |                                     ), | 
					
						
							| 
									
										
										
										
											2022-08-24 14:57:41 +08:00
										 |  |  |                                   ), | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |                                 ], | 
					
						
							|  |  |  |                               ), | 
					
						
							|  |  |  |                             ], | 
					
						
							|  |  |  |                           ).paddingAll(4.0), | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                       ], | 
					
						
							|  |  |  |                     ), | 
					
						
							| 
									
										
										
										
											2022-08-24 14:57:41 +08:00
										 |  |  |                   ), | 
					
						
							|  |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |                 Container( | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |                   color: Theme.of(context).backgroundColor, | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |                   child: Row( | 
					
						
							|  |  |  |                     mainAxisAlignment: MainAxisAlignment.spaceBetween, | 
					
						
							|  |  |  |                     children: [ | 
					
						
							| 
									
										
										
										
											2022-09-22 15:59:51 +08:00
										 |  |  |                       Expanded( | 
					
						
							|  |  |  |                           child: Row(children: [ | 
					
						
							| 
									
										
										
										
											2022-09-25 21:15:00 +08:00
										 |  |  |                         getOnline(8, peer.online), | 
					
						
							| 
									
										
										
										
											2022-09-22 15:59:51 +08:00
										 |  |  |                         Expanded( | 
					
						
							|  |  |  |                             child: Text( | 
					
						
							|  |  |  |                           peer.alias.isEmpty ? formatID(peer.id) : peer.alias, | 
					
						
							|  |  |  |                           overflow: TextOverflow.ellipsis, | 
					
						
							| 
									
										
										
										
											2022-09-27 19:42:05 +08:00
										 |  |  |                           style: Theme.of(context).textTheme.titleSmall, | 
					
						
							| 
									
										
										
										
											2022-09-22 15:59:51 +08:00
										 |  |  |                         )), | 
					
						
							|  |  |  |                       ]).paddingSymmetric(vertical: 8)), | 
					
						
							| 
									
										
										
										
											2022-08-26 13:02:15 +08:00
										 |  |  |                       _actionMore(peer), | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |                     ], | 
					
						
							| 
									
										
										
										
											2022-08-26 13:02:15 +08:00
										 |  |  |                   ).paddingSymmetric(horizontal: 12.0), | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |                 ) | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-08-24 14:57:41 +08:00
										 |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 22:36:40 -07:00
										 |  |  |   Widget _actionMore(Peer peer) => Listener( | 
					
						
							|  |  |  |       onPointerDown: (e) { | 
					
						
							|  |  |  |         final x = e.position.dx; | 
					
						
							|  |  |  |         final y = e.position.dy; | 
					
						
							|  |  |  |         _menuPos = RelativeRect.fromLTRB(x, y, x, y); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |       onPointerUp: (_) => _showPeerMenu(peer.id), | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  |       child: ActionMore()); | 
					
						
							| 
									
										
										
										
											2022-09-01 22:36:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /// Show the peer menu and handle user's choice.
 | 
					
						
							|  |  |  |   /// User might remove the peer or send a file to the peer.
 | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   void _showPeerMenu(String id) async { | 
					
						
							| 
									
										
										
										
											2022-09-01 22:36:40 -07:00
										 |  |  |     await mod_menu.showMenu( | 
					
						
							|  |  |  |       context: context, | 
					
						
							|  |  |  |       position: _menuPos, | 
					
						
							|  |  |  |       items: await super.widget.popupMenuEntryBuilder(context), | 
					
						
							|  |  |  |       elevation: 8, | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   bool get wantKeepAlive => true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  | enum CardType { | 
					
						
							|  |  |  |   recent, | 
					
						
							|  |  |  |   fav, | 
					
						
							|  |  |  |   lan, | 
					
						
							|  |  |  |   ab, | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |   grp, | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  | abstract class BasePeerCard extends StatelessWidget { | 
					
						
							|  |  |  |   final Peer peer; | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |   final EdgeInsets? menuPadding; | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |   final CardType cardType; | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |   BasePeerCard( | 
					
						
							|  |  |  |       {required this.peer, required this.cardType, this.menuPadding, Key? key}) | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       : super(key: key); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return _PeerCard( | 
					
						
							|  |  |  |       peer: peer, | 
					
						
							| 
									
										
										
										
											2022-09-08 00:35:19 -07:00
										 |  |  |       connect: (BuildContext context, String id) => connect(context, id), | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       popupMenuEntryBuilder: _buildPopupMenuEntry, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future<List<mod_menu.PopupMenuEntry<String>>> _buildPopupMenuEntry( | 
					
						
							|  |  |  |           BuildContext context) async => | 
					
						
							|  |  |  |       (await _buildMenuItems(context)) | 
					
						
							|  |  |  |           .map((e) => e.build( | 
					
						
							|  |  |  |               context, | 
					
						
							|  |  |  |               const MenuConfig( | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  |                   commonColor: CustomPopupMenuTheme.commonColor, | 
					
						
							|  |  |  |                   height: CustomPopupMenuTheme.height, | 
					
						
							|  |  |  |                   dividerHeight: CustomPopupMenuTheme.dividerHeight))) | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |           .expand((i) => i) | 
					
						
							|  |  |  |           .toList(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @protected | 
					
						
							|  |  |  |   Future<List<MenuEntryBase<String>>> _buildMenuItems(BuildContext context); | 
					
						
							| 
									
										
										
										
											2022-08-26 13:02:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |   MenuEntryBase<String> _connectCommonAction( | 
					
						
							|  |  |  |       BuildContext context, String id, String title, | 
					
						
							|  |  |  |       {bool isFileTransfer = false, | 
					
						
							|  |  |  |       bool isTcpTunneling = false, | 
					
						
							|  |  |  |       bool isRDP = false}) { | 
					
						
							|  |  |  |     return MenuEntryButton<String>( | 
					
						
							|  |  |  |       childBuilder: (TextStyle? style) => Text( | 
					
						
							| 
									
										
										
										
											2022-09-21 21:20:19 +08:00
										 |  |  |         title, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |         style: style, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       proc: () { | 
					
						
							| 
									
										
										
										
											2022-09-08 00:35:19 -07:00
										 |  |  |         connect( | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |           context, | 
					
						
							|  |  |  |           peer.id, | 
					
						
							|  |  |  |           isFileTransfer: isFileTransfer, | 
					
						
							|  |  |  |           isTcpTunneling: isTcpTunneling, | 
					
						
							|  |  |  |           isRDP: isRDP, | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       padding: menuPadding, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       dismissOnClicked: true, | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |   @protected | 
					
						
							| 
									
										
										
										
											2022-09-21 21:20:19 +08:00
										 |  |  |   MenuEntryBase<String> _connectAction(BuildContext context, Peer peer) { | 
					
						
							|  |  |  |     return _connectCommonAction( | 
					
						
							|  |  |  |         context, | 
					
						
							|  |  |  |         peer.id, | 
					
						
							|  |  |  |         peer.alias.isEmpty | 
					
						
							|  |  |  |             ? translate('Connect') | 
					
						
							|  |  |  |             : "${translate('Connect')} ${peer.id}"); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @protected | 
					
						
							|  |  |  |   MenuEntryBase<String> _transferFileAction(BuildContext context, String id) { | 
					
						
							|  |  |  |     return _connectCommonAction( | 
					
						
							|  |  |  |       context, | 
					
						
							|  |  |  |       id, | 
					
						
							| 
									
										
										
										
											2022-09-21 21:20:19 +08:00
										 |  |  |       translate('Transfer File'), | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       isFileTransfer: true, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @protected | 
					
						
							|  |  |  |   MenuEntryBase<String> _tcpTunnelingAction(BuildContext context, String id) { | 
					
						
							|  |  |  |     return _connectCommonAction( | 
					
						
							|  |  |  |       context, | 
					
						
							|  |  |  |       id, | 
					
						
							| 
									
										
										
										
											2022-09-21 21:20:19 +08:00
										 |  |  |       translate('TCP Tunneling'), | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       isTcpTunneling: true, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @protected | 
					
						
							|  |  |  |   MenuEntryBase<String> _rdpAction(BuildContext context, String id) { | 
					
						
							|  |  |  |     return MenuEntryButton<String>( | 
					
						
							| 
									
										
										
										
											2022-09-01 22:36:40 -07:00
										 |  |  |       childBuilder: (TextStyle? style) => Container( | 
					
						
							|  |  |  |           alignment: AlignmentDirectional.center, | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  |           height: CustomPopupMenuTheme.height, | 
					
						
							| 
									
										
										
										
											2022-09-01 22:36:40 -07:00
										 |  |  |           child: Row( | 
					
						
							|  |  |  |             children: [ | 
					
						
							|  |  |  |               Text( | 
					
						
							|  |  |  |                 translate('RDP'), | 
					
						
							|  |  |  |                 style: style, | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |               Expanded( | 
					
						
							|  |  |  |                   child: Align( | 
					
						
							|  |  |  |                 alignment: Alignment.centerRight, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |                 child: Transform.scale( | 
					
						
							|  |  |  |                     scale: 0.8, | 
					
						
							|  |  |  |                     child: IconButton( | 
					
						
							|  |  |  |                       icon: const Icon(Icons.edit), | 
					
						
							|  |  |  |                       padding: EdgeInsets.zero, | 
					
						
							|  |  |  |                       onPressed: () { | 
					
						
							|  |  |  |                         if (Navigator.canPop(context)) { | 
					
						
							|  |  |  |                           Navigator.pop(context); | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |                         _rdpDialog(id, cardType); | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |                       }, | 
					
						
							|  |  |  |                     )), | 
					
						
							| 
									
										
										
										
											2022-09-01 22:36:40 -07:00
										 |  |  |               )) | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |           )), | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       proc: () { | 
					
						
							| 
									
										
										
										
											2022-09-08 00:35:19 -07:00
										 |  |  |         connect(context, id, isRDP: true); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       padding: menuPadding, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       dismissOnClicked: true, | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |   @protected | 
					
						
							|  |  |  |   MenuEntryBase<String> _wolAction(String id) { | 
					
						
							|  |  |  |     return MenuEntryButton<String>( | 
					
						
							|  |  |  |       childBuilder: (TextStyle? style) => Text( | 
					
						
							|  |  |  |         translate('WOL'), | 
					
						
							|  |  |  |         style: style, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       proc: () { | 
					
						
							|  |  |  |         bind.mainWol(id: id); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       padding: menuPadding, | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |       dismissOnClicked: true, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-14 15:41:43 +08:00
										 |  |  |   /// Only avaliable on Windows.
 | 
					
						
							|  |  |  |   @protected | 
					
						
							|  |  |  |   MenuEntryBase<String> _createShortCutAction(String id) { | 
					
						
							|  |  |  |     return MenuEntryButton<String>( | 
					
						
							|  |  |  |       childBuilder: (TextStyle? style) => Text( | 
					
						
							|  |  |  |         translate('Create Desktop Shortcut'), | 
					
						
							|  |  |  |         style: style, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       proc: () { | 
					
						
							|  |  |  |         bind.mainCreateShortcut(id: id); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       padding: menuPadding, | 
					
						
							|  |  |  |       dismissOnClicked: true, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |   @protected | 
					
						
							|  |  |  |   Future<MenuEntryBase<String>> _forceAlwaysRelayAction(String id) async { | 
					
						
							|  |  |  |     const option = 'force-always-relay'; | 
					
						
							|  |  |  |     return MenuEntrySwitch<String>( | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       switchType: SwitchType.scheckbox, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       text: translate('Always connect via relay'), | 
					
						
							|  |  |  |       getter: () async { | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |         if (cardType == CardType.ab) { | 
					
						
							|  |  |  |           return gFFI.abModel.find(id)?.forceAlwaysRelay ?? false; | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |           return (await bind.mainGetPeerOption(id: id, key: option)).isNotEmpty; | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |       }, | 
					
						
							|  |  |  |       setter: (bool v) async { | 
					
						
							|  |  |  |         gFFI.abModel.setPeerForceAlwaysRelay(id, v); | 
					
						
							|  |  |  |         await bind.mainSetPeerOption( | 
					
						
							|  |  |  |             id: id, key: option, value: bool2option('force-always-relay', v)); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       padding: menuPadding, | 
					
						
							|  |  |  |       dismissOnClicked: true, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |   @protected | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |   MenuEntryBase<String> _renameAction(String id) { | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     return MenuEntryButton<String>( | 
					
						
							|  |  |  |       childBuilder: (TextStyle? style) => Text( | 
					
						
							|  |  |  |         translate('Rename'), | 
					
						
							|  |  |  |         style: style, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       proc: () { | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |         _rename(id); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       padding: menuPadding, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       dismissOnClicked: true, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |   @protected | 
					
						
							| 
									
										
										
										
											2022-09-01 06:18:29 -07:00
										 |  |  |   MenuEntryBase<String> _removeAction( | 
					
						
							| 
									
										
										
										
											2022-09-25 21:03:19 +08:00
										 |  |  |       String id, Future<void> Function() reloadFunc, | 
					
						
							|  |  |  |       {bool isLan = false}) { | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     return MenuEntryButton<String>( | 
					
						
							|  |  |  |       childBuilder: (TextStyle? style) => Text( | 
					
						
							|  |  |  |         translate('Remove'), | 
					
						
							|  |  |  |         style: style, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       proc: () { | 
					
						
							|  |  |  |         () async { | 
					
						
							| 
									
										
										
										
											2022-09-25 21:03:19 +08:00
										 |  |  |           if (isLan) { | 
					
						
							|  |  |  |             // TODO
 | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             await bind.mainRemovePeer(id: id); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |           removePreference(id); | 
					
						
							| 
									
										
										
										
											2022-09-01 06:18:29 -07:00
										 |  |  |           await reloadFunc(); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |         }(); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       padding: menuPadding, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       dismissOnClicked: true, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |   @protected | 
					
						
							|  |  |  |   MenuEntryBase<String> _unrememberPasswordAction(String id) { | 
					
						
							|  |  |  |     return MenuEntryButton<String>( | 
					
						
							|  |  |  |       childBuilder: (TextStyle? style) => Text( | 
					
						
							|  |  |  |         translate('Unremember Password'), | 
					
						
							|  |  |  |         style: style, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       proc: () { | 
					
						
							|  |  |  |         bind.mainForgetPassword(id: id); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       padding: menuPadding, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       dismissOnClicked: true, | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-29 12:03:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |   @protected | 
					
						
							|  |  |  |   MenuEntryBase<String> _addFavAction(String id) { | 
					
						
							|  |  |  |     return MenuEntryButton<String>( | 
					
						
							|  |  |  |       childBuilder: (TextStyle? style) => Text( | 
					
						
							|  |  |  |         translate('Add to Favorites'), | 
					
						
							|  |  |  |         style: style, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       proc: () { | 
					
						
							|  |  |  |         () async { | 
					
						
							|  |  |  |           final favs = (await bind.mainGetFav()).toList(); | 
					
						
							|  |  |  |           if (!favs.contains(id)) { | 
					
						
							|  |  |  |             favs.add(id); | 
					
						
							| 
									
										
										
										
											2022-09-14 22:22:23 -07:00
										 |  |  |             await bind.mainStoreFav(favs: favs); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |           } | 
					
						
							|  |  |  |         }(); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       padding: menuPadding, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       dismissOnClicked: true, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @protected | 
					
						
							| 
									
										
										
										
											2022-09-14 22:22:23 -07:00
										 |  |  |   MenuEntryBase<String> _rmFavAction( | 
					
						
							|  |  |  |       String id, Future<void> Function() reloadFunc) { | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     return MenuEntryButton<String>( | 
					
						
							|  |  |  |       childBuilder: (TextStyle? style) => Text( | 
					
						
							|  |  |  |         translate('Remove from Favorites'), | 
					
						
							|  |  |  |         style: style, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       proc: () { | 
					
						
							|  |  |  |         () async { | 
					
						
							|  |  |  |           final favs = (await bind.mainGetFav()).toList(); | 
					
						
							|  |  |  |           if (favs.remove(id)) { | 
					
						
							| 
									
										
										
										
											2022-09-14 22:22:23 -07:00
										 |  |  |             await bind.mainStoreFav(favs: favs); | 
					
						
							|  |  |  |             await reloadFunc(); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |           } | 
					
						
							|  |  |  |         }(); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       padding: menuPadding, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       dismissOnClicked: true, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-27 12:16:45 +08:00
										 |  |  |   @protected | 
					
						
							|  |  |  |   MenuEntryBase<String> _addToAb(Peer peer) { | 
					
						
							|  |  |  |     return MenuEntryButton<String>( | 
					
						
							|  |  |  |       childBuilder: (TextStyle? style) => Text( | 
					
						
							|  |  |  |         translate('Add to Address Book'), | 
					
						
							|  |  |  |         style: style, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       proc: () { | 
					
						
							|  |  |  |         () async { | 
					
						
							|  |  |  |           if (!gFFI.abModel.idContainBy(peer.id)) { | 
					
						
							|  |  |  |             gFFI.abModel.addPeer(peer); | 
					
						
							|  |  |  |             await gFFI.abModel.pushAb(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }(); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       padding: menuPadding, | 
					
						
							|  |  |  |       dismissOnClicked: true, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |   void _rename(String id) async { | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     RxBool isInProgress = false.obs; | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |     String name; | 
					
						
							|  |  |  |     if (cardType == CardType.ab) { | 
					
						
							|  |  |  |       name = gFFI.abModel.find(id)?.alias ?? ""; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       name = await bind.mainGetPeerOption(id: id, key: 'alias'); | 
					
						
							| 
									
										
										
										
											2022-07-29 12:03:24 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |     var controller = TextEditingController(text: name); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     gFFI.dialogManager.show((setState, close) { | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       submit() async { | 
					
						
							|  |  |  |         isInProgress.value = true; | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |         String name = controller.text.trim(); | 
					
						
							| 
									
										
										
										
											2022-11-12 22:33:10 +08:00
										 |  |  |         await bind.mainSetPeerAlias(id: id, alias: name); | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |         gFFI.abModel.setPeerAlias(id, name); | 
					
						
							|  |  |  |         update(); | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         close(); | 
					
						
							|  |  |  |         isInProgress.value = false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 12:03:24 +08:00
										 |  |  |       return CustomAlertDialog( | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |         title: Text(translate('Rename')), | 
					
						
							| 
									
										
										
										
											2022-07-29 12:03:24 +08:00
										 |  |  |         content: Column( | 
					
						
							|  |  |  |           crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             Container( | 
					
						
							|  |  |  |               child: Form( | 
					
						
							|  |  |  |                 child: TextFormField( | 
					
						
							| 
									
										
										
										
											2022-08-28 21:43:18 +08:00
										 |  |  |                   controller: controller, | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                   focusNode: FocusNode()..requestFocus(), | 
					
						
							|  |  |  |                   decoration: | 
					
						
							|  |  |  |                       const InputDecoration(border: OutlineInputBorder()), | 
					
						
							| 
									
										
										
										
											2022-07-29 12:03:24 +08:00
										 |  |  |                 ), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |             Obx(() => Offstage( | 
					
						
							|  |  |  |                 offstage: isInProgress.isFalse, | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                 child: const LinearProgressIndicator())), | 
					
						
							| 
									
										
										
										
											2022-07-29 12:03:24 +08:00
										 |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         actions: [ | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |           TextButton(onPressed: close, child: Text(translate("Cancel"))), | 
					
						
							|  |  |  |           TextButton(onPressed: submit, child: Text(translate("OK"))), | 
					
						
							| 
									
										
										
										
											2022-07-29 12:03:24 +08:00
										 |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         onSubmit: submit, | 
					
						
							|  |  |  |         onCancel: close, | 
					
						
							| 
									
										
										
										
											2022-07-29 12:03:24 +08:00
										 |  |  |       ); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void update() { | 
					
						
							|  |  |  |     switch (cardType) { | 
					
						
							|  |  |  |       case CardType.recent: | 
					
						
							|  |  |  |         bind.mainLoadRecentPeers(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case CardType.fav: | 
					
						
							|  |  |  |         bind.mainLoadFavPeers(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case CardType.lan: | 
					
						
							|  |  |  |         bind.mainLoadLanPeers(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case CardType.ab: | 
					
						
							|  |  |  |         gFFI.abModel.pullAb(); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       case CardType.grp: | 
					
						
							|  |  |  |         gFFI.groupModel.pull(); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  | class RecentPeerCard extends BasePeerCard { | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |   RecentPeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |       : super( | 
					
						
							|  |  |  |             peer: peer, | 
					
						
							|  |  |  |             cardType: CardType.recent, | 
					
						
							|  |  |  |             menuPadding: menuPadding, | 
					
						
							|  |  |  |             key: key); | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |   Future<List<MenuEntryBase<String>>> _buildMenuItems( | 
					
						
							|  |  |  |       BuildContext context) async { | 
					
						
							|  |  |  |     final List<MenuEntryBase<String>> menuItems = [ | 
					
						
							| 
									
										
										
										
											2022-09-21 21:20:19 +08:00
										 |  |  |       _connectAction(context, peer), | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       _transferFileAction(context, peer.id), | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |     ]; | 
					
						
							| 
									
										
										
										
											2022-09-29 21:58:11 +08:00
										 |  |  |     if (isDesktop && peer.platform != 'Android') { | 
					
						
							| 
									
										
										
										
											2022-09-22 16:45:14 +08:00
										 |  |  |       menuItems.add(_tcpTunnelingAction(context, peer.id)); | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     menuItems.add(await _forceAlwaysRelayAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-09-22 16:45:14 +08:00
										 |  |  |     if (peer.platform == 'Windows') { | 
					
						
							|  |  |  |       menuItems.add(_rdpAction(context, peer.id)); | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     menuItems.add(_wolAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-11-14 15:41:43 +08:00
										 |  |  |     if (Platform.isWindows) { | 
					
						
							|  |  |  |       menuItems.add(_createShortCutAction(peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |     menuItems.add(MenuEntryDivider()); | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |     menuItems.add(_renameAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-09-01 06:18:29 -07:00
										 |  |  |     menuItems.add(_removeAction(peer.id, () async { | 
					
						
							|  |  |  |       await bind.mainLoadRecentPeers(); | 
					
						
							|  |  |  |     })); | 
					
						
							| 
									
										
										
										
											2022-09-25 21:03:19 +08:00
										 |  |  |     if (await bind.mainPeerHasPassword(id: peer.id)) { | 
					
						
							|  |  |  |       menuItems.add(_unrememberPasswordAction(peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     menuItems.add(_addFavAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-11-27 12:16:45 +08:00
										 |  |  |     if (!gFFI.abModel.idContainBy(peer.id)) { | 
					
						
							|  |  |  |       menuItems.add(_addToAb(peer)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     return menuItems; | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FavoritePeerCard extends BasePeerCard { | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |   FavoritePeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |       : super( | 
					
						
							|  |  |  |             peer: peer, | 
					
						
							|  |  |  |             cardType: CardType.fav, | 
					
						
							|  |  |  |             menuPadding: menuPadding, | 
					
						
							|  |  |  |             key: key); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Future<List<MenuEntryBase<String>>> _buildMenuItems( | 
					
						
							|  |  |  |       BuildContext context) async { | 
					
						
							|  |  |  |     final List<MenuEntryBase<String>> menuItems = [ | 
					
						
							| 
									
										
										
										
											2022-09-21 21:20:19 +08:00
										 |  |  |       _connectAction(context, peer), | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       _transferFileAction(context, peer.id), | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |     ]; | 
					
						
							| 
									
										
										
										
											2022-09-29 21:58:11 +08:00
										 |  |  |     if (isDesktop && peer.platform != 'Android') { | 
					
						
							| 
									
										
										
										
											2022-09-22 16:45:14 +08:00
										 |  |  |       menuItems.add(_tcpTunnelingAction(context, peer.id)); | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     menuItems.add(await _forceAlwaysRelayAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-09-22 16:45:14 +08:00
										 |  |  |     if (peer.platform == 'Windows') { | 
					
						
							|  |  |  |       menuItems.add(_rdpAction(context, peer.id)); | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     menuItems.add(_wolAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-11-14 15:41:43 +08:00
										 |  |  |     if (Platform.isWindows) { | 
					
						
							|  |  |  |       menuItems.add(_createShortCutAction(peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |     menuItems.add(MenuEntryDivider()); | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |     menuItems.add(_renameAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-09-01 06:18:29 -07:00
										 |  |  |     menuItems.add(_removeAction(peer.id, () async { | 
					
						
							|  |  |  |       await bind.mainLoadFavPeers(); | 
					
						
							|  |  |  |     })); | 
					
						
							| 
									
										
										
										
											2022-09-25 21:03:19 +08:00
										 |  |  |     if (await bind.mainPeerHasPassword(id: peer.id)) { | 
					
						
							|  |  |  |       menuItems.add(_unrememberPasswordAction(peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-14 22:22:23 -07:00
										 |  |  |     menuItems.add(_rmFavAction(peer.id, () async { | 
					
						
							|  |  |  |       await bind.mainLoadFavPeers(); | 
					
						
							|  |  |  |     })); | 
					
						
							| 
									
										
										
										
											2022-11-27 12:16:45 +08:00
										 |  |  |     if (!gFFI.abModel.idContainBy(peer.id)) { | 
					
						
							|  |  |  |       menuItems.add(_addToAb(peer)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     return menuItems; | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DiscoveredPeerCard extends BasePeerCard { | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |   DiscoveredPeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |       : super( | 
					
						
							|  |  |  |             peer: peer, | 
					
						
							|  |  |  |             cardType: CardType.lan, | 
					
						
							|  |  |  |             menuPadding: menuPadding, | 
					
						
							|  |  |  |             key: key); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Future<List<MenuEntryBase<String>>> _buildMenuItems( | 
					
						
							|  |  |  |       BuildContext context) async { | 
					
						
							|  |  |  |     final List<MenuEntryBase<String>> menuItems = [ | 
					
						
							| 
									
										
										
										
											2022-09-21 21:20:19 +08:00
										 |  |  |       _connectAction(context, peer), | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       _transferFileAction(context, peer.id), | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |     ]; | 
					
						
							| 
									
										
										
										
											2022-09-29 21:58:11 +08:00
										 |  |  |     if (isDesktop && peer.platform != 'Android') { | 
					
						
							| 
									
										
										
										
											2022-09-22 16:45:14 +08:00
										 |  |  |       menuItems.add(_tcpTunnelingAction(context, peer.id)); | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     menuItems.add(await _forceAlwaysRelayAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-09-22 16:45:14 +08:00
										 |  |  |     if (peer.platform == 'Windows') { | 
					
						
							|  |  |  |       menuItems.add(_rdpAction(context, peer.id)); | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     menuItems.add(_wolAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-11-14 15:41:43 +08:00
										 |  |  |     if (Platform.isWindows) { | 
					
						
							|  |  |  |       menuItems.add(_createShortCutAction(peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |     menuItems.add(MenuEntryDivider()); | 
					
						
							| 
									
										
										
										
											2022-09-25 21:03:19 +08:00
										 |  |  |     menuItems.add(_removeAction(peer.id, () async {})); | 
					
						
							| 
									
										
										
										
											2022-11-27 12:16:45 +08:00
										 |  |  |     if (!gFFI.abModel.idContainBy(peer.id)) { | 
					
						
							|  |  |  |       menuItems.add(_addToAb(peer)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     return menuItems; | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class AddressBookPeerCard extends BasePeerCard { | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |   AddressBookPeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |       : super( | 
					
						
							|  |  |  |             peer: peer, | 
					
						
							|  |  |  |             cardType: CardType.ab, | 
					
						
							|  |  |  |             menuPadding: menuPadding, | 
					
						
							|  |  |  |             key: key); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Future<List<MenuEntryBase<String>>> _buildMenuItems( | 
					
						
							|  |  |  |       BuildContext context) async { | 
					
						
							|  |  |  |     final List<MenuEntryBase<String>> menuItems = [ | 
					
						
							| 
									
										
										
										
											2022-09-21 21:20:19 +08:00
										 |  |  |       _connectAction(context, peer), | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       _transferFileAction(context, peer.id), | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  |     ]; | 
					
						
							| 
									
										
										
										
											2022-09-29 21:58:11 +08:00
										 |  |  |     if (isDesktop && peer.platform != 'Android') { | 
					
						
							| 
									
										
										
										
											2022-09-22 16:45:14 +08:00
										 |  |  |       menuItems.add(_tcpTunnelingAction(context, peer.id)); | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     menuItems.add(await _forceAlwaysRelayAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-09-22 16:45:14 +08:00
										 |  |  |     if (peer.platform == 'Windows') { | 
					
						
							|  |  |  |       menuItems.add(_rdpAction(context, peer.id)); | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     menuItems.add(_wolAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-11-14 15:41:43 +08:00
										 |  |  |     if (Platform.isWindows) { | 
					
						
							|  |  |  |       menuItems.add(_createShortCutAction(peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |     menuItems.add(MenuEntryDivider()); | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |     menuItems.add(_renameAction(peer.id)); | 
					
						
							| 
									
										
										
										
											2022-09-01 06:18:29 -07:00
										 |  |  |     menuItems.add(_removeAction(peer.id, () async {})); | 
					
						
							| 
									
										
										
										
											2022-09-25 21:03:19 +08:00
										 |  |  |     if (await bind.mainPeerHasPassword(id: peer.id)) { | 
					
						
							|  |  |  |       menuItems.add(_unrememberPasswordAction(peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-10-08 17:39:05 +09:00
										 |  |  |     if (gFFI.abModel.tags.isNotEmpty) { | 
					
						
							|  |  |  |       menuItems.add(_editTagAction(peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     return menuItems; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @protected | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-09-01 06:18:29 -07:00
										 |  |  |   MenuEntryBase<String> _removeAction( | 
					
						
							| 
									
										
										
										
											2022-09-25 21:03:19 +08:00
										 |  |  |       String id, Future<void> Function() reloadFunc, | 
					
						
							|  |  |  |       {bool isLan = false}) { | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |     return MenuEntryButton<String>( | 
					
						
							|  |  |  |       childBuilder: (TextStyle? style) => Text( | 
					
						
							|  |  |  |         translate('Remove'), | 
					
						
							|  |  |  |         style: style, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       proc: () { | 
					
						
							|  |  |  |         () async { | 
					
						
							|  |  |  |           gFFI.abModel.deletePeer(id); | 
					
						
							| 
									
										
										
										
											2022-10-08 17:13:24 +09:00
										 |  |  |           await gFFI.abModel.pushAb(); | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |         }(); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       padding: super.menuPadding, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       dismissOnClicked: true, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @protected | 
					
						
							|  |  |  |   MenuEntryBase<String> _editTagAction(String id) { | 
					
						
							|  |  |  |     return MenuEntryButton<String>( | 
					
						
							|  |  |  |       childBuilder: (TextStyle? style) => Text( | 
					
						
							|  |  |  |         translate('Edit Tag'), | 
					
						
							|  |  |  |         style: style, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       proc: () { | 
					
						
							|  |  |  |         _abEditTag(id); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2022-09-23 12:20:40 +08:00
										 |  |  |       padding: super.menuPadding, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       dismissOnClicked: true, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void _abEditTag(String id) { | 
					
						
							|  |  |  |     var isInProgress = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     final tags = List.of(gFFI.abModel.tags); | 
					
						
							|  |  |  |     var selectedTag = gFFI.abModel.getPeerTags(id).obs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     gFFI.dialogManager.show((setState, close) { | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       submit() async { | 
					
						
							|  |  |  |         setState(() { | 
					
						
							|  |  |  |           isInProgress = true; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         gFFI.abModel.changeTagForPeer(id, selectedTag); | 
					
						
							| 
									
										
										
										
											2022-10-08 17:13:24 +09:00
										 |  |  |         await gFFI.abModel.pushAb(); | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         close(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       return CustomAlertDialog( | 
					
						
							|  |  |  |         title: Text(translate("Edit Tag")), | 
					
						
							|  |  |  |         content: Column( | 
					
						
							|  |  |  |           crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             Container( | 
					
						
							| 
									
										
										
										
											2022-10-08 17:39:05 +09:00
										 |  |  |               padding: const EdgeInsets.symmetric(vertical: 8.0), | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |               child: Wrap( | 
					
						
							|  |  |  |                 children: tags | 
					
						
							| 
									
										
										
										
											2022-10-08 17:39:05 +09:00
										 |  |  |                     .map((e) => AddressBookTag( | 
					
						
							|  |  |  |                         name: e, | 
					
						
							|  |  |  |                         tags: selectedTag, | 
					
						
							|  |  |  |                         onTap: () { | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |                           if (selectedTag.contains(e)) { | 
					
						
							|  |  |  |                             selectedTag.remove(e); | 
					
						
							|  |  |  |                           } else { | 
					
						
							|  |  |  |                             selectedTag.add(e); | 
					
						
							|  |  |  |                           } | 
					
						
							| 
									
										
										
										
											2022-10-08 17:39:05 +09:00
										 |  |  |                         }, | 
					
						
							| 
									
										
										
										
											2022-10-08 19:52:02 +09:00
										 |  |  |                         showActionMenu: false)) | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |                     .toList(growable: false), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |             Offstage( | 
					
						
							|  |  |  |                 offstage: !isInProgress, child: const LinearProgressIndicator()) | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         actions: [ | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |           TextButton(onPressed: close, child: Text(translate("Cancel"))), | 
					
						
							|  |  |  |           TextButton(onPressed: submit, child: Text(translate("OK"))), | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         onSubmit: submit, | 
					
						
							|  |  |  |         onCancel: close, | 
					
						
							| 
									
										
										
										
											2022-09-01 03:56:12 -07:00
										 |  |  |       ); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-08-25 14:35:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  | class MyGroupPeerCard extends BasePeerCard { | 
					
						
							|  |  |  |   MyGroupPeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) | 
					
						
							|  |  |  |       : super( | 
					
						
							|  |  |  |             peer: peer, | 
					
						
							|  |  |  |             cardType: CardType.grp, | 
					
						
							|  |  |  |             menuPadding: menuPadding, | 
					
						
							|  |  |  |             key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Future<List<MenuEntryBase<String>>> _buildMenuItems( | 
					
						
							|  |  |  |       BuildContext context) async { | 
					
						
							|  |  |  |     final List<MenuEntryBase<String>> menuItems = [ | 
					
						
							|  |  |  |       _connectAction(context, peer), | 
					
						
							|  |  |  |       _transferFileAction(context, peer.id), | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |     if (isDesktop && peer.platform != 'Android') { | 
					
						
							|  |  |  |       menuItems.add(_tcpTunnelingAction(context, peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     menuItems.add(await _forceAlwaysRelayAction(peer.id)); | 
					
						
							|  |  |  |     if (peer.platform == 'Windows') { | 
					
						
							|  |  |  |       menuItems.add(_rdpAction(context, peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     menuItems.add(_wolAction(peer.id)); | 
					
						
							|  |  |  |     if (Platform.isWindows) { | 
					
						
							|  |  |  |       menuItems.add(_createShortCutAction(peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     menuItems.add(MenuEntryDivider()); | 
					
						
							|  |  |  |     menuItems.add(_renameAction(peer.id)); | 
					
						
							|  |  |  |     if (await bind.mainPeerHasPassword(id: peer.id)) { | 
					
						
							|  |  |  |       menuItems.add(_unrememberPasswordAction(peer.id)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return menuItems; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  | void _rdpDialog(String id, CardType card) async { | 
					
						
							|  |  |  |   String port, username; | 
					
						
							|  |  |  |   if (card == CardType.ab) { | 
					
						
							|  |  |  |     port = gFFI.abModel.find(id)?.rdpPort ?? ''; | 
					
						
							|  |  |  |     username = gFFI.abModel.find(id)?.rdpUsername ?? ''; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     port = await bind.mainGetPeerOption(id: id, key: 'rdp_port'); | 
					
						
							|  |  |  |     username = await bind.mainGetPeerOption(id: id, key: 'rdp_username'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   final portController = TextEditingController(text: port); | 
					
						
							|  |  |  |   final userController = TextEditingController(text: username); | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  |   final passwordController = TextEditingController( | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |       text: await bind.mainGetPeerOption(id: id, key: 'rdp_password')); | 
					
						
							|  |  |  |   RxBool secure = true.obs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   gFFI.dialogManager.show((setState, close) { | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |     submit() async { | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |       String port = portController.text.trim(); | 
					
						
							|  |  |  |       String username = userController.text; | 
					
						
							|  |  |  |       String password = passwordController.text; | 
					
						
							|  |  |  |       await bind.mainSetPeerOption(id: id, key: 'rdp_port', value: port); | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       await bind.mainSetPeerOption( | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |           id: id, key: 'rdp_username', value: username); | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       await bind.mainSetPeerOption( | 
					
						
							| 
									
										
										
										
											2022-11-28 18:16:29 +08:00
										 |  |  |           id: id, key: 'rdp_password', value: password); | 
					
						
							|  |  |  |       gFFI.abModel.setRdp(id, port, username); | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       close(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |     return CustomAlertDialog( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       title: Text('RDP ${translate('Settings')}'), | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |       content: ConstrainedBox( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         constraints: const BoxConstraints(minWidth: 500), | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |         child: Column( | 
					
						
							|  |  |  |           crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |           children: [ | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |             const SizedBox( | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |               height: 8.0, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             Row( | 
					
						
							|  |  |  |               children: [ | 
					
						
							|  |  |  |                 ConstrainedBox( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                     constraints: const BoxConstraints(minWidth: 100), | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |                     child: Text( | 
					
						
							|  |  |  |                       "${translate('Port')}:", | 
					
						
							|  |  |  |                       textAlign: TextAlign.start, | 
					
						
							|  |  |  |                     ).marginOnly(bottom: 16.0)), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                 const SizedBox( | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |                   width: 24.0, | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 Expanded( | 
					
						
							|  |  |  |                   child: TextField( | 
					
						
							|  |  |  |                     inputFormatters: [ | 
					
						
							|  |  |  |                       FilteringTextInputFormatter.allow(RegExp( | 
					
						
							|  |  |  |                           r'^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$')) | 
					
						
							|  |  |  |                     ], | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                     decoration: const InputDecoration( | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |                         border: OutlineInputBorder(), hintText: '3389'), | 
					
						
							|  |  |  |                     controller: portController, | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                     focusNode: FocusNode()..requestFocus(), | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |                   ), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |             const SizedBox( | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |               height: 8.0, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             Row( | 
					
						
							|  |  |  |               children: [ | 
					
						
							|  |  |  |                 ConstrainedBox( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                     constraints: const BoxConstraints(minWidth: 100), | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |                     child: Text( | 
					
						
							|  |  |  |                       "${translate('Username')}:", | 
					
						
							|  |  |  |                       textAlign: TextAlign.start, | 
					
						
							|  |  |  |                     ).marginOnly(bottom: 16.0)), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                 const SizedBox( | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |                   width: 24.0, | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 Expanded( | 
					
						
							|  |  |  |                   child: TextField( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                     decoration: | 
					
						
							|  |  |  |                         const InputDecoration(border: OutlineInputBorder()), | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |                     controller: userController, | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |             const SizedBox( | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |               height: 8.0, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             Row( | 
					
						
							|  |  |  |               children: [ | 
					
						
							|  |  |  |                 ConstrainedBox( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                     constraints: const BoxConstraints(minWidth: 100), | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |                     child: Text("${translate('Password')}:") | 
					
						
							|  |  |  |                         .marginOnly(bottom: 16.0)), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                 const SizedBox( | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |                   width: 24.0, | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 Expanded( | 
					
						
							|  |  |  |                   child: Obx(() => TextField( | 
					
						
							|  |  |  |                         obscureText: secure.value, | 
					
						
							|  |  |  |                         decoration: InputDecoration( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                             border: const OutlineInputBorder(), | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |                             suffixIcon: IconButton( | 
					
						
							|  |  |  |                                 onPressed: () => secure.value = !secure.value, | 
					
						
							|  |  |  |                                 icon: Icon(secure.value | 
					
						
							|  |  |  |                                     ? Icons.visibility_off | 
					
						
							|  |  |  |                                     : Icons.visibility))), | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  |                         controller: passwordController, | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |                       )), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       actions: [ | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         TextButton(onPressed: close, child: Text(translate("Cancel"))), | 
					
						
							|  |  |  |         TextButton(onPressed: submit, child: Text(translate("OK"))), | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |       ], | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       onSubmit: submit, | 
					
						
							|  |  |  |       onCancel: close, | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-09-23 15:12:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-25 21:15:00 +08:00
										 |  |  | Widget getOnline(double rightPadding, bool online) { | 
					
						
							| 
									
										
										
										
											2022-09-23 15:12:50 +08:00
										 |  |  |   return Tooltip( | 
					
						
							|  |  |  |       message: translate(online ? 'Online' : 'Offline'), | 
					
						
							|  |  |  |       waitDuration: const Duration(seconds: 1), | 
					
						
							|  |  |  |       child: Padding( | 
					
						
							| 
									
										
										
										
											2022-09-25 21:15:00 +08:00
										 |  |  |           padding: EdgeInsets.fromLTRB(0, 4, rightPadding, 4), | 
					
						
							| 
									
										
										
										
											2022-09-23 15:12:50 +08:00
										 |  |  |           child: CircleAvatar( | 
					
						
							|  |  |  |               radius: 3, backgroundColor: online ? Colors.green : kColorWarn))); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-10-08 19:28:20 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | class ActionMore extends StatelessWidget { | 
					
						
							|  |  |  |   final RxBool _iconMoreHover = false.obs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return MouseRegion( | 
					
						
							|  |  |  |         onEnter: (_) => _iconMoreHover.value = true, | 
					
						
							|  |  |  |         onExit: (_) => _iconMoreHover.value = false, | 
					
						
							|  |  |  |         child: Obx(() => CircleAvatar( | 
					
						
							|  |  |  |             radius: 14, | 
					
						
							|  |  |  |             backgroundColor: _iconMoreHover.value | 
					
						
							|  |  |  |                 ? Theme.of(context).scaffoldBackgroundColor | 
					
						
							|  |  |  |                 : Theme.of(context).backgroundColor, | 
					
						
							|  |  |  |             child: Icon(Icons.more_vert, | 
					
						
							|  |  |  |                 size: 18, | 
					
						
							|  |  |  |                 color: _iconMoreHover.value | 
					
						
							|  |  |  |                     ? Theme.of(context).textTheme.titleLarge?.color | 
					
						
							|  |  |  |                     : Theme.of(context) | 
					
						
							|  |  |  |                         .textTheme | 
					
						
							|  |  |  |                         .titleLarge | 
					
						
							|  |  |  |                         ?.color | 
					
						
							|  |  |  |                         ?.withOpacity(0.5))))); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |