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:
parent
c2b7810c33
commit
96f41fcc02
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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'))));
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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(() {});
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
)),
|
||||
)
|
||||
];
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
@ -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);
|
||||
})));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)'),
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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'];
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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")
|
||||
|
@ -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] = &[
|
||||
|
@ -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" {
|
||||
|
@ -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: {}",
|
||||
|
121
src/common.rs
121
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<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() {
|
||||
|
@ -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)
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) => {
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user