Refact. Flutter web, mid commit (#7494)

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2024-03-24 11:23:06 +08:00 committed by GitHub
parent 96e1b5b0f6
commit 85cafda168
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 298 additions and 152 deletions

View file

@ -635,8 +635,12 @@ closeConnection({String? id}) {
gFFI.chatModel.hideChatOverlay(); gFFI.chatModel.hideChatOverlay();
Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/")); Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/"));
} else { } else {
final controller = Get.find<DesktopTabController>(); if (isWeb) {
controller.closeBy(id); Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/"));
} else {
final controller = Get.find<DesktopTabController>();
controller.closeBy(id);
}
} }
} }
@ -2980,7 +2984,6 @@ Future<bool> setServerConfig(
await bind.mainSetOption(key: 'relay-server', value: config.relayServer); await bind.mainSetOption(key: 'relay-server', value: config.relayServer);
await bind.mainSetOption(key: 'api-server', value: config.apiServer); await bind.mainSetOption(key: 'api-server', value: config.apiServer);
await bind.mainSetOption(key: 'key', value: config.key); await bind.mainSetOption(key: 'key', value: config.key);
final newApiServer = await bind.mainGetApiServer(); final newApiServer = await bind.mainGetApiServer();
if (oldApiServer.isNotEmpty && if (oldApiServer.isNotEmpty &&
oldApiServer != newApiServer && oldApiServer != newApiServer &&

View file

@ -625,7 +625,7 @@ class _DialogVerificationCodeField extends State<DialogVerificationCodeField> {
// software secure keyboard will take the focus since flutter 3.13 // software secure keyboard will take the focus since flutter 3.13
// request focus again when android account password obtain focus // request focus again when android account password obtain focus
if (Platform.isAndroid && widget.reRequestFocus) { if (isAndroid && widget.reRequestFocus) {
_focusNode.addListener(() { _focusNode.addListener(() {
if (_focusNode.hasFocus) { if (_focusNode.hasFocus) {
_timerReRequestFocus?.cancel(); _timerReRequestFocus?.cancel();
@ -694,7 +694,7 @@ class _PasswordWidgetState extends State<PasswordWidget> {
} }
// software secure keyboard will take the focus since flutter 3.13 // software secure keyboard will take the focus since flutter 3.13
// request focus again when android account password obtain focus // request focus again when android account password obtain focus
if (Platform.isAndroid && widget.reRequestFocus) { if (isAndroid && widget.reRequestFocus) {
_focusNode.addListener(() { _focusNode.addListener(() {
if (_focusNode.hasFocus) { if (_focusNode.hasFocus) {
_timerReRequestFocus?.cancel(); _timerReRequestFocus?.cancel();

View file

@ -1,5 +1,3 @@
import 'dart:io';
import 'package:bot_toast/bot_toast.dart'; import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -875,10 +873,10 @@ class RecentPeerCard extends BasePeerCard {
} }
// menuItems.add(await _openNewConnInOptAction(peer.id)); // menuItems.add(await _openNewConnInOptAction(peer.id));
menuItems.add(await _forceAlwaysRelayAction(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(_rdpAction(context, peer.id));
} }
if (Platform.isWindows) { if (isWindows) {
menuItems.add(_createShortCutAction(peer.id)); menuItems.add(_createShortCutAction(peer.id));
} }
menuItems.add(MenuEntryDivider()); menuItems.add(MenuEntryDivider());
@ -927,10 +925,10 @@ class FavoritePeerCard extends BasePeerCard {
} }
// menuItems.add(await _openNewConnInOptAction(peer.id)); // menuItems.add(await _openNewConnInOptAction(peer.id));
menuItems.add(await _forceAlwaysRelayAction(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(_rdpAction(context, peer.id));
} }
if (Platform.isWindows) { if (isWindows) {
menuItems.add(_createShortCutAction(peer.id)); menuItems.add(_createShortCutAction(peer.id));
} }
menuItems.add(MenuEntryDivider()); menuItems.add(MenuEntryDivider());
@ -979,11 +977,11 @@ class DiscoveredPeerCard extends BasePeerCard {
} }
// menuItems.add(await _openNewConnInOptAction(peer.id)); // menuItems.add(await _openNewConnInOptAction(peer.id));
menuItems.add(await _forceAlwaysRelayAction(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(_rdpAction(context, peer.id));
} }
menuItems.add(_wolAction(peer.id)); menuItems.add(_wolAction(peer.id));
if (Platform.isWindows) { if (isWindows) {
menuItems.add(_createShortCutAction(peer.id)); menuItems.add(_createShortCutAction(peer.id));
} }
@ -1027,10 +1025,10 @@ class AddressBookPeerCard extends BasePeerCard {
} }
// menuItems.add(await _openNewConnInOptAction(peer.id)); // menuItems.add(await _openNewConnInOptAction(peer.id));
// menuItems.add(await _forceAlwaysRelayAction(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(_rdpAction(context, peer.id));
} }
if (Platform.isWindows) { if (isWindows) {
menuItems.add(_createShortCutAction(peer.id)); menuItems.add(_createShortCutAction(peer.id));
} }
if (gFFI.abModel.current.canWrite()) { if (gFFI.abModel.current.canWrite()) {
@ -1154,10 +1152,10 @@ class MyGroupPeerCard extends BasePeerCard {
} }
// menuItems.add(await _openNewConnInOptAction(peer.id)); // menuItems.add(await _openNewConnInOptAction(peer.id));
// menuItems.add(await _forceAlwaysRelayAction(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(_rdpAction(context, peer.id));
} }
if (Platform.isWindows) { if (isWindows) {
menuItems.add(_createShortCutAction(peer.id)); menuItems.add(_createShortCutAction(peer.id));
} }
// menuItems.add(MenuEntryDivider()); // menuItems.add(MenuEntryDivider());

View file

@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -633,8 +632,8 @@ List<TToggleMenu> toolbarKeyboardToggles(FFI ffi) {
// swap key // swap key
if (ffiModel.keyboard && if (ffiModel.keyboard &&
((Platform.isMacOS && pi.platform != kPeerPlatformMacOS) || ((isMacOS && pi.platform != kPeerPlatformMacOS) ||
(!Platform.isMacOS && pi.platform == kPeerPlatformMacOS))) { (!isMacOS && pi.platform == kPeerPlatformMacOS))) {
final option = 'allow_swap_key'; final option = 'allow_swap_key';
final value = final value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option); bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);

View file

@ -115,16 +115,16 @@ const double kDefaultQuality = 50;
const double kMaxQuality = 100; const double kMaxQuality = 100;
const double kMaxMoreQuality = 2000; const double kMaxMoreQuality = 2000;
double kNewWindowOffset = Platform.isWindows double kNewWindowOffset = isWindows
? 56.0 ? 56.0
: Platform.isLinux : isLinux
? 50.0 ? 50.0
: Platform.isMacOS : isMacOS
? 30.0 ? 30.0
: 50.0; : 50.0;
EdgeInsets get kDragToResizeAreaPadding => EdgeInsets get kDragToResizeAreaPadding =>
!kUseCompatibleUiMode && Platform.isLinux !kUseCompatibleUiMode && isLinux
? stateGlobal.fullscreen.isTrue || stateGlobal.isMaximized.value ? stateGlobal.fullscreen.isTrue || stateGlobal.isMaximized.value
? EdgeInsets.zero ? EdgeInsets.zero
: EdgeInsets.all(5.0) : EdgeInsets.all(5.0)
@ -152,7 +152,7 @@ const kDefaultScrollDuration = Duration(milliseconds: 50);
const kDefaultMouseWheelThrottleDuration = Duration(milliseconds: 50); const kDefaultMouseWheelThrottleDuration = Duration(milliseconds: 50);
const kFullScreenEdgeSize = 0.0; const kFullScreenEdgeSize = 0.0;
const kMaximizeEdgeSize = 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 kWindowBorderWidth = 1.0;
const kDesktopMenuPadding = EdgeInsets.only(left: 12.0, right: 3.0); const kDesktopMenuPadding = EdgeInsets.only(left: 12.0, right: 3.0);

View file

@ -2,7 +2,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:auto_size_text/auto_size_text.dart'; import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -231,7 +230,7 @@ class _ConnectionPageState extends State<ConnectionPage>
if (eventName == 'minimize') { if (eventName == 'minimize') {
isWindowMinimized = true; isWindowMinimized = true;
} else if (eventName == 'maximize' || eventName == 'restore') { } else if (eventName == 'maximize' || eventName == 'restore') {
if (isWindowMinimized && Platform.isWindows) { if (isWindowMinimized && isWindows) {
// windows can't update when minimized. // windows can't update when minimized.
Get.forceAppUpdate(); Get.forceAppUpdate();
} }

View file

@ -469,7 +469,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
return buildInstallCard("", systemError, "", () {}); return buildInstallCard("", systemError, "", () {});
} }
if (Platform.isWindows && !bind.isDisableInstallation()) { if (isWindows && !bind.isDisableInstallation()) {
if (!bind.mainIsInstalled()) { if (!bind.mainIsInstalled()) {
return buildInstallCard( return buildInstallCard(
"", bind.isOutgoingOnly() ? "" : "install_tip", "Install", "", bind.isOutgoingOnly() ? "" : "install_tip", "Install",
@ -485,7 +485,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
bind.mainUpdateMe(); bind.mainUpdateMe();
}); });
} }
} else if (Platform.isMacOS) { } else if (isMacOS) {
if (!(bind.isOutgoingOnly() || if (!(bind.isOutgoingOnly() ||
bind.mainIsCanScreenRecording(prompt: false))) { bind.mainIsCanScreenRecording(prompt: false))) {
return buildInstallCard("Permissions", "config_screen", "Configure", return buildInstallCard("Permissions", "config_screen", "Configure",
@ -521,7 +521,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
// watchIsCanRecordAudio = true; // watchIsCanRecordAudio = true;
// }); // });
// } // }
} else if (Platform.isLinux) { } else if (isLinux) {
if (bind.isOutgoingOnly()) { if (bind.isOutgoingOnly()) {
return Container(); return Container();
} }
@ -570,7 +570,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
onPressed: () { onPressed: () {
SystemNavigator.pop(); // Close the application SystemNavigator.pop(); // Close the application
// https://github.com/flutter/flutter/issues/66631 // https://github.com/flutter/flutter/issues/66631
if (Platform.isWindows) { if (isWindows) {
exit(0); exit(0);
} }
}, },
@ -740,7 +740,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
} }
} }
if (watchIsCanRecordAudio) { if (watchIsCanRecordAudio) {
if (Platform.isMacOS) { if (isMacOS) {
Future.microtask(() async { Future.microtask(() async {
if ((await osxCanRecordAudio() == if ((await osxCanRecordAudio() ==
PermissionAuthorizeType.authorized)) { PermissionAuthorizeType.authorized)) {

View file

@ -414,7 +414,7 @@ class _GeneralState extends State<_General> {
} }
String getDefault() { String getDefault() {
if (Platform.isWindows) return translate('System Sound'); if (isWindows) return translate('System Sound');
return ''; return '';
} }
@ -434,7 +434,7 @@ class _GeneralState extends State<_General> {
return futureBuilder(future: () async { return futureBuilder(future: () async {
List<String> devices = (await bind.mainGetSoundInputs()).toList(); List<String> devices = (await bind.mainGetSoundInputs()).toList();
if (Platform.isWindows) { if (isWindows) {
devices.insert(0, translate('System Sound')); devices.insert(0, translate('System Sound'));
} }
String current = await getValue(); String current = await getValue();
@ -705,7 +705,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
_OptionCheckBox( _OptionCheckBox(
context, 'Enable recording session', 'enable-record-session', context, 'Enable recording session', 'enable-record-session',
enabled: enabled, fakeValue: fakeValue), enabled: enabled, fakeValue: fakeValue),
if (Platform.isWindows) if (isWindows)
_OptionCheckBox( _OptionCheckBox(
context, 'Enable blocking user input', 'enable-block-input', context, 'Enable blocking user input', 'enable-block-input',
enabled: enabled, fakeValue: fakeValue), enabled: enabled, fakeValue: fakeValue),
@ -845,7 +845,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
bool value = bind.mainIsShareRdp(); bool value = bind.mainIsShareRdp();
return Offstage( return Offstage(
offstage: !(Platform.isWindows && bind.mainIsInstalled()), offstage: !(isWindows && bind.mainIsInstalled()),
child: GestureDetector( child: GestureDetector(
child: Row( child: Row(
children: [ children: [

View file

@ -90,7 +90,7 @@ class _DesktopTabPageState extends State<DesktopTabPage> {
), ),
), ),
))); )));
return Platform.isMacOS || kUseCompatibleUiMode return isMacOS || kUseCompatibleUiMode
? tabWidget ? tabWidget
: Obx( : Obx(
() => DragToResizeArea( () => DragToResizeArea(

View file

@ -93,7 +93,7 @@ class _FileManagerPageState extends State<FileManagerPage>
.showLoading(translate('Connecting...'), onCancel: closeConnection); .showLoading(translate('Connecting...'), onCancel: closeConnection);
}); });
Get.put(_ffi, tag: 'ft_${widget.id}'); Get.put(_ffi, tag: 'ft_${widget.id}');
if (!Platform.isLinux) { if (!isLinux) {
WakelockPlus.enable(); WakelockPlus.enable();
} }
debugPrint("File manager page init success with id ${widget.id}"); debugPrint("File manager page init success with id ${widget.id}");
@ -106,7 +106,7 @@ class _FileManagerPageState extends State<FileManagerPage>
model.close().whenComplete(() { model.close().whenComplete(() {
_ffi.close(); _ffi.close();
_ffi.dialogManager.dismissAll(); _ffi.dialogManager.dismissAll();
if (!Platform.isLinux) { if (!isLinux) {
WakelockPlus.disable(); WakelockPlus.disable();
} }
Get.delete<FFI>(tag: 'ft_${widget.id}'); Get.delete<FFI>(tag: 'ft_${widget.id}');
@ -1298,7 +1298,7 @@ class _FileManagerViewState extends State<FileManagerView> {
onPointerSignal: (e) { onPointerSignal: (e) {
if (e is PointerScrollEvent) { if (e is PointerScrollEvent) {
final sc = _breadCrumbScroller; final sc = _breadCrumbScroller;
final scale = Platform.isWindows ? 2 : 4; final scale = isWindows ? 2 : 4;
sc.jumpTo(sc.offset + e.scrollDelta.dy / scale); sc.jumpTo(sc.offset + e.scrollDelta.dy / scale);
} }
}, },

View file

@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -104,7 +103,7 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
labelGetter: DesktopTab.tablabelGetter, labelGetter: DesktopTab.tablabelGetter,
)), )),
); );
return Platform.isMacOS || kUseCompatibleUiMode return isMacOS || kUseCompatibleUiMode
? tabWidget ? tabWidget
: SubWindowDragToResizeArea( : SubWindowDragToResizeArea(
child: tabWidget, child: tabWidget,

View file

@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -113,7 +112,7 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
labelGetter: DesktopTab.tablabelGetter, labelGetter: DesktopTab.tablabelGetter,
)), )),
); );
return Platform.isMacOS || kUseCompatibleUiMode return isMacOS || kUseCompatibleUiMode
? tabWidget ? tabWidget
: Obx( : Obx(
() => SubWindowDragToResizeArea( () => SubWindowDragToResizeArea(

View file

@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -125,7 +124,7 @@ class _RemotePageState extends State<RemotePage>
_ffi.dialogManager _ffi.dialogManager
.showLoading(translate('Connecting...'), onCancel: closeConnection); .showLoading(translate('Connecting...'), onCancel: closeConnection);
}); });
if (!Platform.isLinux) { if (!isLinux) {
WakelockPlus.enable(); WakelockPlus.enable();
} }
@ -160,7 +159,7 @@ class _RemotePageState extends State<RemotePage>
// On windows, we use `focus` way to handle keyboard better. // On windows, we use `focus` way to handle keyboard better.
// Now on Linux, there's some rdev issues which will break the input. // Now on Linux, there's some rdev issues which will break the input.
// We disable the `focus` way for non-Windows temporarily. // We disable the `focus` way for non-Windows temporarily.
if (Platform.isWindows) { if (isWindows) {
_isWindowBlur = true; _isWindowBlur = true;
// unfocus the primary-focus when the whole window is lost focus, // unfocus the primary-focus when the whole window is lost focus,
// and let OS to handle events instead. // and let OS to handle events instead.
@ -172,7 +171,7 @@ class _RemotePageState extends State<RemotePage>
void onWindowFocus() { void onWindowFocus() {
super.onWindowFocus(); super.onWindowFocus();
// See [onWindowBlur]. // See [onWindowBlur].
if (Platform.isWindows) { if (isWindows) {
_isWindowBlur = false; _isWindowBlur = false;
} }
} }
@ -182,10 +181,10 @@ class _RemotePageState extends State<RemotePage>
super.onWindowRestore(); super.onWindowRestore();
// On windows, we use `onWindowRestore` way to handle window restore from // On windows, we use `onWindowRestore` way to handle window restore from
// a minimized state. // a minimized state.
if (Platform.isWindows) { if (isWindows) {
_isWindowBlur = false; _isWindowBlur = false;
} }
if (!Platform.isLinux) { if (!isLinux) {
WakelockPlus.enable(); WakelockPlus.enable();
} }
} }
@ -194,7 +193,7 @@ class _RemotePageState extends State<RemotePage>
@override @override
void onWindowMaximize() { void onWindowMaximize() {
super.onWindowMaximize(); super.onWindowMaximize();
if (!Platform.isLinux) { if (!isLinux) {
WakelockPlus.enable(); WakelockPlus.enable();
} }
} }
@ -202,7 +201,7 @@ class _RemotePageState extends State<RemotePage>
@override @override
void onWindowMinimize() { void onWindowMinimize() {
super.onWindowMinimize(); super.onWindowMinimize();
if (!Platform.isLinux) { if (!isLinux) {
WakelockPlus.disable(); WakelockPlus.disable();
} }
} }
@ -228,7 +227,7 @@ class _RemotePageState extends State<RemotePage>
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values); overlays: SystemUiOverlay.values);
} }
if (!Platform.isLinux) { if (!isLinux) {
await WakelockPlus.disable(); await WakelockPlus.disable();
} }
await Get.delete<FFI>(tag: widget.id); await Get.delete<FFI>(tag: widget.id);
@ -266,7 +265,7 @@ class _RemotePageState extends State<RemotePage>
debugPrint( debugPrint(
"onFocusChange(window active:${!_isWindowBlur}) $imageFocused"); "onFocusChange(window active:${!_isWindowBlur}) $imageFocused");
// See [onWindowBlur]. // See [onWindowBlur].
if (Platform.isWindows) { if (isWindows) {
if (_isWindowBlur) { if (_isWindowBlur) {
imageFocused = false; imageFocused = false;
Future.delayed(Duration.zero, () { Future.delayed(Duration.zero, () {
@ -362,7 +361,7 @@ class _RemotePageState extends State<RemotePage>
} }
} }
// See [onWindowBlur]. // See [onWindowBlur].
if (!Platform.isWindows) { if (!isWindows) {
if (!_rawKeyFocusNode.hasFocus) { if (!_rawKeyFocusNode.hasFocus) {
_rawKeyFocusNode.requestFocus(); _rawKeyFocusNode.requestFocus();
} }
@ -385,7 +384,7 @@ class _RemotePageState extends State<RemotePage>
} }
} }
// See [onWindowBlur]. // See [onWindowBlur].
if (!Platform.isWindows) { if (!isWindows) {
_ffi.inputModel.enterOrLeave(false); _ffi.inputModel.enterOrLeave(false);
} }
} }
@ -537,7 +536,7 @@ class _ImagePaintState extends State<ImagePaint> {
double getCursorScale() { double getCursorScale() {
var c = Provider.of<CanvasModel>(context); var c = Provider.of<CanvasModel>(context);
var cursorScale = 1.0; var cursorScale = 1.0;
if (Platform.isWindows) { if (isWindows) {
// debug win10 // debug win10
if (zoomCursor.value && isViewAdaptive()) { if (zoomCursor.value && isViewAdaptive()) {
cursorScale = s * c.devicePixelRatio; cursorScale = s * c.devicePixelRatio;
@ -604,8 +603,8 @@ class _ImagePaintState extends State<ImagePaint> {
c, c,
s, s,
Offset( Offset(
Platform.isLinux ? c.x.toInt().toDouble() : c.x, isLinux ? c.x.toInt().toDouble() : c.x,
Platform.isLinux ? c.y.toInt().toDouble() : c.y, isLinux ? c.y.toInt().toDouble() : c.y,
), ),
c.size, c.size,
isViewOriginal()) isViewOriginal())

View file

@ -1,6 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
@ -127,7 +126,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
tryMoveToScreenAndSetFullscreen(screenRect); tryMoveToScreenAndSetFullscreen(screenRect);
if (tabController.length == 0) { if (tabController.length == 0) {
// Show the hidden window. // Show the hidden window.
if (Platform.isMacOS && stateGlobal.closeOnFullscreen == true) { if (isMacOS && stateGlobal.closeOnFullscreen == true) {
stateGlobal.setFullscreen(true); stateGlobal.setFullscreen(true);
} }
// Reset the state // Reset the state
@ -328,7 +327,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
), ),
), ),
); );
return Platform.isMacOS || kUseCompatibleUiMode return isMacOS || kUseCompatibleUiMode
? tabWidget ? tabWidget
: Obx(() => SubWindowDragToResizeArea( : Obx(() => SubWindowDragToResizeArea(
key: contentKey, key: contentKey,

View file

@ -1,7 +1,6 @@
// original cm window in Sciter version. // original cm window in Sciter version.
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -52,7 +51,7 @@ class _DesktopServerPageState extends State<DesktopServerPage>
@override @override
void onWindowClose() { void onWindowClose() {
Future.wait([gFFI.serverModel.closeAll(), gFFI.close()]).then((_) { Future.wait([gFFI.serverModel.closeAll(), gFFI.close()]).then((_) {
if (Platform.isMacOS) { if (isMacOS) {
RdPlatformChannel.instance.terminate(); RdPlatformChannel.instance.terminate();
} else { } else {
windowManager.setPreventClose(false); windowManager.setPreventClose(false);
@ -651,7 +650,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
translate('Enable recording session'), translate('Enable recording session'),
), ),
// only windows support block input // only windows support block input
if (Platform.isWindows) if (isWindows)
buildPermissionIcon( buildPermissionIcon(
client.blockInput, client.blockInput,
Icons.block, Icons.block,

View file

@ -1,5 +1,3 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/desktop/pages/remote_tab_page.dart'; import 'package:flutter_hbb/desktop/pages/remote_tab_page.dart';
@ -28,7 +26,7 @@ class DesktopRemoteScreen extends StatelessWidget {
child: Scaffold( child: Scaffold(
// Set transparent background for padding the resize area out of the flutter view. // 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). // 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( body: ConnectionTabPage(
params: params, params: params,
), ),

View file

@ -1,4 +1,3 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/consts.dart';
@ -175,9 +174,9 @@ String getLocalPlatformForKBLayoutType(String peerPlatform) {
return localPlatform; return localPlatform;
} }
if (Platform.isWindows) { if (isWindows) {
localPlatform = kPeerPlatformWindows; localPlatform = kPeerPlatformWindows;
} else if (Platform.isLinux) { } else if (isLinux) {
localPlatform = kPeerPlatformLinux; localPlatform = kPeerPlatformLinux;
} }
// to-do: web desktop support ? // to-do: web desktop support ?

View file

@ -1,6 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -112,10 +111,10 @@ class _ToolbarTheme {
static const double iconRadius = 8; static const double iconRadius = 8;
static const double elevation = 3; 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 double menuBorderRadius = isWindows ? 5.0 : 7.0;
static EdgeInsets menuPadding = Platform.isWindows static EdgeInsets menuPadding = isWindows
? EdgeInsets.fromLTRB(4, 12, 4, 12) ? EdgeInsets.fromLTRB(4, 12, 4, 12)
: EdgeInsets.fromLTRB(6, 14, 6, 14); : EdgeInsets.fromLTRB(6, 14, 6, 14);
static const double menuButtonBorderRadius = 3.0; static const double menuButtonBorderRadius = 3.0;

View file

@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'dart:ui' as ui; import 'dart:ui' as ui;
@ -392,12 +391,12 @@ class DesktopTab extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
Offstage( Offstage(
offstage: !Platform.isMacOS, offstage: !isMacOS,
child: const SizedBox( child: const SizedBox(
width: 78, width: 78,
)), )),
Offstage( Offstage(
offstage: kUseCompatibleUiMode || Platform.isMacOS, offstage: kUseCompatibleUiMode || isMacOS,
child: Row(children: [ child: Row(children: [
Offstage( Offstage(
offstage: !showLogo, offstage: !showLogo,
@ -585,7 +584,7 @@ class WindowActionPanelState extends State<WindowActionPanel>
notMainWindowClose(WindowController controller) async { notMainWindowClose(WindowController controller) async {
if (widget.tabController.length != 0) { if (widget.tabController.length != 0) {
debugPrint("close not emtpy multiwindow from taskbar"); debugPrint("close not emtpy multiwindow from taskbar");
if (Platform.isWindows) { if (isWindows) {
await controller.show(); await controller.show();
await controller.focus(); await controller.focus();
final res = await widget.onClose?.call() ?? true; final res = await widget.onClose?.call() ?? true;
@ -620,7 +619,7 @@ class WindowActionPanelState extends State<WindowActionPanel>
await rustDeskWinManager.unregisterActiveWindow(kMainWindowId); await rustDeskWinManager.unregisterActiveWindow(kMainWindowId);
} }
// macOS specific workaround, the window is not hiding when in fullscreen. // 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; stateGlobal.closeOnFullscreen ??= true;
await windowManager.setFullScreen(false); await windowManager.setFullScreen(false);
await macOSWindowClose( await macOSWindowClose(
@ -634,7 +633,7 @@ class WindowActionPanelState extends State<WindowActionPanel>
} else { } else {
// it's safe to hide the subwindow // it's safe to hide the subwindow
final controller = WindowController.fromWindowId(kWindowId!); final controller = WindowController.fromWindowId(kWindowId!);
if (Platform.isMacOS) { if (isMacOS) {
// onWindowClose() maybe called multiple times because of loopCloseWindow() in remote_tab_page.dart. // onWindowClose() maybe called multiple times because of loopCloseWindow() in remote_tab_page.dart.
// use ??= to make sure the value is set on first call. // use ??= to make sure the value is set on first call.
@ -670,7 +669,7 @@ class WindowActionPanelState extends State<WindowActionPanel>
child: Row( child: Row(
children: [ children: [
Offstage( Offstage(
offstage: !widget.showMinimize || Platform.isMacOS, offstage: !widget.showMinimize || isMacOS,
child: ActionIcon( child: ActionIcon(
message: 'Minimize', message: 'Minimize',
icon: IconFont.min, icon: IconFont.min,
@ -684,7 +683,7 @@ class WindowActionPanelState extends State<WindowActionPanel>
isClose: false, isClose: false,
)), )),
Offstage( Offstage(
offstage: !widget.showMaximize || Platform.isMacOS, offstage: !widget.showMaximize || isMacOS,
child: Obx(() => ActionIcon( child: Obx(() => ActionIcon(
message: stateGlobal.isMaximized.isTrue message: stateGlobal.isMaximized.isTrue
? 'Restore' ? 'Restore'
@ -698,7 +697,7 @@ class WindowActionPanelState extends State<WindowActionPanel>
isClose: false, isClose: false,
))), ))),
Offstage( Offstage(
offstage: !widget.showClose || Platform.isMacOS, offstage: !widget.showClose || isMacOS,
child: ActionIcon( child: ActionIcon(
message: 'Close', message: 'Close',
icon: IconFont.close, icon: IconFont.close,

View file

@ -48,7 +48,7 @@ Future<void> main(List<String> args) async {
if (args.isNotEmpty && args.first == 'multi_window') { if (args.isNotEmpty && args.first == 'multi_window') {
kWindowId = int.parse(args[1]); kWindowId = int.parse(args[1]);
stateGlobal.setWindowId(kWindowId!); stateGlobal.setWindowId(kWindowId!);
if (!Platform.isMacOS) { if (!isMacOS) {
WindowController.fromWindowId(kWindowId!).showTitleBar(false); WindowController.fromWindowId(kWindowId!).showTitleBar(false);
} }
final argument = args[2].isEmpty final argument = args[2].isEmpty

View file

@ -57,6 +57,7 @@ class _RemotePageState extends State<RemotePage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
gFFI.ffiModel.updateEventListener(sessionId, widget.id);
gFFI.start( gFFI.start(
widget.id, widget.id,
password: widget.password, password: widget.password,
@ -69,7 +70,6 @@ class _RemotePageState extends State<RemotePage> {
}); });
WakelockPlus.enable(); WakelockPlus.enable();
_physicalFocusNode.requestFocus(); _physicalFocusNode.requestFocus();
gFFI.ffiModel.updateEventListener(sessionId, widget.id);
gFFI.inputModel.listenToMouse(true); gFFI.inputModel.listenToMouse(true);
gFFI.qualityMonitorModel.checkShowQualityMonitor(sessionId); gFFI.qualityMonitorModel.checkShowQualityMonitor(sessionId);
keyboardSubscription = keyboardSubscription =

View file

@ -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'; 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. // Feature flutter_texture_render need to be enabled if feature gpucodec is enabled.
final useTextureRender = final useTextureRender = !isWeb &&
bind.mainHasPixelbufferTextureRender() || bind.mainHasGpuTextureRender(); (bind.mainHasPixelbufferTextureRender() || bind.mainHasGpuTextureRender());
class _PixelbufferTexture { class _PixelbufferTexture {
int _textureKey = -1; int _textureKey = -1;

View file

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common.dart';
@ -292,7 +291,7 @@ class FileController {
name: isLocal ? "local_show_hidden" : "remote_show_hidden")) name: isLocal ? "local_show_hidden" : "remote_show_hidden"))
.isNotEmpty; .isNotEmpty;
options.value.isWindows = isLocal options.value.isWindows = isLocal
? Platform.isWindows ? isWindows
: rootState.target?.ffiModel.pi.platform == kPeerPlatformWindows; : rootState.target?.ffiModel.pi.platform == kPeerPlatformWindows;
await Future.delayed(Duration(milliseconds: 100)); await Future.delayed(Duration(milliseconds: 100));

View file

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui' as ui; import 'dart:ui' as ui;
@ -1537,7 +1536,7 @@ class CursorData {
} }
if (_doubleToInt(oldScale) != _doubleToInt(scale)) { if (_doubleToInt(oldScale) != _doubleToInt(scale)) {
if (Platform.isWindows) { if (isWindows) {
data = img2 data = img2
.copyResize( .copyResize(
image, image,
@ -1616,7 +1615,7 @@ class PredefinedCursor {
data, defaultImg.width, defaultImg.height, ui.PixelFormat.rgba8888); data, defaultImg.width, defaultImg.height, ui.PixelFormat.rgba8888);
double scale = 1.0; double scale = 1.0;
if (Platform.isWindows) { if (isWindows) {
data = _image2!.getBytes(order: img2.ChannelOrder.bgra); data = _image2!.getBytes(order: img2.ChannelOrder.bgra);
} else { } else {
data = Uint8List.fromList(img2.encodePng(_image2!)); data = Uint8List.fromList(img2.encodePng(_image2!));
@ -1841,7 +1840,7 @@ class CursorModel with ChangeNotifier {
Uint8List? data; Uint8List? data;
img2.Image imgOrigin = img2.Image.fromBytes( img2.Image imgOrigin = img2.Image.fromBytes(
width: w, height: h, bytes: rgba.buffer, order: img2.ChannelOrder.rgba); width: w, height: h, bytes: rgba.buffer, order: img2.ChannelOrder.rgba);
if (Platform.isWindows) { if (isWindows) {
data = imgOrigin.getBytes(order: img2.ChannelOrder.bgra); data = imgOrigin.getBytes(order: img2.ChannelOrder.bgra);
} else { } else {
ByteData? imgBytes = ByteData? imgBytes =
@ -2200,6 +2199,7 @@ class FFI {
imageModel.id = id; imageModel.id = id;
cursorModel.peerId = id; cursorModel.peerId = id;
} }
// If tabWindowId != null, this session is a "tab -> window" one. // If tabWindowId != null, this session is a "tab -> window" one.
// Else this session is a new one. // Else this session is a new one.
if (tabWindowId == null) { if (tabWindowId == null) {
@ -2235,6 +2235,10 @@ class FFI {
textureModel.updateCurrentDisplay(display ?? 0); textureModel.updateCurrentDisplay(display ?? 0);
} }
final stream = bind.sessionStart(sessionId: sessionId, id: id); final stream = bind.sessionStart(sessionId: sessionId, id: id);
if (isWeb) {
return;
}
final cb = ffiModel.startEventListener(sessionId, id); final cb = ffiModel.startEventListener(sessionId, id);
// Force refresh displays. // Force refresh displays.

View file

@ -111,13 +111,13 @@ class PlatformFFI {
/// Init the FFI class, loads the native Rust core library. /// Init the FFI class, loads the native Rust core library.
Future<void> init(String appType) async { Future<void> init(String appType) async {
_appType = appType; _appType = appType;
final dylib = Platform.isAndroid final dylib = isAndroid
? DynamicLibrary.open('librustdesk.so') ? DynamicLibrary.open('librustdesk.so')
: Platform.isLinux : isLinux
? DynamicLibrary.open('librustdesk.so') ? DynamicLibrary.open('librustdesk.so')
: Platform.isWindows : isWindows
? DynamicLibrary.open('librustdesk.dll') ? DynamicLibrary.open('librustdesk.dll')
: Platform.isMacOS : isMacOS
? DynamicLibrary.open("liblibrustdesk.dylib") ? DynamicLibrary.open("liblibrustdesk.dylib")
: DynamicLibrary.process(); : DynamicLibrary.process();
debugPrint('initializing FFI $_appType'); debugPrint('initializing FFI $_appType');
@ -131,11 +131,11 @@ class PlatformFFI {
} }
_ffiBind = RustdeskImpl(dylib); _ffiBind = RustdeskImpl(dylib);
if (Platform.isLinux) { if (isLinux) {
// Start a dbus service, no need to await // Start a dbus service, no need to await
_ffiBind.mainStartDbusServer(); _ffiBind.mainStartDbusServer();
_ffiBind.mainStartPa(); _ffiBind.mainStartPa();
} else if (Platform.isMacOS && isMain) { } else if (isMacOS && isMain) {
// Start ipc service for uri links. // Start ipc service for uri links.
_ffiBind.mainStartIpcUrlServer(); _ffiBind.mainStartIpcUrlServer();
} }
@ -155,20 +155,20 @@ class PlatformFFI {
String id = 'NA'; String id = 'NA';
String name = 'Flutter'; String name = 'Flutter';
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
if (Platform.isAndroid) { if (isAndroid) {
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
name = '${androidInfo.brand}-${androidInfo.model}'; name = '${androidInfo.brand}-${androidInfo.model}';
id = androidInfo.id.hashCode.toString(); id = androidInfo.id.hashCode.toString();
androidVersion = androidInfo.version.sdkInt; androidVersion = androidInfo.version.sdkInt;
} else if (Platform.isIOS) { } else if (isIOS) {
IosDeviceInfo iosInfo = await deviceInfo.iosInfo; IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
name = iosInfo.utsname.machine; name = iosInfo.utsname.machine;
id = iosInfo.identifierForVendor.hashCode.toString(); id = iosInfo.identifierForVendor.hashCode.toString();
} else if (Platform.isLinux) { } else if (isLinux) {
LinuxDeviceInfo linuxInfo = await deviceInfo.linuxInfo; LinuxDeviceInfo linuxInfo = await deviceInfo.linuxInfo;
name = linuxInfo.name; name = linuxInfo.name;
id = linuxInfo.machineId ?? linuxInfo.id; id = linuxInfo.machineId ?? linuxInfo.id;
} else if (Platform.isWindows) { } else if (isWindows) {
try { try {
// request windows build number to fix overflow on win7 // request windows build number to fix overflow on win7
windowsBuildNumber = getWindowsTargetBuildNumber(); windowsBuildNumber = getWindowsTargetBuildNumber();
@ -180,7 +180,7 @@ class PlatformFFI {
name = "unknown"; name = "unknown";
id = "unknown"; id = "unknown";
} }
} else if (Platform.isMacOS) { } else if (isMacOS) {
MacOsDeviceInfo macOsInfo = await deviceInfo.macOsInfo; MacOsDeviceInfo macOsInfo = await deviceInfo.macOsInfo;
name = macOsInfo.computerName; name = macOsInfo.computerName;
id = macOsInfo.systemGUID ?? ''; id = macOsInfo.systemGUID ?? '';

View file

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/consts.dart';
@ -383,7 +382,7 @@ class ServerModel with ChangeNotifier {
// ugly is here, because for desktop, below is useless // ugly is here, because for desktop, below is useless
await bind.mainStartService(); await bind.mainStartService();
updateClientState(); updateClientState();
if (Platform.isAndroid) { if (isAndroid) {
WakelockPlus.enable(); WakelockPlus.enable();
} }
} }
@ -395,7 +394,7 @@ class ServerModel with ChangeNotifier {
await parent.target?.invokeMethod("stop_service"); await parent.target?.invokeMethod("stop_service");
await bind.mainStopService(); await bind.mainStopService();
notifyListeners(); notifyListeners();
if (!Platform.isLinux) { if (!isLinux) {
// current linux is not supported // current linux is not supported
WakelockPlus.disable(); WakelockPlus.disable();
} }

View file

@ -1,5 +1,3 @@
import 'dart:io';
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common.dart';
@ -60,7 +58,7 @@ class StateGlobal {
_resizeEdgeSize.value = _resizeEdgeSize.value =
isMaximized.isTrue ? kMaximizeEdgeSize : kWindowEdgeSize; isMaximized.isTrue ? kMaximizeEdgeSize : kWindowEdgeSize;
} }
if (!Platform.isMacOS) { if (!isMacOS) {
_windowBorderWidth.value = v ? 0 : kWindowBorderWidth; _windowBorderWidth.value = v ? 0 : kWindowBorderWidth;
} }
} }
@ -84,7 +82,7 @@ class StateGlobal {
final wc = WindowController.fromWindowId(windowId); final wc = WindowController.fromWindowId(windowId);
wc.setFullscreen(_fullscreen.isTrue).then((_) { wc.setFullscreen(_fullscreen.isTrue).then((_) {
// https://github.com/leanflutter/window_manager/issues/131#issuecomment-1111587982 // https://github.com/leanflutter/window_manager/issues/131#issuecomment-1111587982
if (Platform.isWindows && !v) { if (isWindows && !v) {
Future.delayed(Duration.zero, () async { Future.delayed(Duration.zero, () async {
final frame = await wc.getFrame(); final frame = await wc.getFrame();
final newRect = Rect.fromLTWH( final newRect = Rect.fromLTWH(

View file

@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -139,7 +138,7 @@ class RustDeskMultiWindowManager {
overrideType: type, overrideType: type,
)); ));
} }
if (Platform.isMacOS) { if (isMacOS) {
Future.microtask(() => windowController.show()); Future.microtask(() => windowController.show());
} }
registerActiveWindow(windowId); registerActiveWindow(windowId);

View file

@ -1,8 +1,7 @@
import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hbb/main.dart'; import 'package:flutter_hbb/main.dart';
import 'package:flutter_hbb/common.dart';
enum SystemWindowTheme { light, dark } enum SystemWindowTheme { light, dark }
@ -19,7 +18,7 @@ class RdPlatformChannel {
/// Change the theme of the system window /// Change the theme of the system window
Future<void> changeSystemWindowTheme(SystemWindowTheme theme) { Future<void> changeSystemWindowTheme(SystemWindowTheme theme) {
assert(Platform.isMacOS); assert(isMacOS);
if (kDebugMode) { if (kDebugMode) {
print( print(
"[Window ${kWindowId ?? 'Main'}] change system window theme to ${theme.name}"); "[Window ${kWindowId ?? 'Main'}] change system window theme to ${theme.name}");
@ -30,7 +29,7 @@ class RdPlatformChannel {
/// Terminate .app manually. /// Terminate .app manually.
Future<void> terminate() { Future<void> terminate() {
assert(Platform.isMacOS); assert(isMacOS);
return _osxMethodChannel.invokeMethod("terminate"); return _osxMethodChannel.invokeMethod("terminate");
} }
} }

View file

@ -78,12 +78,19 @@ class RustdeskImpl {
required String password, required String password,
required bool isSharedPassword, required bool isSharedPassword,
dynamic hint}) { dynamic hint}) {
throw UnimplementedError(); return js.context.callMethod('setByName', [
'session_add_sync',
jsonEncode({'id': id, 'password': password})
]);
} }
Stream<EventToUI> sessionStart( Stream<EventToUI> sessionStart(
{required UuidValue sessionId, required String id, dynamic hint}) { {required UuidValue sessionId, required String id, dynamic hint}) {
throw UnimplementedError(); js.context.callMethod('setByName', [
'session_start',
jsonEncode({'id': id})
]);
return Stream.empty();
} }
Future<bool?> sessionGetRemember( Future<bool?> sessionGetRemember(
@ -93,17 +100,19 @@ class RustdeskImpl {
Future<bool?> sessionGetToggleOption( Future<bool?> sessionGetToggleOption(
{required UuidValue sessionId, required String arg, dynamic hint}) { {required UuidValue sessionId, required String arg, dynamic hint}) {
throw UnimplementedError(); return Future(
() => sessionGetToggleOptionSync(sessionId: sessionId, arg: arg));
} }
bool sessionGetToggleOptionSync( bool sessionGetToggleOptionSync(
{required UuidValue sessionId, required String arg, dynamic hint}) { {required UuidValue sessionId, required String arg, dynamic hint}) {
throw UnimplementedError(); return 'true' == js.context.callMethod('getByName', ['option:toggle', arg]);
} }
Future<String?> sessionGetOption( Future<String?> sessionGetOption(
{required UuidValue sessionId, required String arg, dynamic hint}) { {required UuidValue sessionId, required String arg, dynamic hint}) {
throw UnimplementedError(); return Future(
() => js.context.callMethod('getByName', ['option:peer', arg]));
} }
Future<void> sessionLogin( Future<void> sessionLogin(
@ -122,7 +131,7 @@ class RustdeskImpl {
} }
Future<void> sessionClose({required UuidValue sessionId, dynamic hint}) { Future<void> sessionClose({required UuidValue sessionId, dynamic hint}) {
throw UnimplementedError(); return Future(() => js.context.callMethod('setByName', ['session_close']));
} }
Future<void> sessionRefresh( Future<void> sessionRefresh(
@ -165,7 +174,8 @@ class RustdeskImpl {
Future<String?> sessionGetFlutterOption( Future<String?> sessionGetFlutterOption(
{required UuidValue sessionId, required String k, dynamic hint}) { {required UuidValue sessionId, required String k, dynamic hint}) {
throw UnimplementedError(); return Future(
() => js.context.callMethod('getByName', ['option:flutter:peer', k]));
} }
Future<void> sessionSetFlutterOption( Future<void> sessionSetFlutterOption(
@ -173,12 +183,16 @@ class RustdeskImpl {
required String k, required String k,
required String v, required String v,
dynamic hint}) { dynamic hint}) {
throw UnimplementedError(); return Future(() => js.context.callMethod('setByName', [
'option:flutter:peer',
jsonEncode({'name': k, 'value': v})
]));
} }
Future<String?> sessionGetFlutterOptionByPeerId( Future<String?> sessionGetFlutterOptionByPeerId(
{required String id, required String k, dynamic hint}) { {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}) { int getNextTextureKey({dynamic hint}) {
@ -563,26 +577,30 @@ class RustdeskImpl {
Future<void> mainSetOption( Future<void> mainSetOption(
{required String key, required String value, dynamic hint}) { {required String key, required String value, dynamic hint}) {
return js.context.callMethod('setByName', [ js.context.callMethod('setByName', [
'option', 'option',
jsonEncode({'name': key, 'value': value}) jsonEncode({'name': key, 'value': value})
]); ]);
return Future.value();
} }
// get server settings
Future<String> mainGetOptions({dynamic hint}) { Future<String> mainGetOptions({dynamic hint}) {
throw UnimplementedError(); return Future(() => mainGetOptionsSync());
} }
// get server settings
String mainGetOptionsSync({dynamic hint}) { String mainGetOptionsSync({dynamic hint}) {
throw UnimplementedError(); return js.context.callMethod('getByName', ['options']);
} }
Future<void> mainSetOptions({required String json, dynamic hint}) { Future<void> mainSetOptions({required String json, dynamic hint}) {
throw UnimplementedError(); return Future(() => js.context.callMethod('setByName', ['options', json]));
} }
Future<String> mainTestIfValidServer({required String server, dynamic hint}) { Future<String> mainTestIfValidServer({required String server, dynamic hint}) {
throw UnimplementedError(); // TODO: implement
return Future.value('');
} }
Future<void> mainSetSocks( Future<void> mainSetSocks(
@ -652,7 +670,7 @@ class RustdeskImpl {
} }
Future<String> mainGetApiServer({dynamic hint}) { Future<String> mainGetApiServer({dynamic hint}) {
throw UnimplementedError(); return Future(() => js.context.callMethod('getByName', ['api_server']));
} }
Future<void> mainPostRequest( Future<void> mainPostRequest(
@ -809,7 +827,11 @@ class RustdeskImpl {
} }
Future<String> mainHandleRelayId({required String id, dynamic hint}) { Future<String> 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}) { String mainGetMainDisplay({dynamic hint}) {

View file

@ -6,10 +6,12 @@
- [x] Outgoing - [x] Outgoing
- [ ] Address book - [ ] Address book
- [ ] Force relay
### Unsupported ### Unsupported
1. Incoming 1. Incoming
2. LAN 2. LAN
3. Gpu texture render. We use WebGL instead.
### No plans ### No plans

View file

@ -6,7 +6,7 @@ import * as sha256 from "fast-sha256";
import * as globals from "./globals"; import * as globals from "./globals";
import { decompress, mapKey, sleep } from "./common"; import { decompress, mapKey, sleep } from "./common";
const PORT = 21116; export const PORT = 21116;
const HOSTS = [ const HOSTS = [
"rs-sg.rustdesk.com", "rs-sg.rustdesk.com",
"rs-cn.rustdesk.com", "rs-cn.rustdesk.com",
@ -15,7 +15,7 @@ const HOSTS = [
let HOST = localStorage.getItem("rendezvous-server") || HOSTS[0]; let HOST = localStorage.getItem("rendezvous-server") || HOSTS[0];
const SCHEMA = "ws://"; 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; type DrawCallback = (data: Uint8Array) => void;
//const cursorCanvas = document.createElement("canvas"); //const cursorCanvas = document.createElement("canvas");
@ -41,6 +41,7 @@ export default class Connection {
this._msgs = []; this._msgs = [];
this._id = ""; this._id = "";
this._videoTestSpeed = [0, 0]; this._videoTestSpeed = [0, 0];
this._options = {};
//this._cursors = {}; //this._cursors = {};
} }
@ -318,8 +319,8 @@ export default class Connection {
} }
} }
msgbox(type_: string, title: string, text: string) { msgbox(type_: string, title: string, text: string, link: string = '') {
this._msgbox?.(type_, title, text); this._msgbox?.(type_, title, text, link);
} }
draw(frame: any) { draw(frame: any) {
@ -541,9 +542,20 @@ export default class Connection {
return this._options[name]; 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: // TODO:
getStatus(): String { getStatus(): String {
return JSON.stringify({status_num: 10}); return JSON.stringify({ status_num: 10 });
} }
// TODO: // TODO:
@ -558,8 +570,10 @@ export default class Connection {
} }
this._options["tm"] = new Date().getTime(); this._options["tm"] = new Date().getTime();
const peers = globals.getPeers(); const peers = globals.getPeers();
peers[this._id] = this._options; if (peers) {
localStorage.setItem("peers", JSON.stringify(peers)); peers[this._id] = this._options;
localStorage.setItem("peers", JSON.stringify(peers));
}
} }
inputKey( inputKey(

View file

@ -1,4 +1,5 @@
import Connection from "./connection"; import Connection from "./connection";
import PORT from "./connection";
import _sodium from "libsodium-wrappers"; import _sodium from "libsodium-wrappers";
import { CursorData } from "./message"; import { CursorData } from "./message";
import { loadVp9 } from "./codec"; import { loadVp9 } from "./codec";
@ -16,11 +17,11 @@ export function isDesktop() {
return !isMobile(); return !isMobile();
} }
export function msgbox(type, title, text) { export function msgbox(type, title, text, link) {
if (!type || (type == 'error' && !text)) return; if (!type || (type == 'error' && !text)) return;
const text2 = text.toLowerCase(); const text2 = text.toLowerCase();
var hasRetry = checkIfRetry(type, title, text) ? 'true' : ''; 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) { function jsonfyForDart(payload) {
@ -257,13 +258,17 @@ window.setByName = (name, value) => {
value = JSON.parse(value); value = JSON.parse(value);
localStorage.setItem(value.name, value.value); localStorage.setItem(value.name, value.value);
break; break;
case 'option:local': case 'options':
value = JSON.parse(value); 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; break;
case 'option:local':
case 'option:flutter:local': case 'option:flutter:local':
case 'option:flutter:peer':
value = JSON.parse(value); value = JSON.parse(value);
localStorage.setItem('option:flutter:local:' + value.name, value.value); localStorage.setItem(name + ':' + value.name, value.value);
break; break;
case 'peer_option': case 'peer_option':
value = JSON.parse(value); value = JSON.parse(value);
@ -281,6 +286,14 @@ window.setByName = (name, value) => {
case 'discover': case 'discover':
// TODO: discover // TODO: discover
break; break;
case 'session_add_sync':
return sessionAdd(value);
case 'session_start':
sessionStart(value);
break;
case 'session_close':
sessionClose(value);
break;
default: default:
break; break;
} }
@ -317,17 +330,32 @@ function _getByName(name, arg) {
return curConn.getOption(arg) || false; return curConn.getOption(arg) || false;
case 'option': case 'option':
return localStorage.getItem(arg); 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': case 'option:local':
return localStorage.getItem('option:local:' + arg);
case 'option:flutter:local': case 'option:flutter:local':
return localStorage.getItem('option:flutter:local:' + arg); case 'option:flutter:peer':
return localStorage.getItem(name + ':' + arg);
case 'image_quality': case 'image_quality':
return curConn.getImageQuality(); return curConn.getImageQuality();
case 'translate': case 'translate':
arg = JSON.parse(arg); arg = JSON.parse(arg);
return translate(arg.locale, arg.text); return translate(arg.locale, arg.text);
case 'peer_option': case 'option:peer':
return curConn.getOption(arg); return curConn.getOption(arg);
case 'option:toggle':
return curConn.getToggleOption(arg);
case 'get_conn_status': case 'get_conn_status':
if (curConn) { if (curConn) {
return curConn.getStatus(); return curConn.getStatus();
@ -360,6 +388,8 @@ function _getByName(name, arg) {
return localStorage.getItem('peers-recent') ?? '{}'; return localStorage.getItem('peers-recent') ?? '{}';
case 'load_lan_peers_sync': case 'load_lan_peers_sync':
return localStorage.getItem('peers-lan') ?? '{}'; return localStorage.getItem('peers-lan') ?? '{}';
case 'api_server':
return getApiServer();
} }
return ''; return '';
} }
@ -391,15 +421,15 @@ window.init = async () => {
} }
export function getPeers() { export function getPeers() {
return _getJsonObj('peers'); return getJsonObj('peers');
} }
export function getRecentPeers() { export function getRecentPeers() {
return _getJsonObj('peers-recent'); return getJsonObj('peers-recent');
} }
export function getLanPeers() { export function getLanPeers() {
return _getJsonObj('peers-lan'); return getJsonObj('peers-lan');
} }
export function getJsonObj(key) { export function getJsonObj(key) {
@ -456,3 +486,94 @@ function removeDiscovered(id) {
} }
} }
// ========================== peers end =========================== // ========================== 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 ===========================