| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							| 
									
										
										
										
											2022-07-22 23:12:31 +08:00
										 |  |  | import 'dart:convert'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  | import 'package:contextmenu/contextmenu.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  | import 'package:flutter_hbb/desktop/pages/desktop_home_page.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-27 22:56:28 +08:00
										 |  |  | import 'package:flutter_hbb/desktop/widgets/peer_widget.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  | import 'package:flutter_hbb/desktop/widgets/peercard_widget.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | import 'package:flutter_hbb/utils/multi_window_manager.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  | import 'package:url_launcher/url_launcher_string.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  | import '../../common.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-02 17:19:44 +08:00
										 |  |  | import '../../common/formatter/id_formatter.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  | import '../../models/platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /// Connection page for connecting to a remote peer.
 | 
					
						
							| 
									
										
										
										
											2022-08-09 20:36:52 +08:00
										 |  |  | class ConnectionPage extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |   const ConnectionPage({Key? key}) : super(key: key); | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |   State<ConnectionPage> createState() => _ConnectionPageState(); | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /// State for the connection page.
 | 
					
						
							|  |  |  | class _ConnectionPageState extends State<ConnectionPage> { | 
					
						
							|  |  |  |   /// Controller for the id input bar.
 | 
					
						
							| 
									
										
										
										
											2022-09-02 17:19:44 +08:00
										 |  |  |   final _idController = IDTextEditingController(); | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |   Timer? _updateTimer; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							| 
									
										
										
										
											2022-08-08 17:53:51 +08:00
										 |  |  |     if (_idController.text.isEmpty) { | 
					
						
							|  |  |  |       () async { | 
					
						
							|  |  |  |         final lastRemoteId = await bind.mainGetLastRemoteId(); | 
					
						
							| 
									
										
										
										
											2022-09-02 17:19:44 +08:00
										 |  |  |         if (lastRemoteId != _idController.id) { | 
					
						
							| 
									
										
										
										
											2022-08-08 17:53:51 +08:00
										 |  |  |           setState(() { | 
					
						
							| 
									
										
										
										
											2022-09-02 17:19:44 +08:00
										 |  |  |             _idController.id = lastRemoteId; | 
					
						
							| 
									
										
										
										
											2022-08-08 17:53:51 +08:00
										 |  |  |           }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |     _updateTimer = Timer.periodic(Duration(seconds: 1), (timer) { | 
					
						
							|  |  |  |       updateStatus(); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |     return Container( | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |       child: Column( | 
					
						
							|  |  |  |           mainAxisAlignment: MainAxisAlignment.start, | 
					
						
							|  |  |  |           mainAxisSize: MainAxisSize.max, | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |           crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |           children: <Widget>[ | 
					
						
							| 
									
										
										
										
											2022-07-22 23:12:31 +08:00
										 |  |  |             Expanded( | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |               child: Column( | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Row( | 
					
						
							|  |  |  |                     children: [ | 
					
						
							|  |  |  |                       getSearchBarUI(context), | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                   ).marginOnly(top: 22), | 
					
						
							|  |  |  |                   SizedBox(height: 12), | 
					
						
							|  |  |  |                   Divider(), | 
					
						
							|  |  |  |                   Expanded( | 
					
						
							|  |  |  |                       child: _PeerTabbedPage( | 
					
						
							|  |  |  |                     tabs: [ | 
					
						
							|  |  |  |                       translate('Recent Sessions'), | 
					
						
							|  |  |  |                       translate('Favorites'), | 
					
						
							|  |  |  |                       translate('Discovered'), | 
					
						
							|  |  |  |                       translate('Address Book') | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                     children: [ | 
					
						
							|  |  |  |                       RecentPeerWidget(), | 
					
						
							|  |  |  |                       FavoritePeerWidget(), | 
					
						
							|  |  |  |                       DiscoveredPeerWidget(), | 
					
						
							|  |  |  |                       FutureBuilder<Widget>( | 
					
						
							|  |  |  |                           future: buildAddressBook(context), | 
					
						
							|  |  |  |                           builder: (context, snapshot) { | 
					
						
							|  |  |  |                             if (snapshot.hasData) { | 
					
						
							|  |  |  |                               return snapshot.data!; | 
					
						
							|  |  |  |                             } else { | 
					
						
							| 
									
										
										
										
											2022-09-01 06:18:29 -07:00
										 |  |  |                               return const Offstage(); | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |                             } | 
					
						
							|  |  |  |                           }), | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                   )), | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               ).marginSymmetric(horizontal: 22), | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |             const Divider(), | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |             SizedBox(height: 50, child: Obx(() => buildStatus())) | 
					
						
							|  |  |  |                 .paddingSymmetric(horizontal: 12.0) | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |           ]), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Callback for the connect button.
 | 
					
						
							|  |  |  |   /// Connects to the selected peer.
 | 
					
						
							| 
									
										
										
										
											2022-05-30 13:25:06 +08:00
										 |  |  |   void onConnect({bool isFileTransfer = false}) { | 
					
						
							| 
									
										
										
										
											2022-09-02 17:19:44 +08:00
										 |  |  |     final id = _idController.id; | 
					
						
							| 
									
										
										
										
											2022-05-30 13:25:06 +08:00
										 |  |  |     connect(id, isFileTransfer: isFileTransfer); | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Connect to a peer with [id].
 | 
					
						
							|  |  |  |   /// If [isFileTransfer], starts a session only for file transfer.
 | 
					
						
							|  |  |  |   void connect(String id, {bool isFileTransfer = false}) async { | 
					
						
							|  |  |  |     if (id == '') return; | 
					
						
							|  |  |  |     id = id.replaceAll(' ', ''); | 
					
						
							|  |  |  |     if (isFileTransfer) { | 
					
						
							| 
									
										
										
										
											2022-09-01 06:18:29 -07:00
										 |  |  |       await rustDeskWinManager.newFileTransfer(id); | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-09-01 06:18:29 -07:00
										 |  |  |       await rustDeskWinManager.newRemoteDesktop(id); | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     FocusScopeNode currentFocus = FocusScope.of(context); | 
					
						
							|  |  |  |     if (!currentFocus.hasPrimaryFocus) { | 
					
						
							|  |  |  |       currentFocus.unfocus(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// UI for the search bar.
 | 
					
						
							|  |  |  |   /// Search for a peer and connect to it if the id exists.
 | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |   Widget getSearchBarUI(BuildContext context) { | 
					
						
							|  |  |  |     RxBool ftHover = false.obs; | 
					
						
							|  |  |  |     RxBool ftPressed = false.obs; | 
					
						
							|  |  |  |     RxBool connHover = false.obs; | 
					
						
							|  |  |  |     RxBool connPressed = false.obs; | 
					
						
							| 
									
										
										
										
											2022-08-23 19:55:58 +08:00
										 |  |  |     RxBool inputFocused = false.obs; | 
					
						
							|  |  |  |     FocusNode focusNode = FocusNode(); | 
					
						
							|  |  |  |     focusNode.addListener(() { | 
					
						
							|  |  |  |       inputFocused.value = focusNode.hasFocus; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |     var w = Container( | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |       width: 320 + 20 * 2, | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       padding: const EdgeInsets.fromLTRB(20, 24, 20, 22), | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |       decoration: BoxDecoration( | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |         color: MyTheme.color(context).bg, | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |         borderRadius: const BorderRadius.all(Radius.circular(13)), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       child: Ink( | 
					
						
							|  |  |  |         child: Column( | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             Row( | 
					
						
							| 
									
										
										
										
											2022-08-23 19:55:58 +08:00
										 |  |  |               children: [ | 
					
						
							|  |  |  |                 Text( | 
					
						
							|  |  |  |                   translate('Control Remote Desktop'), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                   style: const TextStyle(fontSize: 19, height: 1), | 
					
						
							| 
									
										
										
										
											2022-08-23 19:55:58 +08:00
										 |  |  |                 ), | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ).marginOnly(bottom: 15), | 
					
						
							|  |  |  |             Row( | 
					
						
							|  |  |  |               children: [ | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |                 Expanded( | 
					
						
							| 
									
										
										
										
											2022-09-02 17:19:44 +08:00
										 |  |  |                   child: Obx( | 
					
						
							|  |  |  |                     () => TextField( | 
					
						
							|  |  |  |                       autocorrect: false, | 
					
						
							|  |  |  |                       enableSuggestions: false, | 
					
						
							|  |  |  |                       keyboardType: TextInputType.visiblePassword, | 
					
						
							|  |  |  |                       focusNode: focusNode, | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                       style: const TextStyle( | 
					
						
							| 
									
										
										
										
											2022-09-02 17:19:44 +08:00
										 |  |  |                         fontFamily: 'WorkSans', | 
					
						
							|  |  |  |                         fontSize: 22, | 
					
						
							|  |  |  |                         height: 1, | 
					
						
							|  |  |  |                       ), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                       maxLines: 1, | 
					
						
							|  |  |  |                       cursorColor: MyTheme.color(context).text!, | 
					
						
							| 
									
										
										
										
											2022-09-02 17:19:44 +08:00
										 |  |  |                       decoration: InputDecoration( | 
					
						
							|  |  |  |                           hintText: inputFocused.value | 
					
						
							|  |  |  |                               ? null | 
					
						
							|  |  |  |                               : translate('Enter Remote ID'), | 
					
						
							|  |  |  |                           hintStyle: TextStyle( | 
					
						
							|  |  |  |                               color: MyTheme.color(context).placeholder), | 
					
						
							|  |  |  |                           border: OutlineInputBorder( | 
					
						
							|  |  |  |                               borderRadius: BorderRadius.zero, | 
					
						
							|  |  |  |                               borderSide: BorderSide( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                                   color: MyTheme.color(context).border!)), | 
					
						
							|  |  |  |                           enabledBorder: OutlineInputBorder( | 
					
						
							|  |  |  |                               borderRadius: BorderRadius.zero, | 
					
						
							|  |  |  |                               borderSide: BorderSide( | 
					
						
							|  |  |  |                                   color: MyTheme.color(context).border!)), | 
					
						
							|  |  |  |                           focusedBorder: const OutlineInputBorder( | 
					
						
							| 
									
										
										
										
											2022-08-23 19:55:58 +08:00
										 |  |  |                             borderRadius: BorderRadius.zero, | 
					
						
							| 
									
										
										
										
											2022-09-02 17:19:44 +08:00
										 |  |  |                             borderSide: | 
					
						
							|  |  |  |                                 BorderSide(color: MyTheme.button, width: 3), | 
					
						
							|  |  |  |                           ), | 
					
						
							|  |  |  |                           isDense: true, | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                           contentPadding: const EdgeInsets.symmetric( | 
					
						
							| 
									
										
										
										
											2022-09-02 17:19:44 +08:00
										 |  |  |                               horizontal: 10, vertical: 12)), | 
					
						
							|  |  |  |                       controller: _idController, | 
					
						
							|  |  |  |                       inputFormatters: [IDTextInputFormatter()], | 
					
						
							|  |  |  |                       onSubmitted: (s) { | 
					
						
							|  |  |  |                         onConnect(); | 
					
						
							|  |  |  |                       }, | 
					
						
							|  |  |  |                     ), | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |                   ), | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             Padding( | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |               padding: const EdgeInsets.only(top: 13.0), | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |               child: Row( | 
					
						
							|  |  |  |                 mainAxisAlignment: MainAxisAlignment.end, | 
					
						
							|  |  |  |                 children: [ | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |                   Obx(() => InkWell( | 
					
						
							|  |  |  |                         onTapDown: (_) => ftPressed.value = true, | 
					
						
							|  |  |  |                         onTapUp: (_) => ftPressed.value = false, | 
					
						
							|  |  |  |                         onTapCancel: () => ftPressed.value = false, | 
					
						
							|  |  |  |                         onHover: (value) => ftHover.value = value, | 
					
						
							|  |  |  |                         onTap: () { | 
					
						
							|  |  |  |                           onConnect(isFileTransfer: true); | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                         child: Container( | 
					
						
							|  |  |  |                           height: 24, | 
					
						
							|  |  |  |                           alignment: Alignment.center, | 
					
						
							|  |  |  |                           decoration: BoxDecoration( | 
					
						
							|  |  |  |                             color: ftPressed.value | 
					
						
							|  |  |  |                                 ? MyTheme.accent | 
					
						
							|  |  |  |                                 : Colors.transparent, | 
					
						
							|  |  |  |                             border: Border.all( | 
					
						
							|  |  |  |                               color: ftPressed.value | 
					
						
							|  |  |  |                                   ? MyTheme.accent | 
					
						
							|  |  |  |                                   : ftHover.value | 
					
						
							|  |  |  |                                       ? MyTheme.hoverBorder | 
					
						
							|  |  |  |                                       : MyTheme.border, | 
					
						
							|  |  |  |                             ), | 
					
						
							|  |  |  |                             borderRadius: BorderRadius.circular(5), | 
					
						
							|  |  |  |                           ), | 
					
						
							|  |  |  |                           child: Text( | 
					
						
							|  |  |  |                             translate( | 
					
						
							|  |  |  |                               "Transfer File", | 
					
						
							|  |  |  |                             ), | 
					
						
							|  |  |  |                             style: TextStyle( | 
					
						
							|  |  |  |                                 fontSize: 12, | 
					
						
							|  |  |  |                                 color: ftPressed.value | 
					
						
							|  |  |  |                                     ? MyTheme.color(context).bg | 
					
						
							|  |  |  |                                     : MyTheme.color(context).text), | 
					
						
							| 
									
										
										
										
											2022-08-29 19:28:00 +08:00
										 |  |  |                           ).marginSymmetric(horizontal: 12), | 
					
						
							| 
									
										
										
										
											2022-05-30 13:25:06 +08:00
										 |  |  |                         ), | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |                       )), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                   const SizedBox( | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |                     width: 17, | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |                   ), | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |                   Obx( | 
					
						
							|  |  |  |                     () => InkWell( | 
					
						
							|  |  |  |                       onTapDown: (_) => connPressed.value = true, | 
					
						
							|  |  |  |                       onTapUp: (_) => connPressed.value = false, | 
					
						
							|  |  |  |                       onTapCancel: () => connPressed.value = false, | 
					
						
							|  |  |  |                       onHover: (value) => connHover.value = value, | 
					
						
							|  |  |  |                       onTap: onConnect, | 
					
						
							|  |  |  |                       child: Container( | 
					
						
							|  |  |  |                         height: 24, | 
					
						
							|  |  |  |                         decoration: BoxDecoration( | 
					
						
							|  |  |  |                           color: connPressed.value | 
					
						
							|  |  |  |                               ? MyTheme.accent | 
					
						
							|  |  |  |                               : MyTheme.button, | 
					
						
							|  |  |  |                           border: Border.all( | 
					
						
							|  |  |  |                             color: connPressed.value | 
					
						
							|  |  |  |                                 ? MyTheme.accent | 
					
						
							|  |  |  |                                 : connHover.value | 
					
						
							|  |  |  |                                     ? MyTheme.hoverBorder | 
					
						
							|  |  |  |                                     : MyTheme.button, | 
					
						
							|  |  |  |                           ), | 
					
						
							|  |  |  |                           borderRadius: BorderRadius.circular(5), | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                         child: Center( | 
					
						
							|  |  |  |                           child: Text( | 
					
						
							|  |  |  |                             translate( | 
					
						
							| 
									
										
										
										
											2022-08-29 19:28:00 +08:00
										 |  |  |                               "Connect", | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |                             ), | 
					
						
							|  |  |  |                             style: TextStyle( | 
					
						
							|  |  |  |                                 fontSize: 12, color: MyTheme.color(context).bg), | 
					
						
							|  |  |  |                           ), | 
					
						
							| 
									
										
										
										
											2022-08-29 19:28:00 +08:00
										 |  |  |                         ).marginSymmetric(horizontal: 12), | 
					
						
							| 
									
										
										
										
											2022-05-30 13:25:06 +08:00
										 |  |  |                       ), | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |                     ), | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |                   ), | 
					
						
							| 
									
										
										
										
											2022-07-14 12:32:01 +08:00
										 |  |  |                 ], | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |           ], | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     return Center( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         child: Container( | 
					
						
							|  |  |  |             constraints: const BoxConstraints(maxWidth: 600), child: w)); | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							|  |  |  |     _idController.dispose(); | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |     _updateTimer?.cancel(); | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |   var svcStopped = false.obs; | 
					
						
							|  |  |  |   var svcStatusCode = 0.obs; | 
					
						
							|  |  |  |   var svcIsUsingPublicServer = true.obs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget buildStatus() { | 
					
						
							|  |  |  |     final light = Container( | 
					
						
							|  |  |  |       height: 8, | 
					
						
							|  |  |  |       width: 8, | 
					
						
							|  |  |  |       decoration: BoxDecoration( | 
					
						
							|  |  |  |         borderRadius: BorderRadius.circular(20), | 
					
						
							| 
									
										
										
										
											2022-08-09 20:50:45 +08:00
										 |  |  |         color: svcStopped.value ? Colors.redAccent : Colors.green, | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |       ), | 
					
						
							| 
									
										
										
										
											2022-08-09 20:50:45 +08:00
										 |  |  |     ).paddingSymmetric(horizontal: 10.0); | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |     if (svcStopped.value) { | 
					
						
							|  |  |  |       return Row( | 
					
						
							|  |  |  |         crossAxisAlignment: CrossAxisAlignment.center, | 
					
						
							| 
									
										
										
										
											2022-08-09 20:50:45 +08:00
										 |  |  |         children: [ | 
					
						
							|  |  |  |           light, | 
					
						
							|  |  |  |           Text(translate("Service is not running")), | 
					
						
							|  |  |  |           TextButton( | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:43 +08:00
										 |  |  |               onPressed: () async { | 
					
						
							|  |  |  |                 bool checked = await bind.mainCheckSuperUserPermission(); | 
					
						
							|  |  |  |                 if (checked) { | 
					
						
							|  |  |  |                   bind.mainSetOption(key: "stop-service", value: ""); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |               }, | 
					
						
							| 
									
										
										
										
											2022-08-09 20:50:45 +08:00
										 |  |  |               child: Text(translate("Start Service"))) | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |       ); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       if (svcStatusCode.value == 0) { | 
					
						
							|  |  |  |         return Row( | 
					
						
							|  |  |  |           crossAxisAlignment: CrossAxisAlignment.center, | 
					
						
							|  |  |  |           children: [light, Text(translate("connecting_status"))], | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       } else if (svcStatusCode.value == -1) { | 
					
						
							|  |  |  |         return Row( | 
					
						
							|  |  |  |           crossAxisAlignment: CrossAxisAlignment.center, | 
					
						
							|  |  |  |           children: [light, Text(translate("not_ready_status"))], | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return Row( | 
					
						
							|  |  |  |       crossAxisAlignment: CrossAxisAlignment.center, | 
					
						
							|  |  |  |       children: [ | 
					
						
							|  |  |  |         light, | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |         Text(translate('Ready')), | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |         svcIsUsingPublicServer.value | 
					
						
							|  |  |  |             ? InkWell( | 
					
						
							|  |  |  |                 onTap: onUsePublicServerGuide, | 
					
						
							|  |  |  |                 child: Text( | 
					
						
							|  |  |  |                   ', ${translate('setup_server_tip')}', | 
					
						
							|  |  |  |                   style: TextStyle(decoration: TextDecoration.underline), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ) | 
					
						
							|  |  |  |             : Offstage() | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void onUsePublicServerGuide() { | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |     const url = "https://rustdesk.com/blog/id-relay-set/"; | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |     canLaunchUrlString(url).then((can) { | 
					
						
							|  |  |  |       if (can) { | 
					
						
							|  |  |  |         launchUrlString(url); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   updateStatus() async { | 
					
						
							| 
									
										
										
										
											2022-08-09 20:50:45 +08:00
										 |  |  |     svcStopped.value = await bind.mainGetOption(key: "stop-service") == "Y"; | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |     final status = | 
					
						
							|  |  |  |         jsonDecode(await bind.mainGetConnectStatus()) as Map<String, dynamic>; | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |     svcStatusCode.value = status["status_num"]; | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |     svcIsUsingPublicServer.value = await bind.mainIsUsingPublicServer(); | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  |   handleLogin() { | 
					
						
							|  |  |  |     loginDialog().then((success) { | 
					
						
							|  |  |  |       if (success) { | 
					
						
							|  |  |  |         setState(() {}); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Future<Widget> buildAddressBook(BuildContext context) async { | 
					
						
							| 
									
										
										
										
											2022-08-08 17:53:51 +08:00
										 |  |  |     final token = await bind.mainGetLocalOption(key: 'access_token'); | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |     if (token.trim().isEmpty) { | 
					
						
							|  |  |  |       return Center( | 
					
						
							|  |  |  |         child: InkWell( | 
					
						
							|  |  |  |           onTap: handleLogin, | 
					
						
							|  |  |  |           child: Text( | 
					
						
							|  |  |  |             translate("Login"), | 
					
						
							|  |  |  |             style: TextStyle(decoration: TextDecoration.underline), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2022-05-29 04:39:12 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |     final model = gFFI.abModel; | 
					
						
							|  |  |  |     return FutureBuilder( | 
					
						
							|  |  |  |         future: model.getAb(), | 
					
						
							|  |  |  |         builder: (context, snapshot) { | 
					
						
							|  |  |  |           if (snapshot.hasData) { | 
					
						
							|  |  |  |             return _buildAddressBook(context); | 
					
						
							| 
									
										
										
										
											2022-07-26 17:14:52 +08:00
										 |  |  |           } else if (snapshot.hasError) { | 
					
						
							|  |  |  |             return Column( | 
					
						
							|  |  |  |               mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |               children: [ | 
					
						
							|  |  |  |                 Text(translate("${snapshot.error}")), | 
					
						
							|  |  |  |                 TextButton( | 
					
						
							|  |  |  |                     onPressed: () { | 
					
						
							|  |  |  |                       setState(() {}); | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     child: Text(translate("Retry"))) | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ); | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |           } else { | 
					
						
							|  |  |  |             if (model.abLoading) { | 
					
						
							| 
									
										
										
										
											2022-09-15 11:06:44 +08:00
										 |  |  |               return const Center( | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |                 child: CircularProgressIndicator(), | 
					
						
							|  |  |  |               ); | 
					
						
							|  |  |  |             } else if (model.abError.isNotEmpty) { | 
					
						
							|  |  |  |               return Center( | 
					
						
							| 
									
										
										
										
											2022-07-26 17:14:52 +08:00
										 |  |  |                 child: Column( | 
					
						
							|  |  |  |                   mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |                   children: [ | 
					
						
							|  |  |  |                     Text(translate("${model.abError}")), | 
					
						
							|  |  |  |                     TextButton( | 
					
						
							|  |  |  |                         onPressed: () { | 
					
						
							|  |  |  |                           setState(() {}); | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                         child: Text(translate("Retry"))) | 
					
						
							|  |  |  |                   ], | 
					
						
							|  |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |               ); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |               return Offstage(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildAddressBook(BuildContext context) { | 
					
						
							|  |  |  |     return Row( | 
					
						
							|  |  |  |       children: [ | 
					
						
							|  |  |  |         Card( | 
					
						
							|  |  |  |           shape: RoundedRectangleBorder( | 
					
						
							|  |  |  |               borderRadius: BorderRadius.circular(20), | 
					
						
							|  |  |  |               side: BorderSide(color: MyTheme.grayBg)), | 
					
						
							|  |  |  |           child: Container( | 
					
						
							|  |  |  |             width: 200, | 
					
						
							|  |  |  |             height: double.infinity, | 
					
						
							|  |  |  |             padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), | 
					
						
							|  |  |  |             child: Column( | 
					
						
							|  |  |  |               children: [ | 
					
						
							|  |  |  |                 Row( | 
					
						
							|  |  |  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | 
					
						
							|  |  |  |                   children: [ | 
					
						
							|  |  |  |                     Text(translate('Tags')), | 
					
						
							|  |  |  |                     InkWell( | 
					
						
							|  |  |  |                       child: PopupMenuButton( | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |                           itemBuilder: (context) => [ | 
					
						
							|  |  |  |                                 PopupMenuItem( | 
					
						
							|  |  |  |                                   child: Text(translate("Add ID")), | 
					
						
							|  |  |  |                                   value: 'add-id', | 
					
						
							|  |  |  |                                 ), | 
					
						
							|  |  |  |                                 PopupMenuItem( | 
					
						
							|  |  |  |                                   child: Text(translate("Add Tag")), | 
					
						
							|  |  |  |                                   value: 'add-tag', | 
					
						
							|  |  |  |                                 ), | 
					
						
							|  |  |  |                                 PopupMenuItem( | 
					
						
							|  |  |  |                                   child: Text(translate("Unselect all tags")), | 
					
						
							|  |  |  |                                   value: 'unset-all-tag', | 
					
						
							|  |  |  |                                 ), | 
					
						
							|  |  |  |                               ], | 
					
						
							|  |  |  |                           onSelected: handleAbOp, | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |                           child: Icon(Icons.more_vert_outlined)), | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                   ], | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 Expanded( | 
					
						
							|  |  |  |                   child: Container( | 
					
						
							|  |  |  |                     width: double.infinity, | 
					
						
							|  |  |  |                     height: double.infinity, | 
					
						
							|  |  |  |                     decoration: BoxDecoration( | 
					
						
							|  |  |  |                         border: Border.all(color: MyTheme.darkGray)), | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |                     child: Obx( | 
					
						
							|  |  |  |                       () => Wrap( | 
					
						
							|  |  |  |                         children: gFFI.abModel.tags | 
					
						
							|  |  |  |                             .map((e) => buildTag(e, gFFI.abModel.selectedTags, | 
					
						
							|  |  |  |                                     onTap: () { | 
					
						
							|  |  |  |                                   //
 | 
					
						
							|  |  |  |                                   if (gFFI.abModel.selectedTags.contains(e)) { | 
					
						
							|  |  |  |                                     gFFI.abModel.selectedTags.remove(e); | 
					
						
							|  |  |  |                                   } else { | 
					
						
							|  |  |  |                                     gFFI.abModel.selectedTags.add(e); | 
					
						
							|  |  |  |                                   } | 
					
						
							|  |  |  |                                 })) | 
					
						
							|  |  |  |                             .toList(), | 
					
						
							|  |  |  |                       ), | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |                     ), | 
					
						
							|  |  |  |                   ).marginSymmetric(vertical: 8.0), | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ).marginOnly(right: 8.0), | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |         Expanded( | 
					
						
							| 
									
										
										
										
											2022-07-29 12:03:24 +08:00
										 |  |  |           child: Align( | 
					
						
							|  |  |  |               alignment: Alignment.topLeft, child: AddressBookPeerWidget()), | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |         ) | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |   Widget buildTag(String tagName, RxList<dynamic> rxTags, {Function()? onTap}) { | 
					
						
							|  |  |  |     return ContextMenuArea( | 
					
						
							|  |  |  |       width: 100, | 
					
						
							|  |  |  |       builder: (context) => [ | 
					
						
							|  |  |  |         ListTile( | 
					
						
							|  |  |  |           title: Text(translate("Delete")), | 
					
						
							|  |  |  |           onTap: () { | 
					
						
							|  |  |  |             gFFI.abModel.deleteTag(tagName); | 
					
						
							|  |  |  |             gFFI.abModel.updateAb(); | 
					
						
							|  |  |  |             Future.delayed(Duration.zero, () => Get.back()); | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |       child: GestureDetector( | 
					
						
							|  |  |  |         onTap: onTap, | 
					
						
							|  |  |  |         child: Obx( | 
					
						
							|  |  |  |           () => Container( | 
					
						
							|  |  |  |             decoration: BoxDecoration( | 
					
						
							|  |  |  |                 color: rxTags.contains(tagName) ? Colors.blue : null, | 
					
						
							|  |  |  |                 border: Border.all(color: MyTheme.darkGray), | 
					
						
							|  |  |  |                 borderRadius: BorderRadius.circular(10)), | 
					
						
							|  |  |  |             margin: EdgeInsets.symmetric(horizontal: 4.0, vertical: 8.0), | 
					
						
							|  |  |  |             padding: EdgeInsets.symmetric(vertical: 2.0, horizontal: 8.0), | 
					
						
							|  |  |  |             child: Text( | 
					
						
							|  |  |  |               tagName, | 
					
						
							|  |  |  |               style: TextStyle( | 
					
						
							|  |  |  |                   color: rxTags.contains(tagName) ? MyTheme.white : null), | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /// tag operation
 | 
					
						
							|  |  |  |   void handleAbOp(String value) { | 
					
						
							|  |  |  |     if (value == 'add-id') { | 
					
						
							|  |  |  |       abAddId(); | 
					
						
							|  |  |  |     } else if (value == 'add-tag') { | 
					
						
							|  |  |  |       abAddTag(); | 
					
						
							|  |  |  |     } else if (value == 'unset-all-tag') { | 
					
						
							|  |  |  |       gFFI.abModel.unsetSelectedTags(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void abAddId() async { | 
					
						
							|  |  |  |     var field = ""; | 
					
						
							|  |  |  |     var msg = ""; | 
					
						
							|  |  |  |     var isInProgress = false; | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |     TextEditingController controller = TextEditingController(text: field); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     gFFI.dialogManager.show((setState, close) { | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       submit() async { | 
					
						
							|  |  |  |         setState(() { | 
					
						
							|  |  |  |           msg = ""; | 
					
						
							|  |  |  |           isInProgress = true; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         field = controller.text.trim(); | 
					
						
							|  |  |  |         if (field.isEmpty) { | 
					
						
							|  |  |  |           // pass
 | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           final ids = field.trim().split(RegExp(r"[\s,;\n]+")); | 
					
						
							|  |  |  |           field = ids.join(','); | 
					
						
							|  |  |  |           for (final newId in ids) { | 
					
						
							|  |  |  |             if (gFFI.abModel.idContainBy(newId)) { | 
					
						
							|  |  |  |               continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             gFFI.abModel.addId(newId); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           await gFFI.abModel.updateAb(); | 
					
						
							|  |  |  |           this.setState(() {}); | 
					
						
							|  |  |  |           // final currentPeers
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         close(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |       return CustomAlertDialog( | 
					
						
							|  |  |  |         title: Text(translate("Add ID")), | 
					
						
							|  |  |  |         content: Column( | 
					
						
							|  |  |  |           crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             Text(translate("whitelist_sep")), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |             const SizedBox( | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |               height: 8.0, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             Row( | 
					
						
							|  |  |  |               children: [ | 
					
						
							|  |  |  |                 Expanded( | 
					
						
							|  |  |  |                   child: TextField( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                       maxLines: null, | 
					
						
							|  |  |  |                       decoration: InputDecoration( | 
					
						
							|  |  |  |                         border: const OutlineInputBorder(), | 
					
						
							|  |  |  |                         errorText: msg.isEmpty ? null : translate(msg), | 
					
						
							|  |  |  |                       ), | 
					
						
							|  |  |  |                       controller: controller, | 
					
						
							|  |  |  |                       focusNode: FocusNode()..requestFocus()), | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |                 ), | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |             const SizedBox( | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |               height: 4.0, | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |             Offstage( | 
					
						
							|  |  |  |                 offstage: !isInProgress, child: const LinearProgressIndicator()) | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +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-26 17:03:19 +08:00
										 |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         onSubmit: submit, | 
					
						
							|  |  |  |         onCancel: close, | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |       ); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void abAddTag() async { | 
					
						
							|  |  |  |     var field = ""; | 
					
						
							|  |  |  |     var msg = ""; | 
					
						
							|  |  |  |     var isInProgress = false; | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |     TextEditingController controller = TextEditingController(text: field); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     gFFI.dialogManager.show((setState, close) { | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       submit() async { | 
					
						
							|  |  |  |         setState(() { | 
					
						
							|  |  |  |           msg = ""; | 
					
						
							|  |  |  |           isInProgress = true; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         field = controller.text.trim(); | 
					
						
							|  |  |  |         if (field.isEmpty) { | 
					
						
							|  |  |  |           // pass
 | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           final tags = field.trim().split(RegExp(r"[\s,;\n]+")); | 
					
						
							|  |  |  |           field = tags.join(','); | 
					
						
							|  |  |  |           for (final tag in tags) { | 
					
						
							|  |  |  |             gFFI.abModel.addTag(tag); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           await gFFI.abModel.updateAb(); | 
					
						
							|  |  |  |           // final currentPeers
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         close(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |       return CustomAlertDialog( | 
					
						
							|  |  |  |         title: Text(translate("Add Tag")), | 
					
						
							|  |  |  |         content: Column( | 
					
						
							|  |  |  |           crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             Text(translate("whitelist_sep")), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |             const SizedBox( | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |               height: 8.0, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             Row( | 
					
						
							|  |  |  |               children: [ | 
					
						
							|  |  |  |                 Expanded( | 
					
						
							|  |  |  |                   child: TextField( | 
					
						
							|  |  |  |                     maxLines: null, | 
					
						
							|  |  |  |                     decoration: InputDecoration( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                       border: const OutlineInputBorder(), | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |                       errorText: msg.isEmpty ? null : translate(msg), | 
					
						
							|  |  |  |                     ), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |                     controller: controller, | 
					
						
							|  |  |  |                     focusNode: FocusNode()..requestFocus(), | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |                   ), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |             const SizedBox( | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |               height: 4.0, | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |             Offstage( | 
					
						
							|  |  |  |                 offstage: !isInProgress, child: const LinearProgressIndicator()) | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +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-26 17:03:19 +08:00
										 |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         onSubmit: submit, | 
					
						
							|  |  |  |         onCancel: close, | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |       ); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void abEditTag(String id) { | 
					
						
							|  |  |  |     var isInProgress = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     final tags = List.of(gFFI.abModel.tags); | 
					
						
							|  |  |  |     var selectedTag = gFFI.abModel.getPeerTags(id).obs; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     gFFI.dialogManager.show((setState, close) { | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |       submit() async { | 
					
						
							|  |  |  |         setState(() { | 
					
						
							|  |  |  |           isInProgress = true; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         gFFI.abModel.changeTagForPeer(id, selectedTag); | 
					
						
							|  |  |  |         await gFFI.abModel.updateAb(); | 
					
						
							|  |  |  |         close(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |       return CustomAlertDialog( | 
					
						
							|  |  |  |         title: Text(translate("Edit Tag")), | 
					
						
							|  |  |  |         content: Column( | 
					
						
							|  |  |  |           crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |           children: [ | 
					
						
							|  |  |  |             Container( | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |               padding: | 
					
						
							|  |  |  |                   const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |               child: Wrap( | 
					
						
							|  |  |  |                 children: tags | 
					
						
							|  |  |  |                     .map((e) => buildTag(e, selectedTag, onTap: () { | 
					
						
							|  |  |  |                           if (selectedTag.contains(e)) { | 
					
						
							|  |  |  |                             selectedTag.remove(e); | 
					
						
							|  |  |  |                           } else { | 
					
						
							|  |  |  |                             selectedTag.add(e); | 
					
						
							|  |  |  |                           } | 
					
						
							|  |  |  |                         })) | 
					
						
							|  |  |  |                     .toList(growable: false), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |             Offstage( | 
					
						
							|  |  |  |                 offstage: !isInProgress, child: const LinearProgressIndicator()) | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +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-26 17:03:19 +08:00
										 |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-09-03 18:19:50 +08:00
										 |  |  |         onSubmit: submit, | 
					
						
							|  |  |  |         onCancel: close, | 
					
						
							| 
									
										
										
										
											2022-07-26 17:03:19 +08:00
										 |  |  |       ); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-02 13:10:09 +08:00
										 |  |  | class _PeerTabbedPage extends StatefulWidget { | 
					
						
							|  |  |  |   final List<String> tabs; | 
					
						
							|  |  |  |   final List<Widget> children; | 
					
						
							|  |  |  |   const _PeerTabbedPage({required this.tabs, required this.children, Key? key}) | 
					
						
							|  |  |  |       : super(key: key); | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   _PeerTabbedPageState createState() => _PeerTabbedPageState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _PeerTabbedPageState extends State<_PeerTabbedPage> | 
					
						
							|  |  |  |     with SingleTickerProviderStateMixin { | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |   late PageController _pageController = PageController(); | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |   RxInt _tabIndex = 0.obs; | 
					
						
							| 
									
										
										
										
											2022-08-02 13:10:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // hard code for now
 | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |   void _handleTabSelection(int index) { | 
					
						
							|  |  |  |     // reset search text
 | 
					
						
							|  |  |  |     peerSearchText.value = ""; | 
					
						
							|  |  |  |     peerSearchTextController.clear(); | 
					
						
							|  |  |  |     _tabIndex.value = index; | 
					
						
							|  |  |  |     _pageController.jumpToPage(index); | 
					
						
							|  |  |  |     switch (index) { | 
					
						
							|  |  |  |       case 0: | 
					
						
							|  |  |  |         bind.mainLoadRecentPeers(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case 1: | 
					
						
							|  |  |  |         bind.mainLoadFavPeers(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case 2: | 
					
						
							|  |  |  |         bind.mainDiscover(); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case 3: | 
					
						
							| 
									
										
										
										
											2022-09-14 22:22:23 -07:00
										 |  |  |         gFFI.abModel.updateAb(); | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2022-08-02 13:10:09 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |     _pageController.dispose(); | 
					
						
							| 
									
										
										
										
											2022-08-02 13:10:09 +08:00
										 |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Column( | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |       textBaseline: TextBaseline.ideographic, | 
					
						
							| 
									
										
										
										
											2022-08-02 13:10:09 +08:00
										 |  |  |       crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |       children: [ | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |         Container( | 
					
						
							|  |  |  |           height: 28, | 
					
						
							|  |  |  |           child: Row( | 
					
						
							|  |  |  |             children: [ | 
					
						
							|  |  |  |               Expanded(child: _createTabBar(context)), | 
					
						
							|  |  |  |               _createSearchBar(context), | 
					
						
							|  |  |  |               _createPeerViewTypeSwitch(context), | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |           ), | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |         ), | 
					
						
							| 
									
										
										
										
											2022-08-02 13:10:09 +08:00
										 |  |  |         _createTabBarView(), | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 17:58:48 +08:00
										 |  |  |   Widget _createTabBar(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |     return ListView( | 
					
						
							|  |  |  |         scrollDirection: Axis.horizontal, | 
					
						
							|  |  |  |         shrinkWrap: true, | 
					
						
							| 
									
										
										
										
											2022-09-12 11:23:45 +08:00
										 |  |  |         controller: ScrollController(), | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |         children: super.widget.tabs.asMap().entries.map((t) { | 
					
						
							|  |  |  |           return Obx(() => GestureDetector( | 
					
						
							|  |  |  |                 child: Container( | 
					
						
							|  |  |  |                     padding: EdgeInsets.symmetric(horizontal: 8), | 
					
						
							|  |  |  |                     decoration: BoxDecoration( | 
					
						
							|  |  |  |                       color: _tabIndex.value == t.key | 
					
						
							|  |  |  |                           ? MyTheme.color(context).bg | 
					
						
							|  |  |  |                           : null, | 
					
						
							|  |  |  |                       borderRadius: BorderRadius.circular(2), | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                     child: Align( | 
					
						
							|  |  |  |                       alignment: Alignment.center, | 
					
						
							|  |  |  |                       child: Text( | 
					
						
							|  |  |  |                         t.value, | 
					
						
							|  |  |  |                         textAlign: TextAlign.center, | 
					
						
							|  |  |  |                         style: TextStyle( | 
					
						
							|  |  |  |                             height: 1, | 
					
						
							|  |  |  |                             fontSize: 14, | 
					
						
							|  |  |  |                             color: _tabIndex.value == t.key | 
					
						
							|  |  |  |                                 ? MyTheme.color(context).text | 
					
						
							|  |  |  |                                 : MyTheme.color(context).lightText), | 
					
						
							|  |  |  |                       ), | 
					
						
							|  |  |  |                     )), | 
					
						
							|  |  |  |                 onTap: () => _handleTabSelection(t.key), | 
					
						
							|  |  |  |               )); | 
					
						
							| 
									
										
										
										
											2022-08-02 13:10:09 +08:00
										 |  |  |         }).toList()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _createTabBarView() { | 
					
						
							|  |  |  |     return Expanded( | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |         child: PageView( | 
					
						
							|  |  |  |                 controller: _pageController, children: super.widget.children) | 
					
						
							|  |  |  |             .marginSymmetric(vertical: 12)); | 
					
						
							| 
									
										
										
										
											2022-08-02 13:10:09 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   _createSearchBar(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |     RxBool focused = false.obs; | 
					
						
							|  |  |  |     FocusNode focusNode = FocusNode(); | 
					
						
							|  |  |  |     focusNode.addListener(() => focused.value = focusNode.hasFocus); | 
					
						
							|  |  |  |     RxBool rowHover = false.obs; | 
					
						
							|  |  |  |     RxBool clearHover = false.obs; | 
					
						
							| 
									
										
										
										
											2022-08-23 17:52:53 +08:00
										 |  |  |     return Container( | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |       width: 120, | 
					
						
							|  |  |  |       height: 25, | 
					
						
							|  |  |  |       margin: EdgeInsets.only(right: 13), | 
					
						
							|  |  |  |       decoration: BoxDecoration(color: MyTheme.color(context).bg), | 
					
						
							|  |  |  |       child: Obx(() => Row( | 
					
						
							|  |  |  |             children: [ | 
					
						
							|  |  |  |               Expanded( | 
					
						
							|  |  |  |                 child: MouseRegion( | 
					
						
							|  |  |  |                   onEnter: (_) => rowHover.value = true, | 
					
						
							|  |  |  |                   onExit: (_) => rowHover.value = false, | 
					
						
							|  |  |  |                   child: Row( | 
					
						
							|  |  |  |                     children: [ | 
					
						
							|  |  |  |                       Icon( | 
					
						
							|  |  |  |                         IconFont.search, | 
					
						
							|  |  |  |                         size: 16, | 
					
						
							|  |  |  |                         color: MyTheme.color(context).placeholder, | 
					
						
							|  |  |  |                       ).marginSymmetric(horizontal: 4), | 
					
						
							|  |  |  |                       Expanded( | 
					
						
							|  |  |  |                         child: TextField( | 
					
						
							|  |  |  |                           controller: peerSearchTextController, | 
					
						
							|  |  |  |                           onChanged: (searchText) { | 
					
						
							|  |  |  |                             peerSearchText.value = searchText; | 
					
						
							|  |  |  |                           }, | 
					
						
							|  |  |  |                           focusNode: focusNode, | 
					
						
							|  |  |  |                           textAlign: TextAlign.start, | 
					
						
							|  |  |  |                           maxLines: 1, | 
					
						
							|  |  |  |                           cursorColor: MyTheme.color(context).lightText, | 
					
						
							|  |  |  |                           cursorHeight: 18, | 
					
						
							|  |  |  |                           cursorWidth: 1, | 
					
						
							|  |  |  |                           style: TextStyle(fontSize: 14), | 
					
						
							|  |  |  |                           decoration: InputDecoration( | 
					
						
							|  |  |  |                             contentPadding: EdgeInsets.symmetric(vertical: 6), | 
					
						
							|  |  |  |                             hintText: | 
					
						
							|  |  |  |                                 focused.value ? null : translate("Search ID"), | 
					
						
							|  |  |  |                             hintStyle: TextStyle( | 
					
						
							|  |  |  |                                 fontSize: 14, | 
					
						
							|  |  |  |                                 color: MyTheme.color(context).placeholder), | 
					
						
							|  |  |  |                             border: InputBorder.none, | 
					
						
							|  |  |  |                             isDense: true, | 
					
						
							|  |  |  |                           ), | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                       ), | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                   ), | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |               Offstage( | 
					
						
							|  |  |  |                 offstage: !(peerSearchText.value.isNotEmpty && | 
					
						
							|  |  |  |                     (rowHover.value || clearHover.value)), | 
					
						
							|  |  |  |                 child: InkWell( | 
					
						
							|  |  |  |                     onHover: (value) => clearHover.value = value, | 
					
						
							|  |  |  |                     child: Icon( | 
					
						
							|  |  |  |                       IconFont.round_close, | 
					
						
							|  |  |  |                       size: 16, | 
					
						
							|  |  |  |                       color: clearHover.value | 
					
						
							|  |  |  |                           ? MyTheme.color(context).text | 
					
						
							|  |  |  |                           : MyTheme.color(context).placeholder, | 
					
						
							|  |  |  |                     ).marginSymmetric(horizontal: 4), | 
					
						
							|  |  |  |                     onTap: () { | 
					
						
							|  |  |  |                       peerSearchTextController.clear(); | 
					
						
							|  |  |  |                       peerSearchText.value = ""; | 
					
						
							|  |  |  |                     }), | 
					
						
							|  |  |  |               ) | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |           )), | 
					
						
							| 
									
										
										
										
											2022-08-23 17:52:53 +08:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _createPeerViewTypeSwitch(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |     final activeDeco = BoxDecoration(color: MyTheme.color(context).bg); | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |     return Row( | 
					
						
							|  |  |  |       children: [ | 
					
						
							|  |  |  |         Obx( | 
					
						
							|  |  |  |           () => Container( | 
					
						
							|  |  |  |             padding: EdgeInsets.all(4.0), | 
					
						
							|  |  |  |             decoration: | 
					
						
							|  |  |  |                 peerCardUiType.value == PeerUiType.grid ? activeDeco : null, | 
					
						
							|  |  |  |             child: InkWell( | 
					
						
							|  |  |  |                 onTap: () { | 
					
						
							|  |  |  |                   peerCardUiType.value = PeerUiType.grid; | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 child: Icon( | 
					
						
							|  |  |  |                   Icons.grid_view_rounded, | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |                   size: 18, | 
					
						
							|  |  |  |                   color: peerCardUiType.value == PeerUiType.grid | 
					
						
							|  |  |  |                       ? MyTheme.color(context).text | 
					
						
							|  |  |  |                       : MyTheme.color(context).lightText, | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |                 )), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         Obx( | 
					
						
							|  |  |  |           () => Container( | 
					
						
							|  |  |  |             padding: EdgeInsets.all(4.0), | 
					
						
							|  |  |  |             decoration: | 
					
						
							|  |  |  |                 peerCardUiType.value == PeerUiType.list ? activeDeco : null, | 
					
						
							|  |  |  |             child: InkWell( | 
					
						
							|  |  |  |                 onTap: () { | 
					
						
							|  |  |  |                   peerCardUiType.value = PeerUiType.list; | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 child: Icon( | 
					
						
							|  |  |  |                   Icons.list, | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |                   size: 18, | 
					
						
							|  |  |  |                   color: peerCardUiType.value == PeerUiType.list | 
					
						
							|  |  |  |                       ? MyTheme.color(context).text | 
					
						
							|  |  |  |                       : MyTheme.color(context).lightText, | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |                 )), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ], | 
					
						
							| 
									
										
										
										
											2022-08-24 11:01:58 +08:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-08-23 17:21:50 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-02 13:10:09 +08:00
										 |  |  | } |