| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							|  |  |  | import 'dart:io'; | 
					
						
							|  |  |  | import 'dart:ui' as ui; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import 'package:flutter/gestures.dart'; | 
					
						
							|  |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  | import 'package:flutter/services.dart'; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | import 'package:provider/provider.dart'; | 
					
						
							|  |  |  | import 'package:wakelock/wakelock.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  | import 'package:flutter_custom_cursor/flutter_custom_cursor.dart'; | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  | import 'package:flutter_improved_scrolling/flutter_improved_scrolling.dart'; | 
					
						
							| 
									
										
										
										
											2022-06-27 10:34:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  | import '../../consts.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-27 23:05:11 +08:00
										 |  |  | import '../../common/widgets/overlay.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  | import '../../common/widgets/remote_input.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | import '../../common.dart'; | 
					
						
							|  |  |  | import '../../mobile/widgets/dialog.dart'; | 
					
						
							|  |  |  | import '../../models/model.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  | import '../../models/platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  | import '../../common/shared_state.dart'; | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  | import '../widgets/remote_menubar.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  | bool _isCustomCursorInited = false; | 
					
						
							| 
									
										
										
										
											2022-10-03 22:03:49 -07:00
										 |  |  | final SimpleWrapper<bool> _firstEnterImage = SimpleWrapper(false); | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | class RemotePage extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |   const RemotePage({ | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |     Key? key, | 
					
						
							|  |  |  |     required this.id, | 
					
						
							|  |  |  |     required this.tabBarHeight, | 
					
						
							| 
									
										
										
										
											2022-10-04 21:19:31 +08:00
										 |  |  |     required this.windowBorderWidth, | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |   }) : super(key: key); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   final String id; | 
					
						
							| 
									
										
										
										
											2022-08-03 15:31:19 +08:00
										 |  |  |   final double tabBarHeight; | 
					
						
							| 
									
										
										
										
											2022-10-04 21:19:31 +08:00
										 |  |  |   final double windowBorderWidth; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  |   State<RemotePage> createState() => _RemotePageState(); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-17 22:21:49 +08:00
										 |  |  | class _RemotePageState extends State<RemotePage> | 
					
						
							| 
									
										
										
										
											2022-06-27 09:48:35 +08:00
										 |  |  |     with AutomaticKeepAliveClientMixin { | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   Timer? _timer; | 
					
						
							| 
									
										
										
										
											2022-09-05 10:18:29 -04:00
										 |  |  |   String keyboardMode = "legacy"; | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |   final _cursorOverImage = false.obs; | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   late RxBool _showRemoteCursor; | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |   late RxBool _remoteCursorMoved; | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   late RxBool _keyboardEnabled; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |   final FocusNode _rawKeyFocusNode = FocusNode(); | 
					
						
							| 
									
										
										
										
											2022-08-16 20:48:36 +08:00
										 |  |  |   var _imageFocused = false; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |   Function(bool)? _onEnterOrLeaveImage4Menubar; | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |   late FFI _ffi; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |   void _updateTabBarHeight() { | 
					
						
							|  |  |  |     _ffi.canvasModel.tabBarHeight = widget.tabBarHeight; | 
					
						
							| 
									
										
										
										
											2022-10-04 21:19:31 +08:00
										 |  |  |     _ffi.canvasModel.windowBorderWidth = widget.windowBorderWidth; | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |   void _initStates(String id) { | 
					
						
							|  |  |  |     PrivacyModeState.init(id); | 
					
						
							|  |  |  |     BlockInputState.init(id); | 
					
						
							|  |  |  |     CurrentDisplayState.init(id); | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     KeyboardEnabledState.init(id); | 
					
						
							|  |  |  |     ShowRemoteCursorState.init(id); | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     RemoteCursorMovedState.init(id); | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     _showRemoteCursor = ShowRemoteCursorState.find(id); | 
					
						
							|  |  |  |     _keyboardEnabled = KeyboardEnabledState.find(id); | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     _remoteCursorMoved = RemoteCursorMovedState.find(id); | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void _removeStates(String id) { | 
					
						
							|  |  |  |     PrivacyModeState.delete(id); | 
					
						
							|  |  |  |     BlockInputState.delete(id); | 
					
						
							|  |  |  |     CurrentDisplayState.delete(id); | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     ShowRemoteCursorState.delete(id); | 
					
						
							|  |  |  |     KeyboardEnabledState.delete(id); | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     RemoteCursorMovedState.delete(id); | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     _initStates(widget.id); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     _ffi = FFI(); | 
					
						
							| 
									
										
										
										
											2022-09-14 23:49:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |     _updateTabBarHeight(); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     Get.put(_ffi, tag: widget.id); | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  |     _ffi.start(widget.id); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     WidgetsBinding.instance.addPostFrameCallback((_) { | 
					
						
							|  |  |  |       SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |       _ffi.dialogManager | 
					
						
							| 
									
										
										
										
											2022-08-16 21:27:21 +08:00
										 |  |  |           .showLoading(translate('Connecting...'), onCancel: closeConnection); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  |     if (!Platform.isLinux) { | 
					
						
							|  |  |  |       Wakelock.enable(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |     _rawKeyFocusNode.requestFocus(); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     _ffi.ffiModel.updateEventListener(widget.id); | 
					
						
							| 
									
										
										
										
											2022-08-15 20:26:20 +08:00
										 |  |  |     _ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id); | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     _showRemoteCursor.value = bind.sessionGetToggleOptionSync( | 
					
						
							|  |  |  |         id: widget.id, arg: 'show-remote-cursor'); | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |     if (!_isCustomCursorInited) { | 
					
						
							|  |  |  |       customCursorController.registerNeedUpdateCursorCallback( | 
					
						
							|  |  |  |           (String? lastKey, String? currentKey) async { | 
					
						
							| 
									
										
										
										
											2022-10-03 22:03:49 -07:00
										 |  |  |         if (_firstEnterImage.value) { | 
					
						
							|  |  |  |           _firstEnterImage.value = false; | 
					
						
							|  |  |  |           return true; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |         return lastKey == null || lastKey != currentKey; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       _isCustomCursorInited = true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |     debugPrint("REMOTE PAGE dispose ${widget.id}"); | 
					
						
							| 
									
										
										
										
											2022-09-08 22:18:02 +08:00
										 |  |  |     _ffi.dialogManager.hideMobileActionsOverlay(); | 
					
						
							| 
									
										
										
										
											2022-09-21 16:03:08 +08:00
										 |  |  |     _ffi.recordingModel.onClose(); | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |     _rawKeyFocusNode.dispose(); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     _ffi.close(); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     _timer?.cancel(); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     _ffi.dialogManager.dismissAll(); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, | 
					
						
							|  |  |  |         overlays: SystemUiOverlay.values); | 
					
						
							|  |  |  |     if (!Platform.isLinux) { | 
					
						
							|  |  |  |       Wakelock.disable(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     Get.delete<FFI>(tag: widget.id); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     super.dispose(); | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |     _removeStates(widget.id); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   Widget buildBody(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-08-06 18:48:07 +08:00
										 |  |  |     return Scaffold( | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |         backgroundColor: Theme.of(context).backgroundColor, | 
					
						
							| 
									
										
										
										
											2022-08-06 18:48:07 +08:00
										 |  |  |         body: Overlay( | 
					
						
							|  |  |  |           initialEntries: [ | 
					
						
							|  |  |  |             OverlayEntry(builder: (context) { | 
					
						
							| 
									
										
										
										
											2022-08-11 10:19:12 +08:00
										 |  |  |               _ffi.chatModel.setOverlayState(Overlay.of(context)); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |               _ffi.dialogManager.setOverlayState(Overlay.of(context)); | 
					
						
							| 
									
										
										
										
											2022-08-06 18:48:07 +08:00
										 |  |  |               return Container( | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |                   color: Colors.black, | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  |                   child: RawKeyFocusScope( | 
					
						
							|  |  |  |                       focusNode: _rawKeyFocusNode, | 
					
						
							|  |  |  |                       onFocusChange: (bool v) { | 
					
						
							|  |  |  |                         _imageFocused = v; | 
					
						
							|  |  |  |                       }, | 
					
						
							|  |  |  |                       inputModel: _ffi.inputModel, | 
					
						
							|  |  |  |                       child: getBodyForDesktop(context))); | 
					
						
							| 
									
										
										
										
											2022-08-06 18:48:07 +08:00
										 |  |  |             }) | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         )); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-06-17 22:21:49 +08:00
										 |  |  |     super.build(context); | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |     _updateTabBarHeight(); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     return WillPopScope( | 
					
						
							| 
									
										
										
										
											2022-06-17 22:21:49 +08:00
										 |  |  |         onWillPop: () async { | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |           clientClose(_ffi.dialogManager); | 
					
						
							| 
									
										
										
										
											2022-06-17 00:06:49 +08:00
										 |  |  |           return false; | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |         child: MultiProvider(providers: [ | 
					
						
							|  |  |  |           ChangeNotifierProvider.value(value: _ffi.ffiModel), | 
					
						
							|  |  |  |           ChangeNotifierProvider.value(value: _ffi.imageModel), | 
					
						
							|  |  |  |           ChangeNotifierProvider.value(value: _ffi.cursorModel), | 
					
						
							|  |  |  |           ChangeNotifierProvider.value(value: _ffi.canvasModel), | 
					
						
							| 
									
										
										
										
											2022-09-15 17:31:28 +08:00
										 |  |  |           ChangeNotifierProvider.value(value: _ffi.recordingModel), | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |         ], child: buildBody(context))); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-05 06:19:05 -04:00
										 |  |  |   void enterView(PointerEnterEvent evt) { | 
					
						
							|  |  |  |     if (!_imageFocused) { | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |       _rawKeyFocusNode.requestFocus(); | 
					
						
							| 
									
										
										
										
											2022-09-05 06:19:05 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |     _cursorOverImage.value = true; | 
					
						
							| 
									
										
										
										
											2022-10-03 22:03:49 -07:00
										 |  |  |     _firstEnterImage.value = true; | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |     if (_onEnterOrLeaveImage4Menubar != null) { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         _onEnterOrLeaveImage4Menubar!(true); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         //
 | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     _ffi.inputModel.enterOrLeave(true); | 
					
						
							| 
									
										
										
										
											2022-09-05 06:19:05 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void leaveView(PointerExitEvent evt) { | 
					
						
							|  |  |  |     _cursorOverImage.value = false; | 
					
						
							| 
									
										
										
										
											2022-10-03 22:03:49 -07:00
										 |  |  |     _firstEnterImage.value = false; | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |     if (_onEnterOrLeaveImage4Menubar != null) { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         _onEnterOrLeaveImage4Menubar!(false); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         //
 | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     _ffi.inputModel.enterOrLeave(false); | 
					
						
							| 
									
										
										
										
											2022-09-05 06:19:05 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   Widget getBodyForDesktop(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     var paints = <Widget>[ | 
					
						
							| 
									
										
										
										
											2022-08-11 16:03:04 +08:00
										 |  |  |       MouseRegion(onEnter: (evt) { | 
					
						
							|  |  |  |         bind.hostStopSystemKeyPropagate(stopped: false); | 
					
						
							|  |  |  |       }, onExit: (evt) { | 
					
						
							|  |  |  |         bind.hostStopSystemKeyPropagate(stopped: true); | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |       }, child: LayoutBuilder(builder: (context, constraints) { | 
					
						
							|  |  |  |         Future.delayed(Duration.zero, () { | 
					
						
							|  |  |  |           Provider.of<CanvasModel>(context, listen: false).updateViewStyle(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         return ImagePaint( | 
					
						
							|  |  |  |           id: widget.id, | 
					
						
							|  |  |  |           cursorOverImage: _cursorOverImage, | 
					
						
							|  |  |  |           keyboardEnabled: _keyboardEnabled, | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |           remoteCursorMoved: _remoteCursorMoved, | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  |           listenerBuilder: (child) => RawPointerMouseRegion( | 
					
						
							|  |  |  |             onEnter: enterView, | 
					
						
							|  |  |  |             onExit: leaveView, | 
					
						
							|  |  |  |             inputModel: _ffi.inputModel, | 
					
						
							|  |  |  |             child: child, | 
					
						
							|  |  |  |           ), | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |         ); | 
					
						
							|  |  |  |       })) | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     ]; | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     paints.add(Obx(() => Visibility( | 
					
						
							| 
									
										
										
										
											2022-09-07 02:14:52 -07:00
										 |  |  |         visible: _showRemoteCursor.isTrue && _remoteCursorMoved.isTrue, | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |         child: CursorPaint( | 
					
						
							|  |  |  |           id: widget.id, | 
					
						
							|  |  |  |         )))); | 
					
						
							| 
									
										
										
										
											2022-08-15 20:26:20 +08:00
										 |  |  |     paints.add(QualityMonitor(_ffi.qualityMonitorModel)); | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |     paints.add(RemoteMenubar( | 
					
						
							|  |  |  |       id: widget.id, | 
					
						
							|  |  |  |       ffi: _ffi, | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |       onEnterOrLeaveImageSetter: (func) => _onEnterOrLeaveImage4Menubar = func, | 
					
						
							|  |  |  |       onEnterOrLeaveImageCleaner: () => _onEnterOrLeaveImage4Menubar = null, | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |     )); | 
					
						
							| 
									
										
										
										
											2022-08-11 10:19:12 +08:00
										 |  |  |     return Stack( | 
					
						
							|  |  |  |       children: paints, | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-17 22:21:49 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   bool get wantKeepAlive => true; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ImagePaint extends StatelessWidget { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   final String id; | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |   final Rx<bool> cursorOverImage; | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   final Rx<bool> keyboardEnabled; | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |   final Rx<bool> remoteCursorMoved; | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |   final Widget Function(Widget)? listenerBuilder; | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |   final ScrollController _horizontal = ScrollController(); | 
					
						
							|  |  |  |   final ScrollController _vertical = ScrollController(); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |   ImagePaint( | 
					
						
							|  |  |  |       {Key? key, | 
					
						
							|  |  |  |       required this.id, | 
					
						
							|  |  |  |       required this.cursorOverImage, | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |       required this.keyboardEnabled, | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |       required this.remoteCursorMoved, | 
					
						
							| 
									
										
										
										
											2022-09-01 22:36:40 -07:00
										 |  |  |       this.listenerBuilder}) | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |       : super(key: key); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-06-17 00:06:49 +08:00
										 |  |  |     final m = Provider.of<ImageModel>(context); | 
					
						
							| 
									
										
										
										
											2022-08-12 20:14:53 +08:00
										 |  |  |     var c = Provider.of<CanvasModel>(context); | 
					
						
							|  |  |  |     final s = c.scale; | 
					
						
							| 
									
										
										
										
											2022-09-08 21:03:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     mouseRegion({child}) => Obx(() => MouseRegion( | 
					
						
							|  |  |  |         cursor: (cursorOverImage.isTrue && keyboardEnabled.isTrue) | 
					
						
							|  |  |  |             ? (remoteCursorMoved.isTrue | 
					
						
							|  |  |  |                 ? SystemMouseCursors.none | 
					
						
							|  |  |  |                 : _buildCustomCursorLinux(context, s)) | 
					
						
							|  |  |  |             : MouseCursor.defer, | 
					
						
							|  |  |  |         onHover: (evt) {}, | 
					
						
							|  |  |  |         child: child)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |     if (c.scrollStyle == ScrollStyle.scrollbar) { | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |       final imageWidget = SizedBox( | 
					
						
							|  |  |  |           width: c.getDisplayWidth() * s, | 
					
						
							|  |  |  |           height: c.getDisplayHeight() * s, | 
					
						
							|  |  |  |           child: CustomPaint( | 
					
						
							| 
									
										
										
										
											2022-08-31 18:41:55 +08:00
										 |  |  |             painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s), | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |           )); | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |       return Center( | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |         child: NotificationListener<ScrollNotification>( | 
					
						
							|  |  |  |           onNotification: (notification) { | 
					
						
							|  |  |  |             final percentX = _horizontal.position.extentBefore / | 
					
						
							|  |  |  |                 (_horizontal.position.extentBefore + | 
					
						
							|  |  |  |                     _horizontal.position.extentInside + | 
					
						
							|  |  |  |                     _horizontal.position.extentAfter); | 
					
						
							|  |  |  |             final percentY = _vertical.position.extentBefore / | 
					
						
							|  |  |  |                 (_vertical.position.extentBefore + | 
					
						
							|  |  |  |                     _vertical.position.extentInside + | 
					
						
							|  |  |  |                     _vertical.position.extentAfter); | 
					
						
							|  |  |  |             c.setScrollPercent(percentX, percentY); | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |           }, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:03:20 -07:00
										 |  |  |           child: mouseRegion( | 
					
						
							|  |  |  |               child: _buildCrossScrollbar(_buildListener(imageWidget))), | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |         ), | 
					
						
							|  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |       final imageWidget = SizedBox( | 
					
						
							|  |  |  |           width: c.size.width, | 
					
						
							|  |  |  |           height: c.size.height, | 
					
						
							|  |  |  |           child: CustomPaint( | 
					
						
							| 
									
										
										
										
											2022-08-31 18:41:55 +08:00
										 |  |  |             painter: | 
					
						
							|  |  |  |                 ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s), | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |           )); | 
					
						
							| 
									
										
										
										
											2022-09-08 21:03:20 -07:00
										 |  |  |       return mouseRegion(child: _buildListener(imageWidget)); | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-13 15:08:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 19:52:30 -07:00
										 |  |  |   MouseCursor _buildCustomCursorLinux(BuildContext context, double scale) { | 
					
						
							|  |  |  |     final cursor = Provider.of<CursorModel>(context); | 
					
						
							|  |  |  |     final cacheLinux = cursor.cacheLinux; | 
					
						
							|  |  |  |     if (cacheLinux == null) { | 
					
						
							|  |  |  |       return MouseCursor.defer; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       final key = cacheLinux.key(scale); | 
					
						
							|  |  |  |       cursor.addKeyLinux(key); | 
					
						
							|  |  |  |       return FlutterCustomMemoryImageCursor( | 
					
						
							|  |  |  |         pixbuf: cacheLinux.data, | 
					
						
							|  |  |  |         key: key, | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |         hotx: cacheLinux.hotx, | 
					
						
							|  |  |  |         hoty: cacheLinux.hoty, | 
					
						
							| 
									
										
										
										
											2022-09-07 19:52:30 -07:00
										 |  |  |         imageWidth: (cacheLinux.width * scale).toInt(), | 
					
						
							|  |  |  |         imageHeight: (cacheLinux.height * scale).toInt(), | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |   Widget _buildCrossScrollbar(Widget child) { | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  |     final scrollConfig = CustomMouseWheelScrollConfig( | 
					
						
							|  |  |  |         scrollDuration: kDefaultScrollDuration, | 
					
						
							|  |  |  |         scrollCurve: Curves.linearToEaseOut, | 
					
						
							|  |  |  |         mouseWheelTurnsThrottleTimeMs: | 
					
						
							|  |  |  |             kDefaultMouseWheelThrottleDuration.inMilliseconds, | 
					
						
							|  |  |  |         scrollAmountMultiplier: kDefaultScrollAmountMultiplier); | 
					
						
							|  |  |  |     return Obx(() => ImprovedScrolling( | 
					
						
							|  |  |  |         scrollController: _vertical, | 
					
						
							|  |  |  |         enableCustomMouseWheelScrolling: cursorOverImage.isFalse, | 
					
						
							|  |  |  |         customMouseWheelScrollConfig: scrollConfig, | 
					
						
							|  |  |  |         child: ImprovedScrolling( | 
					
						
							|  |  |  |             scrollController: _horizontal, | 
					
						
							|  |  |  |             enableCustomMouseWheelScrolling: cursorOverImage.isFalse, | 
					
						
							|  |  |  |             customMouseWheelScrollConfig: scrollConfig, | 
					
						
							|  |  |  |             child: Scrollbar( | 
					
						
							|  |  |  |                 controller: _vertical, | 
					
						
							|  |  |  |                 thumbVisibility: false, | 
					
						
							|  |  |  |                 trackVisibility: false, | 
					
						
							|  |  |  |                 child: Scrollbar( | 
					
						
							|  |  |  |                     controller: _horizontal, | 
					
						
							|  |  |  |                     thumbVisibility: false, | 
					
						
							|  |  |  |                     trackVisibility: false, | 
					
						
							|  |  |  |                     notificationPredicate: (notif) => notif.depth == 1, | 
					
						
							|  |  |  |                     child: SingleChildScrollView( | 
					
						
							|  |  |  |                       controller: _vertical, | 
					
						
							|  |  |  |                       physics: cursorOverImage.isTrue | 
					
						
							|  |  |  |                           ? const NeverScrollableScrollPhysics() | 
					
						
							|  |  |  |                           : null, | 
					
						
							|  |  |  |                       child: SingleChildScrollView( | 
					
						
							|  |  |  |                         controller: _horizontal, | 
					
						
							|  |  |  |                         scrollDirection: Axis.horizontal, | 
					
						
							|  |  |  |                         physics: cursorOverImage.isTrue | 
					
						
							|  |  |  |                             ? const NeverScrollableScrollPhysics() | 
					
						
							|  |  |  |                             : null, | 
					
						
							|  |  |  |                         child: child, | 
					
						
							|  |  |  |                       ), | 
					
						
							|  |  |  |                     )))))); | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildListener(Widget child) { | 
					
						
							|  |  |  |     if (listenerBuilder != null) { | 
					
						
							|  |  |  |       return listenerBuilder!(child); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return child; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-13 15:08:17 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class CursorPaint extends StatelessWidget { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   final String id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const CursorPaint({Key? key, required this.id}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-06-17 00:06:49 +08:00
										 |  |  |     final m = Provider.of<CursorModel>(context); | 
					
						
							|  |  |  |     final c = Provider.of<CanvasModel>(context); | 
					
						
							|  |  |  |     // final adjust = m.adjustForKeyboard();
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     return CustomPaint( | 
					
						
							| 
									
										
										
										
											2022-08-31 18:41:55 +08:00
										 |  |  |       painter: ImagePainter( | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |           image: m.image, | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |           x: m.x - m.hotx + c.x / c.scale, | 
					
						
							|  |  |  |           y: m.y - m.hoty + c.y / c.scale, | 
					
						
							|  |  |  |           scale: c.scale), | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ImagePainter extends CustomPainter { | 
					
						
							|  |  |  |   ImagePainter({ | 
					
						
							|  |  |  |     required this.image, | 
					
						
							|  |  |  |     required this.x, | 
					
						
							|  |  |  |     required this.y, | 
					
						
							|  |  |  |     required this.scale, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ui.Image? image; | 
					
						
							|  |  |  |   double x; | 
					
						
							|  |  |  |   double y; | 
					
						
							|  |  |  |   double scale; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void paint(Canvas canvas, Size size) { | 
					
						
							|  |  |  |     if (image == null) return; | 
					
						
							| 
									
										
										
										
											2022-08-31 18:41:55 +08:00
										 |  |  |     if (x.isNaN || y.isNaN) return; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     canvas.scale(scale, scale); | 
					
						
							| 
									
										
										
										
											2022-08-05 11:07:24 +08:00
										 |  |  |     // https://github.com/flutter/flutter/issues/76187#issuecomment-784628161
 | 
					
						
							| 
									
										
										
										
											2022-08-08 09:41:24 +08:00
										 |  |  |     // https://api.flutter-io.cn/flutter/dart-ui/FilterQuality.html
 | 
					
						
							| 
									
										
										
										
											2022-08-31 18:41:55 +08:00
										 |  |  |     var paint = Paint(); | 
					
						
							| 
									
										
										
										
											2022-08-08 09:41:24 +08:00
										 |  |  |     paint.filterQuality = FilterQuality.medium; | 
					
						
							|  |  |  |     if (scale > 10.00000) { | 
					
						
							| 
									
										
										
										
											2022-08-05 11:07:24 +08:00
										 |  |  |       paint.filterQuality = FilterQuality.high; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-31 18:41:55 +08:00
										 |  |  |     canvas.drawImage(image!, Offset(x, y), paint); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   bool shouldRepaint(CustomPainter oldDelegate) { | 
					
						
							|  |  |  |     return oldDelegate != this; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |