| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							|  |  |  | import 'dart:convert'; | 
					
						
							| 
									
										
										
										
											2022-10-10 10:53:10 +08:00
										 |  |  | import 'dart:io'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | import 'dart:math'; | 
					
						
							|  |  |  | import 'dart:ui' as ui; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2020-11-28 13:22:19 +08:00
										 |  |  | import 'package:flutter/services.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-31 18:41:55 +08:00
										 |  |  | import 'package:flutter_hbb/consts.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-31 14:44:06 +08:00
										 |  |  | import 'package:flutter_hbb/generated_bridge.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-25 16:23:45 +08:00
										 |  |  | import 'package:flutter_hbb/models/ab_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-03-03 14:58:57 +08:00
										 |  |  | import 'package:flutter_hbb/models/chat_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  | import 'package:flutter_hbb/models/file_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  | import 'package:flutter_hbb/models/group_model.dart'; | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  | import 'package:flutter_hbb/models/peer_tab_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  | import 'package:flutter_hbb/models/server_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  | import 'package:flutter_hbb/models/user_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-11-01 17:01:43 +08:00
										 |  |  | import 'package:flutter_hbb/models/state_model.dart'; | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  | import 'package:flutter_hbb/plugin/event.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/plugin/desc.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/plugin/widget.dart'; | 
					
						
							| 
									
										
										
										
											2022-11-12 22:33:10 +08:00
										 |  |  | import 'package:flutter_hbb/common/shared_state.dart'; | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  | import 'package:tuple/tuple.dart'; | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  | import 'package:image/image.dart' as img2; | 
					
						
							| 
									
										
										
										
											2022-12-11 14:17:29 +08:00
										 |  |  | import 'package:flutter_custom_cursor/cursor_manager.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-27 18:34:05 +08:00
										 |  |  | import 'package:flutter_svg/flutter_svg.dart'; | 
					
						
							| 
									
										
										
										
											2023-01-06 20:25:18 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-28 18:29:25 +08:00
										 |  |  | import '../common.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  | import '../utils/image.dart' as img; | 
					
						
							| 
									
										
										
										
											2023-03-24 15:21:14 +08:00
										 |  |  | import '../common/widgets/dialog.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  | import 'input_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  | import 'platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  | typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id); | 
					
						
							| 
									
										
										
										
											2023-02-16 14:54:13 +08:00
										 |  |  | typedef ReconnectHandle = Function(OverlayDialogManager, String, bool); | 
					
						
							| 
									
										
										
										
											2022-10-27 12:07:48 +08:00
										 |  |  | final _waitForImage = <String, bool>{}; | 
					
						
							| 
									
										
										
										
											2022-03-19 23:28:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | class FfiModel with ChangeNotifier { | 
					
						
							| 
									
										
										
										
											2022-02-17 15:22:14 +08:00
										 |  |  |   PeerInfo _pi = PeerInfo(); | 
					
						
							|  |  |  |   Display _display = Display(); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-02 00:46:21 +08:00
										 |  |  |   var _inputBlocked = false; | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   final _permissions = <String, bool>{}; | 
					
						
							| 
									
										
										
										
											2022-02-17 15:22:14 +08:00
										 |  |  |   bool? _secure; | 
					
						
							|  |  |  |   bool? _direct; | 
					
						
							| 
									
										
										
										
											2022-04-28 22:44:54 +08:00
										 |  |  |   bool _touchMode = false; | 
					
						
							| 
									
										
										
										
											2022-03-28 17:24:52 +08:00
										 |  |  |   Timer? _timer; | 
					
						
							|  |  |  |   var _reconnects = 1; | 
					
						
							| 
									
										
										
										
											2023-03-16 09:37:35 +08:00
										 |  |  |   bool _viewOnly = false; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   WeakReference<FFI> parent; | 
					
						
							| 
									
										
										
										
											2020-11-22 21:08:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-28 22:44:54 +08:00
										 |  |  |   Map<String, bool> get permissions => _permissions; | 
					
						
							| 
									
										
										
										
											2022-02-02 17:25:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-28 22:44:54 +08:00
										 |  |  |   Display get display => _display; | 
					
						
							| 
									
										
										
										
											2022-02-02 17:25:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-28 22:44:54 +08:00
										 |  |  |   bool? get secure => _secure; | 
					
						
							| 
									
										
										
										
											2022-02-02 17:25:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-28 22:44:54 +08:00
										 |  |  |   bool? get direct => _direct; | 
					
						
							| 
									
										
										
										
											2022-02-02 17:25:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-28 22:44:54 +08:00
										 |  |  |   PeerInfo get pi => _pi; | 
					
						
							| 
									
										
										
										
											2022-02-17 15:22:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-28 22:44:54 +08:00
										 |  |  |   bool get inputBlocked => _inputBlocked; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool get touchMode => _touchMode; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 17:13:40 +08:00
										 |  |  |   bool get isPeerAndroid => _pi.platform == kPeerPlatformAndroid; | 
					
						
							| 
									
										
										
										
											2022-02-02 00:46:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-16 09:37:35 +08:00
										 |  |  |   bool get viewOnly => _viewOnly; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-02 00:46:21 +08:00
										 |  |  |   set inputBlocked(v) { | 
					
						
							|  |  |  |     _inputBlocked = v; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   FfiModel(this.parent) { | 
					
						
							| 
									
										
										
										
											2020-11-22 21:08:19 +08:00
										 |  |  |     clear(); | 
					
						
							| 
									
										
										
										
											2022-04-17 00:44:05 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   toggleTouchMode() { | 
					
						
							| 
									
										
										
										
											2022-04-28 22:44:54 +08:00
										 |  |  |     if (!isPeerAndroid) { | 
					
						
							|  |  |  |       _touchMode = !_touchMode; | 
					
						
							|  |  |  |       notifyListeners(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   updatePermission(Map<String, dynamic> evt, String id) { | 
					
						
							| 
									
										
										
										
											2020-11-22 21:08:19 +08:00
										 |  |  |     evt.forEach((k, v) { | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |       if (k == 'name' || k.isEmpty) return; | 
					
						
							| 
									
										
										
										
											2020-11-22 21:08:19 +08:00
										 |  |  |       _permissions[k] = v == 'true'; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-10-16 12:29:51 +08:00
										 |  |  |     // Only inited at remote page
 | 
					
						
							|  |  |  |     if (desktopType == DesktopType.remote) { | 
					
						
							|  |  |  |       KeyboardEnabledState.find(id).value = _permissions['keyboard'] != false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     debugPrint('$_permissions'); | 
					
						
							| 
									
										
										
										
											2022-02-06 16:29:56 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 10:36:59 +08:00
										 |  |  |   bool get keyboard => _permissions['keyboard'] != false; | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   clear() { | 
					
						
							| 
									
										
										
										
											2020-11-22 21:08:19 +08:00
										 |  |  |     _pi = PeerInfo(); | 
					
						
							|  |  |  |     _display = Display(); | 
					
						
							| 
									
										
										
										
											2020-11-29 00:13:55 +08:00
										 |  |  |     _secure = null; | 
					
						
							|  |  |  |     _direct = null; | 
					
						
							| 
									
										
										
										
											2022-02-02 00:46:21 +08:00
										 |  |  |     _inputBlocked = false; | 
					
						
							| 
									
										
										
										
											2022-03-28 17:24:52 +08:00
										 |  |  |     _timer?.cancel(); | 
					
						
							|  |  |  |     _timer = null; | 
					
						
							| 
									
										
										
										
											2020-11-28 13:22:19 +08:00
										 |  |  |     clearPermissions(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   setConnectionType(String peerId, bool secure, bool direct) { | 
					
						
							| 
									
										
										
										
											2020-11-29 00:13:55 +08:00
										 |  |  |     _secure = secure; | 
					
						
							|  |  |  |     _direct = direct; | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |     try { | 
					
						
							|  |  |  |       var connectionType = ConnectionTypeState.find(peerId); | 
					
						
							|  |  |  |       connectionType.setSecure(secure); | 
					
						
							|  |  |  |       connectionType.setDirect(direct); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       //
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-29 00:13:55 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 18:34:05 +08:00
										 |  |  |   Widget? getConnectionImage() { | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |     if (secure == null || direct == null) { | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       final icon = | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |           '${secure == true ? 'secure' : 'insecure'}${direct == true ? '' : '_relay'}'; | 
					
						
							| 
									
										
										
										
											2022-09-29 14:08:15 +08:00
										 |  |  |       return SvgPicture.asset('assets/$icon.svg', width: 48, height: 48); | 
					
						
							| 
									
										
										
										
											2020-11-29 00:13:55 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   clearPermissions() { | 
					
						
							| 
									
										
										
										
											2022-02-02 00:46:21 +08:00
										 |  |  |     _inputBlocked = false; | 
					
						
							| 
									
										
										
										
											2020-11-22 21:08:19 +08:00
										 |  |  |     _permissions.clear(); | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  |   StreamEventHandler startEventListener(String peerId) { | 
					
						
							|  |  |  |     return (evt) async { | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       var name = evt['name']; | 
					
						
							|  |  |  |       if (name == 'msgbox') { | 
					
						
							|  |  |  |         handleMsgBox(evt, peerId); | 
					
						
							|  |  |  |       } else if (name == 'peer_info') { | 
					
						
							| 
									
										
										
										
											2022-05-31 22:09:36 +08:00
										 |  |  |         handlePeerInfo(evt, peerId); | 
					
						
							| 
									
										
										
										
											2023-02-17 13:32:17 +08:00
										 |  |  |       } else if (name == 'sync_peer_info') { | 
					
						
							|  |  |  |         handleSyncPeerInfo(evt, peerId); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'connection_ready') { | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |         setConnectionType( | 
					
						
							|  |  |  |             peerId, evt['secure'] == 'true', evt['direct'] == 'true'); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'switch_display') { | 
					
						
							| 
									
										
										
										
											2022-12-30 16:14:30 +08:00
										 |  |  |         handleSwitchDisplay(evt, peerId); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'cursor_data') { | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  |         await parent.target?.cursorModel.updateCursorData(evt); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'cursor_id') { | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  |         await parent.target?.cursorModel.updateCursorId(evt); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'cursor_position') { | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  |         await parent.target?.cursorModel.updateCursorPosition(evt, peerId); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'clipboard') { | 
					
						
							|  |  |  |         Clipboard.setData(ClipboardData(text: evt['content'])); | 
					
						
							|  |  |  |       } else if (name == 'permission') { | 
					
						
							| 
									
										
										
										
											2023-02-25 22:47:22 +08:00
										 |  |  |         updatePermission(evt, peerId); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'chat_client_mode') { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |         parent.target?.chatModel | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |             .receive(ChatModel.clientModeID, evt['text'] ?? ''); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'chat_server_mode') { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |         parent.target?.chatModel | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |             .receive(int.parse(evt['id'] as String), evt['text'] ?? ''); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'file_dir') { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |         parent.target?.fileModel.receiveFileDir(evt); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'job_progress') { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         parent.target?.fileModel.jobController.tryUpdateJobProgress(evt); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'job_done') { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         parent.target?.fileModel.jobController.jobDone(evt); | 
					
						
							|  |  |  |         parent.target?.fileModel.refreshAll(); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'job_error') { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         parent.target?.fileModel.jobController.jobError(evt); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'override_file_confirm') { | 
					
						
							| 
									
										
										
										
											2023-03-15 15:19:40 +08:00
										 |  |  |         parent.target?.fileModel.postOverrideFileConfirm(evt); | 
					
						
							| 
									
										
										
										
											2022-07-11 18:23:58 +08:00
										 |  |  |       } else if (name == 'load_last_job') { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         parent.target?.fileModel.jobController.loadLastJob(evt); | 
					
						
							| 
									
										
										
										
											2022-07-11 10:30:45 +08:00
										 |  |  |       } else if (name == 'update_folder_files') { | 
					
						
							| 
									
										
										
										
											2023-03-08 21:05:55 +09:00
										 |  |  |         parent.target?.fileModel.jobController.updateFolderFiles(evt); | 
					
						
							| 
									
										
										
										
											2022-09-05 19:41:09 +08:00
										 |  |  |       } else if (name == 'add_connection') { | 
					
						
							|  |  |  |         parent.target?.serverModel.addConnection(evt); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } else if (name == 'on_client_remove') { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |         parent.target?.serverModel.onClientRemove(evt); | 
					
						
							| 
									
										
										
										
											2022-08-05 20:29:43 +08:00
										 |  |  |       } else if (name == 'update_quality_status') { | 
					
						
							|  |  |  |         parent.target?.qualityMonitorModel.updateQualityStatus(evt); | 
					
						
							| 
									
										
										
										
											2022-08-08 22:00:01 +08:00
										 |  |  |       } else if (name == 'update_block_input_state') { | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |         updateBlockInputState(evt, peerId); | 
					
						
							| 
									
										
										
										
											2022-08-08 22:00:01 +08:00
										 |  |  |       } else if (name == 'update_privacy_mode') { | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |         updatePrivacyMode(evt, peerId); | 
					
						
							| 
									
										
										
										
											2022-10-11 19:52:03 +08:00
										 |  |  |       } else if (name == 'new_connection') { | 
					
						
							| 
									
										
										
										
											2023-01-18 13:54:56 +08:00
										 |  |  |         var uni_links = evt['uni_links'].toString(); | 
					
						
							|  |  |  |         if (uni_links.startsWith(kUniLinksPrefix)) { | 
					
						
							|  |  |  |           parseRustdeskUri(uni_links); | 
					
						
							| 
									
										
										
										
											2022-10-12 21:57:19 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-11-12 22:33:10 +08:00
										 |  |  |       } else if (name == 'alias') { | 
					
						
							|  |  |  |         handleAliasChanged(evt); | 
					
						
							| 
									
										
										
										
											2022-11-10 10:27:13 +08:00
										 |  |  |       } else if (name == 'show_elevation') { | 
					
						
							|  |  |  |         final show = evt['show'].toString() == 'true'; | 
					
						
							|  |  |  |         parent.target?.serverModel.setShowElevation(show); | 
					
						
							| 
									
										
										
										
											2022-11-15 16:49:55 +08:00
										 |  |  |       } else if (name == 'cancel_msgbox') { | 
					
						
							|  |  |  |         cancelMsgBox(evt, peerId); | 
					
						
							| 
									
										
										
										
											2023-01-17 13:28:33 +08:00
										 |  |  |       } else if (name == 'switch_back') { | 
					
						
							|  |  |  |         final peer_id = evt['peer_id'].toString(); | 
					
						
							|  |  |  |         await bind.sessionSwitchSides(id: peer_id); | 
					
						
							|  |  |  |         closeConnection(id: peer_id); | 
					
						
							| 
									
										
										
										
											2023-02-24 15:51:13 +08:00
										 |  |  |       } else if (name == 'portable_service_running') { | 
					
						
							|  |  |  |         parent.target?.elevationModel.onPortableServiceRunning(evt); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |       } else if (name == 'on_url_scheme_received') { | 
					
						
							| 
									
										
										
										
											2023-02-04 11:23:36 +08:00
										 |  |  |         final url = evt['url'].toString(); | 
					
						
							|  |  |  |         parseRustdeskUri(url); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |       } else if (name == 'on_voice_call_waiting') { | 
					
						
							| 
									
										
										
										
											2023-02-06 20:10:39 +08:00
										 |  |  |         // Waiting for the response from the peer.
 | 
					
						
							|  |  |  |         parent.target?.chatModel.onVoiceCallWaiting(); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |       } else if (name == 'on_voice_call_started') { | 
					
						
							| 
									
										
										
										
											2023-02-06 20:10:39 +08:00
										 |  |  |         // Voice call is connected.
 | 
					
						
							|  |  |  |         parent.target?.chatModel.onVoiceCallStarted(); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |       } else if (name == 'on_voice_call_closed') { | 
					
						
							| 
									
										
										
										
											2023-02-06 20:10:39 +08:00
										 |  |  |         // Voice call is closed with reason.
 | 
					
						
							|  |  |  |         final reason = evt['reason'].toString(); | 
					
						
							|  |  |  |         parent.target?.chatModel.onVoiceCallClosed(reason); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |       } else if (name == 'on_voice_call_incoming') { | 
					
						
							| 
									
										
										
										
											2023-02-06 20:10:39 +08:00
										 |  |  |         // Voice call is requested by the peer.
 | 
					
						
							|  |  |  |         parent.target?.chatModel.onVoiceCallIncoming(); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |       } else if (name == 'update_voice_call_state') { | 
					
						
							| 
									
										
										
										
											2023-02-07 16:11:55 +08:00
										 |  |  |         parent.target?.serverModel.updateVoiceCallState(evt); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |       } else if (name == 'fingerprint') { | 
					
						
							| 
									
										
										
										
											2023-04-19 14:39:22 +08:00
										 |  |  |         FingerprintState.find(peerId).value = evt['fingerprint'] ?? ''; | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |       } else if (name == 'plugin_desc') { | 
					
						
							| 
									
										
										
										
											2023-04-20 18:10:06 +08:00
										 |  |  |         updateDesc(evt); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |       } else if (name == 'plugin_event') { | 
					
						
							| 
									
										
										
										
											2023-04-20 10:29:24 +08:00
										 |  |  |         handlePluginEvent( | 
					
						
							|  |  |  |             evt, peerId, (Map<String, dynamic> e) => handleMsgBox(e, peerId)); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |       } else if (name == 'plugin_reload') { | 
					
						
							| 
									
										
										
										
											2023-04-20 10:29:24 +08:00
										 |  |  |         handleReloading(evt, peerId); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |       } else if (name == 'plugin_option') { | 
					
						
							|  |  |  |         handleOption(evt, peerId); | 
					
						
							| 
									
										
										
										
											2023-02-06 20:10:39 +08:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |         debugPrint('Unknown event name: $name'); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  |   /// Bind the event listener to receive events from the Rust core.
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   updateEventListener(String peerId) { | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     platformFFI.setEventCallback(startEventListener(peerId)); | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-12 22:33:10 +08:00
										 |  |  |   handleAliasChanged(Map<String, dynamic> evt) { | 
					
						
							|  |  |  |     final rxAlias = PeerStringOption.find(evt['id'], 'alias'); | 
					
						
							|  |  |  |     if (rxAlias.value != evt['alias']) { | 
					
						
							|  |  |  |       rxAlias.value = evt['alias']; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-25 22:47:22 +08:00
										 |  |  |   _updateCurDisplay(String peerId, Display newDisplay) { | 
					
						
							|  |  |  |     if (newDisplay != _display) { | 
					
						
							|  |  |  |       if (newDisplay.x != _display.x || newDisplay.y != _display.y) { | 
					
						
							|  |  |  |         parent.target?.cursorModel | 
					
						
							|  |  |  |             .updateDisplayOrigin(newDisplay.x, newDisplay.y); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       _display = newDisplay; | 
					
						
							|  |  |  |       _updateSessionWidthHeight(peerId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-30 16:14:30 +08:00
										 |  |  |   handleSwitchDisplay(Map<String, dynamic> evt, String peerId) { | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     _pi.currentDisplay = int.parse(evt['display']); | 
					
						
							| 
									
										
										
										
											2023-02-25 22:47:22 +08:00
										 |  |  |     var newDisplay = Display(); | 
					
						
							|  |  |  |     newDisplay.x = double.parse(evt['x']); | 
					
						
							|  |  |  |     newDisplay.y = double.parse(evt['y']); | 
					
						
							|  |  |  |     newDisplay.width = int.parse(evt['width']); | 
					
						
							|  |  |  |     newDisplay.height = int.parse(evt['height']); | 
					
						
							|  |  |  |     newDisplay.cursorEmbedded = int.parse(evt['cursor_embedded']) == 1; | 
					
						
							| 
									
										
										
										
											2022-06-02 17:16:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-25 22:47:22 +08:00
										 |  |  |     _updateCurDisplay(peerId, newDisplay); | 
					
						
							| 
									
										
										
										
											2023-02-21 21:56:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-30 16:14:30 +08:00
										 |  |  |     try { | 
					
						
							|  |  |  |       CurrentDisplayState.find(peerId).value = _pi.currentDisplay; | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       //
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-21 16:03:08 +08:00
										 |  |  |     parent.target?.recordingModel.onSwitchDisplay(); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |     handleResolutions(peerId, evt['resolutions']); | 
					
						
							| 
									
										
										
										
											2020-11-25 23:52:58 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-15 16:49:55 +08:00
										 |  |  |   cancelMsgBox(Map<String, dynamic> evt, String id) { | 
					
						
							|  |  |  |     if (parent.target == null) return; | 
					
						
							|  |  |  |     final dialogManager = parent.target!.dialogManager; | 
					
						
							|  |  |  |     final tag = '$id-${evt['tag']}'; | 
					
						
							|  |  |  |     dialogManager.dismissByTag(tag); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  |   /// Handle the message box event based on [evt] and [id].
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   handleMsgBox(Map<String, dynamic> evt, String id) { | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     if (parent.target == null) return; | 
					
						
							|  |  |  |     final dialogManager = parent.target!.dialogManager; | 
					
						
							| 
									
										
										
										
											2022-10-14 11:19:49 +08:00
										 |  |  |     final type = evt['type']; | 
					
						
							|  |  |  |     final title = evt['title']; | 
					
						
							|  |  |  |     final text = evt['text']; | 
					
						
							|  |  |  |     final link = evt['link']; | 
					
						
							| 
									
										
										
										
											2022-03-28 17:24:52 +08:00
										 |  |  |     if (type == 're-input-password') { | 
					
						
							| 
									
										
										
										
											2023-01-30 17:56:35 +08:00
										 |  |  |       wrongPasswordDialog(id, dialogManager, type, title, text); | 
					
						
							| 
									
										
										
										
											2022-03-28 17:24:52 +08:00
										 |  |  |     } else if (type == 'input-password') { | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |       enterPasswordDialog(id, dialogManager); | 
					
						
							| 
									
										
										
										
											2023-03-30 14:11:56 +08:00
										 |  |  |     } else if (type == 'session-login' || type == 'session-re-login') { | 
					
						
							| 
									
										
										
										
											2023-03-29 20:25:41 +08:00
										 |  |  |       enterUserLoginDialog(id, dialogManager); | 
					
						
							| 
									
										
										
										
											2023-03-30 14:11:56 +08:00
										 |  |  |     } else if (type == 'session-login-password' || | 
					
						
							|  |  |  |         type == 'session-login-password') { | 
					
						
							| 
									
										
										
										
											2023-03-29 20:25:41 +08:00
										 |  |  |       enterUserLoginAndPasswordDialog(id, dialogManager); | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |     } else if (type == 'restarting') { | 
					
						
							| 
									
										
										
										
											2022-10-25 11:27:34 +09:00
										 |  |  |       showMsgBox(id, type, title, text, link, false, dialogManager, | 
					
						
							|  |  |  |           hasCancel: false); | 
					
						
							| 
									
										
										
										
											2022-11-20 15:53:08 +08:00
										 |  |  |     } else if (type == 'wait-remote-accept-nook') { | 
					
						
							| 
									
										
										
										
											2023-01-30 17:56:35 +08:00
										 |  |  |       showWaitAcceptDialog(id, type, title, text, dialogManager); | 
					
						
							| 
									
										
										
										
											2023-01-12 21:03:05 +08:00
										 |  |  |     } else if (type == 'on-uac' || type == 'on-foreground-elevated') { | 
					
						
							|  |  |  |       showOnBlockDialog(id, type, title, text, dialogManager); | 
					
						
							|  |  |  |     } else if (type == 'wait-uac') { | 
					
						
							| 
									
										
										
										
											2023-01-30 17:56:35 +08:00
										 |  |  |       showWaitUacDialog(id, dialogManager, type); | 
					
						
							| 
									
										
										
										
											2023-01-12 21:03:05 +08:00
										 |  |  |     } else if (type == 'elevation-error') { | 
					
						
							|  |  |  |       showElevationError(id, type, title, text, dialogManager); | 
					
						
							| 
									
										
										
										
											2023-04-21 21:40:34 +08:00
										 |  |  |     } else if (type == 'relay-hint') { | 
					
						
							| 
									
										
										
										
											2023-02-14 19:44:14 +08:00
										 |  |  |       showRelayHintDialog(id, type, title, text, dialogManager); | 
					
						
							| 
									
										
										
										
											2022-03-28 17:24:52 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       var hasRetry = evt['hasRetry'] == 'true'; | 
					
						
							| 
									
										
										
										
											2022-10-14 11:19:49 +08:00
										 |  |  |       showMsgBox(id, type, title, text, link, hasRetry, dialogManager); | 
					
						
							| 
									
										
										
										
											2022-03-28 17:24:52 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  |   /// Show a message box with [type], [title] and [text].
 | 
					
						
							| 
									
										
										
										
											2022-10-14 11:19:49 +08:00
										 |  |  |   showMsgBox(String id, String type, String title, String text, String link, | 
					
						
							|  |  |  |       bool hasRetry, OverlayDialogManager dialogManager, | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |       {bool? hasCancel}) { | 
					
						
							| 
									
										
										
										
											2023-02-16 14:54:13 +08:00
										 |  |  |     msgBox(id, type, title, text, link, dialogManager, | 
					
						
							|  |  |  |         hasCancel: hasCancel, reconnect: reconnect); | 
					
						
							| 
									
										
										
										
											2022-05-16 00:01:27 +08:00
										 |  |  |     _timer?.cancel(); | 
					
						
							| 
									
										
										
										
											2022-03-28 17:24:52 +08:00
										 |  |  |     if (hasRetry) { | 
					
						
							|  |  |  |       _timer = Timer(Duration(seconds: _reconnects), () { | 
					
						
							| 
									
										
										
										
											2023-02-16 14:54:13 +08:00
										 |  |  |         reconnect(dialogManager, id, false); | 
					
						
							| 
									
										
										
										
											2022-03-28 17:24:52 +08:00
										 |  |  |       }); | 
					
						
							|  |  |  |       _reconnects *= 2; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       _reconnects = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-16 14:54:13 +08:00
										 |  |  |   void reconnect( | 
					
						
							|  |  |  |       OverlayDialogManager dialogManager, String id, bool forceRelay) { | 
					
						
							|  |  |  |     bind.sessionReconnect(id: id, forceRelay: forceRelay); | 
					
						
							|  |  |  |     clearPermissions(); | 
					
						
							|  |  |  |     dialogManager.showLoading(translate('Connecting...'), | 
					
						
							|  |  |  |         onCancel: closeConnection); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 19:44:14 +08:00
										 |  |  |   void showRelayHintDialog(String id, String type, String title, String text, | 
					
						
							|  |  |  |       OverlayDialogManager dialogManager) { | 
					
						
							|  |  |  |     dialogManager.show(tag: '$id-$type', (setState, close) { | 
					
						
							|  |  |  |       onClose() { | 
					
						
							|  |  |  |         closeConnection(); | 
					
						
							|  |  |  |         close(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       final style = | 
					
						
							|  |  |  |           ElevatedButton.styleFrom(backgroundColor: Colors.green[700]); | 
					
						
							|  |  |  |       return CustomAlertDialog( | 
					
						
							|  |  |  |         title: null, | 
					
						
							|  |  |  |         content: msgboxContent(type, title, | 
					
						
							|  |  |  |             "${translate(text)}\n\n${translate('relay_hint_tip')}"), | 
					
						
							|  |  |  |         actions: [ | 
					
						
							|  |  |  |           dialogButton('Close', onPressed: onClose, isOutline: true), | 
					
						
							| 
									
										
										
										
											2023-02-16 14:54:13 +08:00
										 |  |  |           dialogButton('Retry', | 
					
						
							|  |  |  |               onPressed: () => reconnect(dialogManager, id, false)), | 
					
						
							| 
									
										
										
										
											2023-02-14 19:44:14 +08:00
										 |  |  |           dialogButton('Connect via relay', | 
					
						
							| 
									
										
										
										
											2023-02-16 14:54:13 +08:00
										 |  |  |               onPressed: () => reconnect(dialogManager, id, true), | 
					
						
							|  |  |  |               buttonStyle: style), | 
					
						
							| 
									
										
										
										
											2023-02-14 19:44:14 +08:00
										 |  |  |           dialogButton('Always connect via relay', onPressed: () { | 
					
						
							|  |  |  |             const option = 'force-always-relay'; | 
					
						
							|  |  |  |             bind.sessionPeerOption( | 
					
						
							|  |  |  |                 id: id, name: option, value: bool2option(option, true)); | 
					
						
							| 
									
										
										
										
											2023-02-16 14:54:13 +08:00
										 |  |  |             reconnect(dialogManager, id, true); | 
					
						
							| 
									
										
										
										
											2023-02-14 19:44:14 +08:00
										 |  |  |           }, buttonStyle: style), | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         onCancel: onClose, | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-25 22:47:22 +08:00
										 |  |  |   _updateSessionWidthHeight(String id) { | 
					
						
							|  |  |  |     parent.target?.canvasModel.updateViewStyle(); | 
					
						
							| 
									
										
										
										
											2023-03-10 10:53:41 +08:00
										 |  |  |     if (display.width <= 0 || display.height <= 0) { | 
					
						
							| 
									
										
										
										
											2023-03-16 09:37:35 +08:00
										 |  |  |       debugPrintStack( | 
					
						
							|  |  |  |           label: 'invalid display size (${display.width},${display.height})'); | 
					
						
							| 
									
										
										
										
											2023-03-09 19:38:47 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       bind.sessionSetSize(id: id, width: display.width, height: display.height); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-21 21:56:46 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  |   /// Handle the peer info event based on [evt].
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   handlePeerInfo(Map<String, dynamic> evt, String peerId) async { | 
					
						
							| 
									
										
										
										
											2022-09-01 06:18:29 -07:00
										 |  |  |     // recent peer updated by handle_peer_info(ui_session_interface.rs) --> handle_peer_info(client.rs) --> save_config(client.rs)
 | 
					
						
							|  |  |  |     bind.mainLoadRecentPeers(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     parent.target?.dialogManager.dismissAll(); | 
					
						
							| 
									
										
										
										
											2020-11-27 17:34:09 +08:00
										 |  |  |     _pi.version = evt['version']; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     _pi.username = evt['username']; | 
					
						
							|  |  |  |     _pi.hostname = evt['hostname']; | 
					
						
							|  |  |  |     _pi.platform = evt['platform']; | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     _pi.sasEnabled = evt['sas_enabled'] == 'true'; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     _pi.currentDisplay = int.parse(evt['current_display']); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |     try { | 
					
						
							|  |  |  |       CurrentDisplayState.find(peerId).value = _pi.currentDisplay; | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       //
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-18 13:48:56 +08:00
										 |  |  |     final connType = parent.target?.connType; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-28 22:44:54 +08:00
										 |  |  |     if (isPeerAndroid) { | 
					
						
							|  |  |  |       _touchMode = true; | 
					
						
							| 
									
										
										
										
											2023-03-18 13:48:56 +08:00
										 |  |  |       if (connType == ConnType.defaultConn && | 
					
						
							|  |  |  |           parent.target != null && | 
					
						
							| 
									
										
										
										
											2022-09-08 22:18:02 +08:00
										 |  |  |           parent.target!.ffiModel.permissions['keyboard'] != false) { | 
					
						
							| 
									
										
										
										
											2022-09-29 20:50:01 +08:00
										 |  |  |         Timer( | 
					
						
							|  |  |  |             const Duration(milliseconds: 100), | 
					
						
							|  |  |  |             () => parent.target!.dialogManager | 
					
						
							|  |  |  |                 .showMobileActionsOverlay(ffi: parent.target!)); | 
					
						
							| 
									
										
										
										
											2022-04-28 22:44:54 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |       _touchMode = | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |           await bind.sessionGetOption(id: peerId, arg: 'touch-mode') != ''; | 
					
						
							| 
									
										
										
										
											2022-04-28 22:44:54 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-18 13:48:56 +08:00
										 |  |  |     if (connType == ConnType.fileTransfer) { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |       parent.target?.fileModel.onReady(); | 
					
						
							| 
									
										
										
										
											2023-03-18 13:48:56 +08:00
										 |  |  |     } else if (connType == ConnType.defaultConn) { | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |       _pi.displays = []; | 
					
						
							|  |  |  |       List<dynamic> displays = json.decode(evt['displays']); | 
					
						
							|  |  |  |       for (int i = 0; i < displays.length; ++i) { | 
					
						
							|  |  |  |         Map<String, dynamic> d0 = displays[i]; | 
					
						
							|  |  |  |         var d = Display(); | 
					
						
							|  |  |  |         d.x = d0['x'].toDouble(); | 
					
						
							|  |  |  |         d.y = d0['y'].toDouble(); | 
					
						
							|  |  |  |         d.width = d0['width']; | 
					
						
							|  |  |  |         d.height = d0['height']; | 
					
						
							| 
									
										
										
										
											2022-12-31 21:41:16 +08:00
										 |  |  |         d.cursorEmbedded = d0['cursor_embedded'] == 1; | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |         _pi.displays.add(d); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-02-17 13:32:17 +08:00
										 |  |  |       stateGlobal.displaysCount.value = _pi.displays.length; | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |       if (_pi.currentDisplay < _pi.displays.length) { | 
					
						
							|  |  |  |         _display = _pi.displays[_pi.currentDisplay]; | 
					
						
							| 
									
										
										
										
											2023-02-25 22:47:22 +08:00
										 |  |  |         _updateSessionWidthHeight(peerId); | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-10-04 21:19:31 +08:00
										 |  |  |       if (displays.isNotEmpty) { | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |         parent.target?.dialogManager.showLoading( | 
					
						
							|  |  |  |             translate('Connected, waiting for image...'), | 
					
						
							| 
									
										
										
										
											2022-08-16 21:27:21 +08:00
										 |  |  |             onCancel: closeConnection); | 
					
						
							| 
									
										
										
										
											2022-10-27 12:07:48 +08:00
										 |  |  |         _waitForImage[peerId] = true; | 
					
						
							| 
									
										
										
										
											2022-04-26 21:21:08 +08:00
										 |  |  |         _reconnects = 1; | 
					
						
							| 
									
										
										
										
											2022-03-16 15:33:00 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-12-02 21:34:20 +08:00
										 |  |  |       Map<String, dynamic> features = json.decode(evt['features']); | 
					
						
							|  |  |  |       _pi.features.privacyMode = features['privacy_mode'] == 1; | 
					
						
							| 
									
										
										
										
											2023-02-09 15:53:51 +08:00
										 |  |  |       handleResolutions(peerId, evt["resolutions"]); | 
					
						
							| 
									
										
										
										
											2023-02-24 15:51:13 +08:00
										 |  |  |       parent.target?.elevationModel.onPeerInfo(_pi); | 
					
						
							| 
									
										
										
										
											2020-11-19 00:53:10 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-18 13:48:56 +08:00
										 |  |  |     if (connType == ConnType.defaultConn) { | 
					
						
							|  |  |  |       setViewOnly(peerId, | 
					
						
							|  |  |  |           bind.sessionGetToggleOptionSync(id: peerId, arg: 'view-only')); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-21 11:27:30 +08:00
										 |  |  |     if (connType == ConnType.defaultConn) { | 
					
						
							| 
									
										
										
										
											2023-03-21 12:25:47 +08:00
										 |  |  |       final platform_additions = evt['platform_additions']; | 
					
						
							|  |  |  |       if (platform_additions != null && platform_additions != '') { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           _pi.platform_additions = json.decode(platform_additions); | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |           debugPrint('Failed to decode platform_additions $e'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-03-21 11:27:30 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-29 14:28:07 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-08 22:00:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 15:53:51 +08:00
										 |  |  |   handleResolutions(String id, dynamic resolutions) { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       final List<dynamic> dynamicArray = jsonDecode(resolutions as String); | 
					
						
							|  |  |  |       List<Resolution> arr = List.empty(growable: true); | 
					
						
							|  |  |  |       for (int i = 0; i < dynamicArray.length; i++) { | 
					
						
							|  |  |  |         var width = dynamicArray[i]["width"]; | 
					
						
							|  |  |  |         var height = dynamicArray[i]["height"]; | 
					
						
							|  |  |  |         if (width is int && width > 0 && height is int && height > 0) { | 
					
						
							|  |  |  |           arr.add(Resolution(width, height)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       arr.sort((a, b) { | 
					
						
							|  |  |  |         if (b.width != a.width) { | 
					
						
							|  |  |  |           return b.width - a.width; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           return b.height - a.height; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       _pi.resolutions = arr; | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       debugPrint("Failed to parse resolutions:$e"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 13:32:17 +08:00
										 |  |  |   /// Handle the peer info synchronization event based on [evt].
 | 
					
						
							|  |  |  |   handleSyncPeerInfo(Map<String, dynamic> evt, String peerId) async { | 
					
						
							|  |  |  |     if (evt['displays'] != null) { | 
					
						
							|  |  |  |       List<dynamic> displays = json.decode(evt['displays']); | 
					
						
							|  |  |  |       List<Display> newDisplays = []; | 
					
						
							|  |  |  |       for (int i = 0; i < displays.length; ++i) { | 
					
						
							|  |  |  |         Map<String, dynamic> d0 = displays[i]; | 
					
						
							|  |  |  |         var d = Display(); | 
					
						
							|  |  |  |         d.x = d0['x'].toDouble(); | 
					
						
							|  |  |  |         d.y = d0['y'].toDouble(); | 
					
						
							|  |  |  |         d.width = d0['width']; | 
					
						
							|  |  |  |         d.height = d0['height']; | 
					
						
							|  |  |  |         d.cursorEmbedded = d0['cursor_embedded'] == 1; | 
					
						
							|  |  |  |         newDisplays.add(d); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       _pi.displays = newDisplays; | 
					
						
							|  |  |  |       stateGlobal.displaysCount.value = _pi.displays.length; | 
					
						
							| 
									
										
										
										
											2023-02-09 15:53:51 +08:00
										 |  |  |       if (_pi.currentDisplay >= 0 && _pi.currentDisplay < _pi.displays.length) { | 
					
						
							| 
									
										
										
										
											2023-02-25 22:47:22 +08:00
										 |  |  |         _updateCurDisplay(peerId, _pi.displays[_pi.currentDisplay]); | 
					
						
							| 
									
										
										
										
											2023-02-09 15:53:51 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-02-17 13:32:17 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |   updateBlockInputState(Map<String, dynamic> evt, String peerId) { | 
					
						
							| 
									
										
										
										
											2022-08-08 22:00:01 +08:00
										 |  |  |     _inputBlocked = evt['input_state'] == 'on'; | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |     try { | 
					
						
							|  |  |  |       BlockInputState.find(peerId).value = evt['input_state'] == 'on'; | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       //
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-08 22:00:01 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |   updatePrivacyMode(Map<String, dynamic> evt, String peerId) { | 
					
						
							| 
									
										
										
										
											2022-08-08 22:00:01 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |     try { | 
					
						
							|  |  |  |       PrivacyModeState.find(peerId).value = | 
					
						
							|  |  |  |           bind.sessionGetToggleOptionSync(id: peerId, arg: 'privacy-mode'); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       //
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-08 22:00:01 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-03-16 09:37:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void setViewOnly(String id, bool value) { | 
					
						
							| 
									
										
										
										
											2023-03-17 11:27:22 +08:00
										 |  |  |     if (version_cmp(_pi.version, '1.2.0') < 0) return; | 
					
						
							| 
									
										
										
										
											2023-03-23 22:52:58 +08:00
										 |  |  |     // tmp fix for https://github.com/rustdesk/rustdesk/pull/3706#issuecomment-1481242389
 | 
					
						
							|  |  |  |     // because below rx not used in mobile version, so not initialized, below code will cause crash
 | 
					
						
							|  |  |  |     // current our flutter code quality is fucking shit now. !!!!!!!!!!!!!!!!
 | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       if (value) { | 
					
						
							|  |  |  |         ShowRemoteCursorState.find(id).value = value; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         ShowRemoteCursorState.find(id).value = | 
					
						
							|  |  |  |             bind.sessionGetToggleOptionSync(id: id, arg: 'show-remote-cursor'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       //
 | 
					
						
							| 
									
										
										
										
											2023-03-16 09:37:35 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (_viewOnly != value) { | 
					
						
							|  |  |  |       _viewOnly = value; | 
					
						
							|  |  |  |       notifyListeners(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ImageModel with ChangeNotifier { | 
					
						
							| 
									
										
										
										
											2022-02-17 15:22:14 +08:00
										 |  |  |   ui.Image? _image; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-17 15:22:14 +08:00
										 |  |  |   ui.Image? get image => _image; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-13 21:52:22 +08:00
										 |  |  |   String id = ''; | 
					
						
							| 
									
										
										
										
											2022-05-31 22:09:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   WeakReference<FFI> parent; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-21 21:56:46 +08:00
										 |  |  |   final List<Function(String)> callbacksOnFirstImage = []; | 
					
						
							| 
									
										
										
										
											2022-12-27 16:45:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   ImageModel(this.parent); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-21 21:56:46 +08:00
										 |  |  |   addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb); | 
					
						
							| 
									
										
										
										
											2022-12-27 16:45:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  |   onRgba(Uint8List rgba) { | 
					
						
							| 
									
										
										
										
											2023-03-27 16:11:17 +08:00
										 |  |  |     final waitforImage = _waitForImage[id]; | 
					
						
							|  |  |  |     if (waitforImage == null) { | 
					
						
							|  |  |  |       debugPrint('Exception, peer $id not found for waiting image'); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (waitforImage == true) { | 
					
						
							| 
									
										
										
										
											2022-10-27 12:07:48 +08:00
										 |  |  |       _waitForImage[id] = false; | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |       parent.target?.dialogManager.dismissAll(); | 
					
						
							| 
									
										
										
										
											2022-12-27 16:45:13 +08:00
										 |  |  |       if (isDesktop) { | 
					
						
							| 
									
										
										
										
											2023-02-21 21:56:46 +08:00
										 |  |  |         for (final cb in callbacksOnFirstImage) { | 
					
						
							| 
									
										
										
										
											2022-12-27 16:45:13 +08:00
										 |  |  |           cb(id); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-05-31 22:09:36 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-10 18:26:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     final pid = parent.target?.id; | 
					
						
							| 
									
										
										
										
											2023-02-15 16:44:40 +08:00
										 |  |  |     img.decodeImageFromPixels( | 
					
						
							| 
									
										
										
										
											2022-05-31 22:09:36 +08:00
										 |  |  |         rgba, | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |         parent.target?.ffiModel.display.width ?? 0, | 
					
						
							|  |  |  |         parent.target?.ffiModel.display.height ?? 0, | 
					
						
							| 
									
										
										
										
											2023-02-15 16:44:40 +08:00
										 |  |  |         isWeb ? ui.PixelFormat.rgba8888 : ui.PixelFormat.bgra8888, | 
					
						
							|  |  |  |         onPixelsCopied: () { | 
					
						
							|  |  |  |       // Unlock the rgba memory from rust codes.
 | 
					
						
							|  |  |  |       platformFFI.nextRgba(id); | 
					
						
							|  |  |  |     }).then((image) { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |       if (parent.target?.id != pid) return; | 
					
						
							| 
									
										
										
										
											2022-05-31 22:09:36 +08:00
										 |  |  |       try { | 
					
						
							|  |  |  |         // my throw exception, because the listener maybe already dispose
 | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  |         update(image); | 
					
						
							| 
									
										
										
										
											2022-05-31 22:09:36 +08:00
										 |  |  |       } catch (e) { | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  |         debugPrint('update image: $e'); | 
					
						
							| 
									
										
										
										
											2022-05-19 23:45:44 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  |   update(ui.Image? image) async { | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |     if (_image == null && image != null) { | 
					
						
							| 
									
										
										
										
											2022-08-13 15:08:17 +08:00
										 |  |  |       if (isWebDesktop || isDesktop) { | 
					
						
							| 
									
										
										
										
											2022-09-11 19:52:38 -07:00
										 |  |  |         await parent.target?.canvasModel.updateViewStyle(); | 
					
						
							|  |  |  |         await parent.target?.canvasModel.updateScrollStyle(); | 
					
						
							| 
									
										
										
										
											2022-02-03 00:53:59 +08:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  |         final size = MediaQueryData.fromWindow(ui.window).size; | 
					
						
							| 
									
										
										
										
											2022-08-03 15:31:19 +08:00
										 |  |  |         final canvasWidth = size.width; | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  |         final canvasHeight = size.height; | 
					
						
							| 
									
										
										
										
											2022-08-03 15:31:19 +08:00
										 |  |  |         final xscale = canvasWidth / image.width; | 
					
						
							|  |  |  |         final yscale = canvasHeight / image.height; | 
					
						
							|  |  |  |         parent.target?.canvasModel.scale = min(xscale, yscale); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (parent.target != null) { | 
					
						
							| 
									
										
										
										
											2022-09-11 19:52:38 -07:00
										 |  |  |         await initializeCursorAndCanvas(parent.target!); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (parent.target?.ffiModel.isPeerAndroid ?? false) { | 
					
						
							| 
									
										
										
										
											2022-11-17 18:52:27 +08:00
										 |  |  |         bind.sessionSetViewStyle(id: id, value: 'adaptive'); | 
					
						
							| 
									
										
										
										
											2022-09-11 19:52:38 -07:00
										 |  |  |         parent.target?.canvasModel.updateViewStyle(); | 
					
						
							| 
									
										
										
										
											2022-02-03 00:53:59 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     _image = image; | 
					
						
							| 
									
										
										
										
											2020-11-19 18:22:06 +08:00
										 |  |  |     if (image != null) notifyListeners(); | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-11-24 12:11:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-03 15:31:19 +08:00
										 |  |  |   // mobile only
 | 
					
						
							|  |  |  |   // for desktop, height should minus tabbar height
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:11:55 +08:00
										 |  |  |   double get maxScale { | 
					
						
							| 
									
										
										
										
											2022-07-02 21:24:49 +08:00
										 |  |  |     if (_image == null) return 1.5; | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  |     final size = MediaQueryData.fromWindow(ui.window).size; | 
					
						
							| 
									
										
										
										
											2022-02-17 15:22:14 +08:00
										 |  |  |     final xscale = size.width / _image!.width; | 
					
						
							|  |  |  |     final yscale = size.height / _image!.height; | 
					
						
							| 
									
										
										
										
											2022-07-02 21:24:49 +08:00
										 |  |  |     return max(1.5, max(xscale, yscale)); | 
					
						
							| 
									
										
										
										
											2020-11-24 12:11:55 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-03 15:31:19 +08:00
										 |  |  |   // mobile only
 | 
					
						
							|  |  |  |   // for desktop, height should minus tabbar height
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:11:55 +08:00
										 |  |  |   double get minScale { | 
					
						
							| 
									
										
										
										
											2022-07-02 21:24:49 +08:00
										 |  |  |     if (_image == null) return 1.5; | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  |     final size = MediaQueryData.fromWindow(ui.window).size; | 
					
						
							| 
									
										
										
										
											2022-02-17 15:22:14 +08:00
										 |  |  |     final xscale = size.width / _image!.width; | 
					
						
							|  |  |  |     final yscale = size.height / _image!.height; | 
					
						
							| 
									
										
										
										
											2022-07-02 21:24:49 +08:00
										 |  |  |     return min(xscale, yscale) / 1.5; | 
					
						
							| 
									
										
										
										
											2020-11-24 12:11:55 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  | enum ScrollStyle { | 
					
						
							|  |  |  |   scrollbar, | 
					
						
							| 
									
										
										
										
											2022-08-12 20:14:53 +08:00
										 |  |  |   scrollauto, | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  | class ViewStyle { | 
					
						
							|  |  |  |   final String style; | 
					
						
							|  |  |  |   final double width; | 
					
						
							|  |  |  |   final double height; | 
					
						
							|  |  |  |   final int displayWidth; | 
					
						
							|  |  |  |   final int displayHeight; | 
					
						
							|  |  |  |   ViewStyle({ | 
					
						
							| 
									
										
										
										
											2023-02-27 14:24:15 +08:00
										 |  |  |     required this.style, | 
					
						
							|  |  |  |     required this.width, | 
					
						
							|  |  |  |     required this.height, | 
					
						
							|  |  |  |     required this.displayWidth, | 
					
						
							|  |  |  |     required this.displayHeight, | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-27 14:24:15 +08:00
										 |  |  |   static defaultViewStyle() { | 
					
						
							|  |  |  |     final desktop = (isDesktop || isWebDesktop); | 
					
						
							|  |  |  |     final w = | 
					
						
							|  |  |  |         desktop ? kDesktopDefaultDisplayWidth : kMobileDefaultDisplayWidth; | 
					
						
							|  |  |  |     final h = | 
					
						
							|  |  |  |         desktop ? kDesktopDefaultDisplayHeight : kMobileDefaultDisplayHeight; | 
					
						
							|  |  |  |     return ViewStyle( | 
					
						
							|  |  |  |       style: '', | 
					
						
							|  |  |  |       width: w.toDouble(), | 
					
						
							|  |  |  |       height: h.toDouble(), | 
					
						
							|  |  |  |       displayWidth: w, | 
					
						
							|  |  |  |       displayHeight: h, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |   static int _double2Int(double v) => (v * 100).round().toInt(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   bool operator ==(Object other) => | 
					
						
							|  |  |  |       other is ViewStyle && | 
					
						
							|  |  |  |       other.runtimeType == runtimeType && | 
					
						
							|  |  |  |       _innerEqual(other); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool _innerEqual(ViewStyle other) { | 
					
						
							|  |  |  |     return style == other.style && | 
					
						
							|  |  |  |         ViewStyle._double2Int(other.width) == ViewStyle._double2Int(width) && | 
					
						
							|  |  |  |         ViewStyle._double2Int(other.height) == ViewStyle._double2Int(height) && | 
					
						
							|  |  |  |         other.displayWidth == displayWidth && | 
					
						
							|  |  |  |         other.displayHeight == displayHeight; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   int get hashCode => Object.hash( | 
					
						
							|  |  |  |         style, | 
					
						
							|  |  |  |         ViewStyle._double2Int(width), | 
					
						
							|  |  |  |         ViewStyle._double2Int(height), | 
					
						
							|  |  |  |         displayWidth, | 
					
						
							|  |  |  |         displayHeight, | 
					
						
							|  |  |  |       ).hashCode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   double get scale { | 
					
						
							|  |  |  |     double s = 1.0; | 
					
						
							| 
									
										
										
										
											2022-12-30 16:14:30 +08:00
										 |  |  |     if (style == kRemoteViewStyleAdaptive) { | 
					
						
							| 
									
										
										
										
											2023-02-27 14:24:15 +08:00
										 |  |  |       if (width != 0 && | 
					
						
							|  |  |  |           height != 0 && | 
					
						
							|  |  |  |           displayWidth != 0 && | 
					
						
							|  |  |  |           displayHeight != 0) { | 
					
						
							|  |  |  |         final s1 = width / displayWidth; | 
					
						
							|  |  |  |         final s2 = height / displayHeight; | 
					
						
							|  |  |  |         s = s1 < s2 ? s1 : s2; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     return s; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  | class CanvasModel with ChangeNotifier { | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   // image offset of canvas
 | 
					
						
							|  |  |  |   double _x = 0; | 
					
						
							|  |  |  |   // image offset of canvas
 | 
					
						
							|  |  |  |   double _y = 0; | 
					
						
							|  |  |  |   // image scale
 | 
					
						
							|  |  |  |   double _scale = 1.0; | 
					
						
							| 
									
										
										
										
											2023-02-02 14:39:58 +08:00
										 |  |  |   double _devicePixelRatio = 1.0; | 
					
						
							| 
									
										
										
										
											2023-01-06 18:14:31 +08:00
										 |  |  |   Size _size = Size.zero; | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   // the tabbar over the image
 | 
					
						
							| 
									
										
										
										
											2022-11-01 17:01:43 +08:00
										 |  |  |   // double tabBarHeight = 0.0;
 | 
					
						
							| 
									
										
										
										
											2022-10-04 21:19:31 +08:00
										 |  |  |   // the window border's width
 | 
					
						
							| 
									
										
										
										
											2022-11-01 17:01:43 +08:00
										 |  |  |   // double windowBorderWidth = 0.0;
 | 
					
						
							| 
									
										
										
										
											2022-09-13 21:52:22 +08:00
										 |  |  |   // remote id
 | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |   String id = ''; | 
					
						
							| 
									
										
										
										
											2022-08-12 20:14:53 +08:00
										 |  |  |   // scroll offset x percent
 | 
					
						
							|  |  |  |   double _scrollX = 0.0; | 
					
						
							|  |  |  |   // scroll offset y percent
 | 
					
						
							|  |  |  |   double _scrollY = 0.0; | 
					
						
							| 
									
										
										
										
											2022-08-13 15:08:17 +08:00
										 |  |  |   ScrollStyle _scrollStyle = ScrollStyle.scrollauto; | 
					
						
							| 
									
										
										
										
											2023-02-27 14:24:15 +08:00
										 |  |  |   ViewStyle _lastViewStyle = ViewStyle.defaultViewStyle(); | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-06 20:25:18 +08:00
										 |  |  |   final _imageOverflow = false.obs; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   WeakReference<FFI> parent; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CanvasModel(this.parent); | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   double get x => _x; | 
					
						
							|  |  |  |   double get y => _y; | 
					
						
							|  |  |  |   double get scale => _scale; | 
					
						
							| 
									
										
										
										
											2023-02-02 14:39:58 +08:00
										 |  |  |   double get devicePixelRatio => _devicePixelRatio; | 
					
						
							| 
									
										
										
										
											2023-01-06 18:14:31 +08:00
										 |  |  |   Size get size => _size; | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |   ScrollStyle get scrollStyle => _scrollStyle; | 
					
						
							| 
									
										
										
										
											2022-12-30 16:14:30 +08:00
										 |  |  |   ViewStyle get viewStyle => _lastViewStyle; | 
					
						
							| 
									
										
										
										
											2023-01-06 20:25:18 +08:00
										 |  |  |   RxBool get imageOverflow => _imageOverflow; | 
					
						
							| 
									
										
										
										
											2022-12-30 16:14:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   _resetScroll() => setScrollPercent(0.0, 0.0); | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 20:14:53 +08:00
										 |  |  |   setScrollPercent(double x, double y) { | 
					
						
							|  |  |  |     _scrollX = x; | 
					
						
							|  |  |  |     _scrollY = y; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   double get scrollX => _scrollX; | 
					
						
							|  |  |  |   double get scrollY => _scrollY; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 15:30:46 +08:00
										 |  |  |   static double get leftToEdge => (isDesktop || isWebDesktop) | 
					
						
							|  |  |  |       ? windowBorderWidth + kDragToResizeAreaPadding.left | 
					
						
							|  |  |  |       : 0; | 
					
						
							|  |  |  |   static double get rightToEdge => (isDesktop || isWebDesktop) | 
					
						
							|  |  |  |       ? windowBorderWidth + kDragToResizeAreaPadding.right | 
					
						
							|  |  |  |       : 0; | 
					
						
							|  |  |  |   static double get topToEdge => (isDesktop || isWebDesktop) | 
					
						
							|  |  |  |       ? tabBarHeight + windowBorderWidth + kDragToResizeAreaPadding.top | 
					
						
							|  |  |  |       : 0; | 
					
						
							|  |  |  |   static double get bottomToEdge => (isDesktop || isWebDesktop) | 
					
						
							|  |  |  |       ? windowBorderWidth + kDragToResizeAreaPadding.bottom | 
					
						
							|  |  |  |       : 0; | 
					
						
							| 
									
										
										
										
											2023-02-28 14:50:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-11 19:52:38 -07:00
										 |  |  |   updateViewStyle() async { | 
					
						
							| 
									
										
										
										
											2023-01-06 18:14:31 +08:00
										 |  |  |     Size getSize() { | 
					
						
							|  |  |  |       final size = MediaQueryData.fromWindow(ui.window).size; | 
					
						
							|  |  |  |       // If minimized, w or h may be negative here.
 | 
					
						
							| 
									
										
										
										
											2023-02-28 14:50:51 +08:00
										 |  |  |       double w = size.width - leftToEdge - rightToEdge; | 
					
						
							|  |  |  |       double h = size.height - topToEdge - bottomToEdge; | 
					
						
							| 
									
										
										
										
											2023-01-06 18:14:31 +08:00
										 |  |  |       return Size(w < 0 ? 0 : w, h < 0 ? 0 : h); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-17 18:52:27 +08:00
										 |  |  |     final style = await bind.sessionGetViewStyle(id: id); | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |     if (style == null) { | 
					
						
							| 
									
										
										
										
											2022-05-31 22:09:36 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-06 18:14:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     _size = getSize(); | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |     final displayWidth = getDisplayWidth(); | 
					
						
							|  |  |  |     final displayHeight = getDisplayHeight(); | 
					
						
							|  |  |  |     final viewStyle = ViewStyle( | 
					
						
							|  |  |  |       style: style, | 
					
						
							| 
									
										
										
										
											2023-01-06 18:14:31 +08:00
										 |  |  |       width: size.width, | 
					
						
							|  |  |  |       height: size.height, | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |       displayWidth: displayWidth, | 
					
						
							|  |  |  |       displayHeight: displayHeight, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     if (_lastViewStyle == viewStyle) { | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2022-02-03 00:53:59 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-30 16:14:30 +08:00
										 |  |  |     if (_lastViewStyle.style != viewStyle.style) { | 
					
						
							|  |  |  |       _resetScroll(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |     _lastViewStyle = viewStyle; | 
					
						
							|  |  |  |     _scale = viewStyle.scale; | 
					
						
							| 
									
										
										
										
											2023-01-06 18:14:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 14:39:58 +08:00
										 |  |  |     _devicePixelRatio = ui.window.devicePixelRatio; | 
					
						
							| 
									
										
										
										
											2023-01-06 18:14:31 +08:00
										 |  |  |     if (kIgnoreDpi && style == kRemoteViewStyleOriginal) { | 
					
						
							| 
									
										
										
										
											2023-02-02 14:39:58 +08:00
										 |  |  |       _scale = 1.0 / _devicePixelRatio; | 
					
						
							| 
									
										
										
										
											2023-01-06 18:14:31 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     _x = (size.width - displayWidth * _scale) / 2; | 
					
						
							|  |  |  |     _y = (size.height - displayHeight * _scale) / 2; | 
					
						
							| 
									
										
										
										
											2023-01-06 20:25:18 +08:00
										 |  |  |     _imageOverflow.value = _x < 0 || y < 0; | 
					
						
							| 
									
										
										
										
											2022-02-03 00:53:59 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							| 
									
										
										
										
											2023-02-03 17:02:28 +08:00
										 |  |  |     parent.target?.inputModel.refreshMousePos(); | 
					
						
							| 
									
										
										
										
											2022-02-03 00:53:59 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 20:14:53 +08:00
										 |  |  |   updateScrollStyle() async { | 
					
						
							| 
									
										
										
										
											2022-11-17 18:52:27 +08:00
										 |  |  |     final style = await bind.sessionGetScrollStyle(id: id); | 
					
						
							| 
									
										
										
										
											2022-11-24 11:19:16 +08:00
										 |  |  |     if (style == kRemoteScrollStyleBar) { | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |       _scrollStyle = ScrollStyle.scrollbar; | 
					
						
							| 
									
										
										
										
											2022-12-30 16:14:30 +08:00
										 |  |  |       _resetScroll(); | 
					
						
							| 
									
										
										
										
											2022-08-13 15:08:17 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       _scrollStyle = ScrollStyle.scrollauto; | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-13 15:08:17 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-11 19:52:38 -07:00
										 |  |  |   update(double x, double y, double scale) { | 
					
						
							| 
									
										
										
										
											2020-12-21 18:28:28 +08:00
										 |  |  |     _x = x; | 
					
						
							|  |  |  |     _y = y; | 
					
						
							|  |  |  |     _scale = scale; | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-31 21:41:16 +08:00
										 |  |  |   bool get cursorEmbedded => | 
					
						
							|  |  |  |       parent.target?.ffiModel.display.cursorEmbedded ?? false; | 
					
						
							| 
									
										
										
										
											2022-11-29 16:36:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   int getDisplayWidth() { | 
					
						
							| 
									
										
										
										
											2022-08-31 18:41:55 +08:00
										 |  |  |     final defaultWidth = (isDesktop || isWebDesktop) | 
					
						
							|  |  |  |         ? kDesktopDefaultDisplayWidth | 
					
						
							|  |  |  |         : kMobileDefaultDisplayWidth; | 
					
						
							|  |  |  |     return parent.target?.ffiModel.display.width ?? defaultWidth; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int getDisplayHeight() { | 
					
						
							| 
									
										
										
										
											2022-08-31 18:41:55 +08:00
										 |  |  |     final defaultHeight = (isDesktop || isWebDesktop) | 
					
						
							|  |  |  |         ? kDesktopDefaultDisplayHeight | 
					
						
							|  |  |  |         : kMobileDefaultDisplayHeight; | 
					
						
							|  |  |  |     return parent.target?.ffiModel.display.height ?? defaultHeight; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-28 14:50:51 +08:00
										 |  |  |   static double get windowBorderWidth => stateGlobal.windowBorderWidth.value; | 
					
						
							|  |  |  |   static double get tabBarHeight => stateGlobal.tabBarHeight; | 
					
						
							| 
									
										
										
										
											2022-11-01 17:01:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   moveDesktopMouse(double x, double y) { | 
					
						
							| 
									
										
										
										
											2023-02-27 22:24:00 +08:00
										 |  |  |     if (size.width == 0 || size.height == 0) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-27 16:50:02 +08:00
										 |  |  |     // On mobile platforms, move the canvas with the cursor.
 | 
					
						
							| 
									
										
										
										
											2022-08-12 20:14:53 +08:00
										 |  |  |     final dw = getDisplayWidth() * _scale; | 
					
						
							|  |  |  |     final dh = getDisplayHeight() * _scale; | 
					
						
							|  |  |  |     var dxOffset = 0; | 
					
						
							|  |  |  |     var dyOffset = 0; | 
					
						
							| 
									
										
										
										
											2023-02-25 22:47:22 +08:00
										 |  |  |     try { | 
					
						
							|  |  |  |       if (dw > size.width) { | 
					
						
							|  |  |  |         dxOffset = (x - dw * (x / size.width) - _x).toInt(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (dh > size.height) { | 
					
						
							|  |  |  |         dyOffset = (y - dh * (y / size.height) - _y).toInt(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2023-02-26 23:29:36 +08:00
										 |  |  |       debugPrintStack( | 
					
						
							|  |  |  |           label: | 
					
						
							|  |  |  |               '(x,y) ($x,$y), (_x,_y) ($_x,$_y), _scale $_scale, display size (${getDisplayWidth()},${getDisplayHeight()}), size $size, , $e'); | 
					
						
							| 
									
										
										
										
											2023-02-25 22:47:22 +08:00
										 |  |  |       return; | 
					
						
							| 
									
										
										
										
											2022-08-12 20:14:53 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-25 22:47:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 20:14:53 +08:00
										 |  |  |     _x += dxOffset; | 
					
						
							|  |  |  |     _y += dyOffset; | 
					
						
							|  |  |  |     if (dxOffset != 0 || dyOffset != 0) { | 
					
						
							|  |  |  |       notifyListeners(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // If keyboard is not permitted, do not move cursor when mouse is moving.
 | 
					
						
							| 
									
										
										
										
											2023-03-28 10:52:43 +08:00
										 |  |  |     if (parent.target != null && parent.target!.ffiModel.keyboard) { | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |       // Draw cursor if is not desktop.
 | 
					
						
							|  |  |  |       if (!isDesktop) { | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |         parent.target!.cursorModel.moveLocal(x, y); | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           RemoteCursorMovedState.find(id).value = false; | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |           //
 | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-02-06 16:29:56 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-24 12:11:55 +08:00
										 |  |  |   set scale(v) { | 
					
						
							|  |  |  |     _scale = v; | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   panX(double dx) { | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |     _x += dx; | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   resetOffset() { | 
					
						
							| 
									
										
										
										
											2022-05-23 16:02:37 +08:00
										 |  |  |     if (isWebDesktop) { | 
					
						
							| 
									
										
										
										
											2022-02-03 00:53:59 +08:00
										 |  |  |       updateViewStyle(); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |       _x = (size.width - getDisplayWidth() * _scale) / 2; | 
					
						
							|  |  |  |       _y = (size.height - getDisplayHeight() * _scale) / 2; | 
					
						
							| 
									
										
										
										
											2022-02-03 00:53:59 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-27 17:59:42 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   panY(double dy) { | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  |     _y += dy; | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   updateScale(double v) { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     if (parent.target?.imageModel.image == null) return; | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     final offset = parent.target?.cursorModel.offset ?? const Offset(0, 0); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     var r = parent.target?.cursorModel.getVisibleRect() ?? Rect.zero; | 
					
						
							| 
									
										
										
										
											2020-11-25 14:41:57 +08:00
										 |  |  |     final px0 = (offset.dx - r.left) * _scale; | 
					
						
							|  |  |  |     final py0 = (offset.dy - r.top) * _scale; | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  |     _scale *= v; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     final maxs = parent.target?.imageModel.maxScale ?? 1; | 
					
						
							|  |  |  |     final mins = parent.target?.imageModel.minScale ?? 1; | 
					
						
							| 
									
										
										
										
											2020-11-24 12:11:55 +08:00
										 |  |  |     if (_scale > maxs) _scale = maxs; | 
					
						
							|  |  |  |     if (_scale < mins) _scale = mins; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     r = parent.target?.cursorModel.getVisibleRect() ?? Rect.zero; | 
					
						
							| 
									
										
										
										
											2020-11-25 14:41:57 +08:00
										 |  |  |     final px1 = (offset.dx - r.left) * _scale; | 
					
						
							|  |  |  |     final py1 = (offset.dy - r.top) * _scale; | 
					
						
							|  |  |  |     _x -= px1 - px0; | 
					
						
							|  |  |  |     _y -= py1 - py0; | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   clear([bool notify = false]) { | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  |     _x = 0; | 
					
						
							|  |  |  |     _y = 0; | 
					
						
							|  |  |  |     _scale = 1.0; | 
					
						
							| 
									
										
										
										
											2021-08-22 07:50:12 +08:00
										 |  |  |     if (notify) notifyListeners(); | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  | // data for cursor
 | 
					
						
							|  |  |  | class CursorData { | 
					
						
							|  |  |  |   final String peerId; | 
					
						
							|  |  |  |   final int id; | 
					
						
							| 
									
										
										
										
											2023-02-01 22:12:28 +08:00
										 |  |  |   final img2.Image image; | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |   double scale; | 
					
						
							|  |  |  |   Uint8List? data; | 
					
						
							| 
									
										
										
										
											2022-11-15 22:35:10 +08:00
										 |  |  |   final double hotxOrigin; | 
					
						
							|  |  |  |   final double hotyOrigin; | 
					
						
							| 
									
										
										
										
											2022-10-30 13:50:44 +08:00
										 |  |  |   double hotx; | 
					
						
							|  |  |  |   double hoty; | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  |   final int width; | 
					
						
							|  |  |  |   final int height; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CursorData({ | 
					
						
							|  |  |  |     required this.peerId, | 
					
						
							|  |  |  |     required this.id, | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |     required this.image, | 
					
						
							|  |  |  |     required this.scale, | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  |     required this.data, | 
					
						
							| 
									
										
										
										
											2022-11-15 22:35:10 +08:00
										 |  |  |     required this.hotxOrigin, | 
					
						
							|  |  |  |     required this.hotyOrigin, | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  |     required this.width, | 
					
						
							|  |  |  |     required this.height, | 
					
						
							| 
									
										
										
										
											2022-11-15 22:35:10 +08:00
										 |  |  |   })  : hotx = hotxOrigin * scale, | 
					
						
							|  |  |  |         hoty = hotxOrigin * scale; | 
					
						
							| 
									
										
										
										
											2022-09-07 19:52:30 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   int _doubleToInt(double v) => (v * 10e6).round().toInt(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 14:39:58 +08:00
										 |  |  |   double _checkUpdateScale(double scale) { | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |     double oldScale = this.scale; | 
					
						
							| 
									
										
										
										
											2023-02-02 14:39:58 +08:00
										 |  |  |     if (scale != 1.0) { | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |       // Update data if scale changed.
 | 
					
						
							| 
									
										
										
										
											2023-02-01 20:58:21 +08:00
										 |  |  |       final tgtWidth = (width * scale).toInt(); | 
					
						
							|  |  |  |       final tgtHeight = (width * scale).toInt(); | 
					
						
							|  |  |  |       if (tgtWidth < kMinCursorSize || tgtHeight < kMinCursorSize) { | 
					
						
							|  |  |  |         double sw = kMinCursorSize.toDouble() / width; | 
					
						
							|  |  |  |         double sh = kMinCursorSize.toDouble() / height; | 
					
						
							|  |  |  |         scale = sw < sh ? sh : sw; | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 20:58:21 +08:00
										 |  |  |     if (_doubleToInt(oldScale) != _doubleToInt(scale)) { | 
					
						
							| 
									
										
										
										
											2023-02-01 22:12:28 +08:00
										 |  |  |       if (Platform.isWindows) { | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |         data = img2 | 
					
						
							|  |  |  |             .copyResize( | 
					
						
							| 
									
										
										
										
											2023-02-01 22:12:28 +08:00
										 |  |  |               image, | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |               width: (width * scale).toInt(), | 
					
						
							|  |  |  |               height: (height * scale).toInt(), | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |               interpolation: img2.Interpolation.average, | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2022-10-30 13:50:44 +08:00
										 |  |  |             .getBytes(format: img2.Format.bgra); | 
					
						
							| 
									
										
										
										
											2023-02-01 22:12:28 +08:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         data = Uint8List.fromList( | 
					
						
							|  |  |  |           img2.encodePng( | 
					
						
							|  |  |  |             img2.copyResize( | 
					
						
							|  |  |  |               image, | 
					
						
							|  |  |  |               width: (width * scale).toInt(), | 
					
						
							|  |  |  |               height: (height * scale).toInt(), | 
					
						
							|  |  |  |               interpolation: img2.Interpolation.average, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |     this.scale = scale; | 
					
						
							| 
									
										
										
										
											2022-11-15 22:35:10 +08:00
										 |  |  |     hotx = hotxOrigin * scale; | 
					
						
							|  |  |  |     hoty = hotyOrigin * scale; | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |     return scale; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-02 14:39:58 +08:00
										 |  |  |   String updateGetKey(double scale) { | 
					
						
							|  |  |  |     scale = _checkUpdateScale(scale); | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |     return '${peerId}_${id}_${_doubleToInt(width * scale)}_${_doubleToInt(height * scale)}'; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-22 21:34:53 +08:00
										 |  |  | const _forbiddenCursorPng = | 
					
						
							|  |  |  |     'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAkZQTFRFAAAA2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4G2B4GWAwCAAAAAAAA2B4GAAAAMTExAAAAAAAA2B4G2B4G2B4GAAAAmZmZkZGRAQEBAAAA2B4G2B4G2B4G////oKCgAwMDag8D2B4G2B4G2B4Gra2tBgYGbg8D2B4G2B4Gubm5CQkJTwsCVgwC2B4GxcXFDg4OAAAAAAAA2B4G2B4Gz8/PFBQUAAAAAAAA2B4G2B4G2B4G2B4G2B4G2B4G2B4GDgIA2NjYGxsbAAAAAAAA2B4GFwMB4eHhIyMjAAAAAAAA2B4G6OjoLCwsAAAAAAAA2B4G2B4G2B4G2B4G2B4GCQEA4ODgv7+/iYmJY2NjAgICAAAA9PT0Ojo6AAAAAAAAAAAA+/v7SkpKhYWFr6+vAAAAAAAA8/PzOTk5ERER9fX1KCgoAAAAgYGBKioqAAAAAAAApqamlpaWAAAAAAAAAAAAAAAAAAAAAAAALi4u/v7+GRkZAAAAAAAAAAAAAAAAAAAAfn5+AAAAAAAAV1dXkJCQAAAAAAAAAQEBAAAAAAAAAAAA7Hz6BAAAAMJ0Uk5TAAIWEwEynNz6//fVkCAatP2fDUHs6cDD8d0mPfT5fiEskiIR584A0gejr3AZ+P4plfALf5ZiTL85a4ziD6697fzN3UYE4v/4TwrNHuT///tdRKZh///+1U/ZBv///yjb///eAVL//50Cocv//6oFBbPvpGZCbfT//7cIhv///8INM///zBEcWYSZmO7//////1P////ts/////8vBv//////gv//R/z///QQz9sevP///2waXhNO/+fc//8mev/5gAe2r90MAAAByUlEQVR4nGNggANGJmYWBpyAlY2dg5OTi5uHF6s0H78AJxRwCAphyguLgKRExcQlQLSkFLq8tAwnp6ycPNABjAqKQKNElVDllVU4OVVhVquJA81Q10BRoAkUUYbJa4Edoo0sr6PLqaePLG/AyWlohKTAmJPTBFnelAFoixmSAnNOTgsUeQZLTk4rJAXWnJw2EHlbiDyDPCenHZICe04HFrh+RydnBgYWPU5uJAWinJwucPNd3dw9GDw5Ob2QFHBzcnrD7ffx9fMPCOTkDEINhmC4+3x8Q0LDwlEDIoKTMzIKKg9SEBIdE8sZh6SAJZ6Tkx0qD1YQkpCYlIwclCng0AXLQxSEpKalZyCryATKZwkhKQjJzsnNQ1KQXwBUUVhUXBJYWgZREFJeUVmFpMKlWg+anmqgCkJq6+obkG1pLEBTENLU3NKKrIKhrb2js8u4G6Kgpze0r3/CRAZMAHbkpJDJU6ZMmTqtFbuC6TNmhsyaMnsOFlmwgrnzpsxfELJwEXZ5Bp/FS3yWLlsesmLlKuwKVk9Ys5Zh3foN0zduwq5g85atDAzbpqSGbN9RhV0FGOzctWH3lD14FOzdt3H/gQw8Cg4u2gQPAwBYDXXdIH+wqAAAAABJRU5ErkJggg=='; | 
					
						
							|  |  |  | const _defaultCursorPng = | 
					
						
							|  |  |  |     'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAFmSURBVFiF7dWxSlxREMbx34QFDRowYBchZSxSCWlMCOwD5FGEFHap06UI7KPsAyyEEIQFqxRaCqYTsqCJFsKkuAeRXb17wrqV918dztw55zszc2fo6Oh47MR/e3zO1/iAHWmznHKGQwx9ip/LEbCfazbsoY8j/JLOhcC6sCW9wsjEwJf483AC9nPNc1+lFRwI13d+l3rYFS799rFGxJMqARv2pBXh+72XQ7gWvklPS7TmMl9Ak/M+DqrENvxAv/guKKApuKPWl0/TROK4+LbSqzhuB+OZ3fRSeFPWY+Fkyn56Y29hfgTSpnQ+s98cvorVey66uPlNFxKwZOYLCGfCs5n9NMYVrsp6mvXSoFqpqYFDvMBkStgJJe93dZOwVXxbqUnBENulydSReqUrDhcX0PT2EXarBYS3GNXMhboinBgIl9K71kg0L3+PvyYGdVpruT2MwrF0iotiXfIwus0Dj+OOjo6Of+e7ab74RkpgAAAAAElFTkSuQmCC'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | final preForbiddenCursor = PredefinedCursor( | 
					
						
							|  |  |  |   png: _forbiddenCursorPng, | 
					
						
							|  |  |  |   id: -2, | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | final preDefaultCursor = PredefinedCursor( | 
					
						
							|  |  |  |   png: _defaultCursorPng, | 
					
						
							|  |  |  |   id: -1, | 
					
						
							|  |  |  |   hotxGetter: (double w) => w / 2, | 
					
						
							|  |  |  |   hotyGetter: (double h) => h / 2, | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PredefinedCursor { | 
					
						
							|  |  |  |   ui.Image? _image; | 
					
						
							|  |  |  |   img2.Image? _image2; | 
					
						
							|  |  |  |   CursorData? _cache; | 
					
						
							|  |  |  |   String png; | 
					
						
							|  |  |  |   int id; | 
					
						
							|  |  |  |   double Function(double)? hotxGetter; | 
					
						
							|  |  |  |   double Function(double)? hotyGetter; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   PredefinedCursor( | 
					
						
							|  |  |  |       {required this.png, required this.id, this.hotxGetter, this.hotyGetter}) { | 
					
						
							|  |  |  |     init(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ui.Image? get image => _image; | 
					
						
							|  |  |  |   CursorData? get cache => _cache; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   init() { | 
					
						
							|  |  |  |     _image2 = img2.decodePng(base64Decode(png)); | 
					
						
							|  |  |  |     if (_image2 != null) { | 
					
						
							|  |  |  |       () async { | 
					
						
							|  |  |  |         final defaultImg = _image2!; | 
					
						
							|  |  |  |         // This function is called only one time, no need to care about the performance.
 | 
					
						
							|  |  |  |         Uint8List data = defaultImg.getBytes(format: img2.Format.rgba); | 
					
						
							|  |  |  |         _image = await img.decodeImageFromPixels( | 
					
						
							|  |  |  |             data, defaultImg.width, defaultImg.height, ui.PixelFormat.rgba8888); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         double scale = 1.0; | 
					
						
							|  |  |  |         if (Platform.isWindows) { | 
					
						
							|  |  |  |           data = _image2!.getBytes(format: img2.Format.bgra); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           data = Uint8List.fromList(img2.encodePng(_image2!)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         _cache = CursorData( | 
					
						
							|  |  |  |           peerId: '', | 
					
						
							|  |  |  |           id: id, | 
					
						
							| 
									
										
										
										
											2023-02-01 22:12:28 +08:00
										 |  |  |           image: _image2!.clone(), | 
					
						
							| 
									
										
										
										
											2022-11-22 21:34:53 +08:00
										 |  |  |           scale: scale, | 
					
						
							|  |  |  |           data: data, | 
					
						
							|  |  |  |           hotxOrigin: | 
					
						
							|  |  |  |               hotxGetter != null ? hotxGetter!(_image2!.width.toDouble()) : 0, | 
					
						
							|  |  |  |           hotyOrigin: | 
					
						
							|  |  |  |               hotyGetter != null ? hotyGetter!(_image2!.height.toDouble()) : 0, | 
					
						
							|  |  |  |           width: _image2!.width, | 
					
						
							|  |  |  |           height: _image2!.height, | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       }(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | class CursorModel with ChangeNotifier { | 
					
						
							| 
									
										
										
										
											2022-02-17 15:22:14 +08:00
										 |  |  |   ui.Image? _image; | 
					
						
							| 
									
										
										
										
											2022-09-07 02:14:52 -07:00
										 |  |  |   final _images = <int, Tuple3<ui.Image, double, double>>{}; | 
					
						
							| 
									
										
										
										
											2022-10-30 13:50:44 +08:00
										 |  |  |   CursorData? _cache; | 
					
						
							|  |  |  |   final _cacheMap = <int, CursorData>{}; | 
					
						
							|  |  |  |   final _cacheKeys = <String>{}; | 
					
						
							| 
									
										
										
										
											2020-11-22 18:29:04 +08:00
										 |  |  |   double _x = -10000; | 
					
						
							|  |  |  |   double _y = -10000; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   double _hotx = 0; | 
					
						
							|  |  |  |   double _hoty = 0; | 
					
						
							|  |  |  |   double _displayOriginX = 0; | 
					
						
							|  |  |  |   double _displayOriginY = 0; | 
					
						
							| 
									
										
										
										
											2023-02-03 20:27:05 +08:00
										 |  |  |   DateTime? _firstUpdateMouseTime; | 
					
						
							| 
									
										
										
										
											2022-11-14 15:05:44 +08:00
										 |  |  |   bool gotMouseControl = true; | 
					
						
							|  |  |  |   DateTime _lastPeerMouse = DateTime.now() | 
					
						
							| 
									
										
										
										
											2023-02-03 20:27:05 +08:00
										 |  |  |       .subtract(Duration(milliseconds: 3000 * kMouseControlTimeoutMSec)); | 
					
						
							| 
									
										
										
										
											2022-09-13 21:52:22 +08:00
										 |  |  |   String id = ''; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   WeakReference<FFI> parent; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-17 15:22:14 +08:00
										 |  |  |   ui.Image? get image => _image; | 
					
						
							| 
									
										
										
										
											2022-10-30 14:38:35 +08:00
										 |  |  |   CursorData? get cache => _cache; | 
					
						
							| 
									
										
										
										
											2022-02-02 17:25:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  |   double get x => _x - _displayOriginX; | 
					
						
							|  |  |  |   double get y => _y - _displayOriginY; | 
					
						
							| 
									
										
										
										
											2022-02-02 17:25:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-25 14:41:57 +08:00
										 |  |  |   Offset get offset => Offset(_x, _y); | 
					
						
							| 
									
										
										
										
											2022-02-02 17:25:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-23 23:18:42 +08:00
										 |  |  |   double get hotx => _hotx; | 
					
						
							|  |  |  |   double get hoty => _hoty; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-14 15:05:44 +08:00
										 |  |  |   bool get isPeerControlProtected => | 
					
						
							|  |  |  |       DateTime.now().difference(_lastPeerMouse).inMilliseconds < | 
					
						
							| 
									
										
										
										
											2022-11-08 13:37:08 +08:00
										 |  |  |       kMouseControlTimeoutMSec; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-03 20:27:05 +08:00
										 |  |  |   bool isConnIn2Secs() { | 
					
						
							|  |  |  |     if (_firstUpdateMouseTime == null) { | 
					
						
							|  |  |  |       _firstUpdateMouseTime = DateTime.now(); | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return DateTime.now().difference(_firstUpdateMouseTime!).inSeconds < 2; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-22 21:34:53 +08:00
										 |  |  |   CursorModel(this.parent); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-30 13:50:44 +08:00
										 |  |  |   Set<String> get cachedKeys => _cacheKeys; | 
					
						
							|  |  |  |   addKey(String key) => _cacheKeys.add(key); | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-25 14:41:57 +08:00
										 |  |  |   // remote physical display coordinate
 | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |   Rect getVisibleRect() { | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  |     final size = MediaQueryData.fromWindow(ui.window).size; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     final xoffset = parent.target?.canvasModel.x ?? 0; | 
					
						
							|  |  |  |     final yoffset = parent.target?.canvasModel.y ?? 0; | 
					
						
							|  |  |  |     final scale = parent.target?.canvasModel.scale ?? 1; | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |     final x0 = _displayOriginX - xoffset / scale; | 
					
						
							|  |  |  |     final y0 = _displayOriginY - yoffset / scale; | 
					
						
							|  |  |  |     return Rect.fromLTWH(x0, y0, size.width / scale, size.height / scale); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-25 11:20:40 +08:00
										 |  |  |   double adjustForKeyboard() { | 
					
						
							| 
									
										
										
										
											2020-12-21 17:26:23 +08:00
										 |  |  |     final m = MediaQueryData.fromWindow(ui.window); | 
					
						
							|  |  |  |     var keyboardHeight = m.viewInsets.bottom; | 
					
						
							|  |  |  |     final size = m.size; | 
					
						
							| 
									
										
										
										
											2020-11-25 11:20:40 +08:00
										 |  |  |     if (keyboardHeight < 100) return 0; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     final s = parent.target?.canvasModel.scale ?? 1.0; | 
					
						
							| 
									
										
										
										
											2020-12-21 17:26:23 +08:00
										 |  |  |     final thresh = (size.height - keyboardHeight) / 2; | 
					
						
							| 
									
										
										
										
											2020-11-25 14:41:57 +08:00
										 |  |  |     var h = (_y - getVisibleRect().top) * s; // local physical display height
 | 
					
						
							| 
									
										
										
										
											2020-11-27 12:05:23 +08:00
										 |  |  |     return h - thresh; | 
					
						
							| 
									
										
										
										
											2020-11-25 11:20:40 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   move(double x, double y) { | 
					
						
							| 
									
										
										
										
											2022-02-17 18:00:44 +08:00
										 |  |  |     moveLocal(x, y); | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     parent.target?.inputModel.moveMouse(_x, _y); | 
					
						
							| 
									
										
										
										
											2022-02-17 18:00:44 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   moveLocal(double x, double y) { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     final scale = parent.target?.canvasModel.scale ?? 1.0; | 
					
						
							|  |  |  |     final xoffset = parent.target?.canvasModel.x ?? 0; | 
					
						
							|  |  |  |     final yoffset = parent.target?.canvasModel.y ?? 0; | 
					
						
							| 
									
										
										
										
											2021-08-21 17:18:14 +08:00
										 |  |  |     _x = (x - xoffset) / scale + _displayOriginX; | 
					
						
							|  |  |  |     _y = (y - yoffset) / scale + _displayOriginY; | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   reset() { | 
					
						
							| 
									
										
										
										
											2021-08-21 17:18:14 +08:00
										 |  |  |     _x = _displayOriginX; | 
					
						
							|  |  |  |     _y = _displayOriginY; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     parent.target?.inputModel.moveMouse(_x, _y); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     parent.target?.canvasModel.clear(true); | 
					
						
							| 
									
										
										
										
											2021-08-21 17:18:14 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   updatePan(double dx, double dy, bool touchMode) { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     if (parent.target?.imageModel.image == null) return; | 
					
						
							| 
									
										
										
										
											2021-08-21 17:18:14 +08:00
										 |  |  |     if (touchMode) { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |       final scale = parent.target?.canvasModel.scale ?? 1.0; | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |       _x += dx / scale; | 
					
						
							|  |  |  |       _y += dy / scale; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |       parent.target?.inputModel.moveMouse(_x, _y); | 
					
						
							| 
									
										
										
										
											2022-04-19 13:07:45 +08:00
										 |  |  |       notifyListeners(); | 
					
						
							| 
									
										
										
										
											2021-08-21 17:18:14 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     final scale = parent.target?.canvasModel.scale ?? 1.0; | 
					
						
							| 
									
										
										
										
											2020-11-25 00:13:23 +08:00
										 |  |  |     dx /= scale; | 
					
						
							|  |  |  |     dy /= scale; | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |     final r = getVisibleRect(); | 
					
						
							|  |  |  |     var cx = r.center.dx; | 
					
						
							|  |  |  |     var cy = r.center.dy; | 
					
						
							|  |  |  |     var tryMoveCanvasX = false; | 
					
						
							|  |  |  |     if (dx > 0) { | 
					
						
							| 
									
										
										
										
											2022-05-11 22:34:41 +08:00
										 |  |  |       final maxCanvasCanMove = _displayOriginX + | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |           (parent.target?.imageModel.image!.width ?? 1280) - | 
					
						
							| 
									
										
										
										
											2022-05-11 22:34:41 +08:00
										 |  |  |           r.right.roundToDouble(); | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |       tryMoveCanvasX = _x + dx > cx && maxCanvasCanMove > 0; | 
					
						
							|  |  |  |       if (tryMoveCanvasX) { | 
					
						
							|  |  |  |         dx = min(dx, maxCanvasCanMove); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         final maxCursorCanMove = r.right - _x; | 
					
						
							|  |  |  |         dx = min(dx, maxCursorCanMove); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else if (dx < 0) { | 
					
						
							| 
									
										
										
										
											2022-05-11 22:34:41 +08:00
										 |  |  |       final maxCanvasCanMove = _displayOriginX - r.left.roundToDouble(); | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |       tryMoveCanvasX = _x + dx < cx && maxCanvasCanMove < 0; | 
					
						
							|  |  |  |       if (tryMoveCanvasX) { | 
					
						
							|  |  |  |         dx = max(dx, maxCanvasCanMove); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         final maxCursorCanMove = r.left - _x; | 
					
						
							|  |  |  |         dx = max(dx, maxCursorCanMove); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     var tryMoveCanvasY = false; | 
					
						
							|  |  |  |     if (dy > 0) { | 
					
						
							| 
									
										
										
										
											2022-05-11 22:34:41 +08:00
										 |  |  |       final mayCanvasCanMove = _displayOriginY + | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |           (parent.target?.imageModel.image!.height ?? 720) - | 
					
						
							| 
									
										
										
										
											2022-05-11 22:34:41 +08:00
										 |  |  |           r.bottom.roundToDouble(); | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |       tryMoveCanvasY = _y + dy > cy && mayCanvasCanMove > 0; | 
					
						
							|  |  |  |       if (tryMoveCanvasY) { | 
					
						
							|  |  |  |         dy = min(dy, mayCanvasCanMove); | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2020-11-24 23:36:46 +08:00
										 |  |  |         final mayCursorCanMove = r.bottom - _y; | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |         dy = min(dy, mayCursorCanMove); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else if (dy < 0) { | 
					
						
							| 
									
										
										
										
											2022-05-11 22:34:41 +08:00
										 |  |  |       final mayCanvasCanMove = _displayOriginY - r.top.roundToDouble(); | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |       tryMoveCanvasY = _y + dy < cy && mayCanvasCanMove < 0; | 
					
						
							|  |  |  |       if (tryMoveCanvasY) { | 
					
						
							|  |  |  |         dy = max(dy, mayCanvasCanMove); | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2020-11-24 23:36:46 +08:00
										 |  |  |         final mayCursorCanMove = r.top - _y; | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |         dy = max(dy, mayCursorCanMove); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (dx == 0 && dy == 0) return; | 
					
						
							|  |  |  |     _x += dx; | 
					
						
							|  |  |  |     _y += dy; | 
					
						
							|  |  |  |     if (tryMoveCanvasX && dx != 0) { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |       parent.target?.canvasModel.panX(-dx); | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (tryMoveCanvasY && dy != 0) { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |       parent.target?.canvasModel.panY(-dy); | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     parent.target?.inputModel.moveMouse(_x, _y); | 
					
						
							| 
									
										
										
										
											2020-11-24 22:03:04 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  |   updateCursorData(Map<String, dynamic> evt) async { | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     var id = int.parse(evt['id']); | 
					
						
							|  |  |  |     _hotx = double.parse(evt['hotx']); | 
					
						
							|  |  |  |     _hoty = double.parse(evt['hoty']); | 
					
						
							|  |  |  |     var width = int.parse(evt['width']); | 
					
						
							|  |  |  |     var height = int.parse(evt['height']); | 
					
						
							|  |  |  |     List<dynamic> colors = json.decode(evt['colors']); | 
					
						
							|  |  |  |     final rgba = Uint8List.fromList(colors.map((s) => s as int).toList()); | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  |     final image = await img.decodeImageFromPixels( | 
					
						
							|  |  |  |         rgba, width, height, ui.PixelFormat.rgba8888); | 
					
						
							|  |  |  |     _image = image; | 
					
						
							| 
									
										
										
										
											2022-11-21 18:56:27 +08:00
										 |  |  |     if (await _updateCache(rgba, image, id, width, height)) { | 
					
						
							| 
									
										
										
										
											2022-11-13 23:41:07 +08:00
										 |  |  |       _images[id] = Tuple3(image, _hotx, _hoty); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       _hotx = 0; | 
					
						
							|  |  |  |       _hoty = 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  |     try { | 
					
						
							|  |  |  |       // my throw exception, because the listener maybe already dispose
 | 
					
						
							|  |  |  |       notifyListeners(); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2022-11-12 22:33:10 +08:00
										 |  |  |       debugPrint('WARNING: updateCursorId $id, without notifyListeners(). $e'); | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-21 18:56:27 +08:00
										 |  |  |   Future<bool> _updateCache( | 
					
						
							|  |  |  |       Uint8List rgba, ui.Image image, int id, int w, int h) async { | 
					
						
							|  |  |  |     Uint8List? data; | 
					
						
							| 
									
										
										
										
											2023-02-01 22:12:28 +08:00
										 |  |  |     img2.Image imgOrigin = | 
					
						
							|  |  |  |         img2.Image.fromBytes(w, h, rgba, format: img2.Format.rgba); | 
					
						
							| 
									
										
										
										
											2022-10-10 10:53:10 +08:00
										 |  |  |     if (Platform.isWindows) { | 
					
						
							| 
									
										
										
										
											2022-11-21 18:56:27 +08:00
										 |  |  |       data = imgOrigin.getBytes(format: img2.Format.bgra); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       ByteData? imgBytes = | 
					
						
							|  |  |  |           await image.toByteData(format: ui.ImageByteFormat.png); | 
					
						
							|  |  |  |       if (imgBytes == null) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       data = imgBytes.buffer.asUint8List(); | 
					
						
							| 
									
										
										
										
											2022-10-10 10:53:10 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-10-30 13:50:44 +08:00
										 |  |  |     _cache = CursorData( | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  |       peerId: this.id, | 
					
						
							|  |  |  |       id: id, | 
					
						
							| 
									
										
										
										
											2022-11-21 18:56:27 +08:00
										 |  |  |       image: imgOrigin, | 
					
						
							| 
									
										
										
										
											2022-10-27 18:40:45 +08:00
										 |  |  |       scale: 1.0, | 
					
						
							| 
									
										
										
										
											2022-10-27 20:05:36 +08:00
										 |  |  |       data: data, | 
					
						
							| 
									
										
										
										
											2022-11-15 22:35:10 +08:00
										 |  |  |       hotxOrigin: _hotx, | 
					
						
							|  |  |  |       hotyOrigin: _hoty, | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  |       width: w, | 
					
						
							|  |  |  |       height: h, | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-10-30 13:50:44 +08:00
										 |  |  |     _cacheMap[id] = _cache!; | 
					
						
							| 
									
										
										
										
											2022-11-13 23:41:07 +08:00
										 |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  |   updateCursorId(Map<String, dynamic> evt) async { | 
					
						
							|  |  |  |     final id = int.parse(evt['id']); | 
					
						
							| 
									
										
										
										
											2022-10-30 13:50:44 +08:00
										 |  |  |     _cache = _cacheMap[id]; | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  |     final tmp = _images[id]; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     if (tmp != null) { | 
					
						
							| 
									
										
										
										
											2022-09-07 02:14:52 -07:00
										 |  |  |       _image = tmp.item1; | 
					
						
							|  |  |  |       _hotx = tmp.item2; | 
					
						
							|  |  |  |       _hoty = tmp.item3; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |       notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-11-12 22:33:10 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       debugPrint( | 
					
						
							|  |  |  |           'WARNING: updateCursorId $id, cache is ${_cache == null ? "null" : "not null"}. without notifyListeners()'); | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-27 16:50:02 +08:00
										 |  |  |   /// Update the cursor position.
 | 
					
						
							| 
									
										
										
										
											2022-09-10 19:50:48 -07:00
										 |  |  |   updateCursorPosition(Map<String, dynamic> evt, String id) async { | 
					
						
							| 
									
										
										
										
											2023-02-03 20:27:05 +08:00
										 |  |  |     if (!isConnIn2Secs()) { | 
					
						
							| 
									
										
										
										
											2023-02-03 18:28:47 +08:00
										 |  |  |       gotMouseControl = false; | 
					
						
							| 
									
										
										
										
											2023-02-03 20:27:05 +08:00
										 |  |  |       _lastPeerMouse = DateTime.now(); | 
					
						
							| 
									
										
										
										
											2023-02-03 18:28:47 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     _x = double.parse(evt['x']); | 
					
						
							|  |  |  |     _y = double.parse(evt['y']); | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2022-09-07 02:14:52 -07:00
										 |  |  |       RemoteCursorMovedState.find(id).value = true; | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     } catch (e) { | 
					
						
							|  |  |  |       //
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   updateDisplayOrigin(double x, double y) { | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     _displayOriginX = x; | 
					
						
							|  |  |  |     _displayOriginY = y; | 
					
						
							| 
									
										
										
										
											2020-12-21 21:52:20 +08:00
										 |  |  |     _x = x + 1; | 
					
						
							|  |  |  |     _y = y + 1; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     parent.target?.inputModel.moveMouse(x, y); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     parent.target?.canvasModel.resetOffset(); | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   updateDisplayOriginWithCursor( | 
					
						
							| 
									
										
										
										
											2022-05-31 14:44:06 +08:00
										 |  |  |       double x, double y, double xCursor, double yCursor) { | 
					
						
							| 
									
										
										
										
											2020-12-21 18:28:28 +08:00
										 |  |  |     _displayOriginX = x; | 
					
						
							|  |  |  |     _displayOriginY = y; | 
					
						
							|  |  |  |     _x = xCursor; | 
					
						
							|  |  |  |     _y = yCursor; | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     parent.target?.inputModel.moveMouse(x, y); | 
					
						
							| 
									
										
										
										
											2020-12-21 18:28:28 +08:00
										 |  |  |     notifyListeners(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 01:35:56 -07:00
										 |  |  |   clear() { | 
					
						
							| 
									
										
										
										
											2020-11-22 18:29:04 +08:00
										 |  |  |     _x = -10000; | 
					
						
							|  |  |  |     _x = -10000; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |     _image = null; | 
					
						
							|  |  |  |     _images.clear(); | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-30 13:50:44 +08:00
										 |  |  |     _clearCache(); | 
					
						
							|  |  |  |     _cache = null; | 
					
						
							|  |  |  |     _cacheMap.clear(); | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-30 13:50:44 +08:00
										 |  |  |   _clearCache() { | 
					
						
							|  |  |  |     final keys = {...cachedKeys}; | 
					
						
							|  |  |  |     for (var k in keys) { | 
					
						
							| 
									
										
										
										
											2022-12-11 14:17:29 +08:00
										 |  |  |       debugPrint("deleting cursor with key $k"); | 
					
						
							|  |  |  |       CursorManager.instance.deleteCursor(k); | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  | class QualityMonitorData { | 
					
						
							|  |  |  |   String? speed; | 
					
						
							|  |  |  |   String? fps; | 
					
						
							|  |  |  |   String? delay; | 
					
						
							|  |  |  |   String? targetBitrate; | 
					
						
							|  |  |  |   String? codecFormat; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class QualityMonitorModel with ChangeNotifier { | 
					
						
							|  |  |  |   WeakReference<FFI> parent; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   QualityMonitorModel(this.parent); | 
					
						
							|  |  |  |   var _show = false; | 
					
						
							|  |  |  |   final _data = QualityMonitorData(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool get show => _show; | 
					
						
							|  |  |  |   QualityMonitorData get data => _data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-05 20:29:43 +08:00
										 |  |  |   checkShowQualityMonitor(String id) async { | 
					
						
							| 
									
										
										
										
											2022-08-16 15:22:57 +08:00
										 |  |  |     final show = await bind.sessionGetToggleOption( | 
					
						
							| 
									
										
										
										
											2022-08-05 20:29:43 +08:00
										 |  |  |             id: id, arg: 'show-quality-monitor') == | 
					
						
							|  |  |  |         true; | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |     if (_show != show) { | 
					
						
							|  |  |  |       _show = show; | 
					
						
							|  |  |  |       notifyListeners(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   updateQualityStatus(Map<String, dynamic> evt) { | 
					
						
							|  |  |  |     try { | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |       if ((evt['speed'] as String).isNotEmpty) _data.speed = evt['speed']; | 
					
						
							|  |  |  |       if ((evt['fps'] as String).isNotEmpty) _data.fps = evt['fps']; | 
					
						
							|  |  |  |       if ((evt['delay'] as String).isNotEmpty) _data.delay = evt['delay']; | 
					
						
							|  |  |  |       if ((evt['target_bitrate'] as String).isNotEmpty) { | 
					
						
							|  |  |  |         _data.targetBitrate = evt['target_bitrate']; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if ((evt['codec_format'] as String).isNotEmpty) { | 
					
						
							|  |  |  |         _data.codecFormat = evt['codec_format']; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |       notifyListeners(); | 
					
						
							| 
									
										
										
										
											2022-09-07 07:06:05 -07:00
										 |  |  |     } catch (e) { | 
					
						
							|  |  |  |       //
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-04 17:24:02 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-15 17:31:28 +08:00
										 |  |  | class RecordingModel with ChangeNotifier { | 
					
						
							|  |  |  |   WeakReference<FFI> parent; | 
					
						
							|  |  |  |   RecordingModel(this.parent); | 
					
						
							|  |  |  |   bool _start = false; | 
					
						
							|  |  |  |   get start => _start; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 16:03:08 +08:00
										 |  |  |   onSwitchDisplay() { | 
					
						
							| 
									
										
										
										
											2022-10-25 11:27:34 +09:00
										 |  |  |     if (isIOS || !_start) return; | 
					
						
							| 
									
										
										
										
											2022-09-15 17:31:28 +08:00
										 |  |  |     var id = parent.target?.id; | 
					
						
							|  |  |  |     int? width = parent.target?.canvasModel.getDisplayWidth(); | 
					
						
							| 
									
										
										
										
											2022-10-25 11:27:34 +09:00
										 |  |  |     int? height = parent.target?.canvasModel.getDisplayHeight(); | 
					
						
							| 
									
										
										
										
											2022-09-15 17:31:28 +08:00
										 |  |  |     if (id == null || width == null || height == null) return; | 
					
						
							| 
									
										
										
										
											2022-09-21 16:03:08 +08:00
										 |  |  |     bind.sessionRecordScreen(id: id, start: true, width: width, height: height); | 
					
						
							| 
									
										
										
										
											2022-09-15 17:31:28 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 16:03:08 +08:00
										 |  |  |   toggle() { | 
					
						
							| 
									
										
										
										
											2022-10-25 11:27:34 +09:00
										 |  |  |     if (isIOS) return; | 
					
						
							| 
									
										
										
										
											2022-09-15 17:31:28 +08:00
										 |  |  |     var id = parent.target?.id; | 
					
						
							| 
									
										
										
										
											2022-09-21 16:03:08 +08:00
										 |  |  |     if (id == null) return; | 
					
						
							| 
									
										
										
										
											2022-09-15 17:31:28 +08:00
										 |  |  |     _start = !_start; | 
					
						
							|  |  |  |     notifyListeners(); | 
					
						
							|  |  |  |     if (_start) { | 
					
						
							| 
									
										
										
										
											2022-09-21 16:03:08 +08:00
										 |  |  |       bind.sessionRefresh(id: id); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       bind.sessionRecordScreen(id: id, start: false, width: 0, height: 0); | 
					
						
							| 
									
										
										
										
											2022-09-15 17:31:28 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-09-21 16:03:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   onClose() { | 
					
						
							| 
									
										
										
										
											2022-10-25 11:27:34 +09:00
										 |  |  |     if (isIOS) return; | 
					
						
							| 
									
										
										
										
											2022-09-21 16:03:08 +08:00
										 |  |  |     var id = parent.target?.id; | 
					
						
							|  |  |  |     if (id == null) return; | 
					
						
							|  |  |  |     _start = false; | 
					
						
							|  |  |  |     bind.sessionRecordScreen(id: id, start: false, width: 0, height: 0); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-09-15 17:31:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-24 15:51:13 +08:00
										 |  |  | class ElevationModel with ChangeNotifier { | 
					
						
							|  |  |  |   WeakReference<FFI> parent; | 
					
						
							|  |  |  |   ElevationModel(this.parent); | 
					
						
							|  |  |  |   bool _running = false; | 
					
						
							|  |  |  |   bool _canElevate = false; | 
					
						
							|  |  |  |   bool get showRequestMenu => _canElevate && !_running; | 
					
						
							|  |  |  |   onPeerInfo(PeerInfo pi) { | 
					
						
							|  |  |  |     _canElevate = pi.platform == kPeerPlatformWindows && pi.sasEnabled == false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   onPortableServiceRunning(Map<String, dynamic> evt) { | 
					
						
							|  |  |  |     _running = evt['running'] == 'true'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-06 19:08:45 +08:00
										 |  |  | enum ConnType { defaultConn, fileTransfer, portForward, rdp } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-13 21:52:22 +08:00
										 |  |  | /// Flutter state manager and data communication with the Rust core.
 | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | class FFI { | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |   var id = ''; | 
					
						
							|  |  |  |   var version = ''; | 
					
						
							| 
									
										
										
										
											2022-09-06 19:08:45 +08:00
										 |  |  |   var connType = ConnType.defaultConn; | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /// dialogManager use late to ensure init after main page binding [globalKey]
 | 
					
						
							|  |  |  |   late final dialogManager = OverlayDialogManager(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   late final ImageModel imageModel; // session
 | 
					
						
							|  |  |  |   late final FfiModel ffiModel; // session
 | 
					
						
							|  |  |  |   late final CursorModel cursorModel; // session
 | 
					
						
							|  |  |  |   late final CanvasModel canvasModel; // session
 | 
					
						
							|  |  |  |   late final ServerModel serverModel; // global
 | 
					
						
							|  |  |  |   late final ChatModel chatModel; // session
 | 
					
						
							|  |  |  |   late final FileModel fileModel; // session
 | 
					
						
							|  |  |  |   late final AbModel abModel; // global
 | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |   late final GroupModel groupModel; // global
 | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |   late final UserModel userModel; // global
 | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |   late final PeerTabModel peerTabModel; // global
 | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |   late final QualityMonitorModel qualityMonitorModel; // session
 | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |   late final RecordingModel recordingModel; // session
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |   late final InputModel inputModel; // session
 | 
					
						
							| 
									
										
										
										
											2023-02-24 15:51:13 +08:00
										 |  |  |   late final ElevationModel elevationModel; // session
 | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   FFI() { | 
					
						
							| 
									
										
										
										
											2022-08-31 23:02:16 +08:00
										 |  |  |     imageModel = ImageModel(WeakReference(this)); | 
					
						
							|  |  |  |     ffiModel = FfiModel(WeakReference(this)); | 
					
						
							|  |  |  |     cursorModel = CursorModel(WeakReference(this)); | 
					
						
							|  |  |  |     canvasModel = CanvasModel(WeakReference(this)); | 
					
						
							| 
									
										
										
										
											2022-09-13 21:52:22 +08:00
										 |  |  |     serverModel = ServerModel(WeakReference(this)); | 
					
						
							| 
									
										
										
										
											2022-08-31 23:02:16 +08:00
										 |  |  |     chatModel = ChatModel(WeakReference(this)); | 
					
						
							|  |  |  |     fileModel = FileModel(WeakReference(this)); | 
					
						
							|  |  |  |     userModel = UserModel(WeakReference(this)); | 
					
						
							| 
									
										
										
										
											2023-02-03 15:07:45 +08:00
										 |  |  |     peerTabModel = PeerTabModel(WeakReference(this)); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     abModel = AbModel(WeakReference(this)); | 
					
						
							|  |  |  |     groupModel = GroupModel(WeakReference(this)); | 
					
						
							| 
									
										
										
										
											2022-08-31 23:02:16 +08:00
										 |  |  |     qualityMonitorModel = QualityMonitorModel(WeakReference(this)); | 
					
						
							| 
									
										
										
										
											2022-09-15 17:31:28 +08:00
										 |  |  |     recordingModel = RecordingModel(WeakReference(this)); | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     inputModel = InputModel(WeakReference(this)); | 
					
						
							| 
									
										
										
										
											2023-02-24 15:51:13 +08:00
										 |  |  |     elevationModel = ElevationModel(WeakReference(this)); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |   /// Start with the given [id]. Only transfer file if [isFileTransfer], only port forward if [isPortForward].
 | 
					
						
							|  |  |  |   void start(String id, | 
					
						
							| 
									
										
										
										
											2023-01-17 13:28:33 +08:00
										 |  |  |       {bool isFileTransfer = false, | 
					
						
							|  |  |  |       bool isPortForward = false, | 
					
						
							| 
									
										
										
										
											2023-02-13 16:40:24 +08:00
										 |  |  |       String? switchUuid, | 
					
						
							| 
									
										
										
										
											2023-03-20 00:16:06 +08:00
										 |  |  |       String? password, | 
					
						
							| 
									
										
										
										
											2023-02-13 16:40:24 +08:00
										 |  |  |       bool? forceRelay}) { | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     assert(!(isFileTransfer && isPortForward), 'more than one connect type'); | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |     if (isFileTransfer) { | 
					
						
							| 
									
										
										
										
											2022-09-06 19:08:45 +08:00
										 |  |  |       connType = ConnType.fileTransfer; | 
					
						
							|  |  |  |       id = 'ft_$id'; | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |     } else if (isPortForward) { | 
					
						
							| 
									
										
										
										
											2022-09-06 19:08:45 +08:00
										 |  |  |       connType = ConnType.portForward; | 
					
						
							|  |  |  |       id = 'pf_$id'; | 
					
						
							| 
									
										
										
										
											2022-08-26 11:35:28 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |       chatModel.resetClientMode(); | 
					
						
							| 
									
										
										
										
											2023-03-27 16:11:17 +08:00
										 |  |  |       connType = ConnType.defaultConn; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |       canvasModel.id = id; | 
					
						
							| 
									
										
										
										
											2022-09-13 21:52:22 +08:00
										 |  |  |       imageModel.id = id; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |       cursorModel.id = id; | 
					
						
							| 
									
										
										
										
											2022-06-21 17:58:27 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-30 21:15:35 +08:00
										 |  |  |     // ignore: unused_local_variable
 | 
					
						
							|  |  |  |     final addRes = bind.sessionAddSync( | 
					
						
							| 
									
										
										
										
											2023-03-20 00:16:06 +08:00
										 |  |  |       id: id, | 
					
						
							|  |  |  |       isFileTransfer: isFileTransfer, | 
					
						
							|  |  |  |       isPortForward: isPortForward, | 
					
						
							|  |  |  |       switchUuid: switchUuid ?? "", | 
					
						
							|  |  |  |       forceRelay: forceRelay ?? false, | 
					
						
							|  |  |  |       password: password ?? "", | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-08-30 21:15:35 +08:00
										 |  |  |     final stream = bind.sessionStart(id: id); | 
					
						
							| 
									
										
										
										
											2022-06-21 17:58:27 +08:00
										 |  |  |     final cb = ffiModel.startEventListener(id); | 
					
						
							|  |  |  |     () async { | 
					
						
							| 
									
										
										
										
											2023-02-21 23:46:13 +08:00
										 |  |  |       final useTextureRender = bind.mainUseTextureRender(); | 
					
						
							| 
									
										
										
										
											2023-02-12 01:52:11 +08:00
										 |  |  |       // Preserved for the rgba data.
 | 
					
						
							| 
									
										
										
										
											2022-06-21 17:58:27 +08:00
										 |  |  |       await for (final message in stream) { | 
					
						
							| 
									
										
										
										
											2023-01-19 21:21:28 +08:00
										 |  |  |         if (message is EventToUI_Event) { | 
					
						
							| 
									
										
										
										
											2023-02-15 20:39:30 +08:00
										 |  |  |           if (message.field0 == "close") { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2022-06-21 17:58:27 +08:00
										 |  |  |           try { | 
					
						
							|  |  |  |             Map<String, dynamic> event = json.decode(message.field0); | 
					
						
							| 
									
										
										
										
											2022-09-11 19:52:38 -07:00
										 |  |  |             await cb(event); | 
					
						
							| 
									
										
										
										
											2022-06-21 17:58:27 +08:00
										 |  |  |           } catch (e) { | 
					
						
							| 
									
										
										
										
											2022-09-21 16:03:08 +08:00
										 |  |  |             debugPrint('json.decode fail1(): $e, ${message.field0}'); | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2023-01-19 21:21:28 +08:00
										 |  |  |         } else if (message is EventToUI_Rgba) { | 
					
						
							| 
									
										
										
										
											2023-02-21 23:46:13 +08:00
										 |  |  |           if (useTextureRender) { | 
					
						
							| 
									
										
										
										
											2023-02-21 21:56:46 +08:00
										 |  |  |             if (_waitForImage[id]!) { | 
					
						
							|  |  |  |               _waitForImage[id] = false; | 
					
						
							|  |  |  |               dialogManager.dismissAll(); | 
					
						
							|  |  |  |               for (final cb in imageModel.callbacksOnFirstImage) { | 
					
						
							|  |  |  |                 cb(id); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |               await canvasModel.updateViewStyle(); | 
					
						
							|  |  |  |               await canvasModel.updateScrollStyle(); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-02-21 23:46:13 +08:00
										 |  |  |           } else { | 
					
						
							|  |  |  |             // Fetch the image buffer from rust codes.
 | 
					
						
							|  |  |  |             final sz = platformFFI.getRgbaSize(id); | 
					
						
							|  |  |  |             if (sz == null || sz == 0) { | 
					
						
							|  |  |  |               return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             final rgba = platformFFI.getRgba(id, sz); | 
					
						
							|  |  |  |             if (rgba != null) { | 
					
						
							|  |  |  |               imageModel.onRgba(rgba); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-02-21 21:56:46 +08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2022-05-31 17:36:36 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-06-21 17:58:27 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-02-15 21:27:50 +08:00
										 |  |  |       debugPrint('Exit session event loop'); | 
					
						
							| 
									
										
										
										
											2022-06-21 17:58:27 +08:00
										 |  |  |     }(); | 
					
						
							|  |  |  |     // every instance will bind a stream
 | 
					
						
							| 
									
										
										
										
											2022-06-17 22:21:49 +08:00
										 |  |  |     this.id = id; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  |   /// Login with [password], choose if the client should [remember] it.
 | 
					
						
							| 
									
										
										
										
											2023-03-23 19:57:58 +08:00
										 |  |  |   void login(String osUsername, String osPassword, String id, String password, | 
					
						
							|  |  |  |       bool remember) { | 
					
						
							|  |  |  |     bind.sessionLogin( | 
					
						
							|  |  |  |         id: id, | 
					
						
							| 
									
										
										
										
											2023-03-28 08:57:19 +08:00
										 |  |  |         osUsername: osUsername, | 
					
						
							|  |  |  |         osPassword: osPassword, | 
					
						
							| 
									
										
										
										
											2023-03-23 19:57:58 +08:00
										 |  |  |         password: password, | 
					
						
							|  |  |  |         remember: remember); | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 03:56:42 +08:00
										 |  |  |   /// Close the remote session.
 | 
					
						
							| 
									
										
										
										
											2022-06-28 22:04:10 +08:00
										 |  |  |   Future<void> close() async { | 
					
						
							| 
									
										
										
										
											2022-03-25 16:34:27 +08:00
										 |  |  |     chatModel.close(); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     if (imageModel.image != null && !isWebDesktop) { | 
					
						
							| 
									
										
										
										
											2022-11-10 21:25:12 +08:00
										 |  |  |       await setCanvasConfig(id, cursorModel.x, cursorModel.y, canvasModel.x, | 
					
						
							| 
									
										
										
										
											2022-03-07 22:54:34 +08:00
										 |  |  |           canvasModel.y, canvasModel.scale, ffiModel.pi.currentDisplay); | 
					
						
							| 
									
										
										
										
											2022-02-03 17:19:25 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  |     imageModel.update(null); | 
					
						
							| 
									
										
										
										
											2020-11-25 16:28:46 +08:00
										 |  |  |     cursorModel.clear(); | 
					
						
							|  |  |  |     ffiModel.clear(); | 
					
						
							|  |  |  |     canvasModel.clear(); | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     inputModel.resetModifiers(); | 
					
						
							| 
									
										
										
										
											2023-02-10 21:18:55 +08:00
										 |  |  |     await bind.sessionClose(id: id); | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     debugPrint('model $id closed'); | 
					
						
							| 
									
										
										
										
											2023-02-08 10:11:53 +09:00
										 |  |  |     id = ''; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |   void setMethodCallHandler(FMethod callback) { | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |     platformFFI.setMethodCallHandler(callback); | 
					
						
							| 
									
										
										
										
											2022-02-10 02:07:53 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   Future<bool> invokeMethod(String method, [dynamic arguments]) async { | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  |     return await platformFFI.invokeMethod(method, arguments); | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Display { | 
					
						
							|  |  |  |   double x = 0; | 
					
						
							|  |  |  |   double y = 0; | 
					
						
							|  |  |  |   int width = 0; | 
					
						
							|  |  |  |   int height = 0; | 
					
						
							| 
									
										
										
										
											2022-12-31 21:41:16 +08:00
										 |  |  |   bool cursorEmbedded = false; | 
					
						
							| 
									
										
										
										
											2022-09-11 19:52:38 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Display() { | 
					
						
							|  |  |  |     width = (isDesktop || isWebDesktop) | 
					
						
							|  |  |  |         ? kDesktopDefaultDisplayWidth | 
					
						
							|  |  |  |         : kMobileDefaultDisplayWidth; | 
					
						
							|  |  |  |     height = (isDesktop || isWebDesktop) | 
					
						
							|  |  |  |         ? kDesktopDefaultDisplayHeight | 
					
						
							|  |  |  |         : kMobileDefaultDisplayHeight; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-02-25 22:47:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   bool operator ==(Object other) => | 
					
						
							|  |  |  |       other is Display && | 
					
						
							|  |  |  |       other.runtimeType == runtimeType && | 
					
						
							|  |  |  |       _innerEqual(other); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool _innerEqual(Display other) => | 
					
						
							|  |  |  |       other.x == x && | 
					
						
							|  |  |  |       other.y == y && | 
					
						
							|  |  |  |       other.width == width && | 
					
						
							|  |  |  |       other.height == height && | 
					
						
							|  |  |  |       other.cursorEmbedded == cursorEmbedded; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 15:53:51 +08:00
										 |  |  | class Resolution { | 
					
						
							|  |  |  |   int width = 0; | 
					
						
							|  |  |  |   int height = 0; | 
					
						
							|  |  |  |   Resolution(this.width, this.height); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   String toString() { | 
					
						
							|  |  |  |     return 'Resolution($width,$height)'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 21:34:20 +08:00
										 |  |  | class Features { | 
					
						
							|  |  |  |   bool privacyMode = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | class PeerInfo { | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |   String version = ''; | 
					
						
							|  |  |  |   String username = ''; | 
					
						
							|  |  |  |   String hostname = ''; | 
					
						
							|  |  |  |   String platform = ''; | 
					
						
							| 
									
										
										
										
											2022-02-17 15:22:14 +08:00
										 |  |  |   bool sasEnabled = false; | 
					
						
							|  |  |  |   int currentDisplay = 0; | 
					
						
							|  |  |  |   List<Display> displays = []; | 
					
						
							| 
									
										
										
										
											2022-12-02 21:34:20 +08:00
										 |  |  |   Features features = Features(); | 
					
						
							| 
									
										
										
										
											2023-02-09 15:53:51 +08:00
										 |  |  |   List<Resolution> resolutions = []; | 
					
						
							| 
									
										
										
										
											2023-03-21 11:27:30 +08:00
										 |  |  |   Map<String, dynamic> platform_additions = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool get is_wayland => platform_additions['is_wayland'] == true; | 
					
						
							| 
									
										
										
										
											2023-03-30 10:48:18 +08:00
										 |  |  |   bool get is_headless => platform_additions['headless'] == true; | 
					
						
							| 
									
										
										
										
											2020-11-19 00:32:46 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-12-21 18:28:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 21:25:12 +08:00
										 |  |  | const canvasKey = 'canvas'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Future<void> setCanvasConfig(String id, double xCursor, double yCursor, | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     double xCanvas, double yCanvas, double scale, int currentDisplay) async { | 
					
						
							| 
									
										
										
										
											2022-09-01 06:18:29 -07:00
										 |  |  |   final p = <String, dynamic>{}; | 
					
						
							| 
									
										
										
										
											2020-12-21 18:28:28 +08:00
										 |  |  |   p['xCursor'] = xCursor; | 
					
						
							|  |  |  |   p['yCursor'] = yCursor; | 
					
						
							|  |  |  |   p['xCanvas'] = xCanvas; | 
					
						
							|  |  |  |   p['yCanvas'] = yCanvas; | 
					
						
							|  |  |  |   p['scale'] = scale; | 
					
						
							|  |  |  |   p['currentDisplay'] = currentDisplay; | 
					
						
							| 
									
										
										
										
											2022-11-10 21:25:12 +08:00
										 |  |  |   await bind.sessionSetFlutterConfig(id: id, k: canvasKey, v: jsonEncode(p)); | 
					
						
							| 
									
										
										
										
											2020-12-21 18:28:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 21:25:12 +08:00
										 |  |  | Future<Map<String, dynamic>?> getCanvasConfig(String id) async { | 
					
						
							| 
									
										
										
										
											2022-05-23 16:02:37 +08:00
										 |  |  |   if (!isWebDesktop) return null; | 
					
						
							| 
									
										
										
										
											2022-11-10 21:25:12 +08:00
										 |  |  |   var p = await bind.sessionGetFlutterConfig(id: id, k: canvasKey); | 
					
						
							|  |  |  |   if (p == null || p.isEmpty) return null; | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     Map<String, dynamic> m = json.decode(p); | 
					
						
							|  |  |  |     return m; | 
					
						
							|  |  |  |   } catch (e) { | 
					
						
							|  |  |  |     return null; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-12-21 18:28:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  | void removePreference(String id) async { | 
					
						
							| 
									
										
										
										
											2022-11-10 21:25:12 +08:00
										 |  |  |   await bind.sessionSetFlutterConfig(id: id, k: canvasKey, v: ''); | 
					
						
							| 
									
										
										
										
											2020-12-21 19:05:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  | Future<void> initializeCursorAndCanvas(FFI ffi) async { | 
					
						
							| 
									
										
										
										
											2022-11-10 21:25:12 +08:00
										 |  |  |   var p = await getCanvasConfig(ffi.id); | 
					
						
							| 
									
										
										
										
											2020-12-21 18:28:28 +08:00
										 |  |  |   int currentDisplay = 0; | 
					
						
							|  |  |  |   if (p != null) { | 
					
						
							|  |  |  |     currentDisplay = p['currentDisplay']; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   if (p == null || currentDisplay != ffi.ffiModel.pi.currentDisplay) { | 
					
						
							|  |  |  |     ffi.cursorModel | 
					
						
							|  |  |  |         .updateDisplayOrigin(ffi.ffiModel.display.x, ffi.ffiModel.display.y); | 
					
						
							| 
									
										
										
										
											2020-12-21 18:28:28 +08:00
										 |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   double xCursor = p['xCursor']; | 
					
						
							|  |  |  |   double yCursor = p['yCursor']; | 
					
						
							|  |  |  |   double xCanvas = p['xCanvas']; | 
					
						
							|  |  |  |   double yCanvas = p['yCanvas']; | 
					
						
							|  |  |  |   double scale = p['scale']; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   ffi.cursorModel.updateDisplayOriginWithCursor( | 
					
						
							|  |  |  |       ffi.ffiModel.display.x, ffi.ffiModel.display.y, xCursor, yCursor); | 
					
						
							|  |  |  |   ffi.canvasModel.update(xCanvas, yCanvas, scale); | 
					
						
							| 
									
										
										
										
											2020-12-21 18:28:28 +08:00
										 |  |  | } |