| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  | import 'dart:convert'; | 
					
						
							|  |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2022-04-19 23:43:55 +08:00
										 |  |  | import 'package:wakelock/wakelock.dart'; | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  | import '../common.dart'; | 
					
						
							|  |  |  | import '../pages/server_page.dart'; | 
					
						
							|  |  |  | import 'model.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  | const loginDialogTag = "LOGIN"; | 
					
						
							| 
									
										
										
										
											2022-04-17 11:34:46 +08:00
										 |  |  | final _emptyIdShow = translate("Generating ..."); | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  | const kUseTemporaryPassword = "use-temporary-password"; | 
					
						
							|  |  |  | const kUsePermanentPassword = "use-permanent-password"; | 
					
						
							|  |  |  | const kUseBothPasswords = "use-both-passwords"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  | class ServerModel with ChangeNotifier { | 
					
						
							| 
									
										
										
										
											2022-04-17 11:34:46 +08:00
										 |  |  |   bool _isStart = false; // Android MainService status
 | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |   bool _mediaOk = false; | 
					
						
							|  |  |  |   bool _inputOk = false; | 
					
						
							| 
									
										
										
										
											2022-03-28 17:24:52 +08:00
										 |  |  |   bool _audioOk = false; | 
					
						
							|  |  |  |   bool _fileOk = false; | 
					
						
							| 
									
										
										
										
											2022-04-17 11:34:46 +08:00
										 |  |  |   int _connectStatus = 0; // Rendezvous Server status
 | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  |   String _verificationMethod = ""; | 
					
						
							| 
									
										
										
										
											2022-04-17 11:34:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |   final _serverId = TextEditingController(text: _emptyIdShow); | 
					
						
							|  |  |  |   final _serverPasswd = TextEditingController(text: ""); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |   Map<int, Client> _clients = {}; | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |   bool get isStart => _isStart; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |   bool get mediaOk => _mediaOk; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool get inputOk => _inputOk; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |   bool get audioOk => _audioOk; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |   bool get fileOk => _fileOk; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-17 11:34:46 +08:00
										 |  |  |   int get connectStatus => _connectStatus; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  |   String get verificationMethod => _verificationMethod; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |   TextEditingController get serverId => _serverId; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   TextEditingController get serverPasswd => _serverPasswd; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |   Map<int, Client> get clients => _clients; | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-19 21:15:19 +08:00
										 |  |  |   final controller = ScrollController(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |   ServerModel() { | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |     () async { | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |       /** | 
					
						
							|  |  |  |        * 1. check android permission | 
					
						
							|  |  |  |        * 2. check config | 
					
						
							| 
									
										
										
										
											2022-04-09 21:38:46 +08:00
										 |  |  |        * audio true by default (if permission on) (false default < Android 10) | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |        * file true by default (if permission on) | 
					
						
							|  |  |  |        */ | 
					
						
							|  |  |  |       await Future.delayed(Duration(seconds: 1)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // audio
 | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |       if (androidVersion < 30 || !await PermissionManager.check("audio")) { | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |         _audioOk = false; | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |         FFI.setByName( | 
					
						
							|  |  |  |             'option', | 
					
						
							|  |  |  |             jsonEncode(Map() | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |               ..["name"] = "enable-audio" | 
					
						
							|  |  |  |               ..["value"] = "N")); | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |         final audioOption = FFI.getByName('option', 'enable-audio'); | 
					
						
							|  |  |  |         _audioOk = audioOption.isEmpty; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |       // file
 | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |       if (!await PermissionManager.check("file")) { | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |         _fileOk = false; | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |         FFI.setByName( | 
					
						
							|  |  |  |             'option', | 
					
						
							|  |  |  |             jsonEncode(Map() | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |               ..["name"] = "enable-file-transfer" | 
					
						
							|  |  |  |               ..["value"] = "N")); | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |         final fileOption = FFI.getByName('option', 'enable-file-transfer'); | 
					
						
							|  |  |  |         _fileOk = fileOption.isEmpty; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-28 17:24:52 +08:00
										 |  |  |       notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |     }(); | 
					
						
							| 
									
										
										
										
											2022-04-17 11:34:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Timer.periodic(Duration(seconds: 1), (timer) { | 
					
						
							|  |  |  |       var status = int.tryParse(FFI.getByName('connect_statue')) ?? 0; | 
					
						
							|  |  |  |       if (status > 0) { | 
					
						
							|  |  |  |         status = 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (status != _connectStatus) { | 
					
						
							|  |  |  |         _connectStatus = status; | 
					
						
							| 
									
										
										
										
											2022-07-29 22:07:45 +08:00
										 |  |  |         notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-04-17 11:34:46 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-04-19 21:15:19 +08:00
										 |  |  |       final res = | 
					
						
							|  |  |  |           FFI.getByName('check_clients_length', _clients.length.toString()); | 
					
						
							|  |  |  |       if (res.isNotEmpty) { | 
					
						
							|  |  |  |         debugPrint("clients not match!"); | 
					
						
							|  |  |  |         updateClientState(res); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 22:07:45 +08:00
										 |  |  |       updatePasswordModel(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 22:07:45 +08:00
										 |  |  |   updatePasswordModel() { | 
					
						
							|  |  |  |     var update = false; | 
					
						
							|  |  |  |     final temporaryPassword = FFI.getByName("temporary_password"); | 
					
						
							|  |  |  |     final verificationMethod = FFI.getByName("option", "verification-method"); | 
					
						
							|  |  |  |     if (_serverPasswd.text != temporaryPassword) { | 
					
						
							|  |  |  |       _serverPasswd.text = temporaryPassword; | 
					
						
							|  |  |  |       update = true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 22:07:45 +08:00
										 |  |  |     if (_verificationMethod != verificationMethod) { | 
					
						
							|  |  |  |       _verificationMethod = verificationMethod; | 
					
						
							|  |  |  |       update = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (update) { | 
					
						
							|  |  |  |       notifyListeners(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |   toggleAudio() async { | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |     if (!_audioOk && !await PermissionManager.check("audio")) { | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |       final res = await PermissionManager.request("audio"); | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |       if (!res) { | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |         // TODO handle fail
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |     _audioOk = !_audioOk; | 
					
						
							|  |  |  |     Map<String, String> res = Map() | 
					
						
							|  |  |  |       ..["name"] = "enable-audio" | 
					
						
							|  |  |  |       ..["value"] = _audioOk ? '' : 'N'; | 
					
						
							|  |  |  |     FFI.setByName('option', jsonEncode(res)); | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |   toggleFile() async { | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |     if (!_fileOk && !await PermissionManager.check("file")) { | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |       final res = await PermissionManager.request("file"); | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |       if (!res) { | 
					
						
							| 
									
										
										
										
											2022-04-04 14:54:00 +08:00
										 |  |  |         // TODO handle fail
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |     _fileOk = !_fileOk; | 
					
						
							|  |  |  |     Map<String, String> res = Map() | 
					
						
							|  |  |  |       ..["name"] = "enable-file-transfer" | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |       ..["value"] = _fileOk ? '' : 'N'; | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |     FFI.setByName('option', jsonEncode(res)); | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |   toggleInput() { | 
					
						
							|  |  |  |     if (_inputOk) { | 
					
						
							| 
									
										
										
										
											2022-03-24 17:58:33 +08:00
										 |  |  |       FFI.invokeMethod("stop_input"); | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |       showInputWarnAlert(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   toggleService() async { | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |     if (_isStart) { | 
					
						
							|  |  |  |       final res = | 
					
						
							|  |  |  |           await DialogManager.show<bool>((setState, close) => CustomAlertDialog( | 
					
						
							|  |  |  |                 title: Row(children: [ | 
					
						
							|  |  |  |                   Icon(Icons.warning_amber_sharp, | 
					
						
							|  |  |  |                       color: Colors.redAccent, size: 28), | 
					
						
							|  |  |  |                   SizedBox(width: 10), | 
					
						
							|  |  |  |                   Text(translate("Warning")), | 
					
						
							|  |  |  |                 ]), | 
					
						
							|  |  |  |                 content: Text(translate("android_stop_service_tip")), | 
					
						
							|  |  |  |                 actions: [ | 
					
						
							|  |  |  |                   TextButton( | 
					
						
							|  |  |  |                       onPressed: () => close(), | 
					
						
							|  |  |  |                       child: Text(translate("Cancel"))), | 
					
						
							|  |  |  |                   ElevatedButton( | 
					
						
							|  |  |  |                       onPressed: () => close(true), | 
					
						
							|  |  |  |                       child: Text(translate("OK"))), | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               )); | 
					
						
							|  |  |  |       if (res == true) { | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |         stopService(); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       final res = | 
					
						
							|  |  |  |           await DialogManager.show<bool>((setState, close) => CustomAlertDialog( | 
					
						
							|  |  |  |                 title: Row(children: [ | 
					
						
							|  |  |  |                   Icon(Icons.warning_amber_sharp, | 
					
						
							|  |  |  |                       color: Colors.redAccent, size: 28), | 
					
						
							|  |  |  |                   SizedBox(width: 10), | 
					
						
							|  |  |  |                   Text(translate("Warning")), | 
					
						
							|  |  |  |                 ]), | 
					
						
							|  |  |  |                 content: Text(translate("android_service_will_start_tip")), | 
					
						
							|  |  |  |                 actions: [ | 
					
						
							|  |  |  |                   TextButton( | 
					
						
							|  |  |  |                       onPressed: () => close(), | 
					
						
							|  |  |  |                       child: Text(translate("Cancel"))), | 
					
						
							|  |  |  |                   ElevatedButton( | 
					
						
							|  |  |  |                       onPressed: () => close(true), | 
					
						
							|  |  |  |                       child: Text(translate("OK"))), | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |               )); | 
					
						
							|  |  |  |       if (res == true) { | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |         startService(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |   Future<Null> startService() async { | 
					
						
							|  |  |  |     _isStart = true; | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-05-17 19:59:37 +08:00
										 |  |  |     FFI.ffiModel.updateEventListener(""); | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |     await FFI.invokeMethod("init_service"); | 
					
						
							|  |  |  |     FFI.setByName("start_service"); | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  |     _fetchID(); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:45:48 +08:00
										 |  |  |     updateClientState(); | 
					
						
							| 
									
										
										
										
											2022-04-19 23:43:55 +08:00
										 |  |  |     Wakelock.enable(); | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |   Future<Null> stopService() async { | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |     _isStart = false; | 
					
						
							|  |  |  |     FFI.serverModel.closeAll(); | 
					
						
							|  |  |  |     await FFI.invokeMethod("stop_service"); | 
					
						
							|  |  |  |     FFI.setByName("stop_service"); | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-04-19 23:43:55 +08:00
										 |  |  |     Wakelock.disable(); | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future<Null> initInput() async { | 
					
						
							|  |  |  |     await FFI.invokeMethod("init_input"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  |   Future<bool> setPermanentPassword(String newPW) async { | 
					
						
							|  |  |  |     FFI.setByName("permanent_password", newPW); | 
					
						
							| 
									
										
										
										
											2022-03-30 23:09:19 +08:00
										 |  |  |     await Future.delayed(Duration(milliseconds: 500)); | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  |     final pw = FFI.getByName("permanent_password", newPW); | 
					
						
							|  |  |  |     if (newPW == pw) { | 
					
						
							|  |  |  |       return true; | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  |       return false; | 
					
						
							| 
									
										
										
										
											2022-03-30 23:09:19 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  |   _fetchID() async { | 
					
						
							|  |  |  |     final old = _serverId.text; | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |     var count = 0; | 
					
						
							|  |  |  |     const maxCount = 10; | 
					
						
							|  |  |  |     while (count < maxCount) { | 
					
						
							|  |  |  |       await Future.delayed(Duration(seconds: 1)); | 
					
						
							|  |  |  |       final id = FFI.getByName("server_id"); | 
					
						
							|  |  |  |       if (id.isEmpty) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         _serverId.text = id; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  |       debugPrint("fetch id again at $count:id:${_serverId.text}"); | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |       count++; | 
					
						
							| 
									
										
										
										
											2022-07-29 18:34:25 +08:00
										 |  |  |       if (_serverId.text != old) { | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |   changeStatue(String name, bool value) { | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |     debugPrint("changeStatue value $value"); | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |     switch (name) { | 
					
						
							|  |  |  |       case "media": | 
					
						
							|  |  |  |         _mediaOk = value; | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |         if (value && !_isStart) { | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |           startService(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |         break; | 
					
						
							|  |  |  |       case "input": | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |         if (_inputOk != value) { | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |           Map<String, String> res = Map() | 
					
						
							|  |  |  |             ..["name"] = "enable-keyboard" | 
					
						
							|  |  |  |             ..["value"] = value ? '' : 'N'; | 
					
						
							|  |  |  |           FFI.setByName('option', jsonEncode(res)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |         _inputOk = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-19 21:15:19 +08:00
										 |  |  |   updateClientState([String? json]) { | 
					
						
							|  |  |  |     var res = json ?? FFI.getByName("clients_state"); | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |     try { | 
					
						
							|  |  |  |       final List clientsJson = jsonDecode(res); | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |       for (var clientJson in clientsJson) { | 
					
						
							| 
									
										
										
										
											2022-04-15 17:45:48 +08:00
										 |  |  |         final client = Client.fromJson(clientJson); | 
					
						
							| 
									
										
										
										
											2022-03-25 16:34:27 +08:00
										 |  |  |         _clients[client.id] = client; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |       notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:45:48 +08:00
										 |  |  |     } catch (e) { | 
					
						
							|  |  |  |       debugPrint("Failed to updateClientState:$e"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |   void loginRequest(Map<String, dynamic> evt) { | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |       final client = Client.fromJson(jsonDecode(evt["client"])); | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |       if (_clients.containsKey(client.id)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       _clients[client.id] = client; | 
					
						
							| 
									
										
										
										
											2022-04-19 21:15:19 +08:00
										 |  |  |       scrollToBottom(); | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |       notifyListeners(); | 
					
						
							|  |  |  |       showLoginDialog(client); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       debugPrint("Failed to call loginRequest,error:$e"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void showLoginDialog(Client client) { | 
					
						
							|  |  |  |     DialogManager.show( | 
					
						
							|  |  |  |         (setState, close) => CustomAlertDialog( | 
					
						
							|  |  |  |               title: Row( | 
					
						
							|  |  |  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | 
					
						
							| 
									
										
										
										
											2022-03-30 17:31:32 +08:00
										 |  |  |                   children: [ | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |                     Text(translate(client.isFileTransfer | 
					
						
							|  |  |  |                         ? "File Connection" | 
					
						
							|  |  |  |                         : "Screen Connection")), | 
					
						
							|  |  |  |                     IconButton( | 
					
						
							|  |  |  |                         onPressed: () { | 
					
						
							|  |  |  |                           close(); | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                         icon: Icon(Icons.close)) | 
					
						
							|  |  |  |                   ]), | 
					
						
							|  |  |  |               content: Column( | 
					
						
							|  |  |  |                 mainAxisSize: MainAxisSize.min, | 
					
						
							|  |  |  |                 mainAxisAlignment: MainAxisAlignment.center, | 
					
						
							|  |  |  |                 crossAxisAlignment: CrossAxisAlignment.start, | 
					
						
							|  |  |  |                 children: [ | 
					
						
							|  |  |  |                   Text(translate("Do you accept?")), | 
					
						
							|  |  |  |                   clientInfo(client), | 
					
						
							|  |  |  |                   Text( | 
					
						
							|  |  |  |                     translate("android_new_connection_tip"), | 
					
						
							|  |  |  |                     style: TextStyle(color: Colors.black54), | 
					
						
							|  |  |  |                   ), | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |                 ], | 
					
						
							|  |  |  |               ), | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |               actions: [ | 
					
						
							|  |  |  |                 TextButton( | 
					
						
							|  |  |  |                     child: Text(translate("Dismiss")), | 
					
						
							|  |  |  |                     onPressed: () { | 
					
						
							|  |  |  |                       sendLoginResponse(client, false); | 
					
						
							|  |  |  |                       close(); | 
					
						
							|  |  |  |                     }), | 
					
						
							|  |  |  |                 ElevatedButton( | 
					
						
							|  |  |  |                     child: Text(translate("Accept")), | 
					
						
							|  |  |  |                     onPressed: () { | 
					
						
							|  |  |  |                       sendLoginResponse(client, true); | 
					
						
							|  |  |  |                       close(); | 
					
						
							|  |  |  |                     }), | 
					
						
							|  |  |  |               ], | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |         tag: getLoginDialogTag(client.id)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-19 21:15:19 +08:00
										 |  |  |   scrollToBottom() { | 
					
						
							|  |  |  |     Future.delayed(Duration(milliseconds: 200), () { | 
					
						
							|  |  |  |       controller.animateTo(controller.position.maxScrollExtent, | 
					
						
							|  |  |  |           duration: Duration(milliseconds: 200), | 
					
						
							|  |  |  |           curve: Curves.fastLinearToSlowEaseIn); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |   void sendLoginResponse(Client client, bool res) { | 
					
						
							|  |  |  |     final Map<String, dynamic> response = Map(); | 
					
						
							|  |  |  |     response["id"] = client.id; | 
					
						
							|  |  |  |     response["res"] = res; | 
					
						
							|  |  |  |     if (res) { | 
					
						
							|  |  |  |       FFI.setByName("login_res", jsonEncode(response)); | 
					
						
							|  |  |  |       if (!client.isFileTransfer) { | 
					
						
							|  |  |  |         FFI.invokeMethod("start_capture"); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       FFI.invokeMethod("cancel_notification", client.id); | 
					
						
							|  |  |  |       _clients[client.id]?.authorized = true; | 
					
						
							|  |  |  |       notifyListeners(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       FFI.setByName("login_res", jsonEncode(response)); | 
					
						
							|  |  |  |       FFI.invokeMethod("cancel_notification", client.id); | 
					
						
							|  |  |  |       _clients.remove(client.id); | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |   void onClientAuthorized(Map<String, dynamic> evt) { | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2022-03-25 16:34:27 +08:00
										 |  |  |       final client = Client.fromJson(jsonDecode(evt['client'])); | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |       DialogManager.dismissByTag(getLoginDialogTag(client.id)); | 
					
						
							| 
									
										
										
										
											2022-03-25 16:34:27 +08:00
										 |  |  |       _clients[client.id] = client; | 
					
						
							| 
									
										
										
										
											2022-04-19 21:15:19 +08:00
										 |  |  |       scrollToBottom(); | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |       notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |     } catch (e) {} | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void onClientRemove(Map<String, dynamic> evt) { | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |       final id = int.parse(evt['id'] as String); | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |       if (_clients.containsKey(id)) { | 
					
						
							| 
									
										
										
										
											2022-03-29 23:10:43 +08:00
										 |  |  |         _clients.remove(id); | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |         DialogManager.dismissByTag(getLoginDialogTag(id)); | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |         FFI.invokeMethod("cancel_notification", id); | 
					
						
							| 
									
										
										
										
											2022-03-29 23:10:43 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |       notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |       debugPrint("onClientRemove failed,error:$e"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 16:40:23 +08:00
										 |  |  |   closeAll() { | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |     _clients.forEach((id, client) { | 
					
						
							| 
									
										
										
										
											2022-03-25 16:34:27 +08:00
										 |  |  |       FFI.setByName("close_conn", id.toString()); | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-03-25 16:34:27 +08:00
										 |  |  |     _clients.clear(); | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Client { | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |   int id = 0; // client connections inner count id
 | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |   bool authorized = false; | 
					
						
							|  |  |  |   bool isFileTransfer = false; | 
					
						
							|  |  |  |   String name = ""; | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |   String peerId = ""; // peer user's id,show at app
 | 
					
						
							|  |  |  |   bool keyboard = false; | 
					
						
							|  |  |  |   bool clipboard = false; | 
					
						
							|  |  |  |   bool audio = false; | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |   Client(this.authorized, this.isFileTransfer, this.name, this.peerId, | 
					
						
							|  |  |  |       this.keyboard, this.clipboard, this.audio); | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Client.fromJson(Map<String, dynamic> json) { | 
					
						
							|  |  |  |     id = json['id']; | 
					
						
							|  |  |  |     authorized = json['authorized']; | 
					
						
							|  |  |  |     isFileTransfer = json['is_file_transfer']; | 
					
						
							|  |  |  |     name = json['name']; | 
					
						
							|  |  |  |     peerId = json['peer_id']; | 
					
						
							| 
									
										
										
										
											2022-04-13 15:33:23 +08:00
										 |  |  |     keyboard = json['keyboard']; | 
					
						
							|  |  |  |     clipboard = json['clipboard']; | 
					
						
							|  |  |  |     audio = json['audio']; | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Map<String, dynamic> toJson() { | 
					
						
							|  |  |  |     final Map<String, dynamic> data = new Map<String, dynamic>(); | 
					
						
							|  |  |  |     data['id'] = this.id; | 
					
						
							|  |  |  |     data['is_start'] = this.authorized; | 
					
						
							|  |  |  |     data['is_file_transfer'] = this.isFileTransfer; | 
					
						
							|  |  |  |     data['name'] = this.name; | 
					
						
							|  |  |  |     data['peer_id'] = this.peerId; | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |     data['keyboard'] = this.keyboard; | 
					
						
							|  |  |  |     data['clipboard'] = this.clipboard; | 
					
						
							|  |  |  |     data['audio'] = this.audio; | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  |     return data; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  | String getLoginDialogTag(int id) { | 
					
						
							|  |  |  |   return loginDialogTag + id.toString(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | showInputWarnAlert() { | 
					
						
							|  |  |  |   DialogManager.show((setState, close) => CustomAlertDialog( | 
					
						
							|  |  |  |         title: Text(translate("How to get Android input permission?")), | 
					
						
							|  |  |  |         content: Column( | 
					
						
							|  |  |  |           mainAxisSize: MainAxisSize.min, | 
					
						
							|  |  |  |           children: [ | 
					
						
							| 
									
										
										
										
											2022-04-20 16:53:10 +08:00
										 |  |  |             Text(translate("android_input_permission_tip1")), | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |             SizedBox(height: 10), | 
					
						
							| 
									
										
										
										
											2022-04-20 16:53:10 +08:00
										 |  |  |             Text(translate("android_input_permission_tip2")), | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  |           ], | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |         ), | 
					
						
							|  |  |  |         actions: [ | 
					
						
							|  |  |  |           TextButton(child: Text(translate("Cancel")), onPressed: close), | 
					
						
							|  |  |  |           ElevatedButton( | 
					
						
							|  |  |  |               child: Text(translate("Open System Setting")), | 
					
						
							|  |  |  |               onPressed: () { | 
					
						
							|  |  |  |                 FFI.serverModel.initInput(); | 
					
						
							|  |  |  |                 close(); | 
					
						
							|  |  |  |               }), | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |       )); | 
					
						
							| 
									
										
										
										
											2022-03-22 21:47:42 +08:00
										 |  |  | } |