refact: custom client, more advanced settings (#8085)

* refact: custom client, more advanced settings

Signed-off-by: fufesou <shuanglongchen@yeah.net>

* feat: custom client, more advanced settings

Signed-off-by: fufesou <shuanglongchen@yeah.net>

---------

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2024-05-18 23:13:54 +08:00 committed by GitHub
parent c2b7810c33
commit 96f41fcc02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 356 additions and 258 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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<AddressBook> {
}
final TextEditingController textEditingController = TextEditingController();
final isOptFixed = isOptionFixed(kOptionCurrentAbName);
return DropdownButton2<String>(
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<AddressBook> {
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<AddressBook> {
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,

View File

@ -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;

View File

@ -74,9 +74,11 @@ class _PeerTabPageState extends State<PeerTabPage>
];
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<PeerTabPage>
: PeerUiType.list;
}
hideAbTagsPanel.value =
bind.mainGetLocalOption(key: "hideAbTagsPanel").isNotEmpty;
bind.mainGetLocalOption(key: kOptionHideAbTagsPanel).isNotEmpty;
super.initState();
}
@ -173,11 +175,13 @@ class _PeerTabPageState extends State<PeerTabPage>
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<PeerTabPage>
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<PeerTabPage>
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<PeerTabPage>
),
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<PeerViewDropdown> {
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<PeerSortDropdown> {
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<PeerSortDropdown> {
if (v != null) {
peerSort.value = v;
await bind.setLocalFlutterOption(
k: "peer-sorting",
k: kOptionPeerSorting,
v: peerSort.value,
);
}

View File

@ -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,
);
}

View File

@ -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),

View File

@ -534,15 +534,15 @@ Future<List<TToggleMenu>> 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'))));

View File

@ -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";

View File

@ -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(() {});
}

View File

@ -94,7 +94,7 @@ class _RemotePageState extends State<RemotePage>
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<RemotePage>
_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(

View File

@ -341,8 +341,9 @@ class PopupMenuItemState<T, W extends PopupMenuItem<T>> extends State<W> {
@protected
void handleTap() {
widget.onTap?.call();
Navigator.pop<T>(context, widget.value);
if (Navigator.canPop(context)) {
Navigator.pop<T>(context, widget.value);
}
}
@override

View File

@ -445,6 +445,8 @@ abstract class MenuEntrySwitchBase<T> extends MenuEntryBase<T> {
dismissCallback: dismissCallback,
);
bool get isEnabled => enabled?.value ?? true;
RxBool get curOption;
Future<void> setOption(bool? option);
@ -481,44 +483,50 @@ abstract class MenuEntrySwitchBase<T> extends MenuEntryBase<T> {
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,
)),
)
];

View File

@ -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;
}

View File

@ -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);
});
}

View File

@ -638,7 +638,7 @@ class _RemotePageState extends State<RemotePage> {
gFFI.ffiModel.toggleTouchMode();
final v = gFFI.ffiModel.touchMode ? 'Y' : '';
bind.sessionPeerOption(
sessionId: sessionId, name: "touch-mode", value: v);
sessionId: sessionId, name: kOptionTouchMode, value: v);
})));
}

View File

@ -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);

View File

@ -87,7 +87,7 @@ class _SettingsState extends State<SettingsPage> 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<SettingsPage> 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<SettingsPage> 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<SettingsPage> 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)'),

View File

@ -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;
}

View File

@ -389,7 +389,7 @@ class FfiModel with ChangeNotifier {
_handleSyncPeerOption(Map<String, dynamic> 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'];

View File

@ -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<String> 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<dynamic> 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<dynamic> 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();
}
}

View File

@ -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;

View File

@ -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")

View File

@ -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<String> = 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] = &[

View File

@ -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" {

View File

@ -319,8 +319,13 @@ impl<T: InvokeUiSession> Remote<T> {
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<T: InvokeUiSession> Remote<T> {
))]
{
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<T: InvokeUiSession> Remote<T> {
};
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: {}",

View File

@ -1572,6 +1572,56 @@ pub fn load_custom_client() {
}
}
fn read_custom_client_advanced_settings(
settings: serde_json::Value,
map_display_settings: &HashMap<String, &&str>,
map_local_settings: &HashMap<String, &&str>,
map_settings: &HashMap<String, &&str>,
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() {

View File

@ -775,7 +775,7 @@ pub fn main_get_error() -> String {
pub fn main_show_option(_key: String) -> SyncReturn<bool> {
#[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)

View File

@ -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]

View File

@ -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;

View File

@ -198,7 +198,7 @@ class Header: Reactor.Component {
{<li #follow-remote-window .toggle-option><span>{svg_checkmark}</span>{translate('Follow remote window focus')}</li>}
<li #show-quality-monitor .toggle-option><span>{svg_checkmark}</span>{translate('Show quality monitor')}</li>
{audio_enabled ? <li #disable-audio .toggle-option><span>{svg_checkmark}</span>{translate('Mute')}</li> : ""}
{(is_win && pi.platform == "Windows") && file_enabled ? <li #enable-file-transfer .toggle-option><span>{svg_checkmark}</span>{translate('Enable file copy and paste')}</li> : ""}
{(is_win && pi.platform == "Windows") && file_enabled ? <li #enable-file-copy-paste .toggle-option><span>{svg_checkmark}</span>{translate('Enable file copy and paste')}</li> : ""}
{keyboard_enabled && clipboard_enabled ? <li #disable-clipboard .toggle-option><span>{svg_checkmark}</span>{translate('Disable clipboard')}</li> : ""}
{keyboard_enabled ? <li #lock-after-session-end .toggle-option><span>{svg_checkmark}</span>{translate('Lock after session end')}</li> : ""}
{keyboard_enabled && pi.platform == "Windows" ? <li #privacy-mode><span>{svg_checkmark}</span>{translate('Privacy mode')}</li> : ""}
@ -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);

View File

@ -79,7 +79,7 @@ struct IpcTaskRunner<T: InvokeUiCM> {
lazy_static::lazy_static! {
static ref CLIENTS: RwLock<HashMap<i32, Client>> = Default::default();
}
static CLICK_TIME: AtomicI64 = AtomicI64::new(0);
#[derive(Clone)]
@ -574,7 +574,9 @@ pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
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) => {

View File

@ -1120,7 +1120,7 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver<ipc:
)
))]
{
let b = OPTIONS.lock().unwrap().get("enable-file-transfer").map(|x| x.to_string()).unwrap_or_default();
let b = OPTIONS.lock().unwrap().get(config::keys::OPTION_ENABLE_FILE_TRANSFER).map(|x| x.to_string()).unwrap_or_default();
if b != enable_file_transfer {
clipboard::ContextSend::enable(b.is_empty());
enable_file_transfer = b;

View File

@ -312,7 +312,7 @@ impl<T: InvokeUiSession> Session<T> {
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 {