| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-10 21:03:35 +08:00
										 |  |  | import 'package:auto_size_text_field/auto_size_text_field.dart'; | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-21 17:54:47 +08:00
										 |  |  | import 'package:flutter_hbb/common/formatter/id_formatter.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | import 'package:provider/provider.dart'; | 
					
						
							|  |  |  | import 'package:url_launcher/url_launcher.dart'; | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  | import 'package:flutter_hbb/models/peer_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-24 23:33:00 +08:00
										 |  |  | import '../../common.dart'; | 
					
						
							| 
									
										
										
										
											2023-01-08 23:30:34 +09:00
										 |  |  | import '../../common/widgets/login.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | import '../../common/widgets/peer_tab_page.dart'; | 
					
						
							| 
									
										
										
										
											2023-10-24 05:30:43 +05:30
										 |  |  | import '../../common/widgets/autocomplete.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  | import '../../consts.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-24 23:33:00 +08:00
										 |  |  | import '../../models/model.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-08 17:53:51 +08:00
										 |  |  | import '../../models/platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | import 'home_page.dart'; | 
					
						
							| 
									
										
										
										
											2022-04-17 20:36:54 +08:00
										 |  |  | import 'scan_page.dart'; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | import 'settings_page.dart'; | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  | /// Connection page for connecting to a remote peer.
 | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | class ConnectionPage extends StatefulWidget implements PageShape { | 
					
						
							|  |  |  |   ConnectionPage({Key? key}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   final icon = const Icon(Icons.connected_tv); | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   final title = translate("Connection"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2023-08-30 21:59:25 +08:00
										 |  |  |   final appBarActions = isWeb ? <Widget>[const WebMenu()] : <Widget>[]; | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   State<ConnectionPage> createState() => _ConnectionPageState(); | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  | /// State for the connection page.
 | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | class _ConnectionPageState extends State<ConnectionPage> { | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  |   /// Controller for the id input bar.
 | 
					
						
							| 
									
										
										
										
											2022-09-21 17:54:47 +08:00
										 |  |  |   final _idController = IDTextEditingController(); | 
					
						
							| 
									
										
										
										
											2023-07-09 19:14:57 +08:00
										 |  |  |   final RxBool _idEmpty = true.obs; | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /// Update url. If it's not null, means an update is available.
 | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |   var _updateUrl = ''; | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |   List<Peer> peers = []; | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |   bool isPeersLoading = false; | 
					
						
							| 
									
										
										
										
											2023-10-23 04:03:05 +05:30
										 |  |  |   bool isPeersLoaded = false; | 
					
						
							| 
									
										
										
										
											2023-11-02 02:13:33 +05:30
										 |  |  |   StreamSubscription? _uniLinksSubscription; | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							| 
									
										
										
										
											2023-11-02 02:13:33 +05:30
										 |  |  |     _uniLinksSubscription = listenUniLinks(); | 
					
						
							| 
									
										
										
										
											2022-08-08 17:53:51 +08:00
										 |  |  |     if (_idController.text.isEmpty) { | 
					
						
							|  |  |  |       () async { | 
					
						
							|  |  |  |         final lastRemoteId = await bind.mainGetLastRemoteId(); | 
					
						
							| 
									
										
										
										
											2022-09-21 17:54:47 +08:00
										 |  |  |         if (lastRemoteId != _idController.id) { | 
					
						
							| 
									
										
										
										
											2022-08-08 17:53:51 +08:00
										 |  |  |           setState(() { | 
					
						
							| 
									
										
										
										
											2022-09-21 17:54:47 +08:00
										 |  |  |             _idController.id = lastRemoteId; | 
					
						
							| 
									
										
										
										
											2022-08-08 17:53:51 +08:00
										 |  |  |           }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |     if (isAndroid) { | 
					
						
							| 
									
										
										
										
											2023-09-26 10:47:45 +08:00
										 |  |  |       Timer(const Duration(seconds: 1), () async { | 
					
						
							| 
									
										
										
										
											2022-08-08 22:27:27 +08:00
										 |  |  |         _updateUrl = await bind.mainGetSoftwareUpdateUrl(); | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |         if (_updateUrl.isNotEmpty) setState(() {}); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-09 19:14:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     _idController.addListener(() { | 
					
						
							|  |  |  |       _idEmpty.value = _idController.text.isEmpty; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-08-08 17:22:25 +08:00
										 |  |  |     Get.put<IDTextEditingController>(_idController); | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     Provider.of<FfiModel>(context); | 
					
						
							| 
									
										
										
										
											2022-09-28 21:07:44 +08:00
										 |  |  |     return CustomScrollView( | 
					
						
							|  |  |  |       slivers: [ | 
					
						
							|  |  |  |         SliverList( | 
					
						
							|  |  |  |             delegate: SliverChildListDelegate([ | 
					
						
							| 
									
										
										
										
											2022-09-21 17:54:47 +08:00
										 |  |  |           _buildUpdateUI(), | 
					
						
							|  |  |  |           _buildRemoteIDTextField(), | 
					
						
							| 
									
										
										
										
											2022-09-28 21:07:44 +08:00
										 |  |  |         ])), | 
					
						
							|  |  |  |         SliverFillRemaining( | 
					
						
							| 
									
										
										
										
											2023-09-25 13:35:01 +08:00
										 |  |  |           hasScrollBody: true, | 
					
						
							| 
									
										
										
										
											2022-12-04 15:15:48 +08:00
										 |  |  |           child: PeerTabPage(), | 
					
						
							| 
									
										
										
										
											2022-09-28 21:07:44 +08:00
										 |  |  |         ) | 
					
						
							|  |  |  |       ], | 
					
						
							|  |  |  |     ).marginOnly(top: 2, left: 10, right: 10); | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  |   /// Callback for the connect button.
 | 
					
						
							|  |  |  |   /// Connects to the selected peer.
 | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |   void onConnect() { | 
					
						
							| 
									
										
										
										
											2022-09-21 17:54:47 +08:00
										 |  |  |     var id = _idController.id; | 
					
						
							| 
									
										
										
										
											2022-09-22 16:45:14 +08:00
										 |  |  |     connect(context, id); | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  |   /// UI for software update.
 | 
					
						
							|  |  |  |   /// If [_updateUrl] is not empty, shows a button to update the software.
 | 
					
						
							| 
									
										
										
										
											2022-09-21 17:54:47 +08:00
										 |  |  |   Widget _buildUpdateUI() { | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |     return _updateUrl.isEmpty | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |         ? const SizedBox(height: 0) | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |         : InkWell( | 
					
						
							| 
									
										
										
										
											2022-03-03 14:58:57 +08:00
										 |  |  |             onTap: () async { | 
					
						
							| 
									
										
										
										
											2023-07-03 16:43:39 +08:00
										 |  |  |               final url = 'https://rustdesk.com/download'; | 
					
						
							| 
									
										
										
										
											2022-06-19 17:15:37 +01:00
										 |  |  |               if (await canLaunchUrl(Uri.parse(url))) { | 
					
						
							|  |  |  |                 await launchUrl(Uri.parse(url)); | 
					
						
							| 
									
										
										
										
											2022-03-03 14:58:57 +08:00
										 |  |  |               } | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             child: Container( | 
					
						
							|  |  |  |                 alignment: AlignmentDirectional.center, | 
					
						
							|  |  |  |                 width: double.infinity, | 
					
						
							|  |  |  |                 color: Colors.pinkAccent, | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                 padding: const EdgeInsets.symmetric(vertical: 12), | 
					
						
							| 
									
										
										
										
											2022-03-03 14:58:57 +08:00
										 |  |  |                 child: Text(translate('Download new version'), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                     style: const TextStyle( | 
					
						
							| 
									
										
										
										
											2022-03-03 14:58:57 +08:00
										 |  |  |                         color: Colors.white, fontWeight: FontWeight.bold)))); | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |   Future<void> _fetchPeers() async { | 
					
						
							|  |  |  |     setState(() { | 
					
						
							|  |  |  |       isPeersLoading = true; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     await Future.delayed(Duration(milliseconds: 100)); | 
					
						
							| 
									
										
										
										
											2023-10-24 05:30:43 +05:30
										 |  |  |     peers = await getAllPeers(); | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |     setState(() { | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  |       isPeersLoading = false; | 
					
						
							|  |  |  |       isPeersLoaded = true; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 17:54:47 +08:00
										 |  |  |   /// UI for the remote ID TextField.
 | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  |   /// Search for a peer and connect to it if the id exists.
 | 
					
						
							| 
									
										
										
										
											2022-09-21 17:54:47 +08:00
										 |  |  |   Widget _buildRemoteIDTextField() { | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |     final w = SizedBox( | 
					
						
							|  |  |  |       height: 84, | 
					
						
							|  |  |  |       child: Padding( | 
					
						
							| 
									
										
										
										
											2022-09-21 17:16:09 +08:00
										 |  |  |         padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 2), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |         child: Ink( | 
					
						
							| 
									
										
										
										
											2022-09-23 17:16:25 +08:00
										 |  |  |           decoration: BoxDecoration( | 
					
						
							|  |  |  |             color: Theme.of(context).cardColor, | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |             borderRadius: BorderRadius.all(Radius.circular(13)), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |           child: Row( | 
					
						
							|  |  |  |             children: <Widget>[ | 
					
						
							|  |  |  |               Expanded( | 
					
						
							|  |  |  |                 child: Container( | 
					
						
							|  |  |  |                   padding: const EdgeInsets.only(left: 16, right: 16), | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                   child: Autocomplete<Peer>( | 
					
						
							|  |  |  |                     optionsBuilder: (TextEditingValue textEditingValue) { | 
					
						
							|  |  |  |                       if (textEditingValue.text == '') { | 
					
						
							|  |  |  |                         return const Iterable<Peer>.empty(); | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  |                       } else if (peers.isEmpty && !isPeersLoaded) { | 
					
						
							|  |  |  |                         Peer emptyPeer = Peer( | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                           id: '', | 
					
						
							|  |  |  |                           username: '', | 
					
						
							|  |  |  |                           hostname: '', | 
					
						
							|  |  |  |                           alias: '', | 
					
						
							|  |  |  |                           platform: '', | 
					
						
							|  |  |  |                           tags: [], | 
					
						
							|  |  |  |                           hash: '', | 
					
						
							| 
									
										
										
										
											2024-03-20 15:05:54 +08:00
										 |  |  |                           password: '', | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                           forceAlwaysRelay: false, | 
					
						
							|  |  |  |                           rdpPort: '', | 
					
						
							|  |  |  |                           rdpUsername: '', | 
					
						
							|  |  |  |                           loginName: '', | 
					
						
							|  |  |  |                         ); | 
					
						
							|  |  |  |                         return [emptyPeer]; | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  |                       } else { | 
					
						
							|  |  |  |                         String textWithoutSpaces = | 
					
						
							|  |  |  |                             textEditingValue.text.replaceAll(" ", ""); | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                         if (int.tryParse(textWithoutSpaces) != null) { | 
					
						
							|  |  |  |                           textEditingValue = TextEditingValue( | 
					
						
							|  |  |  |                             text: textWithoutSpaces, | 
					
						
							|  |  |  |                             selection: textEditingValue.selection, | 
					
						
							|  |  |  |                           ); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         String textToFind = textEditingValue.text.toLowerCase(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  |                         return peers | 
					
						
							|  |  |  |                             .where((peer) => | 
					
						
							|  |  |  |                                 peer.id.toLowerCase().contains(textToFind) || | 
					
						
							|  |  |  |                                 peer.username | 
					
						
							|  |  |  |                                     .toLowerCase() | 
					
						
							|  |  |  |                                     .contains(textToFind) || | 
					
						
							|  |  |  |                                 peer.hostname | 
					
						
							|  |  |  |                                     .toLowerCase() | 
					
						
							|  |  |  |                                     .contains(textToFind) || | 
					
						
							|  |  |  |                                 peer.alias.toLowerCase().contains(textToFind)) | 
					
						
							|  |  |  |                             .toList(); | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                       } | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     fieldViewBuilder: (BuildContext context, | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  |                         TextEditingController fieldTextEditingController, | 
					
						
							|  |  |  |                         FocusNode fieldFocusNode, | 
					
						
							|  |  |  |                         VoidCallback onFieldSubmitted) { | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                       fieldTextEditingController.text = _idController.text; | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  |                       fieldFocusNode.addListener(() async { | 
					
						
							|  |  |  |                         _idEmpty.value = | 
					
						
							|  |  |  |                             fieldTextEditingController.text.isEmpty; | 
					
						
							|  |  |  |                         if (fieldFocusNode.hasFocus && !isPeersLoading) { | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                           _fetchPeers(); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                       }); | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  |                       final textLength = | 
					
						
							|  |  |  |                           fieldTextEditingController.value.text.length; | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                       // select all to facilitate removing text, just following the behavior of address input of chrome
 | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  |                       fieldTextEditingController.selection = TextSelection( | 
					
						
							|  |  |  |                           baseOffset: 0, extentOffset: textLength); | 
					
						
							|  |  |  |                       return AutoSizeTextField( | 
					
						
							|  |  |  |                         controller: fieldTextEditingController, | 
					
						
							|  |  |  |                         focusNode: fieldFocusNode, | 
					
						
							|  |  |  |                         minFontSize: 18, | 
					
						
							|  |  |  |                         autocorrect: false, | 
					
						
							|  |  |  |                         enableSuggestions: false, | 
					
						
							|  |  |  |                         keyboardType: TextInputType.visiblePassword, | 
					
						
							|  |  |  |                         // keyboardType: TextInputType.number,
 | 
					
						
							|  |  |  |                         onChanged: (String text) { | 
					
						
							|  |  |  |                           _idController.id = text; | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                         style: const TextStyle( | 
					
						
							|  |  |  |                           fontFamily: 'WorkSans', | 
					
						
							|  |  |  |                           fontWeight: FontWeight.bold, | 
					
						
							|  |  |  |                           fontSize: 30, | 
					
						
							|  |  |  |                           color: MyTheme.idColor, | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                         decoration: InputDecoration( | 
					
						
							|  |  |  |                           labelText: translate('Remote ID'), | 
					
						
							|  |  |  |                           // hintText: 'Enter your remote ID',
 | 
					
						
							|  |  |  |                           border: InputBorder.none, | 
					
						
							|  |  |  |                           helperStyle: const TextStyle( | 
					
						
							|  |  |  |                             fontWeight: FontWeight.bold, | 
					
						
							|  |  |  |                             fontSize: 16, | 
					
						
							|  |  |  |                             color: MyTheme.darkGray, | 
					
						
							|  |  |  |                           ), | 
					
						
							|  |  |  |                           labelStyle: const TextStyle( | 
					
						
							|  |  |  |                             fontWeight: FontWeight.w600, | 
					
						
							|  |  |  |                             fontSize: 16, | 
					
						
							|  |  |  |                             letterSpacing: 0.2, | 
					
						
							|  |  |  |                             color: MyTheme.darkGray, | 
					
						
							|  |  |  |                           ), | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                         inputFormatters: [IDTextInputFormatter()], | 
					
						
							|  |  |  |                       ); | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                     }, | 
					
						
							| 
									
										
										
										
											2023-10-27 17:00:13 +08:00
										 |  |  |                     onSelected: (option) { | 
					
						
							|  |  |  |                       setState(() { | 
					
						
							|  |  |  |                         _idController.id = option.id; | 
					
						
							|  |  |  |                         FocusScope.of(context).unfocus(); | 
					
						
							|  |  |  |                       }); | 
					
						
							|  |  |  |                     }, | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  |                     optionsViewBuilder: (BuildContext context, | 
					
						
							|  |  |  |                         AutocompleteOnSelected<Peer> onSelected, | 
					
						
							|  |  |  |                         Iterable<Peer> options) { | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                       double maxHeight = options.length * 50; | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  |                       if (options.length == 1) { | 
					
						
							|  |  |  |                         maxHeight = 52; | 
					
						
							|  |  |  |                       } else if (options.length == 3) { | 
					
						
							|  |  |  |                         maxHeight = 146; | 
					
						
							|  |  |  |                       } else if (options.length == 4) { | 
					
						
							|  |  |  |                         maxHeight = 193; | 
					
						
							|  |  |  |                       } | 
					
						
							|  |  |  |                       maxHeight = maxHeight.clamp(0, 200); | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                       return Align( | 
					
						
							| 
									
										
										
										
											2023-12-17 06:52:18 +05:30
										 |  |  |                           alignment: Alignment.topLeft, | 
					
						
							|  |  |  |                           child: Container( | 
					
						
							|  |  |  |                               decoration: BoxDecoration( | 
					
						
							|  |  |  |                                 boxShadow: [ | 
					
						
							|  |  |  |                                   BoxShadow( | 
					
						
							|  |  |  |                                     color: Colors.black.withOpacity(0.3), | 
					
						
							|  |  |  |                                     blurRadius: 5, | 
					
						
							|  |  |  |                                     spreadRadius: 1, | 
					
						
							|  |  |  |                                   ), | 
					
						
							|  |  |  |                                 ], | 
					
						
							|  |  |  |                               ), | 
					
						
							|  |  |  |                               child: ClipRRect( | 
					
						
							|  |  |  |                                   borderRadius: BorderRadius.circular(5), | 
					
						
							|  |  |  |                                   child: Material( | 
					
						
							|  |  |  |                                       elevation: 4, | 
					
						
							|  |  |  |                                       child: ConstrainedBox( | 
					
						
							|  |  |  |                                           constraints: BoxConstraints( | 
					
						
							|  |  |  |                                             maxHeight: maxHeight, | 
					
						
							|  |  |  |                                             maxWidth: 320, | 
					
						
							|  |  |  |                                           ), | 
					
						
							|  |  |  |                                           child: peers.isEmpty && isPeersLoading | 
					
						
							|  |  |  |                                               ? Container( | 
					
						
							|  |  |  |                                                   height: 80, | 
					
						
							|  |  |  |                                                   child: Center( | 
					
						
							|  |  |  |                                                       child: | 
					
						
							|  |  |  |                                                           CircularProgressIndicator( | 
					
						
							|  |  |  |                                                     strokeWidth: 2, | 
					
						
							|  |  |  |                                                   ))) | 
					
						
							|  |  |  |                                               : ListView( | 
					
						
							|  |  |  |                                                   padding: | 
					
						
							|  |  |  |                                                       EdgeInsets.only(top: 5), | 
					
						
							|  |  |  |                                                   children: options | 
					
						
							|  |  |  |                                                       .map((peer) => | 
					
						
							|  |  |  |                                                           AutocompletePeerTile( | 
					
						
							|  |  |  |                                                               onSelect: () => | 
					
						
							|  |  |  |                                                                   onSelected( | 
					
						
							|  |  |  |                                                                       peer), | 
					
						
							|  |  |  |                                                               peer: peer)) | 
					
						
							|  |  |  |                                                       .toList(), | 
					
						
							|  |  |  |                                                 )))))); | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                     }, | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |                   ), | 
					
						
							|  |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |               ), | 
					
						
							| 
									
										
										
										
											2023-07-09 19:14:57 +08:00
										 |  |  |               Obx(() => Offstage( | 
					
						
							|  |  |  |                     offstage: _idEmpty.value, | 
					
						
							|  |  |  |                     child: IconButton( | 
					
						
							|  |  |  |                         onPressed: () { | 
					
						
							| 
									
										
										
										
											2023-10-23 03:21:54 +05:30
										 |  |  |                           setState(() { | 
					
						
							|  |  |  |                             _idController.clear(); | 
					
						
							|  |  |  |                           }); | 
					
						
							| 
									
										
										
										
											2023-07-09 19:14:57 +08:00
										 |  |  |                         }, | 
					
						
							|  |  |  |                         icon: Icon(Icons.clear, color: MyTheme.darkGray)), | 
					
						
							|  |  |  |                   )), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |               SizedBox( | 
					
						
							|  |  |  |                 width: 60, | 
					
						
							|  |  |  |                 height: 60, | 
					
						
							|  |  |  |                 child: IconButton( | 
					
						
							|  |  |  |                   icon: const Icon(Icons.arrow_forward, | 
					
						
							|  |  |  |                       color: MyTheme.darkGray, size: 45), | 
					
						
							|  |  |  |                   onPressed: onConnect, | 
					
						
							| 
									
										
										
										
											2022-03-03 14:58:57 +08:00
										 |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |               ), | 
					
						
							|  |  |  |             ], | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |     return Align( | 
					
						
							| 
									
										
										
										
											2023-06-21 23:29:12 +08:00
										 |  |  |         alignment: Alignment.topCenter, | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |         child: Container(constraints: kMobilePageConstraints, child: w)); | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							| 
									
										
										
										
											2023-11-02 02:13:33 +05:30
										 |  |  |     _uniLinksSubscription?.cancel(); | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |     _idController.dispose(); | 
					
						
							| 
									
										
										
										
											2023-08-09 13:54:09 +08:00
										 |  |  |     if (Get.isRegistered<IDTextEditingController>()) { | 
					
						
							|  |  |  |       Get.delete<IDTextEditingController>(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-02-28 21:26:44 +08:00
										 |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-03-03 14:58:57 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class WebMenu extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   const WebMenu({Key? key}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |   State<WebMenu> createState() => _WebMenuState(); | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _WebMenuState extends State<WebMenu> { | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     Provider.of<FfiModel>(context); | 
					
						
							| 
									
										
										
										
											2022-04-04 01:38:53 +08:00
										 |  |  |     return PopupMenuButton<String>( | 
					
						
							| 
									
										
										
										
											2023-06-29 10:26:03 +08:00
										 |  |  |         tooltip: "", | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |         icon: const Icon(Icons.more_vert), | 
					
						
							| 
									
										
										
										
											2022-04-04 01:38:53 +08:00
										 |  |  |         itemBuilder: (context) { | 
					
						
							| 
									
										
										
										
											2022-04-17 20:36:54 +08:00
										 |  |  |           return (isIOS | 
					
						
							|  |  |  |                   ? [ | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                       const PopupMenuItem( | 
					
						
							| 
									
										
										
										
											2022-04-17 20:36:54 +08:00
										 |  |  |                         value: "scan", | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                         child: Icon(Icons.qr_code_scanner, color: Colors.black), | 
					
						
							| 
									
										
										
										
											2022-04-17 20:36:54 +08:00
										 |  |  |                       ) | 
					
						
							|  |  |  |                     ] | 
					
						
							|  |  |  |                   : <PopupMenuItem<String>>[]) + | 
					
						
							|  |  |  |               [ | 
					
						
							|  |  |  |                 PopupMenuItem( | 
					
						
							|  |  |  |                   value: "server", | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                   child: Text(translate('ID/Relay Server')), | 
					
						
							| 
									
										
										
										
											2022-04-17 20:36:54 +08:00
										 |  |  |                 ) | 
					
						
							|  |  |  |               ] + | 
					
						
							| 
									
										
										
										
											2023-08-30 19:26:15 +08:00
										 |  |  |               [ | 
					
						
							|  |  |  |                 PopupMenuItem( | 
					
						
							|  |  |  |                   value: "login", | 
					
						
							|  |  |  |                   child: Text(gFFI.userModel.userName.value.isEmpty | 
					
						
							|  |  |  |                       ? translate("Login") | 
					
						
							|  |  |  |                       : '${translate("Logout")} (${gFFI.userModel.userName.value})'), | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |               ] + | 
					
						
							| 
									
										
										
										
											2022-04-17 20:36:54 +08:00
										 |  |  |               [ | 
					
						
							|  |  |  |                 PopupMenuItem( | 
					
						
							|  |  |  |                   value: "about", | 
					
						
							| 
									
										
										
										
											2022-09-19 20:26:39 +08:00
										 |  |  |                   child: Text('${translate('About')} RustDesk'), | 
					
						
							| 
									
										
										
										
											2022-04-17 20:36:54 +08:00
										 |  |  |                 ) | 
					
						
							|  |  |  |               ]; | 
					
						
							| 
									
										
										
										
											2022-04-04 01:38:53 +08:00
										 |  |  |         }, | 
					
						
							|  |  |  |         onSelected: (value) { | 
					
						
							|  |  |  |           if (value == 'server') { | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |             showServerSettings(gFFI.dialogManager); | 
					
						
							| 
									
										
										
										
											2022-04-04 01:38:53 +08:00
										 |  |  |           } | 
					
						
							|  |  |  |           if (value == 'about') { | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |             showAbout(gFFI.dialogManager); | 
					
						
							| 
									
										
										
										
											2022-04-04 01:38:53 +08:00
										 |  |  |           } | 
					
						
							|  |  |  |           if (value == 'login') { | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |             if (gFFI.userModel.userName.value.isEmpty) { | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |               loginDialog(); | 
					
						
							| 
									
										
										
										
											2022-04-04 01:38:53 +08:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2023-07-15 07:21:54 +08:00
										 |  |  |               logOutConfirmDialog(); | 
					
						
							| 
									
										
										
										
											2022-04-04 01:38:53 +08:00
										 |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2022-04-17 20:36:54 +08:00
										 |  |  |           if (value == 'scan') { | 
					
						
							|  |  |  |             Navigator.push( | 
					
						
							|  |  |  |               context, | 
					
						
							|  |  |  |               MaterialPageRoute( | 
					
						
							|  |  |  |                 builder: (BuildContext context) => ScanPage(), | 
					
						
							|  |  |  |               ), | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2022-04-04 01:38:53 +08:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2022-03-28 15:44:45 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } |