mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
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:
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user