From 75d8168070b76c4f9051817b6b6eea3abdc05a2e Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 17 Nov 2022 18:52:27 +0800 Subject: [PATCH] enable rust default option Signed-off-by: fufesou --- .../lib/desktop/pages/remote_tab_page.dart | 11 +-- .../lib/desktop/widgets/remote_menubar.dart | 96 +++++++------------ flutter/lib/mobile/pages/remote_page.dart | 4 +- flutter/lib/models/model.dart | 6 +- libs/hbb_common/src/config.rs | 62 +++++++++++- src/client.rs | 15 ++- src/flutter_ffi.rs | 30 +++++- src/server/video_service.rs | 8 +- src/ui_session_interface.rs | 12 ++- 9 files changed, 162 insertions(+), 82 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index f6ebc0f86..df8256496 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -246,13 +246,12 @@ class _ConnectionTabPageState extends State { dismissOnClicked: true, ), ], - curOptionGetter: () async { - return await bind.sessionGetOption(id: key, arg: 'view-style') ?? - 'adaptive'; - }, + curOptionGetter: () async => + // null means peer id is not found, which there's no need to care about + await bind.sessionGetViewStyle(id: key) ?? '', optionSetter: (String oldValue, String newValue) async { - await bind.sessionPeerOption( - id: key, name: "view-style", value: newValue); + await bind.sessionSetViewStyle( + id: key, value: newValue); ffi.canvasModel.updateViewStyle(); cancelFunc(); }, diff --git a/flutter/lib/desktop/widgets/remote_menubar.dart b/flutter/lib/desktop/widgets/remote_menubar.dart index 6db5a7fb7..ed69f3e65 100644 --- a/flutter/lib/desktop/widgets/remote_menubar.dart +++ b/flutter/lib/desktop/widgets/remote_menubar.dart @@ -22,7 +22,7 @@ import './popup_menu.dart'; import './material_mod_popup_menu.dart' as mod_menu; class MenubarState { - final kStoreKey = "remoteMenubarState"; + final kStoreKey = 'remoteMenubarState'; late RxBool show; late RxBool _pin; @@ -195,7 +195,7 @@ class _RemoteMenubarState extends State { } _updateScreen() async { - final v = await DesktopMultiWindow.invokeMethod(0, "get_window_info", ""); + final v = await DesktopMultiWindow.invokeMethod(0, 'get_window_info', ''); final String valueStr = v; if (valueStr.isEmpty) { _screen = null; @@ -322,7 +322,7 @@ class _RemoteMenubarState extends State { child: Obx(() { RxInt display = CurrentDisplayState.find(widget.id); return Text( - "${display.value + 1}/${pi.displays.length}", + '${display.value + 1}/${pi.displays.length}', style: const TextStyle( color: _MenubarTheme.commonColor, fontSize: 8), ); @@ -595,10 +595,10 @@ class _RemoteMenubarState extends State { )); } } - if (perms["restart"] != false && - (pi.platform == "Linux" || - pi.platform == "Windows" || - pi.platform == "Mac OS")) { + if (perms['restart'] != false && + (pi.platform == 'Linux' || + pi.platform == 'Windows' || + pi.platform == 'Mac OS')) { displayMenu.add(MenuEntryButton( childBuilder: (TextStyle? style) => Text( translate('Restart Remote Device'), @@ -629,14 +629,14 @@ class _RemoteMenubarState extends State { displayMenu.add(MenuEntryButton( childBuilder: (TextStyle? style) => Obx(() => Text( translate( - '${BlockInputState.find(widget.id).value ? "Unb" : "B"}lock user input'), + '${BlockInputState.find(widget.id).value ? 'Unb' : 'B'}lock user input'), style: style, )), proc: () { RxBool blockInput = BlockInputState.find(widget.id); bind.sessionToggleOption( id: widget.id, - value: '${blockInput.value ? "un" : ""}block-input'); + value: '${blockInput.value ? 'un' : ''}block-input'); blockInput.value = !blockInput.value; }, padding: padding, @@ -671,7 +671,7 @@ class _RemoteMenubarState extends State { // ClipboardData? data = // await Clipboard.getData(Clipboard.kTextPlain); // if (data != null && data.text != null) { - // bind.sessionInputString(id: widget.id, value: data.text ?? ""); + // bind.sessionInputString(id: widget.id, value: data.text ?? ''); // } // }(); // }, @@ -679,18 +679,6 @@ class _RemoteMenubarState extends State { // dismissOnClicked: true, // )); // } - - displayMenu.add(MenuEntryButton( - childBuilder: (TextStyle? style) => Text( - translate('Reset canvas'), - style: style, - ), - proc: () { - widget.ffi.cursorModel.reset(); - }, - padding: padding, - dismissOnClicked: true, - )); } return displayMenu; @@ -740,14 +728,11 @@ class _RemoteMenubarState extends State { dismissOnClicked: true, ), ], - curOptionGetter: () async { - return await bind.sessionGetOption( - id: widget.id, arg: 'view-style') ?? - 'adaptive'; - }, + curOptionGetter: () async => + // null means peer id is not found, which there's no need to care about + await bind.sessionGetViewStyle(id: widget.id) ?? '', optionSetter: (String oldValue, String newValue) async { - await bind.sessionPeerOption( - id: widget.id, name: "view-style", value: newValue); + await bind.sessionSetViewStyle(id: widget.id, value: newValue); widget.ffi.canvasModel.updateViewStyle(); }, padding: padding, @@ -768,14 +753,11 @@ class _RemoteMenubarState extends State { dismissOnClicked: true, ), ], - curOptionGetter: () async { - return await bind.sessionGetOption( - id: widget.id, arg: 'scroll-style') ?? - ''; - }, + curOptionGetter: () async => + // null means peer id is not found, which there's no need to care about + await bind.sessionGetScrollStyle(id: widget.id) ?? '', optionSetter: (String oldValue, String newValue) async { - await bind.sessionPeerOption( - id: widget.id, name: "scroll-style", value: newValue); + await bind.sessionSetScrollStyle(id: widget.id, value: newValue); widget.ffi.canvasModel.updateScrollStyle(); }, padding: padding, @@ -805,12 +787,9 @@ class _RemoteMenubarState extends State { value: 'custom', dismissOnClicked: true), ], - curOptionGetter: () async { - String quality = - await bind.sessionGetImageQuality(id: widget.id) ?? 'balanced'; - if (quality == '') quality = 'balanced'; - return quality; - }, + curOptionGetter: () async => + // null means peer id is not found, which there's no need to care about + await bind.sessionGetImageQuality(id: widget.id) ?? '', optionSetter: (String oldValue, String newValue) async { if (oldValue != newValue) { await bind.sessionSetImageQuality(id: widget.id, value: newValue); @@ -1075,14 +1054,14 @@ class _RemoteMenubarState extends State { } return list; }, - curOptionGetter: () async { - return await bind.sessionGetOption( - id: widget.id, arg: 'codec-preference') ?? - 'auto'; - }, + curOptionGetter: () async => + // null means peer id is not found, which there's no need to care about + await bind.sessionGetOption( + id: widget.id, arg: 'codec-preference') ?? + '', optionSetter: (String oldValue, String newValue) async { await bind.sessionPeerOption( - id: widget.id, name: "codec-preference", value: newValue); + id: widget.id, name: 'codec-preference', value: newValue); bind.sessionChangePreferCodec(id: widget.id); }, padding: padding, @@ -1195,9 +1174,8 @@ class _RemoteMenubarState extends State { MenuEntryRadioOption(text: translate('Legacy mode'), value: 'legacy'), MenuEntryRadioOption(text: translate('Map mode'), value: 'map'), ], - curOptionGetter: () async { - return await bind.sessionGetKeyboardName(id: widget.id); - }, + curOptionGetter: () async => + await bind.sessionGetKeyboardName(id: widget.id), optionSetter: (String oldValue, String newValue) async { await bind.sessionSetKeyboardMode( id: widget.id, keyboardMode: newValue); @@ -1229,16 +1207,16 @@ class _RemoteMenubarState extends State { void showSetOSPassword( String id, bool login, OverlayDialogManager dialogManager) async { final controller = TextEditingController(); - var password = await bind.sessionGetOption(id: id, arg: "os-password") ?? ""; - var autoLogin = await bind.sessionGetOption(id: id, arg: "auto-login") != ""; + var password = await bind.sessionGetOption(id: id, arg: 'os-password') ?? ''; + var autoLogin = await bind.sessionGetOption(id: id, arg: 'auto-login') != ''; controller.text = password; dialogManager.show((setState, close) { submit() { var text = controller.text.trim(); - bind.sessionPeerOption(id: id, name: "os-password", value: text); + bind.sessionPeerOption(id: id, name: 'os-password', value: text); bind.sessionPeerOption( - id: id, name: "auto-login", value: autoLogin ? 'Y' : ''); - if (text != "" && login) { + id: id, name: 'auto-login', value: autoLogin ? 'Y' : ''); + if (text != '' && login) { bind.sessionInputOsPassword(id: id, value: text); } close(); @@ -1285,7 +1263,7 @@ void showAuditDialog(String id, dialogManager) async { dialogManager.show((setState, close) { submit() { var text = controller.text.trim(); - if (text != "") { + if (text != '') { bind.sessionSendNote(id: id, note: text); } close(); @@ -1324,11 +1302,11 @@ void showAuditDialog(String id, dialogManager) async { keyboardType: TextInputType.multiline, textInputAction: TextInputAction.newline, decoration: const InputDecoration.collapsed( - hintText: "input note here", + hintText: 'input note here', ), // inputFormatters: [ // LengthLimitingTextInputFormatter(16), - // // FilteringTextInputFormatter(RegExp(r"[a-zA-z][a-zA-z0-9\_]*"), allow: true) + // // FilteringTextInputFormatter(RegExp(r'[a-zA-z][a-zA-z0-9\_]*'), allow: true) // ], maxLines: null, maxLength: 256, diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 719b7dc28..b48e9960a 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -474,7 +474,7 @@ class _RemotePageState extends State { }, onTwoFingerScaleEnd: (d) { _scale = 1; - bind.sessionPeerOption(id: widget.id, name: "view-style", value: ""); + bind.sessionSetViewStyle(id: widget.id, value: ""); }, onThreeFingerVerticalDragUpdate: gFFI.ffiModel.isPeerAndroid ? null @@ -1001,7 +1001,7 @@ void showOptions( setState(() { viewStyle = value; bind - .sessionPeerOption(id: id, name: "view-style", value: value) + .sessionSetViewStyle(id: id, value: value) .then((_) => gFFI.canvasModel.updateViewStyle()); }); } diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index eca94d5e5..cae4485cb 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -413,7 +413,7 @@ class ImageModel with ChangeNotifier { await initializeCursorAndCanvas(parent.target!); } if (parent.target?.ffiModel.isPeerAndroid ?? false) { - bind.sessionPeerOption(id: id, name: 'view-style', value: 'adaptive'); + bind.sessionSetViewStyle(id: id, value: 'adaptive'); parent.target?.canvasModel.updateViewStyle(); } } @@ -535,7 +535,7 @@ class CanvasModel with ChangeNotifier { double get scrollY => _scrollY; updateViewStyle() async { - final style = await bind.sessionGetOption(id: id, arg: 'view-style'); + final style = await bind.sessionGetViewStyle(id: id); if (style == null) { return; } @@ -561,7 +561,7 @@ class CanvasModel with ChangeNotifier { } updateScrollStyle() async { - final style = await bind.sessionGetOption(id: id, arg: 'scroll-style'); + final style = await bind.sessionGetScrollStyle(id: id); if (style == 'scrollbar') { _scrollStyle = ScrollStyle.scrollbar; _scrollX = 0.0; diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index a7836cef7..f4b6661b4 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -9,6 +9,7 @@ use std::{ use anyhow::Result; use rand::Rng; +use serde as de; use serde_derive::{Deserialize, Serialize}; use sodiumoxide::crypto::sign; @@ -79,6 +80,26 @@ pub const RS_PUB_KEY: &'static str = "OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmB pub const RENDEZVOUS_PORT: i32 = 21116; pub const RELAY_PORT: i32 = 21117; +macro_rules! serde_field_string { + ($default_func:ident, $de_func:ident, $default_expr:expr) => { + fn $default_func() -> String { + $default_expr + } + + fn $de_func<'de, D>(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + let s: &str = de::Deserialize::deserialize(deserializer)?; + Ok(if s.is_empty() { + Self::$default_func() + } else { + s.to_owned() + }) + } + }; +} + #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum NetworkType { Direct, @@ -141,9 +162,20 @@ pub struct PeerConfig { pub size_ft: Size, #[serde(default)] pub size_pf: Size, - #[serde(default)] - pub view_style: String, // original (default), scale - #[serde(default)] + #[serde( + default = "PeerConfig::default_view_style", + deserialize_with = "PeerConfig::deserialize_view_style" + )] + pub view_style: String, + #[serde( + default = "PeerConfig::default_scroll_style", + deserialize_with = "PeerConfig::deserialize_scroll_style" + )] + pub scroll_style: String, + #[serde( + default = "PeerConfig::default_image_quality", + deserialize_with = "PeerConfig::deserialize_image_quality" + )] pub image_quality: String, #[serde(default)] pub custom_image_quality: Vec, @@ -167,7 +199,10 @@ pub struct PeerConfig { pub show_quality_monitor: bool, // The other scalar value must before this - #[serde(default)] + #[serde( + default, + deserialize_with = "PeerConfig::deserialize_options" + )] pub options: HashMap, // Various data for flutter ui #[serde(default)] @@ -400,7 +435,9 @@ impl Config { #[cfg(target_os = "macos")] let org = ORG.read().unwrap().clone(); // /var/root for root - if let Some(project) = directories_next::ProjectDirs::from("", &org, &*APP_NAME.read().unwrap()) { + if let Some(project) = + directories_next::ProjectDirs::from("", &org, &*APP_NAME.read().unwrap()) + { let mut path = patch(project.config_dir().to_path_buf()); path.push(p); return path; @@ -896,6 +933,21 @@ impl PeerConfig { } Default::default() } + + serde_field_string!(default_view_style, deserialize_view_style, "original".to_owned()); + serde_field_string!(default_scroll_style, deserialize_scroll_style, "scrollauto".to_owned()); + serde_field_string!(default_image_quality, deserialize_image_quality, "balanced".to_owned()); + + fn deserialize_options<'de, D>(deserializer: D) -> Result, D::Error> + where + D: de::Deserializer<'de>, + { + let mut mp: HashMap = de::Deserialize::deserialize(deserializer)?; + if !mp.contains_key("codec-preference") { + mp.insert("codec-preference".to_owned(), "auto".to_owned()); + } + Ok(mp) + } } #[derive(Debug, Default, Serialize, Deserialize, Clone)] diff --git a/src/client.rs b/src/client.rs index a938702b3..657c50572 100644 --- a/src/client.rs +++ b/src/client.rs @@ -974,6 +974,8 @@ impl LoginConfigHandler { self.save_config(config); } + //to-do: too many dup code below. + /// Save view style to the current config. /// /// # Arguments @@ -985,13 +987,24 @@ impl LoginConfigHandler { self.save_config(config); } + /// Save scroll style to the current config. + /// + /// # Arguments + /// + /// * `value` - The view style to be saved. + pub fn save_scroll_style(&mut self, value: String) { + let mut config = self.load_config(); + config.scroll_style = value; + self.save_config(config); + } + /// Set a ui config of flutter for handler's [`PeerConfig`]. /// /// # Arguments /// /// * `k` - key of option /// * `v` - value of option - pub fn set_ui_flutter(&mut self, k: String, v: String) { + pub fn save_ui_flutter(&mut self, k: String, v: String) { let mut config = self.load_config(); config.ui_flutter.insert(k, v); self.save_config(config); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 8627168a4..520efea70 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -170,7 +170,7 @@ pub fn session_get_flutter_config(id: String, k: String) -> Option { pub fn session_set_flutter_config(id: String, k: String, v: String) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { - session.set_flutter_config(k, v); + session.save_flutter_config(k, v); } } @@ -182,6 +182,34 @@ pub fn set_local_flutter_config(k: String, v: String) { ui_interface::set_local_flutter_config(k, v); } +pub fn session_get_view_style(id: String) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&id) { + Some(session.get_view_style()) + } else { + None + } +} + +pub fn session_set_view_style(id: String, value: String) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { + session.save_view_style(value); + } +} + +pub fn session_get_scroll_style(id: String) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&id) { + Some(session.get_scroll_style()) + } else { + None + } +} + +pub fn session_set_scroll_style(id: String, value: String) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { + session.save_scroll_style(value); + } +} + pub fn session_get_image_quality(id: String) -> Option { if let Some(session) = SESSIONS.read().unwrap().get(&id) { Some(session.get_image_quality()) diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 43ce013f5..3ccc3af39 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -25,12 +25,16 @@ use hbb_common::tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, Mutex as TokioMutex, }; +#[cfg(not(windows))] +use scrap::Capturer; use scrap::{ codec::{Encoder, EncoderCfg, HwEncoderConfig}, record::{Recorder, RecorderContext}, vpxcodec::{VpxEncoderConfig, VpxVideoCodecId}, - Capturer, Display, TraitCapturer, + Display, TraitCapturer, }; +#[cfg(windows)] +use std::sync::Once; use std::{ collections::HashSet, io::ErrorKind::WouldBlock, @@ -38,8 +42,6 @@ use std::{ time::{self, Duration, Instant}, }; #[cfg(windows)] -use std::sync::Once; -#[cfg(windows)] use virtual_display; pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 5119a6e1b..9b00730e5 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -79,6 +79,10 @@ impl Session { self.lc.read().unwrap().view_style.clone() } + pub fn get_scroll_style(&self) -> String { + self.lc.read().unwrap().scroll_style.clone() + } + pub fn get_image_quality(&self) -> String { self.lc.read().unwrap().image_quality.clone() } @@ -99,8 +103,12 @@ impl Session { self.lc.write().unwrap().save_view_style(value); } - pub fn set_flutter_config(&mut self, k: String, v: String) { - self.lc.write().unwrap().set_ui_flutter(k, v); + pub fn save_scroll_style(&mut self, value: String) { + self.lc.write().unwrap().save_scroll_style(value); + } + + pub fn save_flutter_config(&mut self, k: String, v: String) { + self.lc.write().unwrap().save_ui_flutter(k, v); } pub fn get_flutter_config(&self, k: String) -> String {