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

@ -634,10 +634,14 @@ closeConnection({String? id}) {
if (isAndroid || isIOS) {
gFFI.chatModel.hideChatOverlay();
Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/"));
} else {
if (isWeb) {
Navigator.popUntil(globalKey.currentContext!, ModalRoute.withName("/"));
} else {
final controller = Get.find<DesktopTabController>();
controller.closeBy(id);
}
}
}
Future<void> windowOnTop(int? id) async {
@ -2980,7 +2984,6 @@ Future<bool> 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 &&

View file

@ -625,7 +625,7 @@ class _DialogVerificationCodeField extends State<DialogVerificationCodeField> {
// 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<PasswordWidget> {
}
// 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();

View file

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

View file

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

View file

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

View file

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

View file

@ -469,7 +469,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
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<DesktopHomePage>
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<DesktopHomePage>
// watchIsCanRecordAudio = true;
// });
// }
} else if (Platform.isLinux) {
} else if (isLinux) {
if (bind.isOutgoingOnly()) {
return Container();
}
@ -570,7 +570,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
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<DesktopHomePage>
}
}
if (watchIsCanRecordAudio) {
if (Platform.isMacOS) {
if (isMacOS) {
Future.microtask(() async {
if ((await osxCanRecordAudio() ==
PermissionAuthorizeType.authorized)) {

View file

@ -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<String> 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: [

View file

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

View file

@ -93,7 +93,7 @@ class _FileManagerPageState extends State<FileManagerPage>
.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<FileManagerPage>
model.close().whenComplete(() {
_ffi.close();
_ffi.dialogManager.dismissAll();
if (!Platform.isLinux) {
if (!isLinux) {
WakelockPlus.disable();
}
Get.delete<FFI>(tag: 'ft_${widget.id}');
@ -1298,7 +1298,7 @@ class _FileManagerViewState extends State<FileManagerView> {
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);
}
},

View file

@ -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<FileManagerTabPage> {
labelGetter: DesktopTab.tablabelGetter,
)),
);
return Platform.isMacOS || kUseCompatibleUiMode
return isMacOS || kUseCompatibleUiMode
? tabWidget
: SubWindowDragToResizeArea(
child: tabWidget,

View file

@ -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<PortForwardTabPage> {
labelGetter: DesktopTab.tablabelGetter,
)),
);
return Platform.isMacOS || kUseCompatibleUiMode
return isMacOS || kUseCompatibleUiMode
? tabWidget
: Obx(
() => SubWindowDragToResizeArea(

View file

@ -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<RemotePage>
_ffi.dialogManager
.showLoading(translate('Connecting...'), onCancel: closeConnection);
});
if (!Platform.isLinux) {
if (!isLinux) {
WakelockPlus.enable();
}
@ -160,7 +159,7 @@ class _RemotePageState extends State<RemotePage>
// 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<RemotePage>
void onWindowFocus() {
super.onWindowFocus();
// See [onWindowBlur].
if (Platform.isWindows) {
if (isWindows) {
_isWindowBlur = false;
}
}
@ -182,10 +181,10 @@ class _RemotePageState extends State<RemotePage>
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<RemotePage>
@override
void onWindowMaximize() {
super.onWindowMaximize();
if (!Platform.isLinux) {
if (!isLinux) {
WakelockPlus.enable();
}
}
@ -202,7 +201,7 @@ class _RemotePageState extends State<RemotePage>
@override
void onWindowMinimize() {
super.onWindowMinimize();
if (!Platform.isLinux) {
if (!isLinux) {
WakelockPlus.disable();
}
}
@ -228,7 +227,7 @@ class _RemotePageState extends State<RemotePage>
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
}
if (!Platform.isLinux) {
if (!isLinux) {
await WakelockPlus.disable();
}
await Get.delete<FFI>(tag: widget.id);
@ -266,7 +265,7 @@ class _RemotePageState extends State<RemotePage>
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<RemotePage>
}
}
// See [onWindowBlur].
if (!Platform.isWindows) {
if (!isWindows) {
if (!_rawKeyFocusNode.hasFocus) {
_rawKeyFocusNode.requestFocus();
}
@ -385,7 +384,7 @@ class _RemotePageState extends State<RemotePage>
}
}
// See [onWindowBlur].
if (!Platform.isWindows) {
if (!isWindows) {
_ffi.inputModel.enterOrLeave(false);
}
}
@ -537,7 +536,7 @@ class _ImagePaintState extends State<ImagePaint> {
double getCursorScale() {
var c = Provider.of<CanvasModel>(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<ImagePaint> {
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())

View file

@ -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<ConnectionTabPage> {
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<ConnectionTabPage> {
),
),
);
return Platform.isMacOS || kUseCompatibleUiMode
return isMacOS || kUseCompatibleUiMode
? tabWidget
: Obx(() => SubWindowDragToResizeArea(
key: contentKey,

View file

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

View file

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

View file

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

View file

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

View file

@ -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<WindowActionPanel>
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<WindowActionPanel>
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<WindowActionPanel>
} 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<WindowActionPanel>
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<WindowActionPanel>
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<WindowActionPanel>
isClose: false,
))),
Offstage(
offstage: !widget.showClose || Platform.isMacOS,
offstage: !widget.showClose || isMacOS,
child: ActionIcon(
message: 'Close',
icon: IconFont.close,

View file

@ -48,7 +48,7 @@ Future<void> main(List<String> 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

View file

@ -57,6 +57,7 @@ class _RemotePageState extends State<RemotePage> {
@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<RemotePage> {
});
WakelockPlus.enable();
_physicalFocusNode.requestFocus();
gFFI.ffiModel.updateEventListener(sessionId, widget.id);
gFFI.inputModel.listenToMouse(true);
gFFI.qualityMonitorModel.checkShowQualityMonitor(sessionId);
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';
// 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;

View file

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

View file

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

View file

@ -111,13 +111,13 @@ class PlatformFFI {
/// Init the FFI class, loads the native Rust core library.
Future<void> 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 ?? '';

View file

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

View file

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

View file

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

View file

@ -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<void> 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<void> terminate() {
assert(Platform.isMacOS);
assert(isMacOS);
return _osxMethodChannel.invokeMethod("terminate");
}
}

View file

@ -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<EventToUI> sessionStart(
{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(
@ -93,17 +100,19 @@ class RustdeskImpl {
Future<bool?> 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<String?> sessionGetOption(
{required UuidValue sessionId, required String arg, dynamic hint}) {
throw UnimplementedError();
return Future(
() => js.context.callMethod('getByName', ['option:peer', arg]));
}
Future<void> sessionLogin(
@ -122,7 +131,7 @@ class RustdeskImpl {
}
Future<void> sessionClose({required UuidValue sessionId, dynamic hint}) {
throw UnimplementedError();
return Future(() => js.context.callMethod('setByName', ['session_close']));
}
Future<void> sessionRefresh(
@ -165,7 +174,8 @@ class RustdeskImpl {
Future<String?> sessionGetFlutterOption(
{required UuidValue sessionId, required String k, dynamic hint}) {
throw UnimplementedError();
return Future(
() => js.context.callMethod('getByName', ['option:flutter:peer', k]));
}
Future<void> 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<String?> 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<void> 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<String> mainGetOptions({dynamic hint}) {
throw UnimplementedError();
return Future(() => mainGetOptionsSync());
}
// get server settings
String mainGetOptionsSync({dynamic hint}) {
throw UnimplementedError();
return js.context.callMethod('getByName', ['options']);
}
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}) {
throw UnimplementedError();
// TODO: implement
return Future.value('');
}
Future<void> mainSetSocks(
@ -652,7 +670,7 @@ class RustdeskImpl {
}
Future<String> mainGetApiServer({dynamic hint}) {
throw UnimplementedError();
return Future(() => js.context.callMethod('getByName', ['api_server']));
}
Future<void> mainPostRequest(
@ -809,7 +827,11 @@ class RustdeskImpl {
}
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}) {

View file

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

View file

@ -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,9 +570,11 @@ export default class Connection {
}
this._options["tm"] = new Date().getTime();
const peers = globals.getPeers();
if (peers) {
peers[this._id] = this._options;
localStorage.setItem("peers", JSON.stringify(peers));
}
}
inputKey(
name: string,

View file

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