diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 39f0a3cd5..2618be2b2 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1408,7 +1408,7 @@ bool option2bool(String option, String value) { res = value != "N"; } else if (option.startsWith("allow-") || option == "stop-service" || - option == "direct-server" || + option == kOptionDirectServer || option == "stop-rendezvous-service" || option == kOptionForceAlwaysRelay) { res = value == "Y"; @@ -1425,7 +1425,7 @@ String bool2option(String option, bool b) { res = b ? defaultOptionYes : 'N'; } else if (option.startsWith('allow-') || option == "stop-service" || - option == "direct-server" || + option == kOptionDirectServer || option == "stop-rendezvous-service" || option == kOptionForceAlwaysRelay) { res = b ? 'Y' : defaultOptionNo; diff --git a/flutter/lib/common/shared_state.dart b/flutter/lib/common/shared_state.dart index c62ad671e..bd95f1db9 100644 --- a/flutter/lib/common/shared_state.dart +++ b/flutter/lib/common/shared_state.dart @@ -341,7 +341,7 @@ initSharedStates(String id) { ShowRemoteCursorLockState.init(id); RemoteCursorMovedState.init(id); FingerprintState.init(id); - PeerBoolOption.init(id, 'zoom-cursor', () => false); + PeerBoolOption.init(id, kOptionZoomCursor, () => false); UnreadChatCountState.init(id); if (isMobile) ConnectionTypeState.init(id); // desktop in other places } @@ -355,7 +355,7 @@ removeSharedStates(String id) { KeyboardEnabledState.delete(id); RemoteCursorMovedState.delete(id); FingerprintState.delete(id); - PeerBoolOption.delete(id, 'zoom-cursor'); + PeerBoolOption.delete(id, kOptionZoomCursor); UnreadChatCountState.delete(id); if (isMobile) ConnectionTypeState.delete(id); } diff --git a/flutter/lib/common/widgets/address_book.dart b/flutter/lib/common/widgets/address_book.dart index b0a2128d8..7e1ec95e7 100644 --- a/flutter/lib/common/widgets/address_book.dart +++ b/flutter/lib/common/widgets/address_book.dart @@ -7,6 +7,7 @@ import 'package:flutter_hbb/common/formatter/id_formatter.dart'; import 'package:flutter_hbb/common/hbbs/hbbs.dart'; import 'package:flutter_hbb/common/widgets/peer_card.dart'; import 'package:flutter_hbb/common/widgets/peers_view.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/desktop/widgets/popup_menu.dart'; import 'package:flutter_hbb/models/ab_model.dart'; import 'package:flutter_hbb/models/platform_model.dart'; @@ -191,14 +192,17 @@ class _AddressBookState extends State { } final TextEditingController textEditingController = TextEditingController(); + final isOptFixed = isOptionFixed(kOptionCurrentAbName); return DropdownButton2( value: gFFI.abModel.currentName.value, - onChanged: (value) { - if (value != null) { - gFFI.abModel.setCurrentName(value); - bind.setLocalFlutterOption(k: 'current-ab-name', v: value); - } - }, + onChanged: isOptFixed + ? null + : (value) { + if (value != null) { + gFFI.abModel.setCurrentName(value); + bind.setLocalFlutterOption(k: kOptionCurrentAbName, v: value); + } + }, underline: Container( height: 0.7, color: Theme.of(context).dividerColor.withOpacity(0.1), @@ -358,7 +362,8 @@ class _AddressBookState extends State { return shouldSortTags(); }, setter: (bool v) async { - bind.mainSetLocalOption(key: sortAbTagsOption, value: v ? 'Y' : defaultOptionNo); + bind.mainSetLocalOption( + key: sortAbTagsOption, value: v ? 'Y' : defaultOptionNo); gFFI.abModel.sortTags.value = v; }, dismissOnClicked: true, @@ -376,7 +381,8 @@ class _AddressBookState extends State { return filterAbTagByIntersection(); }, setter: (bool v) async { - bind.mainSetLocalOption(key: filterAbTagOption, value: v ? 'Y' : defaultOptionNo); + bind.mainSetLocalOption( + key: filterAbTagOption, value: v ? 'Y' : defaultOptionNo); gFFI.abModel.filterByIntersection.value = v; }, dismissOnClicked: true, diff --git a/flutter/lib/common/widgets/dialog.dart b/flutter/lib/common/widgets/dialog.dart index cfafdc166..1b4839dfc 100644 --- a/flutter/lib/common/widgets/dialog.dart +++ b/flutter/lib/common/widgets/dialog.dart @@ -204,6 +204,7 @@ void changeWhiteList({Function()? callback}) async { errorText: msg.isEmpty ? null : translate(msg), ), controller: controller, + enabled: !isOptFixed, autofocus: true), ), ], @@ -217,15 +218,15 @@ void changeWhiteList({Function()? callback}) async { ), actions: [ dialogButton("Cancel", onPressed: close, isOutline: true), - dialogButton("Clear", onPressed: isOptFixed ? null : () async { + if (!isOptFixed)dialogButton("Clear", onPressed: () async { await bind.mainSetOption( key: kOptionWhitelist, value: defaultOptionWhitelist); callback?.call(); close(); }, isOutline: true), - dialogButton( + if (!isOptFixed) dialogButton( "OK", - onPressed: isOptFixed ? null : () async { + onPressed: () async { setState(() { msg = ""; isInProgress = true; diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index f4a41008e..ef44870c2 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -74,9 +74,11 @@ class _PeerTabPageState extends State ]; RelativeRect? mobileTabContextMenuPos; + final isOptVisiableFixed = isOptionFixed(kOptionPeerTabVisible); + @override void initState() { - final uiType = bind.getLocalFlutterOption(k: 'peer-card-ui-type'); + final uiType = bind.getLocalFlutterOption(k: kOptionPeerCardUiType); if (uiType != '') { peerCardUiType.value = int.parse(uiType) == 0 ? PeerUiType.grid @@ -85,7 +87,7 @@ class _PeerTabPageState extends State : PeerUiType.list; } hideAbTagsPanel.value = - bind.mainGetLocalOption(key: "hideAbTagsPanel").isNotEmpty; + bind.mainGetLocalOption(key: kOptionHideAbTagsPanel).isNotEmpty; super.initState(); } @@ -173,11 +175,13 @@ class _PeerTabPageState extends State child: Icon(model.tabIcon(t), color: color) .paddingSymmetric(horizontal: 4), ).paddingSymmetric(horizontal: 4), - onTap: () async { - await handleTabSelection(t); - await bind.setLocalFlutterOption( - k: PeerTabModel.kPeerTabIndex, v: t.toString()); - }, + onTap: isOptionFixed(kOptionPeerTabIndex) + ? null + : () async { + await handleTabSelection(t); + await bind.setLocalFlutterOption( + k: kOptionPeerTabIndex, v: t.toString()); + }, onHover: (value) => hover.value = value, ), ))); @@ -265,17 +269,22 @@ class _PeerTabPageState extends State if (!model.isEnabled[i]) continue; items.add(PopupMenuItem( height: kMinInteractiveDimension * 0.8, - onTap: () => model.setTabVisible(i, !model.isVisibleEnabled[i]), + onTap: isOptVisiableFixed + ? null + : () => model.setTabVisible(i, !model.isVisibleEnabled[i]), + enabled: !isOptVisiableFixed, child: Row( children: [ Checkbox( value: model.isVisibleEnabled[i], - onChanged: (_) { - model.setTabVisible(i, !model.isVisibleEnabled[i]); - if (Navigator.canPop(context)) { - Navigator.pop(context); - } - }), + onChanged: isOptVisiableFixed + ? null + : (_) { + model.setTabVisible(i, !model.isVisibleEnabled[i]); + if (Navigator.canPop(context)) { + Navigator.pop(context); + } + }), Expanded(child: Text(model.tabTooltip(i))), ], ), @@ -333,7 +342,8 @@ class _PeerTabPageState extends State setter: (show) async { model.setTabVisible(tabIndex, show); cancelFunc(); - })); + }, + enabled: (!isOptVisiableFixed).obs)); } return mod_menu.PopupMenu( items: menu @@ -537,7 +547,8 @@ class _PeerTabPageState extends State ), onTap: () async { await bind.mainSetLocalOption( - key: "hideAbTagsPanel", value: hideAbTagsPanel.value ? defaultOptionNo : "Y"); + key: kOptionHideAbTagsPanel, + value: hideAbTagsPanel.value ? defaultOptionNo : "Y"); hideAbTagsPanel.value = !hideAbTagsPanel.value; }); } @@ -799,16 +810,19 @@ class _PeerViewDropdownState extends State { style: style), e, peerCardUiType.value, - dense: true, (PeerUiType? v) async { - if (v != null) { - peerCardUiType.value = v; - setState(() {}); - await bind.setLocalFlutterOption( - k: "peer-card-ui-type", - v: peerCardUiType.value.index.toString(), - ); - } - }), + dense: true, + isOptionFixed(kOptionPeerCardUiType) + ? null + : (PeerUiType? v) async { + if (v != null) { + peerCardUiType.value = v; + setState(() {}); + await bind.setLocalFlutterOption( + k: kOptionPeerCardUiType, + v: peerCardUiType.value.index.toString(), + ); + } + }), ), )))); } @@ -852,7 +866,7 @@ class _PeerSortDropdownState extends State { if (!PeerSortType.values.contains(peerSort.value)) { peerSort.value = PeerSortType.remoteId; bind.setLocalFlutterOption( - k: "peer-sorting", + k: kOptionPeerSorting, v: peerSort.value, ); } @@ -882,7 +896,7 @@ class _PeerSortDropdownState extends State { if (v != null) { peerSort.value = v; await bind.setLocalFlutterOption( - k: "peer-sorting", + k: kOptionPeerSorting, v: peerSort.value, ); } diff --git a/flutter/lib/common/widgets/peers_view.dart b/flutter/lib/common/widgets/peers_view.dart index fae9fc901..787f4f775 100644 --- a/flutter/lib/common/widgets/peers_view.dart +++ b/flutter/lib/common/widgets/peers_view.dart @@ -4,12 +4,12 @@ import 'dart:collection'; import 'package:dynamic_layouts/dynamic_layouts.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/desktop/widgets/scroll_wrapper.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; import 'package:visibility_detector/visibility_detector.dart'; import 'package:window_manager/window_manager.dart'; -import 'package:flutter_hbb/models/peer_tab_model.dart'; import '../../common.dart'; import '../../models/peer_model.dart'; @@ -45,7 +45,7 @@ class LoadEvent { final peerSearchText = "".obs; /// for peer sort, global obs value -final peerSort = bind.getLocalFlutterOption(k: 'peer-sorting').obs; +final peerSort = bind.getLocalFlutterOption(k: kOptionPeerSorting).obs; // list for listener final obslist = [peerSearchText, peerSort].obs; @@ -302,7 +302,7 @@ class _PeersViewState extends State<_PeersView> with WindowListener { if (!PeerSortType.values.contains(sortedBy)) { sortedBy = PeerSortType.remoteId; bind.setLocalFlutterOption( - k: "peer-sorting", + k: kOptionPeerSorting, v: sortedBy, ); } diff --git a/flutter/lib/common/widgets/setting_widgets.dart b/flutter/lib/common/widgets/setting_widgets.dart index 552323090..b0bfd5f1f 100644 --- a/flutter/lib/common/widgets/setting_widgets.dart +++ b/flutter/lib/common/widgets/setting_widgets.dart @@ -227,7 +227,8 @@ List<(String, String)> otherDefaultSettings() { if ((isDesktop || isWebDesktop)) ('Zoom cursor', kOptionZoomCursor), ('Show quality monitor', kOptionShowQualityMonitor), ('Mute', kOptionDisableAudio), - if (isDesktop) ('Enable file copy and paste', kOptionEnableFileTransfer), + if (isDesktop) + ('Enable file copy and paste', kOptionEnableFileCopyPaste), ('Disable clipboard', kOptionDisableClipboard), ('Lock after session end', kOptionLockAfterSessionEnd), ('Privacy mode', kOptionPrivacyMode), diff --git a/flutter/lib/common/widgets/toolbar.dart b/flutter/lib/common/widgets/toolbar.dart index db90237f9..691bc4e7e 100644 --- a/flutter/lib/common/widgets/toolbar.dart +++ b/flutter/lib/common/widgets/toolbar.dart @@ -534,15 +534,15 @@ Future> toolbarDisplayToggle( perms['file'] != false && (isSupportIfPeer_1_2_3 || isSupportIfPeer_1_2_4)) { final enabled = !ffiModel.viewOnly; - final option = 'enable-file-transfer'; - final value = - bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option); + final value = bind.sessionGetToggleOptionSync( + sessionId: sessionId, arg: kOptionEnableFileCopyPaste); v.add(TToggleMenu( value: value, onChanged: enabled ? (value) { if (value == null) return; - bind.sessionToggleOption(sessionId: sessionId, value: option); + bind.sessionToggleOption( + sessionId: sessionId, value: kOptionEnableFileCopyPaste); } : null, child: Text(translate('Enable file copy and paste')))); diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index e23d036e6..66c768369 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -107,14 +107,27 @@ const String kOptionFollowRemoteWindow = "follow_remote_window"; const String kOptionZoomCursor = "zoom-cursor"; const String kOptionShowQualityMonitor = "show_quality_monitor"; const String kOptionDisableAudio = "disable_audio"; +const String kOptionEnableFileCopyPaste = "enable-file-copy-paste"; // "Settings -> Display -> Other default options" const String kOptionDisableClipboard = "disable_clipboard"; const String kOptionLockAfterSessionEnd = "lock_after_session_end"; const String kOptionPrivacyMode = "privacy_mode"; const String kOptionTouchMode = "touch-mode"; const String kOptionI444 = "i444"; -const String kOptionSwapLeftRightMouse = 'swap-left-right-mouse'; -const String kOptionCodecPreference = 'codec-preference'; +const String kOptionSwapLeftRightMouse = "swap-left-right-mouse"; +const String kOptionCodecPreference = "codec-preference"; +const String kOptionRemoteMenubarDragLeft = "remote-menubar-drag-left"; +const String kOptionRemoteMenubarDragRight = "remote-menubar-drag-right"; +const String kOptionHideAbTagsPanel = "hideAbTagsPanel"; +const String kOptionRemoteMenubarState = "remoteMenubarState"; +const String kOptionPeerSorting = "peer-sorting"; +const String kOptionPeerTabIndex = "peer-tab-index"; +const String kOptionPeerTabOrder = "peer-tab-order"; +const String kOptionPeerTabVisible = "peer-tab-visible"; +const String kOptionPeerCardUiType = "peer-card-ui-type"; +const String kOptionCurrentAbName = "current-ab-name"; + +const String kOptionToggleViewOnly = "view-only"; const String kUrlActionClose = "close"; diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 26a69fa53..069c30cdf 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -377,7 +377,7 @@ class _GeneralState extends State<_General> { _OptionCheckBox(context, 'Confirm before closing multiple tabs', 'enable-confirm-closing-tabs', isServer: false), - _OptionCheckBox(context, 'Adaptive bitrate', 'enable-abr'), + _OptionCheckBox(context, 'Adaptive bitrate', kOptionEnableAbr), wallpaper(), if (!bind.isIncomingOnly()) ...[ _OptionCheckBox( @@ -456,9 +456,9 @@ class _GeneralState extends State<_General> { _OptionCheckBox( context, 'Enable hardware codec', - 'enable-hwcodec', + kOptionEnableHwcodec, update: () { - if (mainGetBoolOptionSync('enable-hwcodec')) { + if (mainGetBoolOptionSync(kOptionEnableHwcodec)) { bind.mainCheckHwcodec(); } }, @@ -510,7 +510,7 @@ class _GeneralState extends State<_General> { bool user_dir_exists = map['user_dir_exists']!; return _Card(title: 'Recording', children: [ _OptionCheckBox(context, 'Automatically record incoming sessions', - 'allow-auto-record-incoming'), + kOptionAllowAutoRecordIncoming), if (showRootDir) Row( children: [ @@ -705,7 +705,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { bool enabled = !locked; // Simple temp wrapper for PR check tmpWrapper() { - String accessMode = bind.mainGetOptionSync(key: 'access-mode'); + String accessMode = bind.mainGetOptionSync(key: kOptionAccessMode); _AccessMode mode; if (accessMode == 'full') { mode = _AccessMode.full; @@ -1347,14 +1347,14 @@ class _DisplayState extends State<_Display> { } Widget imageQuality(BuildContext context) { - final key = 'image_quality'; onChanged(String value) async { - await bind.mainSetUserDefaultOption(key: key, value: value); + await bind.mainSetUserDefaultOption( + key: kOptionImageQuality, value: value); setState(() {}); } - final isOptFixed = isOptionFixed(key); - final groupValue = bind.mainGetUserDefaultOption(key: key); + final isOptFixed = isOptionFixed(kOptionImageQuality); + final groupValue = bind.mainGetUserDefaultOption(key: kOptionImageQuality); return _Card(title: 'Default Image Quality', children: [ _Radio(context, value: kRemoteImageQualityBest, @@ -1484,7 +1484,7 @@ class _DisplayState extends State<_Display> { key: key, value: b ? 'Y' - : (key == kOptionEnableFileTransfer ? 'N' : defaultOptionNo)); + : (key == kOptionEnableFileCopyPaste ? 'N' : defaultOptionNo)); setState(() {}); } diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 9ce4c1827..a4532411b 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -94,7 +94,7 @@ class _RemotePageState extends State void _initStates(String id) { initSharedStates(id); - _zoomCursor = PeerBoolOption.find(id, 'zoom-cursor'); + _zoomCursor = PeerBoolOption.find(id, kOptionZoomCursor); _showRemoteCursor = ShowRemoteCursorState.find(id); _keyboardEnabled = KeyboardEnabledState.find(id); _remoteCursorMoved = RemoteCursorMovedState.find(id); @@ -136,7 +136,7 @@ class _RemotePageState extends State _showRemoteCursor.value = bind.sessionGetToggleOptionSync( sessionId: sessionId, arg: 'show-remote-cursor'); _zoomCursor.value = bind.sessionGetToggleOptionSync( - sessionId: sessionId, arg: 'zoom-cursor'); + sessionId: sessionId, arg: kOptionZoomCursor); DesktopMultiWindow.addListener(this); // if (!_isCustomCursorInited) { // customCursorController.registerNeedUpdateCursorCallback( diff --git a/flutter/lib/desktop/widgets/material_mod_popup_menu.dart b/flutter/lib/desktop/widgets/material_mod_popup_menu.dart index 7377c1e25..69ee882e8 100644 --- a/flutter/lib/desktop/widgets/material_mod_popup_menu.dart +++ b/flutter/lib/desktop/widgets/material_mod_popup_menu.dart @@ -341,8 +341,9 @@ class PopupMenuItemState> extends State { @protected void handleTap() { widget.onTap?.call(); - - Navigator.pop(context, widget.value); + if (Navigator.canPop(context)) { + Navigator.pop(context, widget.value); + } } @override diff --git a/flutter/lib/desktop/widgets/popup_menu.dart b/flutter/lib/desktop/widgets/popup_menu.dart index 086d7a622..1e15b74b0 100644 --- a/flutter/lib/desktop/widgets/popup_menu.dart +++ b/flutter/lib/desktop/widgets/popup_menu.dart @@ -445,6 +445,8 @@ abstract class MenuEntrySwitchBase extends MenuEntryBase { dismissCallback: dismissCallback, ); + bool get isEnabled => enabled?.value ?? true; + RxBool get curOption; Future setOption(bool? option); @@ -481,44 +483,50 @@ abstract class MenuEntrySwitchBase extends MenuEntryBase { if (switchType == SwitchType.sswitch) { return Switch( value: curOption.value, - onChanged: (v) { - if (super.dismissOnClicked && - Navigator.canPop(context)) { - Navigator.pop(context); - if (super.dismissCallback != null) { - super.dismissCallback!(); - } - } - setOption(v); - }, + onChanged: isEnabled + ? (v) { + if (super.dismissOnClicked && + Navigator.canPop(context)) { + Navigator.pop(context); + if (super.dismissCallback != null) { + super.dismissCallback!(); + } + } + setOption(v); + } + : null, ); } else { return Checkbox( value: curOption.value, - onChanged: (v) { - if (super.dismissOnClicked && - Navigator.canPop(context)) { - Navigator.pop(context); - if (super.dismissCallback != null) { - super.dismissCallback!(); - } - } - setOption(v); - }, + onChanged: isEnabled + ? (v) { + if (super.dismissOnClicked && + Navigator.canPop(context)) { + Navigator.pop(context); + if (super.dismissCallback != null) { + super.dismissCallback!(); + } + } + setOption(v); + } + : null, ); } })), )) ])), - onPressed: () { - if (super.dismissOnClicked && Navigator.canPop(context)) { - Navigator.pop(context); - if (super.dismissCallback != null) { - super.dismissCallback!(); - } - } - setOption(!curOption.value); - }, + onPressed: isEnabled + ? () { + if (super.dismissOnClicked && Navigator.canPop(context)) { + Navigator.pop(context); + if (super.dismissCallback != null) { + super.dismissCallback!(); + } + } + setOption(!curOption.value); + } + : null, )), ) ]; diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index fca64f832..609ebbb1c 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -27,12 +27,11 @@ import './popup_menu.dart'; import './kb_layout_type_chooser.dart'; class ToolbarState { - final kStoreKey = 'remoteMenubarState'; late RxBool show; late RxBool _pin; ToolbarState() { - final s = bind.getLocalFlutterOption(k: kStoreKey); + final s = bind.getLocalFlutterOption(k: kOptionRemoteMenubarState); if (s.isEmpty) { _initSet(false, false); return; @@ -53,8 +52,8 @@ class ToolbarState { _initSet(bool s, bool p) { // Show remubar when connection is established. - show = - RxBool(bind.mainGetUserDefaultOption(key: kOptionCollapseToolbar) != 'Y'); + show = RxBool( + bind.mainGetUserDefaultOption(key: kOptionCollapseToolbar) != 'Y'); _pin = RxBool(p); } @@ -86,7 +85,7 @@ class ToolbarState { _savePin() async { bind.setLocalFlutterOption( - k: kStoreKey, v: jsonEncode({'pin': _pin.value})); + k: kOptionRemoteMenubarState, v: jsonEncode({'pin': _pin.value})); } save() async { @@ -1875,7 +1874,7 @@ class _KeyboardMenu extends StatelessWidget { ? (value) async { if (value == null) return; await bind.sessionToggleOption( - sessionId: ffi.sessionId, value: kOptionViewOnly); + sessionId: ffi.sessionId, value: kOptionToggleViewOnly); ffiModel.setViewOnly(id, value); } : null, @@ -2019,6 +2018,7 @@ class _VoiceCallMenu extends StatelessWidget { ); } } + class _RecordMenu extends StatelessWidget { const _RecordMenu({Key? key}) : super(key: key); @@ -2372,18 +2372,18 @@ class _DraggableShowHideState extends State<_DraggableShowHide> { super.initState(); final confLeft = double.tryParse( - bind.mainGetLocalOption(key: 'remote-menubar-drag-left')); + bind.mainGetLocalOption(key: kOptionRemoteMenubarDragLeft)); if (confLeft == null) { bind.mainSetLocalOption( - key: 'remote-menubar-drag-left', value: left.toString()); + key: kOptionRemoteMenubarDragLeft, value: left.toString()); } else { left = confLeft; } final confRight = double.tryParse( - bind.mainGetLocalOption(key: 'remote-menubar-drag-right')); + bind.mainGetLocalOption(key: kOptionRemoteMenubarDragRight)); if (confRight == null) { bind.mainSetLocalOption( - key: 'remote-menubar-drag-right', value: right.toString()); + key: kOptionRemoteMenubarDragRight, value: right.toString()); } else { right = confRight; } diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 431379b2a..9cde22eb9 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -323,11 +323,11 @@ class DesktopTab extends StatelessWidget { return buildRemoteBlock( child: child, use: () async { - var access_mode = await bind.mainGetOption(key: 'access-mode'); + var access_mode = await bind.mainGetOption(key: kOptionAccessMode); var option = option2bool( - 'allow-remote-config-modification', + kOptionAllowRemoteConfigModification, await bind.mainGetOption( - key: 'allow-remote-config-modification')); + key: kOptionAllowRemoteConfigModification)); return access_mode == 'view' || (access_mode.isEmpty && !option); }); } diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 281cf7419..ce46f5d43 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -638,7 +638,7 @@ class _RemotePageState extends State { gFFI.ffiModel.toggleTouchMode(); final v = gFFI.ffiModel.touchMode ? 'Y' : ''; bind.sessionPeerOption( - sessionId: sessionId, name: "touch-mode", value: v); + sessionId: sessionId, name: kOptionTouchMode, value: v); }))); } diff --git a/flutter/lib/mobile/pages/server_page.dart b/flutter/lib/mobile/pages/server_page.dart index b5bd1e4f2..43f1ee9b2 100644 --- a/flutter/lib/mobile/pages/server_page.dart +++ b/flutter/lib/mobile/pages/server_page.dart @@ -111,7 +111,7 @@ class ServerPage extends StatefulWidget implements PageShape { } else if (value == kUsePermanentPassword || value == kUseTemporaryPassword || value == kUseBothPasswords) { - bind.mainSetOption(key: "verification-method", value: value); + bind.mainSetOption(key: kOptionVerificationMethod, value: value); gFFI.serverModel.updatePasswordModel(); } else if (value.startsWith("AcceptSessionsVia")) { value = value.substring("AcceptSessionsVia".length); diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index 3585beb8d..e0fe16cca 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -87,7 +87,7 @@ class _SettingsState extends State with WidgetsBindingObserver { } final enableAbrRes = option2bool( - "enable-abr", await bind.mainGetOption(key: "enable-abr")); + kOptionEnableAbr, await bind.mainGetOption(key: kOptionEnableAbr)); if (enableAbrRes != _enableAbr) { update = true; _enableAbr = enableAbrRes; @@ -107,30 +107,30 @@ class _SettingsState extends State with WidgetsBindingObserver { _onlyWhiteList = onlyWhiteList; } - final enableDirectIPAccess = option2bool( - 'direct-server', await bind.mainGetOption(key: 'direct-server')); + final enableDirectIPAccess = option2bool(kOptionDirectServer, + await bind.mainGetOption(key: kOptionDirectServer)); if (enableDirectIPAccess != _enableDirectIPAccess) { update = true; _enableDirectIPAccess = enableDirectIPAccess; } - final enableRecordSession = option2bool('enable-record-session', - await bind.mainGetOption(key: 'enable-record-session')); + final enableRecordSession = option2bool(kOptionEnableRecordSession, + await bind.mainGetOption(key: kOptionEnableRecordSession)); if (enableRecordSession != _enableRecordSession) { update = true; _enableRecordSession = enableRecordSession; } - final enableHardwareCodec = option2bool( - 'enable-hwcodec', await bind.mainGetOption(key: 'enable-hwcodec')); + final enableHardwareCodec = option2bool(kOptionEnableHwcodec, + await bind.mainGetOption(key: kOptionEnableHwcodec)); if (_enableHardwareCodec != enableHardwareCodec) { update = true; _enableHardwareCodec = enableHardwareCodec; } final autoRecordIncomingSession = option2bool( - 'allow-auto-record-incoming', - await bind.mainGetOption(key: 'allow-auto-record-incoming')); + kOptionAllowAutoRecordIncoming, + await bind.mainGetOption(key: kOptionAllowAutoRecordIncoming)); if (autoRecordIncomingSession != _autoRecordIncomingSession) { update = true; _autoRecordIncomingSession = autoRecordIncomingSession; @@ -161,15 +161,15 @@ class _SettingsState extends State with WidgetsBindingObserver { _buildDate = buildDate; } - final allowAutoDisconnect = option2bool('allow-auto-disconnect', - await bind.mainGetOption(key: 'allow-auto-disconnect')); + final allowAutoDisconnect = option2bool(kOptionAllowAutoDisconnect, + await bind.mainGetOption(key: kOptionAllowAutoDisconnect)); if (allowAutoDisconnect != _allowAutoDisconnect) { update = true; _allowAutoDisconnect = allowAutoDisconnect; } final autoDisconnectTimeout = - await bind.mainGetOption(key: 'auto-disconnect-timeout'); + await bind.mainGetOption(key: kOptionAutoDisconnectTimeout); if (autoDisconnectTimeout != _autoDisconnectTimeout) { update = true; _autoDisconnectTimeout = autoDisconnectTimeout; @@ -281,19 +281,19 @@ class _SettingsState extends State with WidgetsBindingObserver { ]), initialValue: _onlyWhiteList, onToggle: (_) async { - update() async { - final onlyWhiteList = - (await bind.mainGetOption(key: kOptionWhitelist)) != - defaultOptionWhitelist; - if (onlyWhiteList != _onlyWhiteList) { - setState(() { - _onlyWhiteList = onlyWhiteList; - }); - } - } + update() async { + final onlyWhiteList = + (await bind.mainGetOption(key: kOptionWhitelist)) != + defaultOptionWhitelist; + if (onlyWhiteList != _onlyWhiteList) { + setState(() { + _onlyWhiteList = onlyWhiteList; + }); + } + } - changeWhiteList(callback: update); - }, + changeWhiteList(callback: update); + }, ), SettingsTile.switchTile( title: Text('${translate('Adaptive bitrate')} (beta)'), diff --git a/flutter/lib/models/ab_model.dart b/flutter/lib/models/ab_model.dart index c3852bd2b..376842ee6 100644 --- a/flutter/lib/models/ab_model.dart +++ b/flutter/lib/models/ab_model.dart @@ -5,6 +5,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common/hbbs/hbbs.dart'; import 'package:flutter_hbb/common/widgets/peers_view.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/models/model.dart'; import 'package:flutter_hbb/models/peer_model.dart'; import 'package:flutter_hbb/models/platform_model.dart'; @@ -548,7 +549,7 @@ class AbModel { } trySetCurrentToLast() { - final name = bind.getLocalFlutterOption(k: 'current-ab-name'); + final name = bind.getLocalFlutterOption(k: kOptionCurrentAbName); if (addressbooks.containsKey(name)) { _currentName.value = name; } diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 78ec0c018..d897a9ec2 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -389,7 +389,7 @@ class FfiModel with ChangeNotifier { _handleSyncPeerOption(Map evt, String peer) { final k = evt['k']; final v = evt['v']; - if (k == kOptionViewOnly) { + if (k == kOptionToggleViewOnly) { setViewOnly(peer, v as bool); } else if (k == 'keyboard_mode') { parent.target?.inputModel.updateKeyboardMode(); @@ -765,7 +765,7 @@ class FfiModel with ChangeNotifier { _touchMode = true; } else { _touchMode = await bind.sessionGetOption( - sessionId: sessionId, arg: 'touch-mode') != + sessionId: sessionId, arg: kOptionTouchMode) != ''; } if (connType == ConnType.fileTransfer) { @@ -797,7 +797,7 @@ class FfiModel with ChangeNotifier { setViewOnly( peerId, bind.sessionGetToggleOptionSync( - sessionId: sessionId, arg: kOptionViewOnly)); + sessionId: sessionId, arg: kOptionToggleViewOnly)); } if (connType == ConnType.defaultConn) { final platformAdditions = evt['platform_additions']; diff --git a/flutter/lib/models/peer_tab_model.dart b/flutter/lib/models/peer_tab_model.dart index 52e43bfea..5247c1bbb 100644 --- a/flutter/lib/models/peer_tab_model.dart +++ b/flutter/lib/models/peer_tab_model.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/models/peer_model.dart'; import 'package:flutter_hbb/models/platform_model.dart'; import 'package:get/get.dart'; @@ -22,9 +23,6 @@ class PeerTabModel with ChangeNotifier { int get currentTab => _currentTab; int _currentTab = 0; // index in tabNames static const int maxTabCount = 5; - static const String kPeerTabIndex = 'peer-tab-index'; - static const String kPeerTabOrder = 'peer-tab-order'; - static const String kPeerTabVisible = 'peer-tab-visible'; static const List tabNames = [ 'Recent sessions', 'Favorites', @@ -72,7 +70,7 @@ class PeerTabModel with ChangeNotifier { PeerTabModel(this.parent) { // visible try { - final option = bind.getLocalFlutterOption(k: kPeerTabVisible); + final option = bind.getLocalFlutterOption(k: kOptionPeerTabVisible); if (option.isNotEmpty) { List decodeList = jsonDecode(option); if (decodeList.length == _isVisible.length) { @@ -88,7 +86,7 @@ class PeerTabModel with ChangeNotifier { } // order try { - final option = bind.getLocalFlutterOption(k: kPeerTabOrder); + final option = bind.getLocalFlutterOption(k: kOptionPeerTabOrder); if (option.isNotEmpty) { List decodeList = jsonDecode(option); if (decodeList.length == maxTabCount) { @@ -112,7 +110,7 @@ class PeerTabModel with ChangeNotifier { } // init currentTab _currentTab = - int.tryParse(bind.getLocalFlutterOption(k: kPeerTabIndex)) ?? 0; + int.tryParse(bind.getLocalFlutterOption(k: kOptionPeerTabIndex)) ?? 0; if (_currentTab < 0 || _currentTab >= maxTabCount) { _currentTab = 0; } @@ -222,7 +220,7 @@ class PeerTabModel with ChangeNotifier { } try { bind.setLocalFlutterOption( - k: kPeerTabVisible, v: jsonEncode(_isVisible)); + k: kOptionPeerTabVisible, v: jsonEncode(_isVisible)); } catch (_) {} notifyListeners(); } @@ -258,7 +256,7 @@ class PeerTabModel with ChangeNotifier { for (int i = 0; i < list.length; i++) { orders[i] = list[i]; } - bind.setLocalFlutterOption(k: kPeerTabOrder, v: jsonEncode(orders)); + bind.setLocalFlutterOption(k: kOptionPeerTabOrder, v: jsonEncode(orders)); notifyListeners(); } } diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index f495c5519..6bc090901 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -125,8 +125,8 @@ class ServerModel with ChangeNotifier { /* // initital _hideCm at startup final verificationMethod = - bind.mainGetOptionSync(key: "verification-method"); - final approveMode = bind.mainGetOptionSync(key: 'approve-mode'); + bind.mainGetOptionSync(key: kOptionVerificationMethod); + final approveMode = bind.mainGetOptionSync(key: kOptionApproveMode); _hideCm = option2bool( 'allow-hide-cm', bind.mainGetOptionSync(key: 'allow-hide-cm')); if (!(approveMode == 'password' && @@ -187,18 +187,19 @@ class ServerModel with ChangeNotifier { if (androidVersion < 30 || !await AndroidPermissionManager.check(kRecordAudio)) { _audioOk = false; - bind.mainSetOption(key: "enable-audio", value: "N"); + bind.mainSetOption(key: kOptionEnableAudio, value: "N"); } else { - final audioOption = await bind.mainGetOption(key: 'enable-audio'); + final audioOption = await bind.mainGetOption(key: kOptionEnableAudio); _audioOk = audioOption.isEmpty; } // file if (!await AndroidPermissionManager.check(kManageExternalStorage)) { _fileOk = false; - bind.mainSetOption(key: "enable-file-transfer", value: "N"); + bind.mainSetOption(key: kOptionEnableFileTransfer, value: "N"); } else { - final fileOption = await bind.mainGetOption(key: 'enable-file-transfer'); + final fileOption = + await bind.mainGetOption(key: kOptionEnableFileTransfer); _fileOk = fileOption.isEmpty; } @@ -209,10 +210,10 @@ class ServerModel with ChangeNotifier { var update = false; final temporaryPassword = await bind.mainGetTemporaryPassword(); final verificationMethod = - await bind.mainGetOption(key: "verification-method"); + await bind.mainGetOption(key: kOptionVerificationMethod); final temporaryPasswordLength = await bind.mainGetOption(key: "temporary-password-length"); - final approveMode = await bind.mainGetOption(key: 'approve-mode'); + final approveMode = await bind.mainGetOption(key: kOptionApproveMode); /* var hideCm = option2bool( 'allow-hide-cm', await bind.mainGetOption(key: 'allow-hide-cm')); @@ -283,7 +284,8 @@ class ServerModel with ChangeNotifier { } _audioOk = !_audioOk; - bind.mainSetOption(key: "enable-audio", value: _audioOk ? defaultOptionYes : 'N'); + bind.mainSetOption( + key: kOptionEnableAudio, value: _audioOk ? defaultOptionYes : 'N'); notifyListeners(); } @@ -302,7 +304,9 @@ class ServerModel with ChangeNotifier { } _fileOk = !_fileOk; - bind.mainSetOption(key: kOptionEnableFileTransfer, value: _fileOk ? defaultOptionYes : 'N'); + bind.mainSetOption( + key: kOptionEnableFileTransfer, + value: _fileOk ? defaultOptionYes : 'N'); notifyListeners(); } @@ -445,7 +449,9 @@ class ServerModel with ChangeNotifier { break; case "input": if (_inputOk != value) { - bind.mainSetOption(key: kOptionEnableKeyboard, value: value ? defaultOptionYes : 'N'); + bind.mainSetOption( + key: kOptionEnableKeyboard, + value: value ? defaultOptionYes : 'N'); } _inputOk = value; break; diff --git a/flutter/web/js/src/connection.ts b/flutter/web/js/src/connection.ts index 9eb24caec..297004bd8 100644 --- a/flutter/web/js/src/connection.ts +++ b/flutter/web/js/src/connection.ts @@ -660,7 +660,7 @@ export default class Connection { const defaultToggleTrue = [ 'show-remote-cursor', 'privacy-mode', - 'enable-file-transfer', + 'enable-file-copy-paste', 'allow_swap_key', ]; return this._options[name] || (defaultToggleTrue.includes(name) ? true : false); @@ -906,7 +906,7 @@ export default class Connection { case "privacy-mode": option.privacy_mode = v2; break; - case "enable-file-transfer": + case "enable-file-copy-paste": option.enable_file_transfer = v2; break; case "block-input": @@ -933,7 +933,7 @@ export default class Connection { option.show_remote_cursor = this.getToggleOption("show-remote-cursor") ? message.OptionMessage_BoolOption.Yes : message.OptionMessage_BoolOption.No; - option.enable_file_transfer = this.getToggleOption("enable-file-transfer") + option.enable_file_transfer = this.getToggleOption("enable-file-copy-paste") ? message.OptionMessage_BoolOption.Yes : message.OptionMessage_BoolOption.No; option.lock_after_session_end = this.getToggleOption("lock-after-session-end") diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 2a76f6926..a2ffca9cb 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -40,10 +40,6 @@ const SERIAL: i32 = 3; const PASSWORD_ENC_VERSION: &str = "00"; const ENCRYPT_MAX_LEN: usize = 128; -// config2 options -#[cfg(target_os = "linux")] -pub const CONFIG_OPTION_ALLOW_LINUX_HEADLESS: &str = "allow-linux-headless"; - #[cfg(target_os = "macos")] lazy_static::lazy_static! { pub static ref ORG: RwLock = RwLock::new("com.carriez".to_owned()); @@ -278,7 +274,7 @@ pub struct PeerConfig { #[serde(flatten)] pub disable_clipboard: DisableClipboard, #[serde(flatten)] - pub enable_file_transfer: EnableFileTransfer, + pub enable_file_copy_paste: EnableFileCopyPaste, #[serde(flatten)] pub show_quality_monitor: ShowQualityMonitor, #[serde(flatten)] @@ -355,7 +351,7 @@ impl Default for PeerConfig { direct_failures: Default::default(), disable_audio: Default::default(), disable_clipboard: Default::default(), - enable_file_transfer: Default::default(), + enable_file_copy_paste: Default::default(), show_quality_monitor: Default::default(), follow_remote_cursor: Default::default(), follow_remote_window: Default::default(), @@ -1289,11 +1285,13 @@ serde_field_bool!( default_disable_audio, "DisableAudio::default_disable_audio" ); +// The key is enable_file_transfer, but no need to keep the old name. +// This option should always be true. serde_field_bool!( - EnableFileTransfer, - "enable_file_transfer", - default_enable_file_transfer, - "EnableFileTransfer::default_enable_file_transfer" + EnableFileCopyPaste, + "enable_file_copy_paste", + default_enable_file_copy_paste, + "EnableFileCopyPaste::default_enable_file_copy_paste" ); serde_field_bool!( DisableClipboard, @@ -1438,11 +1436,13 @@ impl LocalConfig { } pub fn get_flutter_option(k: &str) -> String { - if let Some(v) = LOCAL_CONFIG.read().unwrap().ui_flutter.get(k) { - v.clone() - } else { - "".to_owned() - } + get_or( + &OVERWRITE_LOCAL_SETTINGS, + &LOCAL_CONFIG.read().unwrap().ui_flutter, + &DEFAULT_LOCAL_SETTINGS, + k, + ) + .unwrap_or_default() } pub fn set_flutter_option(k: String, v: String) { @@ -1591,7 +1591,7 @@ impl UserDefaultConfig { self.get_double_string(key, 50.0, 10.0, 0xFFF as f64) } keys::OPTION_CUSTOM_FPS => self.get_double_string(key, 30.0, 5.0, 120.0), - keys::OPTION_ENABLE_FILE_TRANSFER => self.get_string(key, "Y", vec!["", "N"]), + keys::OPTION_ENABLE_FILE_COPY_PASTE => self.get_string(key, "Y", vec!["", "N"]), _ => self .get_after(key) .map(|v| v.to_string()) @@ -1992,6 +1992,7 @@ pub mod keys { pub const OPTION_ZOOM_CURSOR: &str = "zoom-cursor"; pub const OPTION_SHOW_QUALITY_MONITOR: &str = "show_quality_monitor"; pub const OPTION_DISABLE_AUDIO: &str = "disable_audio"; + pub const OPTION_ENABLE_FILE_COPY_PASTE: &str = "enable-file-copy-paste"; pub const OPTION_DISABLE_CLIPBOARD: &str = "disable_clipboard"; pub const OPTION_LOCK_AFTER_SESSION_END: &str = "lock_after_session_end"; pub const OPTION_PRIVACY_MODE: &str = "privacy_mode"; @@ -2010,6 +2011,9 @@ pub mod keys { pub const OPTION_CODEC_PREFERENCE: &str = "codec-preference"; pub const OPTION_THEME: &str = "theme"; pub const OPTION_LANGUAGE: &str = "lang"; + pub const OPTION_REMOTE_MENUBAR_DRAG_LEFT: &str = "remote-menubar-drag-left"; + pub const OPTION_REMOTE_MENUBAR_DRAG_RIGHT: &str = "remote-menubar-drag-right"; + pub const OPTION_HIDE_AB_TAGS_PANEL: &str = "hideAbTagsPanel"; pub const OPTION_ENABLE_CONFIRM_CLOSING_TABS: &str = "enable-confirm-closing-tabs"; pub const OPTION_ENABLE_OPEN_NEW_CONNECTIONS_IN_TABS: &str = "enable-open-new-connections-in-tabs"; @@ -2043,6 +2047,15 @@ pub mod keys { pub const OPTION_ENABLE_HWCODEC: &str = "enable-hwcodec"; pub const OPTION_APPROVE_MODE: &str = "approve-mode"; + // flutter local options + pub const OPTION_FLUTTER_REMOTE_MENUBAR_STATE: &str = "remoteMenubarState"; + pub const OPTION_FLUTTER_PEER_SORTING: &str = "peer-sorting"; + pub const OPTION_FLUTTER_PEER_TAB_INDEX: &str = "peer-tab-index"; + pub const OPTION_FLUTTER_PEER_TAB_ORDER: &str = "peer-tab-order"; + pub const OPTION_FLUTTER_PEER_TAB_VISIBLE: &str = "peer-tab-visible"; + pub const OPTION_FLUTTER_PEER_CARD_UI_TYLE: &str = "peer-card-ui-type"; + pub const OPTION_FLUTTER_CURRENT_AB_NAME: &str = "current-ab-name"; + // DEFAULT_DISPLAY_SETTINGS, OVERWRITE_DISPLAY_SETTINGS pub const KEYS_DISPLAY_SETTINGS: &[&str] = &[ OPTION_VIEW_ONLY, @@ -2054,7 +2067,7 @@ pub mod keys { OPTION_ZOOM_CURSOR, OPTION_SHOW_QUALITY_MONITOR, OPTION_DISABLE_AUDIO, - OPTION_ENABLE_FILE_TRANSFER, + OPTION_ENABLE_FILE_COPY_PASTE, OPTION_DISABLE_CLIPBOARD, OPTION_LOCK_AFTER_SESSION_END, OPTION_PRIVACY_MODE, @@ -2081,6 +2094,16 @@ pub mod keys { OPTION_SYNC_AB_WITH_RECENT_SESSIONS, OPTION_SYNC_AB_TAGS, OPTION_FILTER_AB_BY_INTERSECTION, + OPTION_REMOTE_MENUBAR_DRAG_LEFT, + OPTION_REMOTE_MENUBAR_DRAG_RIGHT, + OPTION_HIDE_AB_TAGS_PANEL, + OPTION_FLUTTER_REMOTE_MENUBAR_STATE, + OPTION_FLUTTER_PEER_SORTING, + OPTION_FLUTTER_PEER_TAB_INDEX, + OPTION_FLUTTER_PEER_TAB_ORDER, + OPTION_FLUTTER_PEER_TAB_VISIBLE, + OPTION_FLUTTER_PEER_CARD_UI_TYLE, + OPTION_FLUTTER_CURRENT_AB_NAME, ]; // DEFAULT_SETTINGS, OVERWRITE_SETTINGS pub const KEYS_SETTINGS: &[&str] = &[ diff --git a/src/client.rs b/src/client.rs index 78cb91fcf..111576595 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1503,9 +1503,9 @@ impl LoginConfigHandler { BoolOption::Yes }) .into(); - } else if name == "enable-file-transfer" { - config.enable_file_transfer.v = !config.enable_file_transfer.v; - option.enable_file_transfer = (if config.enable_file_transfer.v { + } else if name == "enable-file-copy-paste" { + config.enable_file_copy_paste.v = !config.enable_file_copy_paste.v; + option.enable_file_transfer = (if config.enable_file_copy_paste.v { BoolOption::Yes } else { BoolOption::No @@ -1538,7 +1538,7 @@ impl LoginConfigHandler { 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")); - option.enable_file_transfer = f(self.config.enable_file_transfer.v); + option.enable_file_transfer = f(self.config.enable_file_copy_paste.v); option.lock_after_session_end = f(self.config.lock_after_session_end.v); } } else { @@ -1631,7 +1631,7 @@ impl LoginConfigHandler { if self.get_toggle_option("disable-audio") { msg.disable_audio = BoolOption::Yes.into(); } - if !view_only && self.get_toggle_option("enable-file-transfer") { + if !view_only && self.get_toggle_option(config::keys::OPTION_ENABLE_FILE_COPY_PASTE) { msg.enable_file_transfer = BoolOption::Yes.into(); } if view_only || self.get_toggle_option("disable-clipboard") { @@ -1704,8 +1704,8 @@ impl LoginConfigHandler { self.config.lock_after_session_end.v } else if name == "privacy-mode" { self.config.privacy_mode.v - } else if name == "enable-file-transfer" { - self.config.enable_file_transfer.v + } else if name == config::keys::OPTION_ENABLE_FILE_COPY_PASTE { + self.config.enable_file_copy_paste.v } else if name == "disable-audio" { self.config.disable_audio.v } else if name == "disable-clipboard" { diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 0af3f92d7..471df3a5f 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -319,8 +319,13 @@ impl Remote { let is_stopping_allowed = clip.is_stopping_allowed(); let server_file_transfer_enabled = *self.handler.server_file_transfer_enabled.read().unwrap(); - let file_transfer_enabled = - self.handler.lc.read().unwrap().enable_file_transfer.v; + let file_transfer_enabled = self + .handler + .lc + .read() + .unwrap() + .enable_file_copy_paste + .v; let view_only = self.handler.lc.read().unwrap().view_only.v; let stop = is_stopping_allowed && (view_only @@ -1760,7 +1765,13 @@ impl Remote { ))] { let enabled = *self.handler.server_file_transfer_enabled.read().unwrap() - && self.handler.lc.read().unwrap().enable_file_transfer.v; + && self + .handler + .lc + .read() + .unwrap() + .enable_file_copy_paste + .v; ContextSend::enable(enabled); } } @@ -1783,7 +1794,13 @@ impl Remote { }; let is_stopping_allowed = clip.is_stopping_allowed_from_peer(); - let file_transfer_enabled = self.handler.lc.read().unwrap().enable_file_transfer.v; + let file_transfer_enabled = self + .handler + .lc + .read() + .unwrap() + .enable_file_copy_paste + .v; let stop = is_stopping_allowed && !file_transfer_enabled; log::debug!( "Process clipboard message from server peer, stop: {}, is_stopping_allowed: {}, file_transfer_enabled: {}", diff --git a/src/common.rs b/src/common.rs index 86e53256a..842ada647 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1572,6 +1572,56 @@ pub fn load_custom_client() { } } +fn read_custom_client_advanced_settings( + settings: serde_json::Value, + map_display_settings: &HashMap, + map_local_settings: &HashMap, + map_settings: &HashMap, + is_override: bool, +) { + let mut display_settings = if is_override { + config::OVERWRITE_DISPLAY_SETTINGS.write().unwrap() + } else { + config::DEFAULT_DISPLAY_SETTINGS.write().unwrap() + }; + let mut local_settings = if is_override { + config::OVERWRITE_LOCAL_SETTINGS.write().unwrap() + } else { + config::DEFAULT_LOCAL_SETTINGS.write().unwrap() + }; + let mut server_settings = if is_override { + config::OVERWRITE_SETTINGS.write().unwrap() + } else { + config::DEFAULT_SETTINGS.write().unwrap() + }; + if let Some(settings) = settings.as_object() { + for (k, v) in settings { + let Some(v) = v.as_str() else { + continue; + }; + if let Some(k2) = map_display_settings.get(k) { + display_settings.insert(k2.to_string(), v.to_owned()); + } else if let Some(k2) = map_local_settings.get(k) { + local_settings.insert(k2.to_string(), v.to_owned()); + } else if let Some(k2) = map_settings.get(k) { + server_settings.insert(k2.to_string(), v.to_owned()); + } else { + let k2 = k.replace("_", "-"); + let k = k2.replace("-", "_"); + // display + display_settings.insert(k.clone(), v.to_owned()); + display_settings.insert(k2.clone(), v.to_owned()); + // local + local_settings.insert(k.clone(), v.to_owned()); + local_settings.insert(k2.clone(), v.to_owned()); + // server + server_settings.insert(k.clone(), v.to_owned()); + server_settings.insert(k2.clone(), v.to_owned()); + } + } + } +} + pub fn read_custom_client(config: &str) { let Ok(data) = decode64(config) else { log::error!("Failed to decode custom client config"); @@ -1611,66 +1661,23 @@ pub fn read_custom_client(config: &str) { for s in config::keys::KEYS_SETTINGS { map_settings.insert(s.replace("_", "-"), s); } - if let Some(default_settings) = data.remove("default-settings") { - if let Some(default_settings) = default_settings.as_object() { - for (k, v) in default_settings { - let Some(v) = v.as_str() else { - continue; - }; - if let Some(k2) = map_display_settings.get(k) { - config::DEFAULT_DISPLAY_SETTINGS - .write() - .unwrap() - .insert(k2.to_string(), v.to_owned()); - } else if let Some(k2) = map_local_settings.get(k) { - config::DEFAULT_LOCAL_SETTINGS - .write() - .unwrap() - .insert(k2.to_string(), v.to_owned()); - } else if let Some(k2) = map_settings.get(k) { - config::DEFAULT_SETTINGS - .write() - .unwrap() - .insert(k2.to_string(), v.to_owned()); - } else { - config::DEFAULT_SETTINGS - .write() - .unwrap() - .insert(k.clone(), v.to_owned()); - } - } - } + read_custom_client_advanced_settings( + default_settings, + &map_display_settings, + &map_local_settings, + &map_settings, + false, + ); } if let Some(overwrite_settings) = data.remove("override-settings") { - if let Some(overwrite_settings) = overwrite_settings.as_object() { - for (k, v) in overwrite_settings { - let Some(v) = v.as_str() else { - continue; - }; - if let Some(k2) = map_display_settings.get(k) { - config::OVERWRITE_DISPLAY_SETTINGS - .write() - .unwrap() - .insert(k2.to_string(), v.to_owned()); - } else if let Some(k2) = map_local_settings.get(k) { - config::OVERWRITE_LOCAL_SETTINGS - .write() - .unwrap() - .insert(k2.to_string(), v.to_owned()); - } else if let Some(k2) = map_settings.get(k) { - config::OVERWRITE_SETTINGS - .write() - .unwrap() - .insert(k2.to_string(), v.to_owned()); - } else { - config::OVERWRITE_SETTINGS - .write() - .unwrap() - .insert(k.clone(), v.to_owned()); - } - } - } + read_custom_client_advanced_settings( + overwrite_settings, + &map_display_settings, + &map_local_settings, + &map_settings, + true, + ); } for (k, v) in data { if let Some(v) = v.as_str() { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index f339c729e..c3a4335bd 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -775,7 +775,7 @@ pub fn main_get_error() -> String { pub fn main_show_option(_key: String) -> SyncReturn { #[cfg(target_os = "linux")] - if _key.eq(config::CONFIG_OPTION_ALLOW_LINUX_HEADLESS) { + if _key.eq(config::keys::OPTION_ALLOW_LINUX_HEADLESS) { return SyncReturn(true); } SyncReturn(false) diff --git a/src/platform/linux.rs b/src/platform/linux.rs index ac5b8eddc..d5517f67a 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -1,6 +1,6 @@ use super::{CursorData, ResultType}; use desktop::Desktop; -use hbb_common::config::CONFIG_OPTION_ALLOW_LINUX_HEADLESS; +use hbb_common::config::keys::OPTION_ALLOW_LINUX_HEADLESS; pub use hbb_common::platform::linux::*; use hbb_common::{ allow_err, @@ -95,7 +95,7 @@ pub struct xcb_xfixes_get_cursor_image { #[inline] pub fn is_headless_allowed() -> bool { - Config::get_option(CONFIG_OPTION_ALLOW_LINUX_HEADLESS) == "Y" + Config::get_option(OPTION_ALLOW_LINUX_HEADLESS) == "Y" } #[inline] diff --git a/src/server/connection.rs b/src/server/connection.rs index 2af3e58b3..4aad807d0 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -28,7 +28,7 @@ use hbb_common::platform::linux::run_cmds; #[cfg(target_os = "android")] use hbb_common::protobuf::EnumOrUnknown; use hbb_common::{ - config::Config, + config::{self, Config}, fs::{self, can_enable_overwrite_detection}, futures::{SinkExt, StreamExt}, get_time, get_version_number, @@ -337,7 +337,7 @@ impl Connection { clipboard: Connection::permission("enable-clipboard"), audio: Connection::permission("enable-audio"), // to-do: make sure is the option correct here - file: Connection::permission("enable-file-transfer"), + file: Connection::permission(config::keys::OPTION_ENABLE_FILE_TRANSFER), restart: Connection::permission("enable-remote-restart"), recording: Connection::permission("enable-record-session"), block_input: Connection::permission("enable-block-input"), @@ -1614,7 +1614,7 @@ impl Connection { } match lr.union { Some(login_request::Union::FileTransfer(ft)) => { - if !Connection::permission("enable-file-transfer") { + if !Connection::permission(config::keys::OPTION_ENABLE_FILE_TRANSFER) { self.send_login_error("No permission of file transfer") .await; sleep(1.).await; diff --git a/src/ui/header.tis b/src/ui/header.tis index b40e664da..c4e765280 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -198,7 +198,7 @@ class Header: Reactor.Component { {
  • {svg_checkmark}{translate('Follow remote window focus')}
  • }
  • {svg_checkmark}{translate('Show quality monitor')}
  • {audio_enabled ?
  • {svg_checkmark}{translate('Mute')}
  • : ""} - {(is_win && pi.platform == "Windows") && file_enabled ?
  • {svg_checkmark}{translate('Enable file copy and paste')}
  • : ""} + {(is_win && pi.platform == "Windows") && file_enabled ?
  • {svg_checkmark}{translate('Enable file copy and paste')}
  • : ""} {keyboard_enabled && clipboard_enabled ?
  • {svg_checkmark}{translate('Disable clipboard')}
  • : ""} {keyboard_enabled ?
  • {svg_checkmark}{translate('Lock after session end')}
  • : ""} {keyboard_enabled && pi.platform == "Windows" ?
  • {svg_checkmark}{translate('Privacy mode')}
  • : ""} @@ -481,7 +481,7 @@ function toggleMenuState() { for (var el in $$(menu#keyboard-options>li)) { el.attributes.toggleClass("selected", values.indexOf(el.id) >= 0); } - for (var id in ["show-remote-cursor", "follow-remote-cursor", "follow-remote-window", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end", "allow_swap_key", "i444"]) { + for (var id in ["show-remote-cursor", "follow-remote-cursor", "follow-remote-window", "show-quality-monitor", "disable-audio", "enable-file-copy-paste", "disable-clipboard", "lock-after-session-end", "allow_swap_key", "i444"]) { var el = self.select('#' + id); if (el) { var value = handler.get_toggle_option(id); diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index da483b33a..38bfc72b5 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -79,7 +79,7 @@ struct IpcTaskRunner { lazy_static::lazy_static! { static ref CLIENTS: RwLock> = Default::default(); } - + static CLICK_TIME: AtomicI64 = AtomicI64::new(0); #[derive(Clone)] @@ -574,7 +574,9 @@ pub async fn start_ipc(cm: ConnectionManager) { feature = "unix-file-copy-paste" ), ))] - ContextSend::enable(Config::get_option("enable-file-transfer").is_empty()); + ContextSend::enable( + Config::get_option(hbb_common::config::keys::OPTION_ENABLE_FILE_TRANSFER).is_empty(), + ); match ipc::new_listener("_cm").await { Ok(mut incoming) => { diff --git a/src/ui_interface.rs b/src/ui_interface.rs index e73226fa3..452478e2e 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -1120,7 +1120,7 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver Session { pub fn toggle_option(&self, name: String) { let msg = self.lc.write().unwrap().toggle_option(name.clone()); #[cfg(not(feature = "flutter"))] - if name == "enable-file-transfer" { + if name == hbb_common::config::keys::OPTION_ENABLE_FILE_COPY_PASTE { self.send(Data::ToggleClipboardFile); } if let Some(msg) = msg {