diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 21a1c3b5e..43a231b69 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -635,8 +635,12 @@ closeConnection({String? id}) { gFFI.chatModel.hideChatOverlay(); Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/")); } else { - final controller = Get.find(); - controller.closeBy(id); + if (isWeb) { + Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/")); + } else { + final controller = Get.find(); + controller.closeBy(id); + } } } @@ -2980,7 +2984,6 @@ Future setServerConfig( await bind.mainSetOption(key: 'relay-server', value: config.relayServer); await bind.mainSetOption(key: 'api-server', value: config.apiServer); await bind.mainSetOption(key: 'key', value: config.key); - final newApiServer = await bind.mainGetApiServer(); if (oldApiServer.isNotEmpty && oldApiServer != newApiServer && diff --git a/flutter/lib/common/widgets/dialog.dart b/flutter/lib/common/widgets/dialog.dart index 9dbdfd91b..d2c808adc 100644 --- a/flutter/lib/common/widgets/dialog.dart +++ b/flutter/lib/common/widgets/dialog.dart @@ -625,7 +625,7 @@ class _DialogVerificationCodeField extends State { // software secure keyboard will take the focus since flutter 3.13 // request focus again when android account password obtain focus - if (Platform.isAndroid && widget.reRequestFocus) { + if (isAndroid && widget.reRequestFocus) { _focusNode.addListener(() { if (_focusNode.hasFocus) { _timerReRequestFocus?.cancel(); @@ -694,7 +694,7 @@ class _PasswordWidgetState extends State { } // software secure keyboard will take the focus since flutter 3.13 // request focus again when android account password obtain focus - if (Platform.isAndroid && widget.reRequestFocus) { + if (isAndroid && widget.reRequestFocus) { _focusNode.addListener(() { if (_focusNode.hasFocus) { _timerReRequestFocus?.cancel(); diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index c042244dc..e2609792e 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -875,10 +873,10 @@ class RecentPeerCard extends BasePeerCard { } // menuItems.add(await _openNewConnInOptAction(peer.id)); menuItems.add(await _forceAlwaysRelayAction(peer.id)); - if (Platform.isWindows && peer.platform == kPeerPlatformWindows) { + if (isWindows && peer.platform == kPeerPlatformWindows) { menuItems.add(_rdpAction(context, peer.id)); } - if (Platform.isWindows) { + if (isWindows) { menuItems.add(_createShortCutAction(peer.id)); } menuItems.add(MenuEntryDivider()); @@ -927,10 +925,10 @@ class FavoritePeerCard extends BasePeerCard { } // menuItems.add(await _openNewConnInOptAction(peer.id)); menuItems.add(await _forceAlwaysRelayAction(peer.id)); - if (Platform.isWindows && peer.platform == kPeerPlatformWindows) { + if (isWindows && peer.platform == kPeerPlatformWindows) { menuItems.add(_rdpAction(context, peer.id)); } - if (Platform.isWindows) { + if (isWindows) { menuItems.add(_createShortCutAction(peer.id)); } menuItems.add(MenuEntryDivider()); @@ -979,11 +977,11 @@ class DiscoveredPeerCard extends BasePeerCard { } // menuItems.add(await _openNewConnInOptAction(peer.id)); menuItems.add(await _forceAlwaysRelayAction(peer.id)); - if (Platform.isWindows && peer.platform == kPeerPlatformWindows) { + if (isWindows && peer.platform == kPeerPlatformWindows) { menuItems.add(_rdpAction(context, peer.id)); } menuItems.add(_wolAction(peer.id)); - if (Platform.isWindows) { + if (isWindows) { menuItems.add(_createShortCutAction(peer.id)); } @@ -1027,10 +1025,10 @@ class AddressBookPeerCard extends BasePeerCard { } // menuItems.add(await _openNewConnInOptAction(peer.id)); // menuItems.add(await _forceAlwaysRelayAction(peer.id)); - if (Platform.isWindows && peer.platform == kPeerPlatformWindows) { + if (isWindows && peer.platform == kPeerPlatformWindows) { menuItems.add(_rdpAction(context, peer.id)); } - if (Platform.isWindows) { + if (isWindows) { menuItems.add(_createShortCutAction(peer.id)); } if (gFFI.abModel.current.canWrite()) { @@ -1154,10 +1152,10 @@ class MyGroupPeerCard extends BasePeerCard { } // menuItems.add(await _openNewConnInOptAction(peer.id)); // menuItems.add(await _forceAlwaysRelayAction(peer.id)); - if (Platform.isWindows && peer.platform == kPeerPlatformWindows) { + if (isWindows && peer.platform == kPeerPlatformWindows) { menuItems.add(_rdpAction(context, peer.id)); } - if (Platform.isWindows) { + if (isWindows) { menuItems.add(_createShortCutAction(peer.id)); } // menuItems.add(MenuEntryDivider()); diff --git a/flutter/lib/common/widgets/toolbar.dart b/flutter/lib/common/widgets/toolbar.dart index 638d62cd4..0fcc7e2a4 100644 --- a/flutter/lib/common/widgets/toolbar.dart +++ b/flutter/lib/common/widgets/toolbar.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -633,8 +632,8 @@ List toolbarKeyboardToggles(FFI ffi) { // swap key if (ffiModel.keyboard && - ((Platform.isMacOS && pi.platform != kPeerPlatformMacOS) || - (!Platform.isMacOS && pi.platform == kPeerPlatformMacOS))) { + ((isMacOS && pi.platform != kPeerPlatformMacOS) || + (!isMacOS && pi.platform == kPeerPlatformMacOS))) { final option = 'allow_swap_key'; final value = bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option); diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 7a8056616..a06ff5900 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -115,16 +115,16 @@ const double kDefaultQuality = 50; const double kMaxQuality = 100; const double kMaxMoreQuality = 2000; -double kNewWindowOffset = Platform.isWindows +double kNewWindowOffset = isWindows ? 56.0 - : Platform.isLinux + : isLinux ? 50.0 - : Platform.isMacOS + : isMacOS ? 30.0 : 50.0; EdgeInsets get kDragToResizeAreaPadding => - !kUseCompatibleUiMode && Platform.isLinux + !kUseCompatibleUiMode && isLinux ? stateGlobal.fullscreen.isTrue || stateGlobal.isMaximized.value ? EdgeInsets.zero : EdgeInsets.all(5.0) @@ -152,7 +152,7 @@ const kDefaultScrollDuration = Duration(milliseconds: 50); const kDefaultMouseWheelThrottleDuration = Duration(milliseconds: 50); const kFullScreenEdgeSize = 0.0; const kMaximizeEdgeSize = 0.0; -var kWindowEdgeSize = Platform.isWindows ? 1.0 : 5.0; +var kWindowEdgeSize = isWindows ? 1.0 : 5.0; const kWindowBorderWidth = 1.0; const kDesktopMenuPadding = EdgeInsets.only(left: 12.0, right: 3.0); diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 4c727374e..408e0ee92 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; @@ -231,7 +230,7 @@ class _ConnectionPageState extends State if (eventName == 'minimize') { isWindowMinimized = true; } else if (eventName == 'maximize' || eventName == 'restore') { - if (isWindowMinimized && Platform.isWindows) { + if (isWindowMinimized && isWindows) { // windows can't update when minimized. Get.forceAppUpdate(); } diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index ebc3a591b..b56bc0c75 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -469,7 +469,7 @@ class _DesktopHomePageState extends State return buildInstallCard("", systemError, "", () {}); } - if (Platform.isWindows && !bind.isDisableInstallation()) { + if (isWindows && !bind.isDisableInstallation()) { if (!bind.mainIsInstalled()) { return buildInstallCard( "", bind.isOutgoingOnly() ? "" : "install_tip", "Install", @@ -485,7 +485,7 @@ class _DesktopHomePageState extends State bind.mainUpdateMe(); }); } - } else if (Platform.isMacOS) { + } else if (isMacOS) { if (!(bind.isOutgoingOnly() || bind.mainIsCanScreenRecording(prompt: false))) { return buildInstallCard("Permissions", "config_screen", "Configure", @@ -521,7 +521,7 @@ class _DesktopHomePageState extends State // watchIsCanRecordAudio = true; // }); // } - } else if (Platform.isLinux) { + } else if (isLinux) { if (bind.isOutgoingOnly()) { return Container(); } @@ -570,7 +570,7 @@ class _DesktopHomePageState extends State onPressed: () { SystemNavigator.pop(); // Close the application // https://github.com/flutter/flutter/issues/66631 - if (Platform.isWindows) { + if (isWindows) { exit(0); } }, @@ -740,7 +740,7 @@ class _DesktopHomePageState extends State } } if (watchIsCanRecordAudio) { - if (Platform.isMacOS) { + if (isMacOS) { Future.microtask(() async { if ((await osxCanRecordAudio() == PermissionAuthorizeType.authorized)) { diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 4970b0426..4b24b54fc 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -414,7 +414,7 @@ class _GeneralState extends State<_General> { } String getDefault() { - if (Platform.isWindows) return translate('System Sound'); + if (isWindows) return translate('System Sound'); return ''; } @@ -434,7 +434,7 @@ class _GeneralState extends State<_General> { return futureBuilder(future: () async { List devices = (await bind.mainGetSoundInputs()).toList(); - if (Platform.isWindows) { + if (isWindows) { devices.insert(0, translate('System Sound')); } String current = await getValue(); @@ -705,7 +705,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { _OptionCheckBox( context, 'Enable recording session', 'enable-record-session', enabled: enabled, fakeValue: fakeValue), - if (Platform.isWindows) + if (isWindows) _OptionCheckBox( context, 'Enable blocking user input', 'enable-block-input', enabled: enabled, fakeValue: fakeValue), @@ -845,7 +845,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { bool value = bind.mainIsShareRdp(); return Offstage( - offstage: !(Platform.isWindows && bind.mainIsInstalled()), + offstage: !(isWindows && bind.mainIsInstalled()), child: GestureDetector( child: Row( children: [ diff --git a/flutter/lib/desktop/pages/desktop_tab_page.dart b/flutter/lib/desktop/pages/desktop_tab_page.dart index 526c36dc8..0b3053ab6 100644 --- a/flutter/lib/desktop/pages/desktop_tab_page.dart +++ b/flutter/lib/desktop/pages/desktop_tab_page.dart @@ -90,7 +90,7 @@ class _DesktopTabPageState extends State { ), ), ))); - return Platform.isMacOS || kUseCompatibleUiMode + return isMacOS || kUseCompatibleUiMode ? tabWidget : Obx( () => DragToResizeArea( diff --git a/flutter/lib/desktop/pages/file_manager_page.dart b/flutter/lib/desktop/pages/file_manager_page.dart index 687c9520d..c429fa245 100644 --- a/flutter/lib/desktop/pages/file_manager_page.dart +++ b/flutter/lib/desktop/pages/file_manager_page.dart @@ -93,7 +93,7 @@ class _FileManagerPageState extends State .showLoading(translate('Connecting...'), onCancel: closeConnection); }); Get.put(_ffi, tag: 'ft_${widget.id}'); - if (!Platform.isLinux) { + if (!isLinux) { WakelockPlus.enable(); } debugPrint("File manager page init success with id ${widget.id}"); @@ -106,7 +106,7 @@ class _FileManagerPageState extends State model.close().whenComplete(() { _ffi.close(); _ffi.dialogManager.dismissAll(); - if (!Platform.isLinux) { + if (!isLinux) { WakelockPlus.disable(); } Get.delete(tag: 'ft_${widget.id}'); @@ -1298,7 +1298,7 @@ class _FileManagerViewState extends State { onPointerSignal: (e) { if (e is PointerScrollEvent) { final sc = _breadCrumbScroller; - final scale = Platform.isWindows ? 2 : 4; + final scale = isWindows ? 2 : 4; sc.jumpTo(sc.offset + e.scrollDelta.dy / scale); } }, diff --git a/flutter/lib/desktop/pages/file_manager_tab_page.dart b/flutter/lib/desktop/pages/file_manager_tab_page.dart index 51b953560..054ef91be 100644 --- a/flutter/lib/desktop/pages/file_manager_tab_page.dart +++ b/flutter/lib/desktop/pages/file_manager_tab_page.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:io'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; @@ -104,7 +103,7 @@ class _FileManagerTabPageState extends State { labelGetter: DesktopTab.tablabelGetter, )), ); - return Platform.isMacOS || kUseCompatibleUiMode + return isMacOS || kUseCompatibleUiMode ? tabWidget : SubWindowDragToResizeArea( child: tabWidget, diff --git a/flutter/lib/desktop/pages/port_forward_tab_page.dart b/flutter/lib/desktop/pages/port_forward_tab_page.dart index c03fdb7a7..ce8bbd284 100644 --- a/flutter/lib/desktop/pages/port_forward_tab_page.dart +++ b/flutter/lib/desktop/pages/port_forward_tab_page.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:io'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; @@ -113,7 +112,7 @@ class _PortForwardTabPageState extends State { labelGetter: DesktopTab.tablabelGetter, )), ); - return Platform.isMacOS || kUseCompatibleUiMode + return isMacOS || kUseCompatibleUiMode ? tabWidget : Obx( () => SubWindowDragToResizeArea( diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 740e6cfd7..3fb56d262 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:io'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; @@ -125,7 +124,7 @@ class _RemotePageState extends State _ffi.dialogManager .showLoading(translate('Connecting...'), onCancel: closeConnection); }); - if (!Platform.isLinux) { + if (!isLinux) { WakelockPlus.enable(); } @@ -160,7 +159,7 @@ class _RemotePageState extends State // On windows, we use `focus` way to handle keyboard better. // Now on Linux, there's some rdev issues which will break the input. // We disable the `focus` way for non-Windows temporarily. - if (Platform.isWindows) { + if (isWindows) { _isWindowBlur = true; // unfocus the primary-focus when the whole window is lost focus, // and let OS to handle events instead. @@ -172,7 +171,7 @@ class _RemotePageState extends State void onWindowFocus() { super.onWindowFocus(); // See [onWindowBlur]. - if (Platform.isWindows) { + if (isWindows) { _isWindowBlur = false; } } @@ -182,10 +181,10 @@ class _RemotePageState extends State super.onWindowRestore(); // On windows, we use `onWindowRestore` way to handle window restore from // a minimized state. - if (Platform.isWindows) { + if (isWindows) { _isWindowBlur = false; } - if (!Platform.isLinux) { + if (!isLinux) { WakelockPlus.enable(); } } @@ -194,7 +193,7 @@ class _RemotePageState extends State @override void onWindowMaximize() { super.onWindowMaximize(); - if (!Platform.isLinux) { + if (!isLinux) { WakelockPlus.enable(); } } @@ -202,7 +201,7 @@ class _RemotePageState extends State @override void onWindowMinimize() { super.onWindowMinimize(); - if (!Platform.isLinux) { + if (!isLinux) { WakelockPlus.disable(); } } @@ -228,7 +227,7 @@ class _RemotePageState extends State await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); } - if (!Platform.isLinux) { + if (!isLinux) { await WakelockPlus.disable(); } await Get.delete(tag: widget.id); @@ -266,7 +265,7 @@ class _RemotePageState extends State debugPrint( "onFocusChange(window active:${!_isWindowBlur}) $imageFocused"); // See [onWindowBlur]. - if (Platform.isWindows) { + if (isWindows) { if (_isWindowBlur) { imageFocused = false; Future.delayed(Duration.zero, () { @@ -362,7 +361,7 @@ class _RemotePageState extends State } } // See [onWindowBlur]. - if (!Platform.isWindows) { + if (!isWindows) { if (!_rawKeyFocusNode.hasFocus) { _rawKeyFocusNode.requestFocus(); } @@ -385,7 +384,7 @@ class _RemotePageState extends State } } // See [onWindowBlur]. - if (!Platform.isWindows) { + if (!isWindows) { _ffi.inputModel.enterOrLeave(false); } } @@ -537,7 +536,7 @@ class _ImagePaintState extends State { double getCursorScale() { var c = Provider.of(context); var cursorScale = 1.0; - if (Platform.isWindows) { + if (isWindows) { // debug win10 if (zoomCursor.value && isViewAdaptive()) { cursorScale = s * c.devicePixelRatio; @@ -604,8 +603,8 @@ class _ImagePaintState extends State { c, s, Offset( - Platform.isLinux ? c.x.toInt().toDouble() : c.x, - Platform.isLinux ? c.y.toInt().toDouble() : c.y, + isLinux ? c.x.toInt().toDouble() : c.x, + isLinux ? c.y.toInt().toDouble() : c.y, ), c.size, isViewOriginal()) diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index e4e9431fc..cdca474ab 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -1,6 +1,5 @@ import 'dart:convert'; import 'dart:async'; -import 'dart:io'; import 'dart:ui' as ui; import 'package:desktop_multi_window/desktop_multi_window.dart'; @@ -127,7 +126,7 @@ class _ConnectionTabPageState extends State { tryMoveToScreenAndSetFullscreen(screenRect); if (tabController.length == 0) { // Show the hidden window. - if (Platform.isMacOS && stateGlobal.closeOnFullscreen == true) { + if (isMacOS && stateGlobal.closeOnFullscreen == true) { stateGlobal.setFullscreen(true); } // Reset the state @@ -328,7 +327,7 @@ class _ConnectionTabPageState extends State { ), ), ); - return Platform.isMacOS || kUseCompatibleUiMode + return isMacOS || kUseCompatibleUiMode ? tabWidget : Obx(() => SubWindowDragToResizeArea( key: contentKey, diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index 8b0bf5d17..26bef1f10 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -1,7 +1,6 @@ // original cm window in Sciter version. import 'dart:async'; -import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; @@ -52,7 +51,7 @@ class _DesktopServerPageState extends State @override void onWindowClose() { Future.wait([gFFI.serverModel.closeAll(), gFFI.close()]).then((_) { - if (Platform.isMacOS) { + if (isMacOS) { RdPlatformChannel.instance.terminate(); } else { windowManager.setPreventClose(false); @@ -651,7 +650,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> { translate('Enable recording session'), ), // only windows support block input - if (Platform.isWindows) + if (isWindows) buildPermissionIcon( client.blockInput, Icons.block, diff --git a/flutter/lib/desktop/screen/desktop_remote_screen.dart b/flutter/lib/desktop/screen/desktop_remote_screen.dart index 255f1a5b2..e88078eb2 100644 --- a/flutter/lib/desktop/screen/desktop_remote_screen.dart +++ b/flutter/lib/desktop/screen/desktop_remote_screen.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/desktop/pages/remote_tab_page.dart'; @@ -28,7 +26,7 @@ class DesktopRemoteScreen extends StatelessWidget { child: Scaffold( // Set transparent background for padding the resize area out of the flutter view. // This allows the wallpaper goes through our resize area. (Linux only now). - backgroundColor: Platform.isLinux ? Colors.transparent : null, + backgroundColor: isLinux ? Colors.transparent : null, body: ConnectionTabPage( params: params, ), diff --git a/flutter/lib/desktop/widgets/kb_layout_type_chooser.dart b/flutter/lib/desktop/widgets/kb_layout_type_chooser.dart index 9497c2eec..7828dd4a0 100644 --- a/flutter/lib/desktop/widgets/kb_layout_type_chooser.dart +++ b/flutter/lib/desktop/widgets/kb_layout_type_chooser.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_hbb/consts.dart'; @@ -175,9 +174,9 @@ String getLocalPlatformForKBLayoutType(String peerPlatform) { return localPlatform; } - if (Platform.isWindows) { + if (isWindows) { localPlatform = kPeerPlatformWindows; - } else if (Platform.isLinux) { + } else if (isLinux) { localPlatform = kPeerPlatformLinux; } // to-do: web desktop support ? diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 2aecadb56..3f4ade694 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -1,6 +1,5 @@ import 'dart:convert'; import 'dart:async'; -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -112,10 +111,10 @@ class _ToolbarTheme { static const double iconRadius = 8; static const double elevation = 3; - static double dividerSpaceToAction = Platform.isWindows ? 8 : 14; + static double dividerSpaceToAction = isWindows ? 8 : 14; - static double menuBorderRadius = Platform.isWindows ? 5.0 : 7.0; - static EdgeInsets menuPadding = Platform.isWindows + static double menuBorderRadius = isWindows ? 5.0 : 7.0; + static EdgeInsets menuPadding = isWindows ? EdgeInsets.fromLTRB(4, 12, 4, 12) : EdgeInsets.fromLTRB(6, 14, 6, 14); static const double menuButtonBorderRadius = 3.0; diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index e6b622088..8d84de744 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:io'; import 'dart:math'; import 'dart:ui' as ui; @@ -392,12 +391,12 @@ class DesktopTab extends StatelessWidget { child: Row( children: [ Offstage( - offstage: !Platform.isMacOS, + offstage: !isMacOS, child: const SizedBox( width: 78, )), Offstage( - offstage: kUseCompatibleUiMode || Platform.isMacOS, + offstage: kUseCompatibleUiMode || isMacOS, child: Row(children: [ Offstage( offstage: !showLogo, @@ -585,7 +584,7 @@ class WindowActionPanelState extends State notMainWindowClose(WindowController controller) async { if (widget.tabController.length != 0) { debugPrint("close not emtpy multiwindow from taskbar"); - if (Platform.isWindows) { + if (isWindows) { await controller.show(); await controller.focus(); final res = await widget.onClose?.call() ?? true; @@ -620,7 +619,7 @@ class WindowActionPanelState extends State await rustDeskWinManager.unregisterActiveWindow(kMainWindowId); } // macOS specific workaround, the window is not hiding when in fullscreen. - if (Platform.isMacOS && await windowManager.isFullScreen()) { + if (isMacOS && await windowManager.isFullScreen()) { stateGlobal.closeOnFullscreen ??= true; await windowManager.setFullScreen(false); await macOSWindowClose( @@ -634,7 +633,7 @@ class WindowActionPanelState extends State } else { // it's safe to hide the subwindow final controller = WindowController.fromWindowId(kWindowId!); - if (Platform.isMacOS) { + if (isMacOS) { // onWindowClose() maybe called multiple times because of loopCloseWindow() in remote_tab_page.dart. // use ??= to make sure the value is set on first call. @@ -670,7 +669,7 @@ class WindowActionPanelState extends State child: Row( children: [ Offstage( - offstage: !widget.showMinimize || Platform.isMacOS, + offstage: !widget.showMinimize || isMacOS, child: ActionIcon( message: 'Minimize', icon: IconFont.min, @@ -684,7 +683,7 @@ class WindowActionPanelState extends State isClose: false, )), Offstage( - offstage: !widget.showMaximize || Platform.isMacOS, + offstage: !widget.showMaximize || isMacOS, child: Obx(() => ActionIcon( message: stateGlobal.isMaximized.isTrue ? 'Restore' @@ -698,7 +697,7 @@ class WindowActionPanelState extends State isClose: false, ))), Offstage( - offstage: !widget.showClose || Platform.isMacOS, + offstage: !widget.showClose || isMacOS, child: ActionIcon( message: 'Close', icon: IconFont.close, diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index e7e5aee22..25089871e 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -48,7 +48,7 @@ Future main(List args) async { if (args.isNotEmpty && args.first == 'multi_window') { kWindowId = int.parse(args[1]); stateGlobal.setWindowId(kWindowId!); - if (!Platform.isMacOS) { + if (!isMacOS) { WindowController.fromWindowId(kWindowId!).showTitleBar(false); } final argument = args[2].isEmpty diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index c22feebed..9363d8c3f 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -57,6 +57,7 @@ class _RemotePageState extends State { @override void initState() { super.initState(); + gFFI.ffiModel.updateEventListener(sessionId, widget.id); gFFI.start( widget.id, password: widget.password, @@ -69,7 +70,6 @@ class _RemotePageState extends State { }); WakelockPlus.enable(); _physicalFocusNode.requestFocus(); - gFFI.ffiModel.updateEventListener(sessionId, widget.id); gFFI.inputModel.listenToMouse(true); gFFI.qualityMonitorModel.checkShowQualityMonitor(sessionId); keyboardSubscription = diff --git a/flutter/lib/models/desktop_render_texture.dart b/flutter/lib/models/desktop_render_texture.dart index e56ba5e16..2e3c0ead6 100644 --- a/flutter/lib/models/desktop_render_texture.dart +++ b/flutter/lib/models/desktop_render_texture.dart @@ -11,8 +11,8 @@ import 'package:texture_rgba_renderer/texture_rgba_renderer.dart' if (dart.library.html) 'package:flutter_hbb/web/texture_rgba_renderer.dart'; // Feature flutter_texture_render need to be enabled if feature gpucodec is enabled. -final useTextureRender = - bind.mainHasPixelbufferTextureRender() || bind.mainHasGpuTextureRender(); +final useTextureRender = !isWeb && + (bind.mainHasPixelbufferTextureRender() || bind.mainHasGpuTextureRender()); class _PixelbufferTexture { int _textureKey = -1; diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index 5adae878c..c32ec5405 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; @@ -292,7 +291,7 @@ class FileController { name: isLocal ? "local_show_hidden" : "remote_show_hidden")) .isNotEmpty; options.value.isWindows = isLocal - ? Platform.isWindows + ? isWindows : rootState.target?.ffiModel.pi.platform == kPeerPlatformWindows; await Future.delayed(Duration(milliseconds: 100)); diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 1e3136e94..7540a5b41 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'dart:math'; import 'dart:typed_data'; import 'dart:ui' as ui; @@ -1537,7 +1536,7 @@ class CursorData { } if (_doubleToInt(oldScale) != _doubleToInt(scale)) { - if (Platform.isWindows) { + if (isWindows) { data = img2 .copyResize( image, @@ -1616,7 +1615,7 @@ class PredefinedCursor { data, defaultImg.width, defaultImg.height, ui.PixelFormat.rgba8888); double scale = 1.0; - if (Platform.isWindows) { + if (isWindows) { data = _image2!.getBytes(order: img2.ChannelOrder.bgra); } else { data = Uint8List.fromList(img2.encodePng(_image2!)); @@ -1841,7 +1840,7 @@ class CursorModel with ChangeNotifier { Uint8List? data; img2.Image imgOrigin = img2.Image.fromBytes( width: w, height: h, bytes: rgba.buffer, order: img2.ChannelOrder.rgba); - if (Platform.isWindows) { + if (isWindows) { data = imgOrigin.getBytes(order: img2.ChannelOrder.bgra); } else { ByteData? imgBytes = @@ -2200,6 +2199,7 @@ class FFI { imageModel.id = id; cursorModel.peerId = id; } + // If tabWindowId != null, this session is a "tab -> window" one. // Else this session is a new one. if (tabWindowId == null) { @@ -2235,6 +2235,10 @@ class FFI { textureModel.updateCurrentDisplay(display ?? 0); } final stream = bind.sessionStart(sessionId: sessionId, id: id); + if (isWeb) { + return; + } + final cb = ffiModel.startEventListener(sessionId, id); // Force refresh displays. diff --git a/flutter/lib/models/native_model.dart b/flutter/lib/models/native_model.dart index 53eeca572..9460f12bf 100644 --- a/flutter/lib/models/native_model.dart +++ b/flutter/lib/models/native_model.dart @@ -111,13 +111,13 @@ class PlatformFFI { /// Init the FFI class, loads the native Rust core library. Future init(String appType) async { _appType = appType; - final dylib = Platform.isAndroid + final dylib = isAndroid ? DynamicLibrary.open('librustdesk.so') - : Platform.isLinux + : isLinux ? DynamicLibrary.open('librustdesk.so') - : Platform.isWindows + : isWindows ? DynamicLibrary.open('librustdesk.dll') - : Platform.isMacOS + : isMacOS ? DynamicLibrary.open("liblibrustdesk.dylib") : DynamicLibrary.process(); debugPrint('initializing FFI $_appType'); @@ -131,11 +131,11 @@ class PlatformFFI { } _ffiBind = RustdeskImpl(dylib); - if (Platform.isLinux) { + if (isLinux) { // Start a dbus service, no need to await _ffiBind.mainStartDbusServer(); _ffiBind.mainStartPa(); - } else if (Platform.isMacOS && isMain) { + } else if (isMacOS && isMain) { // Start ipc service for uri links. _ffiBind.mainStartIpcUrlServer(); } @@ -155,20 +155,20 @@ class PlatformFFI { String id = 'NA'; String name = 'Flutter'; DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); - if (Platform.isAndroid) { + if (isAndroid) { AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; name = '${androidInfo.brand}-${androidInfo.model}'; id = androidInfo.id.hashCode.toString(); androidVersion = androidInfo.version.sdkInt; - } else if (Platform.isIOS) { + } else if (isIOS) { IosDeviceInfo iosInfo = await deviceInfo.iosInfo; name = iosInfo.utsname.machine; id = iosInfo.identifierForVendor.hashCode.toString(); - } else if (Platform.isLinux) { + } else if (isLinux) { LinuxDeviceInfo linuxInfo = await deviceInfo.linuxInfo; name = linuxInfo.name; id = linuxInfo.machineId ?? linuxInfo.id; - } else if (Platform.isWindows) { + } else if (isWindows) { try { // request windows build number to fix overflow on win7 windowsBuildNumber = getWindowsTargetBuildNumber(); @@ -180,7 +180,7 @@ class PlatformFFI { name = "unknown"; id = "unknown"; } - } else if (Platform.isMacOS) { + } else if (isMacOS) { MacOsDeviceInfo macOsInfo = await deviceInfo.macOsInfo; name = macOsInfo.computerName; id = macOsInfo.systemGUID ?? ''; diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index 72013fd0b..d62230c72 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/consts.dart'; @@ -383,7 +382,7 @@ class ServerModel with ChangeNotifier { // ugly is here, because for desktop, below is useless await bind.mainStartService(); updateClientState(); - if (Platform.isAndroid) { + if (isAndroid) { WakelockPlus.enable(); } } @@ -395,7 +394,7 @@ class ServerModel with ChangeNotifier { await parent.target?.invokeMethod("stop_service"); await bind.mainStopService(); notifyListeners(); - if (!Platform.isLinux) { + if (!isLinux) { // current linux is not supported WakelockPlus.disable(); } diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index 0d95b560b..58e216c34 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; @@ -60,7 +58,7 @@ class StateGlobal { _resizeEdgeSize.value = isMaximized.isTrue ? kMaximizeEdgeSize : kWindowEdgeSize; } - if (!Platform.isMacOS) { + if (!isMacOS) { _windowBorderWidth.value = v ? 0 : kWindowBorderWidth; } } @@ -84,7 +82,7 @@ class StateGlobal { final wc = WindowController.fromWindowId(windowId); wc.setFullscreen(_fullscreen.isTrue).then((_) { // https://github.com/leanflutter/window_manager/issues/131#issuecomment-1111587982 - if (Platform.isWindows && !v) { + if (isWindows && !v) { Future.delayed(Duration.zero, () async { final frame = await wc.getFrame(); final newRect = Rect.fromLTWH( diff --git a/flutter/lib/utils/multi_window_manager.dart b/flutter/lib/utils/multi_window_manager.dart index 4c498023f..0d157cb69 100644 --- a/flutter/lib/utils/multi_window_manager.dart +++ b/flutter/lib/utils/multi_window_manager.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:io'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/foundation.dart'; @@ -139,7 +138,7 @@ class RustDeskMultiWindowManager { overrideType: type, )); } - if (Platform.isMacOS) { + if (isMacOS) { Future.microtask(() => windowController.show()); } registerActiveWindow(windowId); diff --git a/flutter/lib/utils/platform_channel.dart b/flutter/lib/utils/platform_channel.dart index d7539934a..eaea4e79f 100644 --- a/flutter/lib/utils/platform_channel.dart +++ b/flutter/lib/utils/platform_channel.dart @@ -1,8 +1,7 @@ -import 'dart:io'; - import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/main.dart'; +import 'package:flutter_hbb/common.dart'; enum SystemWindowTheme { light, dark } @@ -19,7 +18,7 @@ class RdPlatformChannel { /// Change the theme of the system window Future changeSystemWindowTheme(SystemWindowTheme theme) { - assert(Platform.isMacOS); + assert(isMacOS); if (kDebugMode) { print( "[Window ${kWindowId ?? 'Main'}] change system window theme to ${theme.name}"); @@ -30,7 +29,7 @@ class RdPlatformChannel { /// Terminate .app manually. Future terminate() { - assert(Platform.isMacOS); + assert(isMacOS); return _osxMethodChannel.invokeMethod("terminate"); } } diff --git a/flutter/lib/web/bridge.dart b/flutter/lib/web/bridge.dart index 5c6dc8c98..03fb4d158 100644 --- a/flutter/lib/web/bridge.dart +++ b/flutter/lib/web/bridge.dart @@ -78,12 +78,19 @@ class RustdeskImpl { required String password, required bool isSharedPassword, dynamic hint}) { - throw UnimplementedError(); + return js.context.callMethod('setByName', [ + 'session_add_sync', + jsonEncode({'id': id, 'password': password}) + ]); } Stream sessionStart( {required UuidValue sessionId, required String id, dynamic hint}) { - throw UnimplementedError(); + js.context.callMethod('setByName', [ + 'session_start', + jsonEncode({'id': id}) + ]); + return Stream.empty(); } Future sessionGetRemember( @@ -93,17 +100,19 @@ class RustdeskImpl { Future sessionGetToggleOption( {required UuidValue sessionId, required String arg, dynamic hint}) { - throw UnimplementedError(); + return Future( + () => sessionGetToggleOptionSync(sessionId: sessionId, arg: arg)); } bool sessionGetToggleOptionSync( {required UuidValue sessionId, required String arg, dynamic hint}) { - throw UnimplementedError(); + return 'true' == js.context.callMethod('getByName', ['option:toggle', arg]); } Future sessionGetOption( {required UuidValue sessionId, required String arg, dynamic hint}) { - throw UnimplementedError(); + return Future( + () => js.context.callMethod('getByName', ['option:peer', arg])); } Future sessionLogin( @@ -122,7 +131,7 @@ class RustdeskImpl { } Future sessionClose({required UuidValue sessionId, dynamic hint}) { - throw UnimplementedError(); + return Future(() => js.context.callMethod('setByName', ['session_close'])); } Future sessionRefresh( @@ -165,7 +174,8 @@ class RustdeskImpl { Future sessionGetFlutterOption( {required UuidValue sessionId, required String k, dynamic hint}) { - throw UnimplementedError(); + return Future( + () => js.context.callMethod('getByName', ['option:flutter:peer', k])); } Future sessionSetFlutterOption( @@ -173,12 +183,16 @@ class RustdeskImpl { required String k, required String v, dynamic hint}) { - throw UnimplementedError(); + return Future(() => js.context.callMethod('setByName', [ + 'option:flutter:peer', + jsonEncode({'name': k, 'value': v}) + ])); } Future sessionGetFlutterOptionByPeerId( {required String id, required String k, dynamic hint}) { - return Future.value(null); + return Future( + () => js.context.callMethod('getByName', ['option:flutter:peer', k])); } int getNextTextureKey({dynamic hint}) { @@ -563,26 +577,30 @@ class RustdeskImpl { Future mainSetOption( {required String key, required String value, dynamic hint}) { - return js.context.callMethod('setByName', [ + js.context.callMethod('setByName', [ 'option', jsonEncode({'name': key, 'value': value}) ]); + return Future.value(); } + // get server settings Future mainGetOptions({dynamic hint}) { - throw UnimplementedError(); + return Future(() => mainGetOptionsSync()); } + // get server settings String mainGetOptionsSync({dynamic hint}) { - throw UnimplementedError(); + return js.context.callMethod('getByName', ['options']); } Future mainSetOptions({required String json, dynamic hint}) { - throw UnimplementedError(); + return Future(() => js.context.callMethod('setByName', ['options', json])); } Future mainTestIfValidServer({required String server, dynamic hint}) { - throw UnimplementedError(); + // TODO: implement + return Future.value(''); } Future mainSetSocks( @@ -652,7 +670,7 @@ class RustdeskImpl { } Future mainGetApiServer({dynamic hint}) { - throw UnimplementedError(); + return Future(() => js.context.callMethod('getByName', ['api_server'])); } Future mainPostRequest( @@ -809,7 +827,11 @@ class RustdeskImpl { } Future mainHandleRelayId({required String id, dynamic hint}) { - throw UnimplementedError(); + var newId = id; + if (id.endsWith("\\r") || id.endsWith("/r")) { + newId = id.substring(0, id.length - 2); + } + return Future.value(newId); } String mainGetMainDisplay({dynamic hint}) { diff --git a/flutter/web/README.md b/flutter/web/README.md index d7cd29a68..e605e72c0 100644 --- a/flutter/web/README.md +++ b/flutter/web/README.md @@ -6,10 +6,12 @@ - [x] Outgoing - [ ] Address book +- [ ] Force relay ### Unsupported 1. Incoming 2. LAN +3. Gpu texture render. We use WebGL instead. ### No plans diff --git a/flutter/web/js/src/connection.ts b/flutter/web/js/src/connection.ts index b6707b4d6..9d89fd231 100644 --- a/flutter/web/js/src/connection.ts +++ b/flutter/web/js/src/connection.ts @@ -6,7 +6,7 @@ import * as sha256 from "fast-sha256"; import * as globals from "./globals"; import { decompress, mapKey, sleep } from "./common"; -const PORT = 21116; +export const PORT = 21116; const HOSTS = [ "rs-sg.rustdesk.com", "rs-cn.rustdesk.com", @@ -15,7 +15,7 @@ const HOSTS = [ let HOST = localStorage.getItem("rendezvous-server") || HOSTS[0]; const SCHEMA = "ws://"; -type MsgboxCallback = (type: string, title: string, text: string) => void; +type MsgboxCallback = (type: string, title: string, text: string, link: string) => void; type DrawCallback = (data: Uint8Array) => void; //const cursorCanvas = document.createElement("canvas"); @@ -41,6 +41,7 @@ export default class Connection { this._msgs = []; this._id = ""; this._videoTestSpeed = [0, 0]; + this._options = {}; //this._cursors = {}; } @@ -318,8 +319,8 @@ export default class Connection { } } - msgbox(type_: string, title: string, text: string) { - this._msgbox?.(type_, title, text); + msgbox(type_: string, title: string, text: string, link: string = '') { + this._msgbox?.(type_, title, text, link); } draw(frame: any) { @@ -541,9 +542,20 @@ export default class Connection { return this._options[name]; } + getToggleOption(name: string): Boolean { + // TODO: more default settings + const defaultToggleTrue = [ + 'show-remote-cursor', + 'privacy-mode', + 'enable-file-transfer', + 'allow_swap_key', + ]; + return this._options[name] || (defaultToggleTrue.includes(name) ? true : false); + } + // TODO: getStatus(): String { - return JSON.stringify({status_num: 10}); + return JSON.stringify({ status_num: 10 }); } // TODO: @@ -558,8 +570,10 @@ export default class Connection { } this._options["tm"] = new Date().getTime(); const peers = globals.getPeers(); - peers[this._id] = this._options; - localStorage.setItem("peers", JSON.stringify(peers)); + if (peers) { + peers[this._id] = this._options; + localStorage.setItem("peers", JSON.stringify(peers)); + } } inputKey( diff --git a/flutter/web/js/src/globals.js b/flutter/web/js/src/globals.js index 992a7f1a6..8ae2ac115 100644 --- a/flutter/web/js/src/globals.js +++ b/flutter/web/js/src/globals.js @@ -1,4 +1,5 @@ import Connection from "./connection"; +import PORT from "./connection"; import _sodium from "libsodium-wrappers"; import { CursorData } from "./message"; import { loadVp9 } from "./codec"; @@ -16,11 +17,11 @@ export function isDesktop() { return !isMobile(); } -export function msgbox(type, title, text) { +export function msgbox(type, title, text, link) { if (!type || (type == 'error' && !text)) return; const text2 = text.toLowerCase(); var hasRetry = checkIfRetry(type, title, text) ? 'true' : ''; - onGlobalEvent(JSON.stringify({ name: 'msgbox', type, title, text, hasRetry })); + onGlobalEvent(JSON.stringify({ name: 'msgbox', type, title, text, link: link ?? '', hasRetry })); } function jsonfyForDart(payload) { @@ -257,13 +258,17 @@ window.setByName = (name, value) => { value = JSON.parse(value); localStorage.setItem(value.name, value.value); break; - case 'option:local': + case 'options': value = JSON.parse(value); - localStorage.setItem('option:local:' + value.name, value.value); + for (const [key, value] of Object.entries(value)) { + localStorage.setItem(key, value); + } break; + case 'option:local': case 'option:flutter:local': + case 'option:flutter:peer': value = JSON.parse(value); - localStorage.setItem('option:flutter:local:' + value.name, value.value); + localStorage.setItem(name + ':' + value.name, value.value); break; case 'peer_option': value = JSON.parse(value); @@ -281,6 +286,14 @@ window.setByName = (name, value) => { case 'discover': // TODO: discover break; + case 'session_add_sync': + return sessionAdd(value); + case 'session_start': + sessionStart(value); + break; + case 'session_close': + sessionClose(value); + break; default: break; } @@ -317,17 +330,32 @@ function _getByName(name, arg) { return curConn.getOption(arg) || false; case 'option': return localStorage.getItem(arg); + case 'options': + const keys = [ + 'custom-rendezvous-server', + 'relay-server', + 'api-server', + 'key' + ]; + const obj = {}; + keys.forEach(key => { + const v = localStorage.getItem(key); + if (v) obj[key] = v; + }); + return JSON.stringify(obj); case 'option:local': - return localStorage.getItem('option:local:' + arg); case 'option:flutter:local': - return localStorage.getItem('option:flutter:local:' + arg); + case 'option:flutter:peer': + return localStorage.getItem(name + ':' + arg); case 'image_quality': return curConn.getImageQuality(); case 'translate': arg = JSON.parse(arg); return translate(arg.locale, arg.text); - case 'peer_option': + case 'option:peer': return curConn.getOption(arg); + case 'option:toggle': + return curConn.getToggleOption(arg); case 'get_conn_status': if (curConn) { return curConn.getStatus(); @@ -360,6 +388,8 @@ function _getByName(name, arg) { return localStorage.getItem('peers-recent') ?? '{}'; case 'load_lan_peers_sync': return localStorage.getItem('peers-lan') ?? '{}'; + case 'api_server': + return getApiServer(); } return ''; } @@ -391,15 +421,15 @@ window.init = async () => { } export function getPeers() { - return _getJsonObj('peers'); + return getJsonObj('peers'); } export function getRecentPeers() { - return _getJsonObj('peers-recent'); + return getJsonObj('peers-recent'); } export function getLanPeers() { - return _getJsonObj('peers-lan'); + return getJsonObj('peers-lan'); } export function getJsonObj(key) { @@ -456,3 +486,94 @@ function removeDiscovered(id) { } } // ========================== peers end =========================== + +// ========================== session begin ========================== +function sessionAdd(value) { + try { + const data = JSON.parse(value); + window.curConn?.close(); + const conn = new Connection(); + if (data['password']) { + // TODO: encrypt password + conn.setOption('password', data['password']) + } else { + conn.setOption('password', undefined); + } + setConn(conn); + return ''; + } catch (e) { + return e.message; + } +} + +function sessionStart(value) { + try { + const conn = getConn(); + if (!conn) { + return; + } + + const data = JSON.parse(value); + if (data['id']) { + startConn(data['id']); + } else { + msgbox('error', 'Error', 'No id found in session data ' + value, ''); + } + } catch (e) { + // TODO: better error handling + msgbox('error', 'Error', e.message, ''); + } +} + +function sessionClose(value) { + close(); +} +// ========================== session end =========================== + +// ========================== settings begin ========================== +function increasePort(host, offset) { + function isIPv6(str) { + const ipv6Pattern = /^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$/; + return ipv6Pattern.test(str); + } + + if (isIPv6(host)) { + if (host.startsWith('[')) { + let tmp = host.split(']:'); + if (tmp.length === 2) { + let port = parseInt(tmp[1]) || 0; + if (port > 0) { + return `${tmp[0]}]:${port + offset}`; + } + } + } + } else if (host.includes(':')) { + let tmp = host.split(':'); + if (tmp.length === 2) { + let port = parseInt(tmp[1]) || 0; + if (port > 0) { + return `${tmp[0]}:${port + offset}`; + } + } + } + return host; +} + +function getApiServer() { + const api_server = localStorage.getItem('api-server'); + if (api_server) { + return api_server; + } + + const custom_rendezvous_server = localStorage.getItem('custom-rendezvous-server'); + if (custom_rendezvous_server) { + let s = increasePort(custom_rendezvous_server, -2); + if (s == custom_rendezvous_server) { + return `http://${s}:${PORT - 2}`; + } else { + return `http://${s}`; + } + } + return 'https://admin.rustdesk.com'; +} +// ========================== settings end ===========================