rustdesk/flutter/lib/main.dart
fufesou c2d843ace6 refactor main runApp()
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-11-02 22:23:23 +08:00

339 lines
10 KiB
Dart

import 'dart:convert';
import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hbb/models/state_model.dart';
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
import 'package:flutter_hbb/desktop/pages/server_page.dart';
import 'package:flutter_hbb/desktop/pages/install_page.dart';
import 'package:flutter_hbb/desktop/screen/desktop_file_transfer_screen.dart';
import 'package:flutter_hbb/desktop/screen/desktop_port_forward_screen.dart';
import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart';
import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:get/get.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:window_manager/window_manager.dart';
import 'package:bot_toast/bot_toast.dart';
// import 'package:window_manager/window_manager.dart';
import 'common.dart';
import 'consts.dart';
import 'mobile/pages/home_page.dart';
import 'mobile/pages/server_page.dart';
import 'models/platform_model.dart';
int? windowId;
late List<String> bootArgs;
Future<void> main(List<String> args) async {
WidgetsFlutterBinding.ensureInitialized();
debugPrint("launch args: $args");
bootArgs = List.from(args);
if (!isDesktop) {
runMobileApp();
return;
}
// main window
if (args.isNotEmpty && args.first == 'multi_window') {
windowId = int.parse(args[1]);
stateGlobal.setWindowId(windowId!);
WindowController.fromWindowId(windowId!).showTitleBar(false);
final argument = args[2].isEmpty
? <String, dynamic>{}
: jsonDecode(args[2]) as Map<String, dynamic>;
int type = argument['type'] ?? -1;
// to-do: No need to parse window id ?
// Because stateGlobal.windowId is a global value.
argument['windowId'] = windowId;
WindowType wType = type.windowType;
switch (wType) {
case WindowType.RemoteDesktop:
desktopType = DesktopType.remote;
runMultiWindow(
argument,
kAppTypeDesktopRemote,
'RustDesk - Remote Desktop',
);
break;
case WindowType.FileTransfer:
desktopType = DesktopType.fileTransfer;
runMultiWindow(
argument,
kAppTypeDesktopFileTransfer,
'RustDesk - File Transfer',
);
break;
case WindowType.PortForward:
desktopType = DesktopType.portForward;
runMultiWindow(
argument,
kAppTypeDesktopPortForward,
'RustDesk - Port Forward',
);
break;
default:
break;
}
} else if (args.isNotEmpty && args.first == '--cm') {
debugPrint("--cm started");
desktopType = DesktopType.cm;
await windowManager.ensureInitialized();
runConnectionManagerScreen();
} else if (args.contains('--install')) {
runInstallPage();
} else {
desktopType = DesktopType.main;
await windowManager.ensureInitialized();
windowManager.setPreventClose(true);
runMainApp(true);
}
}
Future<void> initEnv(String appType) async {
// global shared preference
await Get.putAsync(() => SharedPreferences.getInstance());
await platformFFI.init(appType);
// global FFI, use this **ONLY** for global configuration
// for convenience, use global FFI on mobile platform
// focus on multi-ffi on desktop first
await initGlobalFFI();
// await Firebase.initializeApp();
_registerEventHandler();
}
void runMainApp(bool startService) async {
// register uni links
initUniLinks();
await initEnv(kAppTypeMain);
// trigger connection status updater
await bind.mainCheckConnectStatus();
if (startService) {
// await windowManager.ensureInitialized();
gFFI.serverModel.startService();
}
runApp(App());
// set window option
WindowOptions windowOptions = getHiddenTitleBarWindowOptions();
windowManager.waitUntilReadyToShow(windowOptions, () async {
restoreWindowPosition(WindowType.Main);
await windowManager.show();
await windowManager.focus();
await windowManager.setOpacity(1);
});
}
void runMobileApp() async {
await initEnv(kAppTypeMain);
if (isAndroid) androidChannelInit();
runApp(App());
}
void runMultiWindow(
Map<String, dynamic> argument,
String appType,
String title,
) async {
await initEnv(appType);
_runApp(
title,
DesktopRemoteScreen(
params: argument,
),
MyTheme.currentThemeMode(),
);
}
void runConnectionManagerScreen() async {
await initEnv(kAppTypeMain);
// initialize window
WindowOptions windowOptions =
getHiddenTitleBarWindowOptions(size: kConnectionManagerWindowSize);
_runApp(
'',
const DesktopServerPage(),
MyTheme.currentThemeMode(),
);
windowManager.waitUntilReadyToShow(windowOptions, () async {
await windowManager.show();
// ensure initial window size to be changed
await windowManager.setSize(kConnectionManagerWindowSize);
await Future.wait([
windowManager.setAlignment(Alignment.topRight),
windowManager.focus(),
windowManager.setOpacity(1)
]);
// ensure
windowManager.setAlignment(Alignment.topRight);
});
}
void _runApp(
String title,
Widget home,
ThemeMode themeMode,
) {
final botToastBuilder = BotToastInit();
runApp(RefreshWrapper(
builder: (context) => GetMaterialApp(
navigatorKey: globalKey,
debugShowCheckedModeBanner: false,
title: title,
theme: MyTheme.lightTheme,
darkTheme: MyTheme.darkTheme,
themeMode: themeMode,
home: home,
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: supportedLocales,
navigatorObservers: [
// FirebaseAnalyticsObserver(analytics: analytics),
BotToastNavigatorObserver(),
],
builder: (context, child) {
child = _keepScaleBuilder(context, child);
child = botToastBuilder(context, child);
return child;
},
),
));
}
void runInstallPage() async {
await windowManager.ensureInitialized();
await initEnv(kAppTypeMain);
_runApp('', const InstallPage(), ThemeMode.light);
windowManager.waitUntilReadyToShow(
WindowOptions(size: Size(800, 600), center: true), () async {
windowManager.show();
windowManager.focus();
windowManager.setOpacity(1);
windowManager.setAlignment(Alignment.center); // ensure
});
}
WindowOptions getHiddenTitleBarWindowOptions({Size? size}) {
return WindowOptions(
size: size,
center: false,
backgroundColor: Colors.transparent,
skipTaskbar: false,
titleBarStyle: TitleBarStyle.hidden,
);
}
class App extends StatefulWidget {
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.window.onPlatformBrightnessChanged = () {
final userPreference = MyTheme.getThemeModePreference();
if (userPreference != ThemeMode.system) return;
WidgetsBinding.instance.handlePlatformBrightnessChanged();
final systemIsDark =
WidgetsBinding.instance.platformDispatcher.platformBrightness ==
Brightness.dark;
final ThemeMode to;
if (systemIsDark) {
to = ThemeMode.dark;
} else {
to = ThemeMode.light;
}
Get.changeThemeMode(to);
if (desktopType == DesktopType.main) {
bind.mainChangeTheme(dark: to.toShortString());
}
};
}
@override
Widget build(BuildContext context) {
// final analytics = FirebaseAnalytics.instance;
final botToastBuilder = BotToastInit();
return RefreshWrapper(builder: (context) {
return MultiProvider(
providers: [
// global configuration
// use session related FFI when in remote control or file transfer page
ChangeNotifierProvider.value(value: gFFI.ffiModel),
ChangeNotifierProvider.value(value: gFFI.imageModel),
ChangeNotifierProvider.value(value: gFFI.cursorModel),
ChangeNotifierProvider.value(value: gFFI.canvasModel),
],
child: GetMaterialApp(
navigatorKey: globalKey,
debugShowCheckedModeBanner: false,
title: 'RustDesk',
theme: MyTheme.lightTheme,
darkTheme: MyTheme.darkTheme,
themeMode: MyTheme.currentThemeMode(),
home: isDesktop
? const DesktopTabPage()
: !isAndroid
? WebHomePage()
: HomePage(),
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: supportedLocales,
navigatorObservers: [
// FirebaseAnalyticsObserver(analytics: analytics),
BotToastNavigatorObserver(),
],
builder: isAndroid
? (context, child) => AccessibilityListener(
child: MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaleFactor: 1.0,
),
child: child ?? Container(),
),
)
: (context, child) {
child = _keepScaleBuilder(context, child);
child = botToastBuilder(context, child);
return child;
},
),
);
});
}
}
Widget _keepScaleBuilder(BuildContext context, Widget? child) {
return MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaleFactor: 1.0,
),
child: child ?? Container(),
);
}
_registerEventHandler() {
if (isDesktop && desktopType != DesktopType.main) {
platformFFI.registerEventHandler('theme', 'theme', (evt) async {
String? dark = evt['dark'];
if (dark != null) {
MyTheme.changeDarkMode(MyTheme.themeModeFromString(dark));
}
});
platformFFI.registerEventHandler('language', 'language', (_) async {
reloadAllWindows();
});
}
}