* feat: auto switch display on follow remote cursor Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * feat: auto switch display on follow remote window focus Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build and remove unused imports Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix linux get_focused_window_id Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * lock show remote cursor when follow remote cursor is enabled Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix config Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * prevent auto display switch on show all display and displays as individual windows Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix options Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix options Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove unused function Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove unwraps and improve iterations Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * set updateCursorPos to false to avoid interrupting remote cursor Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * update lang Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix web build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * update checks for options and enable in view mode Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use focused display index for window focus service Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use window center for windows display focused Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove unused imports Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use libxdo instead of xdotool Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix multi monitor check Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * enable show cursor when follow cursor is default Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove show_all_displays,use runtime state instead Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix show cursor lock state on default Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove view mode with follow options Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use separate message for follow current display Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix options Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * sciter support for follow remote cursor and window Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * add check for ui session handlers count Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use cached displays and remove peer info write Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * No follow options when show all displays Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * No follow options when multi ui session Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * turn off follow options when not used|prevent msgs Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use window center for switch in linux Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use subbed display count to prevent switch msgs Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix web build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * move subbed displays count Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * add noperms for window focus Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * add subscribe for window focus Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove window_focus message and unsub on multi ui Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * add multi ui session field Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> --------- Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
		
			
				
	
	
		
			242 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import 'package:debounce_throttle/debounce_throttle.dart';
 | |
| import 'package:flutter/material.dart';
 | |
| import 'package:flutter/services.dart';
 | |
| import 'package:flutter_hbb/common.dart';
 | |
| import 'package:flutter_hbb/consts.dart';
 | |
| import 'package:flutter_hbb/models/desktop_render_texture.dart';
 | |
| import 'package:flutter_hbb/models/platform_model.dart';
 | |
| import 'package:get/get.dart';
 | |
| 
 | |
| customImageQualityWidget(
 | |
|     {required double initQuality,
 | |
|     required double initFps,
 | |
|     required Function(double) setQuality,
 | |
|     required Function(double) setFps,
 | |
|     required bool showFps,
 | |
|     required bool showMoreQuality}) {
 | |
|   if (initQuality < kMinQuality ||
 | |
|       initQuality > (showMoreQuality ? kMaxMoreQuality : kMaxQuality)) {
 | |
|     initQuality = kDefaultQuality;
 | |
|   }
 | |
|   if (initFps < kMinFps || initFps > kMaxFps) {
 | |
|     initFps = kDefaultFps;
 | |
|   }
 | |
|   final qualityValue = initQuality.obs;
 | |
|   final fpsValue = initFps.obs;
 | |
| 
 | |
|   final RxBool moreQualityChecked = RxBool(qualityValue.value > kMaxQuality);
 | |
|   final debouncerQuality = Debouncer<double>(
 | |
|     Duration(milliseconds: 1000),
 | |
|     onChanged: (double v) {
 | |
|       setQuality(v);
 | |
|     },
 | |
|     initialValue: qualityValue.value,
 | |
|   );
 | |
|   final debouncerFps = Debouncer<double>(
 | |
|     Duration(milliseconds: 1000),
 | |
|     onChanged: (double v) {
 | |
|       setFps(v);
 | |
|     },
 | |
|     initialValue: fpsValue.value,
 | |
|   );
 | |
| 
 | |
|   onMoreChanged(bool? value) {
 | |
|     if (value == null) return;
 | |
|     moreQualityChecked.value = value;
 | |
|     if (!value && qualityValue.value > 100) {
 | |
|       qualityValue.value = 100;
 | |
|     }
 | |
|     debouncerQuality.value = qualityValue.value;
 | |
|   }
 | |
| 
 | |
|   return Column(
 | |
|     children: [
 | |
|       Obx(() => Row(
 | |
|             children: [
 | |
|               Expanded(
 | |
|                 flex: 3,
 | |
|                 child: Slider(
 | |
|                   value: qualityValue.value,
 | |
|                   min: kMinQuality,
 | |
|                   max: moreQualityChecked.value ? kMaxMoreQuality : kMaxQuality,
 | |
|                   divisions: moreQualityChecked.value
 | |
|                       ? ((kMaxMoreQuality - kMinQuality) / 10).round()
 | |
|                       : ((kMaxQuality - kMinQuality) / 5).round(),
 | |
|                   onChanged: (double value) async {
 | |
|                     qualityValue.value = value;
 | |
|                     debouncerQuality.value = value;
 | |
|                   },
 | |
|                 ),
 | |
|               ),
 | |
|               Expanded(
 | |
|                   flex: 1,
 | |
|                   child: Text(
 | |
|                     '${qualityValue.value.round()}%',
 | |
|                     style: const TextStyle(fontSize: 15),
 | |
|                   )),
 | |
|               Expanded(
 | |
|                   flex: isMobile ? 2 : 1,
 | |
|                   child: Text(
 | |
|                     translate('Bitrate'),
 | |
|                     style: const TextStyle(fontSize: 15),
 | |
|                   )),
 | |
|               // mobile doesn't have enough space
 | |
|               if (showMoreQuality && !isMobile)
 | |
|                 Expanded(
 | |
|                     flex: 1,
 | |
|                     child: Row(
 | |
|                       children: [
 | |
|                         Checkbox(
 | |
|                           value: moreQualityChecked.value,
 | |
|                           onChanged: onMoreChanged,
 | |
|                         ),
 | |
|                         Expanded(
 | |
|                           child: Text(translate('More')),
 | |
|                         )
 | |
|                       ],
 | |
|                     ))
 | |
|             ],
 | |
|           )),
 | |
|       if (showMoreQuality && isMobile)
 | |
|         Obx(() => Row(
 | |
|               children: [
 | |
|                 Expanded(
 | |
|                   child: Align(
 | |
|                     alignment: Alignment.centerRight,
 | |
|                     child: Checkbox(
 | |
|                       value: moreQualityChecked.value,
 | |
|                       onChanged: onMoreChanged,
 | |
|                     ),
 | |
|                   ),
 | |
|                 ),
 | |
|                 Expanded(
 | |
|                   child: Text(translate('More')),
 | |
|                 )
 | |
|               ],
 | |
|             )),
 | |
|       if (showFps)
 | |
|         Obx(() => Row(
 | |
|               children: [
 | |
|                 Expanded(
 | |
|                   flex: 3,
 | |
|                   child: Slider(
 | |
|                     value: fpsValue.value,
 | |
|                     min: kMinFps,
 | |
|                     max: kMaxFps,
 | |
|                     divisions: ((kMaxFps - kMinFps) / 5).round(),
 | |
|                     onChanged: (double value) async {
 | |
|                       fpsValue.value = value;
 | |
|                       debouncerFps.value = value;
 | |
|                     },
 | |
|                   ),
 | |
|                 ),
 | |
|                 Expanded(
 | |
|                     flex: 1,
 | |
|                     child: Text(
 | |
|                       '${fpsValue.value.round()}',
 | |
|                       style: const TextStyle(fontSize: 15),
 | |
|                     )),
 | |
|                 Expanded(
 | |
|                     flex: 2,
 | |
|                     child: Text(
 | |
|                       translate('FPS'),
 | |
|                       style: const TextStyle(fontSize: 15),
 | |
|                     ))
 | |
|               ],
 | |
|             )),
 | |
|     ],
 | |
|   );
 | |
| }
 | |
| 
 | |
| customImageQualitySetting() {
 | |
|   final qualityKey = 'custom_image_quality';
 | |
|   final fpsKey = 'custom-fps';
 | |
| 
 | |
|   var initQuality =
 | |
|       (double.tryParse(bind.mainGetUserDefaultOption(key: qualityKey)) ??
 | |
|           kDefaultQuality);
 | |
|   var initFps = (double.tryParse(bind.mainGetUserDefaultOption(key: fpsKey)) ??
 | |
|       kDefaultFps);
 | |
| 
 | |
|   return customImageQualityWidget(
 | |
|       initQuality: initQuality,
 | |
|       initFps: initFps,
 | |
|       setQuality: (v) {
 | |
|         bind.mainSetUserDefaultOption(key: qualityKey, value: v.toString());
 | |
|       },
 | |
|       setFps: (v) {
 | |
|         bind.mainSetUserDefaultOption(key: fpsKey, value: v.toString());
 | |
|       },
 | |
|       showFps: true,
 | |
|       showMoreQuality: true);
 | |
| }
 | |
| 
 | |
| List<Widget> ServerConfigImportExportWidgets(
 | |
|   List<TextEditingController> controllers,
 | |
|   List<RxString> errMsgs,
 | |
| ) {
 | |
|   import() {
 | |
|     Clipboard.getData(Clipboard.kTextPlain).then((value) {
 | |
|       importConfig(controllers, errMsgs, value?.text);
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   export() {
 | |
|     final text = ServerConfig(
 | |
|             idServer: controllers[0].text.trim(),
 | |
|             relayServer: controllers[1].text.trim(),
 | |
|             apiServer: controllers[2].text.trim(),
 | |
|             key: controllers[3].text.trim())
 | |
|         .encode();
 | |
|     debugPrint("ServerConfig export: $text");
 | |
|     Clipboard.setData(ClipboardData(text: text));
 | |
|     showToast(translate('Export server configuration successfully'));
 | |
|   }
 | |
| 
 | |
|   return [
 | |
|     Tooltip(
 | |
|       message: translate('Import server config'),
 | |
|       child: IconButton(
 | |
|           icon: Icon(Icons.paste, color: Colors.grey), onPressed: import),
 | |
|     ),
 | |
|     Tooltip(
 | |
|         message: translate('Export Server Config'),
 | |
|         child: IconButton(
 | |
|             icon: Icon(Icons.copy, color: Colors.grey), onPressed: export))
 | |
|   ];
 | |
| }
 | |
| 
 | |
| List<(String, String)> otherDefaultSettings() {
 | |
|   List<(String, String)> v = [
 | |
|     ('View Mode', 'view_only'),
 | |
|     if ((isDesktop || isWebDesktop)) ('show_monitors_tip', kKeyShowMonitorsToolbar),
 | |
|     if ((isDesktop || isWebDesktop)) ('Collapse toolbar', 'collapse_toolbar'),
 | |
|     ('Show remote cursor', 'show_remote_cursor'),
 | |
|     ('Follow remote cursor', 'follow_remote_cursor'),
 | |
|     ('Follow remote window focus', 'follow_remote_window'),
 | |
|     if ((isDesktop || isWebDesktop)) ('Zoom cursor', 'zoom-cursor'),
 | |
|     ('Show quality monitor', 'show_quality_monitor'),
 | |
|     ('Mute', 'disable_audio'),
 | |
|     if (isDesktop) ('Enable file copy and paste', 'enable_file_transfer'),
 | |
|     ('Disable clipboard', 'disable_clipboard'),
 | |
|     ('Lock after session end', 'lock_after_session_end'),
 | |
|     ('Privacy mode', 'privacy_mode'),
 | |
|     if (isMobile) ('Touch mode', 'touch-mode'),
 | |
|     ('True color (4:4:4)', 'i444'),
 | |
|     ('Reverse mouse wheel', kKeyReverseMouseWheel),
 | |
|     ('swap-left-right-mouse', 'swap-left-right-mouse'),
 | |
|     if (isDesktop && useTextureRender)
 | |
|       (
 | |
|         'Show displays as individual windows',
 | |
|         kKeyShowDisplaysAsIndividualWindows
 | |
|       ),
 | |
|     if (isDesktop && useTextureRender)
 | |
|       (
 | |
|         'Use all my displays for the remote session',
 | |
|         kKeyUseAllMyDisplaysForTheRemoteSession
 | |
|       )
 | |
|   ];
 | |
| 
 | |
|   return v;
 | |
| }
 |