Refact. Flutter web, mid commit (#7482)

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2024-03-23 10:08:55 +08:00 committed by GitHub
parent 1c3a2e475d
commit a15cd62fd4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 187 additions and 68 deletions

View File

@ -1,6 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:back_button_interceptor/back_button_interceptor.dart';
@ -1544,7 +1543,7 @@ Future<void> saveWindowPosition(WindowType type, {int? windowId}) async {
late Size sz;
late bool isMaximized;
bool isFullscreen = stateGlobal.fullscreen.isTrue ||
(Platform.isMacOS && stateGlobal.closeOnFullscreen == true);
(isMacOS && stateGlobal.closeOnFullscreen == true);
setFrameIfMaximized() {
if (isMaximized) {
final pos = bind.getLocalFlutterOption(k: windowFramePrefix + type.name);
@ -1583,7 +1582,7 @@ Future<void> saveWindowPosition(WindowType type, {int? windowId}) async {
setFrameIfMaximized();
break;
}
if (Platform.isWindows) {
if (isWindows) {
const kMinOffset = -10000;
const kMaxOffset = 10000;
if (position.dx < kMinOffset ||
@ -1854,7 +1853,7 @@ Future<bool> restoreWindowPosition(WindowType type,
/// initUniLinks should only be used on macos/windows.
/// we use dbus for linux currently.
Future<bool> initUniLinks() async {
if (Platform.isLinux) {
if (isLinux) {
return false;
}
// check cold boot
@ -1876,7 +1875,7 @@ Future<bool> initUniLinks() async {
///
/// Returns a [StreamSubscription] which can listen the uni links.
StreamSubscription? listenUniLinks({handleByFlutter = true}) {
if (Platform.isLinux) {
if (isLinux) {
return null;
}
@ -2024,7 +2023,7 @@ List<String>? urlLinkToCmdArgs(Uri uri) {
command = '--connect';
id = uri.path.substring("/new/".length);
} else if (uri.authority == "config") {
if (Platform.isAndroid || Platform.isIOS) {
if (isAndroid || isIOS) {
final config = uri.path.substring("/".length);
// add a timer to make showToast work
Timer(Duration(seconds: 1), () {
@ -2033,7 +2032,7 @@ List<String>? urlLinkToCmdArgs(Uri uri) {
}
return null;
} else if (uri.authority == "password") {
if (Platform.isAndroid || Platform.isIOS) {
if (isAndroid || isIOS) {
final password = uri.path.substring("/".length);
if (password.isNotEmpty) {
Timer(Duration(seconds: 1), () async {
@ -2253,7 +2252,7 @@ Future<void> reloadAllWindows() async {
/// [Note]
/// Portable build is only available on Windows.
bool isRunningInPortableMode() {
if (!Platform.isWindows) {
if (!isWindows) {
return false;
}
return bool.hasEnvironment(kEnvPortableExecutable);
@ -2266,7 +2265,7 @@ Future<void> onActiveWindowChanged() async {
if (rustDeskWinManager.getActiveWindows().isEmpty) {
// close all sub windows
try {
if (Platform.isLinux) {
if (isLinux) {
await Future.wait([
saveWindowPosition(WindowType.Main),
rustDeskWinManager.closeAllSubWindows()
@ -2280,7 +2279,7 @@ Future<void> onActiveWindowChanged() async {
debugPrint("Start closing RustDesk...");
await windowManager.setPreventClose(false);
await windowManager.close();
if (Platform.isMacOS) {
if (isMacOS) {
RdPlatformChannel.instance.terminate();
}
}
@ -2296,7 +2295,7 @@ Timer periodic_immediate(Duration duration, Future<void> Function() callback) {
/// return a human readable windows version
WindowsTarget getWindowsTarget(int buildNumber) {
if (!Platform.isWindows) {
if (!isWindows) {
return WindowsTarget.naw;
}
if (buildNumber >= 22000) {
@ -2330,7 +2329,7 @@ int getWindowsTargetBuildNumber() {
/// [Conditions]
/// - Windows 7, window will overflow when we use frameless ui.
bool get kUseCompatibleUiMode =>
Platform.isWindows &&
isWindows &&
const [WindowsTarget.w7].contains(windowsBuildNumber.windowsVersion);
class ServerConfig {
@ -2460,7 +2459,7 @@ Future<void> updateSystemWindowTheme() async {
// Set system window theme for macOS.
final userPreference = MyTheme.getThemeModePreference();
if (userPreference != ThemeMode.system) {
if (Platform.isMacOS) {
if (isMacOS) {
await RdPlatformChannel.instance.changeSystemWindowTheme(
userPreference == ThemeMode.light
? SystemWindowTheme.light
@ -2548,7 +2547,7 @@ void onCopyFingerprint(String value) {
Future<bool> callMainCheckSuperUserPermission() async {
bool checked = await bind.mainCheckSuperUserPermission();
if (Platform.isMacOS) {
if (isMacOS) {
await windowManager.show();
}
return checked;
@ -2556,7 +2555,7 @@ Future<bool> callMainCheckSuperUserPermission() async {
Future<void> start_service(bool is_start) async {
bool checked = !bind.mainIsInstalled() ||
!Platform.isMacOS ||
!isMacOS ||
await callMainCheckSuperUserPermission();
if (checked) {
bind.mainSetOption(key: "stop-service", value: is_start ? "" : "Y");
@ -3114,7 +3113,7 @@ Widget loadIcon(double size) {
var imcomingOnlyHomeSize = Size(280, 300);
Size getIncomingOnlyHomeSize() {
final magicWidth = Platform.isWindows ? 11.0 : 2.0;
final magicWidth = isWindows ? 11.0 : 2.0;
final magicHeight = 10.0;
return imcomingOnlyHomeSize +
Offset(magicWidth, kDesktopRemoteTabBarHeight + magicHeight);

View File

@ -125,6 +125,10 @@ void runMainApp(bool startService) async {
await Future.wait([gFFI.abModel.loadCache(), gFFI.groupModel.loadCache()]);
gFFI.userModel.refreshCurrentUser();
runApp(App());
if (isWeb) {
// Web does not support window manager.
return;
}
// Set window option.
WindowOptions windowOptions = getHiddenTitleBarWindowOptions();
windowManager.waitUntilReadyToShow(windowOptions, () async {
@ -150,11 +154,11 @@ void runMainApp(bool startService) async {
void runMobileApp() async {
await initEnv(kAppTypeMain);
if (isAndroid) androidChannelInit();
platformFFI.syncAndroidServiceAppDirConfigPath();
if (isAndroid) platformFFI.syncAndroidServiceAppDirConfigPath();
await Future.wait([gFFI.abModel.loadCache(), gFFI.groupModel.loadCache()]);
gFFI.userModel.refreshCurrentUser();
runApp(App());
await initUniLinks();
if (!isWeb) await initUniLinks();
}
void runMultiWindow(

View File

@ -53,7 +53,7 @@ class _ConnectionPageState extends State<ConnectionPage> {
@override
void initState() {
super.initState();
_uniLinksSubscription = listenUniLinks();
if (!isWeb) _uniLinksSubscription = listenUniLinks();
if (_idController.text.isEmpty) {
() async {
final lastRemoteId = await bind.mainGetLastRemoteId();

View File

@ -18,7 +18,7 @@ typedef HandleEvent = Future<void> Function(Map<String, dynamic> evt);
class PlatformFFI {
final _eventHandlers = <String, Map<String, HandleEvent>>{};
late RustdeskImpl _ffiBind;
final RustdeskImpl _ffiBind = RustdeskImpl();
static String getByName(String name, [String arg = '']) {
return context.callMethod('getByName', [name, arg]);
@ -101,6 +101,15 @@ class PlatformFFI {
isWebDesktop = !context.callMethod('isMobile');
context.callMethod('init');
version = getByName('version');
context['onRegisteredEvent'] = (String message) {
try {
Map<String, dynamic> event = json.decode(message);
tryHandle(event);
} catch (e) {
print('json.decode fail(): $e');
}
};
}
void setEventCallback(void Function(Map<String, dynamic>) fun) {
@ -145,7 +154,5 @@ class PlatformFFI {
}
// just for compilation
void syncAndroidServiceAppDirConfigPath() {
throw UnimplementedError();
}
void syncAndroidServiceAppDirConfigPath() {}
}

View File

@ -1,4 +1,6 @@
import 'dart:async';
import 'dart:js' as js;
import 'dart:convert';
import 'dart:typed_data';
import 'package:uuid/uuid.dart';
@ -176,29 +178,35 @@ class RustdeskImpl {
Future<String?> sessionGetFlutterOptionByPeerId(
{required String id, required String k, dynamic hint}) {
throw UnimplementedError();
return Future.value(null);
}
int getNextTextureKey({dynamic hint}) {
throw UnimplementedError();
return 0;
}
String getLocalFlutterOption({required String k, dynamic hint}) {
throw UnimplementedError();
return js.context.callMethod('getByName', ['option:flutter:local', k]);
}
Future<void> setLocalFlutterOption(
{required String k, required String v, dynamic hint}) {
throw UnimplementedError();
return Future(() => js.context.callMethod('setByName', [
'option:flutter:local',
jsonEncode({'name': k, 'value': v})
]));
}
String getLocalKbLayoutType({dynamic hint}) {
throw UnimplementedError();
throw js.context.callMethod('getByName', ['option:local', 'kb_layout']);
}
Future<void> setLocalKbLayoutType(
{required String kbLayoutType, dynamic hint}) {
throw UnimplementedError();
return Future(() => js.context.callMethod('setByName', [
'option:local',
jsonEncode({'name': 'kb_layout', 'value': kbLayoutType})
]));
}
Future<String?> sessionGetViewStyle(
@ -538,11 +546,11 @@ class RustdeskImpl {
}
Future<String> mainGetOption({required String key, dynamic hint}) {
throw UnimplementedError();
return Future.value(mainGetOptionSync(key: key));
}
String mainGetOptionSync({required String key, dynamic hint}) {
throw UnimplementedError();
return js.context.callMethod('getByName', ['option', key]);
}
Future<String> mainGetError({dynamic hint}) {
@ -555,7 +563,10 @@ class RustdeskImpl {
Future<void> mainSetOption(
{required String key, required String value, dynamic hint}) {
throw UnimplementedError();
return js.context.callMethod('setByName', [
'option',
jsonEncode({'name': key, 'value': value})
]);
}
Future<String> mainGetOptions({dynamic hint}) {
@ -623,11 +634,13 @@ class RustdeskImpl {
}
Future<String> mainGetConnectStatus({dynamic hint}) {
throw UnimplementedError();
return Future(
() => js.context.callMethod('getByName', ["get_conn_status"]));
}
Future<void> mainCheckConnectStatus({dynamic hint}) {
throw UnimplementedError();
return Future(
() => js.context.callMethod('setByName', ["check_conn_status"]));
}
Future<bool> mainIsUsingPublicServer({dynamic hint}) {
@ -635,7 +648,7 @@ class RustdeskImpl {
}
Future<void> mainDiscover({dynamic hint}) {
throw UnimplementedError();
return Future(() => js.context.callMethod('setByName', ['discover']));
}
Future<String> mainGetApiServer({dynamic hint}) {
@ -651,7 +664,7 @@ class RustdeskImpl {
}
String mainGetLocalOption({required String key, dynamic hint}) {
throw UnimplementedError();
return js.context.callMethod('getByName', ['option:local', key]);
}
String mainGetEnv({required String key, dynamic hint}) {
@ -660,7 +673,10 @@ class RustdeskImpl {
Future<void> mainSetLocalOption(
{required String key, required String value, dynamic hint}) {
throw UnimplementedError();
return Future(() => js.context.callMethod('setByName', [
'option:local',
jsonEncode({'name': key, 'value': value})
]));
}
String mainGetInputSource({dynamic hint}) {
@ -741,15 +757,16 @@ class RustdeskImpl {
}
Future<void> mainLoadRecentPeers({dynamic hint}) {
throw UnimplementedError();
return Future(
() => js.context.callMethod('getByName', ['load_recent_peers']));
}
String mainLoadRecentPeersSync({dynamic hint}) {
throw UnimplementedError();
return js.context.callMethod('getByName', ['load_recent_peers_sync']);
}
String mainLoadLanPeersSync({dynamic hint}) {
throw UnimplementedError();
return js.context.callMethod('getByName', ['load_lan_peers_sync']);
}
Future<String> mainLoadRecentPeersForAb(
@ -758,15 +775,16 @@ class RustdeskImpl {
}
Future<void> mainLoadFavPeers({dynamic hint}) {
throw UnimplementedError();
return Future(() => js.context.callMethod('getByName', ['load_fav_peers']));
}
Future<void> mainLoadLanPeers({dynamic hint}) {
throw UnimplementedError();
return Future(() => js.context.callMethod('getByName', ['load_lan_peers']));
}
Future<void> mainRemoveDiscovered({required String id, dynamic hint}) {
throw UnimplementedError();
return Future(
() => js.context.callMethod('getByName', ['remove_discovered']));
}
Future<void> mainChangeTheme({required String dark, dynamic hint}) {
@ -840,7 +858,8 @@ class RustdeskImpl {
}
Future<String> mainGetLastRemoteId({dynamic hint}) {
throw UnimplementedError();
return Future(
() => js.context.callMethod('getByName', ['option', 'last_remote_id']));
}
Future<String> mainGetSoftwareUpdateUrl({dynamic hint}) {
@ -848,7 +867,7 @@ class RustdeskImpl {
}
Future<String> mainGetHomeDir({dynamic hint}) {
throw UnimplementedError();
return Future.value('');
}
Future<String> mainGetLangs({dynamic hint}) {
@ -856,11 +875,11 @@ class RustdeskImpl {
}
Future<String> mainGetTemporaryPassword({dynamic hint}) {
throw UnimplementedError();
return Future.value('');
}
Future<String> mainGetPermanentPassword({dynamic hint}) {
throw UnimplementedError();
return Future.value('');
}
Future<String> mainGetFingerprint({dynamic hint}) {
@ -880,7 +899,7 @@ class RustdeskImpl {
}
Future<void> mainInit({required String appDir, dynamic hint}) {
throw UnimplementedError();
return Future.value();
}
Future<void> mainDeviceId({required String id, dynamic hint}) {
@ -1093,7 +1112,10 @@ class RustdeskImpl {
String translate(
{required String name, required String locale, dynamic hint}) {
throw UnimplementedError();
return js.context.callMethod('getByName', [
'translate',
jsonEncode({'locale': locale, 'text': name})
]);
}
int sessionGetRgbaSize(
@ -1131,7 +1153,7 @@ class RustdeskImpl {
}
Future<bool> optionSynced({dynamic hint}) {
throw UnimplementedError();
return Future.value(true);
}
bool mainIsInstalled({dynamic hint}) {
@ -1257,43 +1279,45 @@ class RustdeskImpl {
}
Future<void> mainTestWallpaper({required int second, dynamic hint}) {
throw UnimplementedError();
// TODO: implement mainTestWallpaper
return Future.value();
}
Future<bool> mainSupportRemoveWallpaper({dynamic hint}) {
throw UnimplementedError();
// TODO: implement mainSupportRemoveWallpaper
return Future.value(false);
}
bool isIncomingOnly({dynamic hint}) {
throw UnimplementedError();
return false;
}
bool isOutgoingOnly({dynamic hint}) {
throw UnimplementedError();
return false;
}
bool isCustomClient({dynamic hint}) {
throw UnimplementedError();
return false;
}
bool isDisableSettings({dynamic hint}) {
throw UnimplementedError();
return false;
}
bool isDisableAb({dynamic hint}) {
throw UnimplementedError();
return false;
}
bool isDisableAccount({dynamic hint}) {
throw UnimplementedError();
return false;
}
bool isDisableInstallation({dynamic hint}) {
throw UnimplementedError();
return false;
}
Future<bool> isPresetPassword({dynamic hint}) {
throw UnimplementedError();
return Future.value(false);
}
Future<void> sendUrlScheme({required String url, dynamic hint}) {

View File

@ -3,19 +3,19 @@
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "./gen_js_from_hbb.py > src/gen_js_from_hbb.ts && ./ts_proto.py && tsc && vite build",
"build": "python ./gen_js_from_hbb.py > src/gen_js_from_hbb.ts && python ./ts_proto.py && tsc && vite build",
"preview": "vite preview"
},
"devDependencies": {
"typescript": "^4.4.4",
"vite": "^2.7.2"
"vite": "2.8"
},
"dependencies": {
"fast-sha256": "^1.3.0",
"libsodium": "^0.7.9",
"libsodium-wrappers": "^0.7.9",
"pcm-player": "^0.0.11",
"ts-proto": "^1.101.0",
"ts-proto": "^1.169.1",
"wasm-feature-detect": "^1.2.11",
"zstddec": "^0.0.2"
}

View File

@ -443,9 +443,9 @@ export default class Connection {
if (this._videoTestSpeed[0] >= 30) {
console.log(
"video decoder: " +
parseInt(
"" + this._videoTestSpeed[1] / this._videoTestSpeed[0]
)
parseInt(
"" + this._videoTestSpeed[1] / this._videoTestSpeed[0]
)
);
this._videoTestSpeed = [0, 0];
}
@ -456,6 +456,7 @@ export default class Connection {
}
handlePeerInfo(pi: message.PeerInfo) {
localStorage.setItem('last_remote_id', this._id);
this._peerInfo = pi;
if (pi.displays.length == 0) {
this.msgbox("error", "Remote Error", "No Display");
@ -540,6 +541,15 @@ export default class Connection {
return this._options[name];
}
// TODO:
getStatus(): String {
return JSON.stringify({status_num: 10});
}
// TODO:
checkConnStatus() {
}
setOption(name: string, value: any) {
if (value == undefined) {
delete this._options[name];

View File

@ -257,6 +257,14 @@ window.setByName = (name, value) => {
value = JSON.parse(value);
localStorage.setItem(value.name, value.value);
break;
case 'option:local':
value = JSON.parse(value);
localStorage.setItem('option:local:' + value.name, value.value);
break;
case 'option:flutter:local':
value = JSON.parse(value);
localStorage.setItem('option:flutter:local:' + value.name, value.value);
break;
case 'peer_option':
value = JSON.parse(value);
curConn.setOption(value.name, value.value);
@ -264,6 +272,15 @@ window.setByName = (name, value) => {
case 'input_os_password':
curConn.inputOsPassword(value);
break;
case 'check_conn_status':
curConn.checkConnStatus();
break;
case 'remove_discovered':
removeDiscovered(value);
break;
case 'discover':
// TODO: discover
break;
default:
break;
}
@ -300,6 +317,10 @@ function _getByName(name, arg) {
return curConn.getOption(arg) || false;
case 'option':
return localStorage.getItem(arg);
case 'option:local':
return localStorage.getItem('option:local:' + arg);
case 'option:flutter:local':
return localStorage.getItem('option:flutter:local:' + arg);
case 'image_quality':
return curConn.getImageQuality();
case 'translate':
@ -307,10 +328,38 @@ function _getByName(name, arg) {
return translate(arg.locale, arg.text);
case 'peer_option':
return curConn.getOption(arg);
case 'get_conn_status':
if (curConn) {
return curConn.getStatus();
} else {
return JSON.stringify({ status_num: 0 });
}
case 'test_if_valid_server':
break;
case 'version':
return version;
case 'load_recent_peers':
const peersRecent = localStorage.getItem('peers-recent');
if (peersRecent) {
onRegisteredEvent(JSON.stringify({ name: 'load_recent_peers', peers: peersRecent }));
}
break;
case 'load_fav_peers':
const peersFav = localStorage.getItem('peers-fav');
if (peersFav) {
onRegisteredEvent(JSON.stringify({ name: 'load_fav_peers', peers: peersFav }));
}
break;
case 'load_lan_peers':
const peersLan = localStorage.getItem('peers-lan');
if (peersLan) {
onRegisteredEvent(JSON.stringify({ name: 'load_lan_peers', peers: peersLan }));
}
break;
case 'load_recent_peers_sync':
return localStorage.getItem('peers-recent') ?? '{}';
case 'load_lan_peers_sync':
return localStorage.getItem('peers-lan') ?? '{}';
}
return '';
}
@ -342,8 +391,20 @@ window.init = async () => {
}
export function getPeers() {
return _getJsonObj('peers');
}
export function getRecentPeers() {
return _getJsonObj('peers-recent');
}
export function getLanPeers() {
return _getJsonObj('peers-lan');
}
export function getJsonObj(key) {
try {
return JSON.parse(localStorage.getItem('peers')) || {};
return JSON.parse(localStorage.getItem(key)) || {};
} catch (e) {
return {};
}
@ -380,4 +441,18 @@ export function copyToClipboard(text) {
document.body.removeChild(textarea);
}
}
}
}
// ========================== peers begin ==========================
function removeDiscovered(id) {
try {
const v = localStorage.getItem('discovered');
if (!v) return;
const discovered = JSON.parse(localStorage.getItem('discovered'));
delete discovered[id];
localStorage.setItem('discovered', JSON.stringify(discovered));
} catch (e) {
console.error(e);
}
}
// ========================== peers end ===========================