From 774694714d4efaa2c591e36a534e1baa15a439ef Mon Sep 17 00:00:00 2001 From: 21pages Date: Fri, 17 Mar 2023 11:27:22 +0800 Subject: [PATCH] fix view mode Signed-off-by: 21pages --- .../desktop/pages/desktop_setting_page.dart | 2 +- flutter/lib/desktop/pages/remote_page.dart | 5 +- .../lib/desktop/widgets/remote_toolbar.dart | 92 ++++++++++--------- flutter/lib/models/model.dart | 3 + libs/hbb_common/src/config.rs | 18 ++-- src/client.rs | 27 +++++- src/flutter_ffi.rs | 6 -- src/ui_session_interface.rs | 41 ++------- 8 files changed, 103 insertions(+), 91 deletions(-) diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index a20d35ed2..87b4a684c 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1318,7 +1318,7 @@ class _DisplayState extends State<_Display> { Widget other(BuildContext context) { return _Card(title: 'Other Default Options', children: [ - otherRow('View Mode', 'view-only'), + otherRow('View Mode', 'view_only'), otherRow('show_monitors_tip', 'show_monitors_toolbar'), otherRow('Show remote cursor', 'show_remote_cursor'), otherRow('Zoom cursor', 'zoom-cursor'), diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index fdd2d05b4..2b1999b42 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -139,9 +139,8 @@ class _RemotePageState extends State _ffi.ffiModel.updateEventListener(widget.id); _ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id); // Session option should be set after models.dart/FFI.start - // _showRemoteCursor has been set by setViewOnly - _ffi.ffiModel.setViewOnly(widget.id, - bind.sessionGetToggleOptionSync(id: widget.id, arg: 'view-only')); + _showRemoteCursor.value = bind.sessionGetToggleOptionSync( + id: widget.id, arg: 'show-remote-cursor'); _zoomCursor.value = bind.sessionGetToggleOptionSync(id: widget.id, arg: 'zoom-cursor'); DesktopMultiWindow.addListener(this); diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 65d763013..edf04b15a 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -385,7 +385,6 @@ class _RemoteMenubarState extends State { } Widget _buildToolbar(BuildContext context) { - final ffiModel = Provider.of(context); final List toolbarItems = []; if (!isWebDesktop) { toolbarItems.add(_PinMenu(state: widget.state)); @@ -397,7 +396,7 @@ class _RemoteMenubarState extends State { if (PrivacyModeState.find(widget.id).isFalse && stateGlobal.displaysCount.value > 1) { toolbarItems.add( - bind.mainGetUserDefaultOption(key: 'show_monitors_menubar') == 'Y' + bind.mainGetUserDefaultOption(key: 'show_monitors_toolbar') == 'Y' ? _MultiMonitorMenu(id: widget.id, ffi: widget.ffi) : _MonitorMenu(id: widget.id, ffi: widget.ffi), ); @@ -411,9 +410,7 @@ class _RemoteMenubarState extends State { state: widget.state, setFullscreen: _setFullscreen, )); - if (!ffiModel.viewOnly) { - toolbarItems.add(_KeyboardMenu(id: widget.id, ffi: widget.ffi)); - } + toolbarItems.add(_KeyboardMenu(id: widget.id, ffi: widget.ffi)); if (!isWeb) { toolbarItems.add(_ChatMenu(id: widget.id, ffi: widget.ffi)); toolbarItems.add(_VoiceCallMenu(id: widget.id, ffi: widget.ffi)); @@ -969,7 +966,6 @@ class _DisplayMenuState extends State<_DisplayMenu> { codec(), resolutions(), Divider(), - view_only(), showRemoteCursor(), zoomCursor(), showQualityMonitor(), @@ -1463,39 +1459,26 @@ class _DisplayMenuState extends State<_DisplayMenu> { child: Text(translate("Resolution"))); } - view_only() { - final visible = version_cmp(pi.version, '1.2.0') >= 0; - if (!visible) return Offstage(); - final ffiModel = widget.ffi.ffiModel; - return _CheckboxMenuButton( - value: ffiModel.viewOnly, - onChanged: (value) async { - if (value == null) return; - bind.sessionSetViewOnly(id: widget.id, viewOnly: value); - ffiModel.setViewOnly(widget.id, value); - }, - ffi: widget.ffi, - child: Text(translate('View Mode'))); - } - showRemoteCursor() { if (widget.ffi.ffiModel.pi.platform == kPeerPlatformAndroid) { return Offstage(); } final ffiModel = widget.ffi.ffiModel; - final visible = - !ffiModel.viewOnly && !widget.ffi.canvasModel.cursorEmbedded; + final visible = !widget.ffi.canvasModel.cursorEmbedded; if (!visible) return Offstage(); + final enabled = !ffiModel.viewOnly; final state = ShowRemoteCursorState.find(widget.id); final option = 'show-remote-cursor'; return _CheckboxMenuButton( value: state.value, - onChanged: (value) async { - if (value == null) return; - await bind.sessionToggleOption(id: widget.id, value: option); - state.value = - bind.sessionGetToggleOptionSync(id: widget.id, arg: option); - }, + onChanged: enabled + ? (value) async { + if (value == null) return; + await bind.sessionToggleOption(id: widget.id, value: option); + state.value = + bind.sessionGetToggleOptionSync(id: widget.id, arg: option); + } + : null, ffi: widget.ffi, child: Text(translate('Show remote cursor'))); } @@ -1568,18 +1551,20 @@ class _DisplayMenuState extends State<_DisplayMenu> { disableClipboard() { final ffiModel = widget.ffi.ffiModel; - final visible = perms['keyboard'] != false && - perms['clipboard'] != false && - !ffiModel.viewOnly; + final visible = perms['keyboard'] != false && perms['clipboard'] != false; if (!visible) return Offstage(); + final enabled = !ffiModel.viewOnly; final option = 'disable-clipboard'; - final value = bind.sessionGetToggleOptionSync(id: widget.id, arg: option); + var value = bind.sessionGetToggleOptionSync(id: widget.id, arg: option); + if (ffiModel.viewOnly) value = true; return _CheckboxMenuButton( value: value, - onChanged: (value) { - if (value == null) return; - bind.sessionToggleOption(id: widget.id, value: option); - }, + onChanged: enabled + ? (value) { + if (value == null) return; + bind.sessionToggleOption(id: widget.id, value: option); + } + : null, ffi: widget.ffi, child: Text(translate('Disable clipboard'))); } @@ -1672,7 +1657,12 @@ class _KeyboardMenu extends StatelessWidget { ffi: ffi, color: _MenubarTheme.blueColor, hoverColor: _MenubarTheme.hoverBlueColor, - menuChildren: [mode(), localKeyboardType()]); + menuChildren: [ + mode(), + localKeyboardType(), + Divider(), + view_mode(), + ]); } mode() { @@ -1686,6 +1676,7 @@ class _KeyboardMenu extends StatelessWidget { KeyboardModeMenu(key: _kKeyTranslateMode, menu: 'Translate mode'), ]; List<_RadioMenuButton> list = []; + final enabled = !ffi.ffiModel.viewOnly; onChanged(String? value) async { if (value == null) return; await bind.sessionSetKeyboardMode(id: id, value: value); @@ -1706,7 +1697,7 @@ class _KeyboardMenu extends StatelessWidget { child: Text(text), value: mode.key, groupValue: groupValue, - onChanged: onChanged, + onChanged: enabled ? onChanged : null, ffi: ffi, )); } @@ -1719,6 +1710,7 @@ class _KeyboardMenu extends StatelessWidget { final localPlatform = getLocalPlatformForKBLayoutType(pi.platform); final visible = localPlatform != ''; if (!visible) return Offstage(); + final enabled = !ffi.ffiModel.viewOnly; return Column( children: [ Divider(), @@ -1727,12 +1719,30 @@ class _KeyboardMenu extends StatelessWidget { '${translate('Local keyboard type')}: ${KBLayoutType.value}'), trailingIcon: const Icon(Icons.settings), ffi: ffi, - onPressed: () => - showKBLayoutTypeChooser(localPlatform, ffi.dialogManager), + onPressed: enabled + ? () => showKBLayoutTypeChooser(localPlatform, ffi.dialogManager) + : null, ) ], ); } + + view_mode() { + final ffiModel = ffi.ffiModel; + final enabled = version_cmp(pi.version, '1.2.0') >= 0 && + ffiModel.permissions["keyboard"] != false; + return _CheckboxMenuButton( + value: ffiModel.viewOnly, + onChanged: enabled + ? (value) async { + if (value == null) return; + await bind.sessionToggleOption(id: id, value: 'view-only'); + ffiModel.setViewOnly(id, value); + } + : null, + ffi: ffi, + child: Text(translate('View Mode'))); + } } class _ChatMenu extends StatefulWidget { diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 50922c52c..70e8c7d60 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -450,6 +450,8 @@ class FfiModel with ChangeNotifier { handleResolutions(peerId, evt["resolutions"]); parent.target?.elevationModel.onPeerInfo(_pi); } + setViewOnly( + peerId, bind.sessionGetToggleOptionSync(id: peerId, arg: 'view-only')); notifyListeners(); } @@ -522,6 +524,7 @@ class FfiModel with ChangeNotifier { } void setViewOnly(String id, bool value) { + if (version_cmp(_pi.version, '1.2.0') < 0) return; if (value) { ShowRemoteCursorState.find(id).value = value; } else { diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index a54c08ce7..0624af672 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -235,10 +235,12 @@ pub struct PeerConfig { pub show_quality_monitor: ShowQualityMonitor, #[serde(default)] pub keyboard_mode: String, + #[serde(flatten)] + pub view_only: ViewOnly, // The other scalar value must before this #[serde(default, deserialize_with = "PeerConfig::deserialize_options")] - pub options: HashMap, + pub options: HashMap, // not use delete to represent default values // Various data for flutter ui #[serde(default)] pub ui_flutter: HashMap, @@ -1061,10 +1063,6 @@ impl PeerConfig { if !mp.contains_key(key) { mp.insert(key.to_owned(), UserDefaultConfig::read().get(key)); } - key = "view-only"; - if !mp.contains_key(key) { - mp.insert(key.to_owned(), UserDefaultConfig::read().get(key)); - } Ok(mp) } } @@ -1119,6 +1117,13 @@ serde_field_bool!( "AllowSwapKey::default_allow_swap_key" ); +serde_field_bool!( + ViewOnly, + "view_only", + default_view_only, + "ViewOnly::default_view_only" +); + #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct LocalConfig { #[serde(default)] @@ -1415,7 +1420,8 @@ impl ConfigOidc { if let Ok(client_id) = env::var(format!("OIDC-{}-CLIENT-ID", k.to_uppercase())) { v.client_id = client_id; } - if let Ok(client_secret) = env::var(format!("OIDC-{}-CLIENT-SECRET", k.to_uppercase())) { + if let Ok(client_secret) = env::var(format!("OIDC-{}-CLIENT-SECRET", k.to_uppercase())) + { v.client_secret = client_secret; } } diff --git a/src/client.rs b/src/client.rs index 66bdc623d..0cd90e1f3 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1235,6 +1235,24 @@ impl LoginConfigHandler { config.show_quality_monitor.v = !config.show_quality_monitor.v; } else if name == "allow_swap_key" { config.allow_swap_key.v = !config.allow_swap_key.v; + } else if name == "view-only" { + config.view_only.v = !config.view_only.v; + let f = |b: bool| { + if b { + BoolOption::Yes.into() + } else { + BoolOption::No.into() + } + }; + if config.view_only.v { + option.disable_keyboard = f(true); + option.disable_clipboard = f(true); + option.show_remote_cursor = f(true); + } else { + option.disable_keyboard = f(false); + option.disable_clipboard = f(self.get_toggle_option("disable-clipboard")); + option.show_remote_cursor = f(self.get_toggle_option("show-remote-cursor")); + } } else { let is_set = self .options @@ -1242,7 +1260,12 @@ impl LoginConfigHandler { .map(|o| !o.is_empty()) .unwrap_or(false); if is_set { - self.config.options.remove(&name); + if name == "zoom-cursor" { + self.config.options.insert(name, "".to_owned()); + } else { + // Notice: When PeerConfig loads, the default value is taken when the option key does not exist. + self.config.options.remove(&name); + } } else { self.config.options.insert(name, "Y".to_owned()); } @@ -1395,6 +1418,8 @@ impl LoginConfigHandler { self.config.show_quality_monitor.v } else if name == "allow_swap_key" { self.config.allow_swap_key.v + } else if name == "view-only" { + self.config.view_only.v } else { !self.get_option(name).is_empty() } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 4b8bf43d3..2a3baad95 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -543,12 +543,6 @@ pub fn session_set_size(_id: String, _width: i32, _height: i32) { } } -pub fn session_set_view_only(id: String, view_only: bool) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { - session.set_view_only(view_only); - } -} - pub fn main_get_sound_inputs() -> Vec { #[cfg(not(any(target_os = "android", target_os = "ios")))] return get_sound_inputs(); diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 735f963e8..5bf065a0b 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -10,7 +10,6 @@ use std::time::{Duration, SystemTime}; use async_trait::async_trait; use bytes::Bytes; -use hbb_common::message_proto::option_message::BoolOption; use rdev::{Event, EventType::*}; use uuid::Uuid; @@ -843,37 +842,6 @@ impl Session { } false } - - pub fn set_view_only(&self, view_only: bool) { - let mut option = OptionMessage::default(); - let f = |b: bool| { - if b { - BoolOption::Yes.into() - } else { - BoolOption::No.into() - } - }; - if view_only { - option.disable_keyboard = f(true); - option.disable_clipboard = f(true); - option.show_remote_cursor = f(true); - } else { - option.disable_keyboard = f(false); - option.disable_clipboard = f(self.get_toggle_option("disable-clipboard".to_string())); - option.show_remote_cursor = f(self.get_toggle_option("show-remote-cursor".to_string())); - } - let mut misc = Misc::new(); - misc.set_option(option); - let mut msg = Message::new(); - msg.set_misc(misc); - self.send(Data::Message(msg)); - if self.get_toggle_option("view-only".to_string()) != view_only { - self.lc - .write() - .unwrap() - .toggle_option("view-only".to_string()); - } - } } pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default { @@ -905,7 +873,14 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default { only_count: bool, ); fn confirm_delete_files(&self, id: i32, i: i32, name: String); - fn override_file_confirm(&self, id: i32, file_num: i32, to: String, is_upload: bool, is_identical: bool); + fn override_file_confirm( + &self, + id: i32, + file_num: i32, + to: String, + is_upload: bool, + is_identical: bool, + ); fn update_block_input_state(&self, on: bool); fn job_progress(&self, id: i32, file_num: i32, speed: f64, finished_size: f64); fn adapt_size(&self);