Merge pull request #1473 from 21pages/optimize

sync theme and language
This commit is contained in:
RustDesk 2022-09-08 12:34:56 +08:00 committed by GitHub
commit 1c170366e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 244 additions and 98 deletions

View File

@ -24,7 +24,5 @@ void main(List<String> args) async {
gFFI.serverModel.clients gFFI.serverModel.clients
.add(Client(3, false, false, "UserD", "441123123", true, false, false)); .add(Client(3, false, false, "UserD", "441123123", true, false, false));
runApp(GetMaterialApp( runApp(GetMaterialApp(
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false, home: DesktopServerPage()));
theme: getCurrentTheme(),
home: DesktopServerPage()));
} }

View File

@ -27,6 +27,7 @@ var isWeb = false;
var isWebDesktop = false; var isWebDesktop = false;
var version = ""; var version = "";
int androidVersion = 0; int androidVersion = 0;
late final DesktopType? desktopType;
typedef F = String Function(String); typedef F = String Function(String);
typedef FMethod = String Function(String, dynamic); typedef FMethod = String Function(String, dynamic);
@ -42,6 +43,15 @@ late final iconFile = MemoryImage(Uint8List.fromList(base64Decode(
late final iconRestart = MemoryImage(Uint8List.fromList(base64Decode( late final iconRestart = MemoryImage(Uint8List.fromList(base64Decode(
'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAB7BAAAewQHDaVRTAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAbhJREFUWIXVlrFqFGEUhb+7UYxaWCQKlrKKxaZSQVGDJih2tj6MD2DnMwiWvoAIRnENIpZiYxEro6IooiS7SPwsMgNLkk3mjmYmnmb45/73nMNwz/x/qH3gMu2gH6rAU+Blw+Lngau4jpmGxVF7qp1iPWjaQKnZ2WnXbuP/NqAeUPc3ZkA9XDwvqc+BVWCgPlJ7tRwUKThZce819b46VH+pfXVRXVO/q2cSul3VOgZUl0ejq86r39TXI8mqZKDuDEwCw3IREQvAbWAGmMsQZQ0sAl3gHPB1Q+0e8BuYzRDuy2yOiFVgaUxtRf0ETGc4syk4rc6PqU0Cx9j8Zf6dAeAK8Fi9sUXtFjABvEgxJlNwRP2svlNPjbw/q35U36oTFbnyMSwabxb/gB/qA3VBHagrauV7RW0DRfP1IvMlXqkXkhz1DYyQTKtHa/Z2VVMx3IiI+PI3/bCHjuOpFrSnAMpL6QfgTcMGesDx0kBr2BMzsNyi/vtQu8CJlgwsRbZDnWP90NkKaxHxJMOXMqAeAn5u0ydwMCKGY+qbkB3C2W3EKWoXk5zVoHbUZ+6Mh7tl4G4F8RJ3qvL+AfV3r5Vdpj70AAAAAElFTkSuQmCC'))); 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAB7BAAAewQHDaVRTAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAbhJREFUWIXVlrFqFGEUhb+7UYxaWCQKlrKKxaZSQVGDJih2tj6MD2DnMwiWvoAIRnENIpZiYxEro6IooiS7SPwsMgNLkk3mjmYmnmb45/73nMNwz/x/qH3gMu2gH6rAU+Blw+Lngau4jpmGxVF7qp1iPWjaQKnZ2WnXbuP/NqAeUPc3ZkA9XDwvqc+BVWCgPlJ7tRwUKThZce819b46VH+pfXVRXVO/q2cSul3VOgZUl0ejq86r39TXI8mqZKDuDEwCw3IREQvAbWAGmMsQZQ0sAl3gHPB1Q+0e8BuYzRDuy2yOiFVgaUxtRf0ETGc4syk4rc6PqU0Cx9j8Zf6dAeAK8Fi9sUXtFjABvEgxJlNwRP2svlNPjbw/q35U36oTFbnyMSwabxb/gB/qA3VBHagrauV7RW0DRfP1IvMlXqkXkhz1DYyQTKtHa/Z2VVMx3IiI+PI3/bCHjuOpFrSnAMpL6QfgTcMGesDx0kBr2BMzsNyi/vtQu8CJlgwsRbZDnWP90NkKaxHxJMOXMqAeAn5u0ydwMCKGY+qbkB3C2W3EKWoXk5zVoHbUZ+6Mh7tl4G4F8RJ3qvL+AfV3r5Vdpj70AAAAAElFTkSuQmCC')));
enum DesktopType {
main,
remote,
fileTransfer,
cm,
portForward,
rdp,
}
class IconFont { class IconFont {
static const _family1 = 'Tabbar'; static const _family1 = 'Tabbar';
static const _family2 = 'PeerSearchbar'; static const _family2 = 'PeerSearchbar';
@ -182,6 +192,32 @@ class MyTheme {
], ],
); );
static changeTo(bool dark) {
if (Get.isDarkMode != dark) {
Get.find<SharedPreferences>().setString("darkTheme", dark ? "Y" : "");
Get.changeThemeMode(dark ? ThemeMode.dark : ThemeMode.light);
if (desktopType == DesktopType.main) {
bind.mainChangeTheme(dark: dark);
}
}
}
static bool _themeInitialed = false;
static ThemeMode initialThemeMode({bool mainPage = false}) {
bool dark;
// Brightnesss is always light on windows, Flutter 3.0.5
if (_themeInitialed || !mainPage || Platform.isWindows) {
dark = "Y" == Get.find<SharedPreferences>().getString("darkTheme");
} else {
dark = WidgetsBinding.instance.platformDispatcher.platformBrightness ==
Brightness.dark;
Get.find<SharedPreferences>().setString("darkTheme", dark ? "Y" : "");
}
_themeInitialed = true;
return dark ? ThemeMode.dark : ThemeMode.light;
}
static ColorThemeExtension color(BuildContext context) { static ColorThemeExtension color(BuildContext context) {
return Theme.of(context).extension<ColorThemeExtension>()!; return Theme.of(context).extension<ColorThemeExtension>()!;
} }
@ -192,8 +228,7 @@ class MyTheme {
} }
bool isDarkTheme() { bool isDarkTheme() {
final isDark = "Y" == Get.find<SharedPreferences>().getString("darkTheme"); return Get.isDarkMode;
return isDark;
} }
final ButtonStyle flatButtonStyle = TextButton.styleFrom( final ButtonStyle flatButtonStyle = TextButton.styleFrom(
@ -478,7 +513,9 @@ void msgBox(
submit() { submit() {
dialogManager.dismissAll(); dialogManager.dismissAll();
// https://github.com/fufesou/rustdesk/blob/5e9a31340b899822090a3731769ae79c6bf5f3e5/src/ui/common.tis#L263 // https://github.com/fufesou/rustdesk/blob/5e9a31340b899822090a3731769ae79c6bf5f3e5/src/ui/common.tis#L263
if (!type.contains("custom")) { if (!type.contains("custom") &&
!(desktopType == DesktopType.portForward ||
desktopType == DesktopType.rdp)) {
closeConnection(); closeConnection();
} }
} }

View File

@ -5,6 +5,8 @@ const String kAppTypeMain = "main";
const String kAppTypeDesktopRemote = "remote"; const String kAppTypeDesktopRemote = "remote";
const String kAppTypeDesktopFileTransfer = "file transfer"; const String kAppTypeDesktopFileTransfer = "file transfer";
const String kAppTypeDesktopPortForward = "port forward"; const String kAppTypeDesktopPortForward = "port forward";
const String kAppTypeDesktopRDP = "rdp";
const String kTabLabelHomePage = "Home"; const String kTabLabelHomePage = "Home";
const String kTabLabelSettingPage = "Settings"; const String kTabLabelSettingPage = "Settings";

View File

@ -218,27 +218,25 @@ class _UserInterfaceState extends State<_UserInterface>
onChanged: (key) async { onChanged: (key) async {
await bind.mainSetLocalOption(key: "lang", value: key); await bind.mainSetLocalOption(key: "lang", value: key);
Get.forceAppUpdate(); Get.forceAppUpdate();
bind.mainChangeLanguage(lang: key);
}, },
).marginOnly(left: _kContentHMargin); ).marginOnly(left: _kContentHMargin);
}); });
} }
Widget theme() { Widget theme() {
var change = () { change() {
bool dark = !isDarkTheme(); MyTheme.changeTo(!isDarkTheme());
Get.changeTheme(dark ? MyTheme.darkTheme : MyTheme.lightTheme); }
Get.find<SharedPreferences>().setString("darkTheme", dark ? "Y" : "");
Get.forceAppUpdate();
};
return GestureDetector( return GestureDetector(
onTap: change,
child: Row( child: Row(
children: [ children: [
Checkbox(value: isDarkTheme(), onChanged: (_) => change()), Checkbox(value: isDarkTheme(), onChanged: (_) => change()),
Expanded(child: Text(translate('Dark Theme'))), Expanded(child: Text(translate('Dark Theme'))),
], ],
).marginOnly(left: _kCheckBoxLeftMargin), ).marginOnly(left: _kCheckBoxLeftMargin),
onTap: change,
); );
} }
} }

View File

@ -33,7 +33,6 @@ class _DesktopTabPageState extends State<DesktopTabPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final dark = isDarkTheme();
RxBool fullscreen = false.obs; RxBool fullscreen = false.obs;
Get.put(fullscreen, tag: 'fullscreen'); Get.put(fullscreen, tag: 'fullscreen');
return Obx(() => DragToResizeArea( return Obx(() => DragToResizeArea(

View File

@ -70,45 +70,38 @@ class _PortForwardPageState extends State<PortForwardPage>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
return Overlay(initialEntries: [ return Scaffold(
OverlayEntry(builder: (context) { backgroundColor: MyTheme.color(context).grayBg,
_ffi.dialogManager.setOverlayState(Overlay.of(context)); body: FutureBuilder(future: () async {
return Scaffold( if (!isRdp) {
backgroundColor: MyTheme.color(context).grayBg, refreshTunnelConfig();
body: FutureBuilder(future: () async { }
if (!isRdp) { }(), builder: (context, snapshot) {
refreshTunnelConfig(); if (snapshot.connectionState == ConnectionState.done) {
} return Container(
}(), builder: (context, snapshot) { decoration: BoxDecoration(
if (snapshot.connectionState == ConnectionState.done) { border: Border.all(
return Container( width: 20, color: MyTheme.color(context).grayBg!)),
decoration: BoxDecoration( child: Column(
border: Border.all( crossAxisAlignment: CrossAxisAlignment.stretch,
width: 20, color: MyTheme.color(context).grayBg!)), children: [
child: Column( buildPrompt(context),
crossAxisAlignment: CrossAxisAlignment.stretch, Flexible(
children: [ child: Container(
buildPrompt(context), decoration: BoxDecoration(
Flexible( color: MyTheme.color(context).bg,
child: Container( border: Border.all(width: 1, color: MyTheme.border)),
decoration: BoxDecoration( child:
color: MyTheme.color(context).bg, widget.isRDP ? buildRdp(context) : buildTunnel(context),
border: ),
Border.all(width: 1, color: MyTheme.border)),
child: widget.isRDP
? buildRdp(context)
: buildTunnel(context),
),
),
],
), ),
); ],
} ),
return const Offstage(); );
}), }
); return const Offstage();
}) }),
]); );
} }
buildPrompt(BuildContext context) { buildPrompt(BuildContext context) {

View File

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
import 'package:flutter_hbb/mobile/pages/chat_page.dart'; import 'package:flutter_hbb/mobile/pages/chat_page.dart';
import 'package:flutter_hbb/models/chat_model.dart'; import 'package:flutter_hbb/models/chat_model.dart';
@ -63,20 +64,15 @@ class _DesktopServerPageState extends State<DesktopServerPage>
border: Border.all(color: MyTheme.color(context).border!)), border: Border.all(color: MyTheme.color(context).border!)),
child: Scaffold( child: Scaffold(
backgroundColor: MyTheme.color(context).bg, backgroundColor: MyTheme.color(context).bg,
body: Overlay(initialEntries: [ body: Center(
OverlayEntry(builder: (context) { child: Column(
gFFI.dialogManager.setOverlayState(Overlay.of(context)); mainAxisAlignment: MainAxisAlignment.start,
return Center( children: [
child: Column( Expanded(child: ConnectionManager()),
mainAxisAlignment: MainAxisAlignment.start, SizedBox.fromSize(size: Size(0, 15.0)),
children: [ ],
Expanded(child: ConnectionManager()), ),
SizedBox.fromSize(size: Size(0, 15.0)), ),
],
),
);
})
]),
)))); ))));
} }
@ -111,7 +107,7 @@ class ConnectionManagerState extends State<ConnectionManager> {
return serverModel.clients.isEmpty return serverModel.clients.isEmpty
? Column( ? Column(
children: [ children: [
buildTitleBar(Offstage()), buildTitleBar(),
Expanded( Expanded(
child: Center( child: Center(
child: Text(translate("Waiting")), child: Text(translate("Waiting")),
@ -134,20 +130,27 @@ class ConnectionManagerState extends State<ConnectionManager> {
])); ]));
} }
Widget buildTitleBar(Widget middle) { Widget buildTitleBar() {
return GestureDetector( return SizedBox(
onPanDown: (d) { height: kDesktopRemoteTabBarHeight,
windowManager.startDragging();
},
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
_AppIcon(), const _AppIcon(),
Expanded(child: middle), Expanded(
child: GestureDetector(
onPanStart: (d) {
windowManager.startDragging();
},
child: Container(
color: MyTheme.color(context).bg,
),
),
),
const SizedBox( const SizedBox(
width: 4.0, width: 4.0,
), ),
_CloseButton() const _CloseButton()
], ],
), ),
); );
@ -209,15 +212,16 @@ class _CloseButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Ink( return IconButton(
child: InkWell( onPressed: () {
onTap: () { windowManager.close();
windowManager.close(); },
}, icon: const Icon(
child: Icon( IconFont.close,
Icons.close, size: 18,
size: 30, ),
)), splashColor: Colors.transparent,
hoverColor: Colors.transparent,
); );
} }
} }

View File

@ -43,12 +43,16 @@ Future<Null> main(List<String> args) async {
WindowType wType = type.windowType; WindowType wType = type.windowType;
switch (wType) { switch (wType) {
case WindowType.RemoteDesktop: case WindowType.RemoteDesktop:
desktopType = DesktopType.remote;
runRemoteScreen(argument); runRemoteScreen(argument);
break; break;
case WindowType.FileTransfer: case WindowType.FileTransfer:
desktopType = DesktopType.fileTransfer;
runFileTransferScreen(argument); runFileTransferScreen(argument);
break; break;
case WindowType.PortForward: case WindowType.PortForward:
desktopType =
argument['isRDP'] ? DesktopType.rdp : DesktopType.portForward;
runPortForwardScreen(argument); runPortForwardScreen(argument);
break; break;
default: default:
@ -56,19 +60,17 @@ Future<Null> main(List<String> args) async {
} }
} else if (args.isNotEmpty && args.first == '--cm') { } else if (args.isNotEmpty && args.first == '--cm') {
print("--cm started"); print("--cm started");
desktopType = DesktopType.cm;
await windowManager.ensureInitialized(); await windowManager.ensureInitialized();
runConnectionManagerScreen(); runConnectionManagerScreen();
} else { } else {
desktopType = DesktopType.main;
await windowManager.ensureInitialized(); await windowManager.ensureInitialized();
windowManager.setPreventClose(true); windowManager.setPreventClose(true);
runMainApp(true); runMainApp(true);
} }
} }
ThemeData getCurrentTheme() {
return isDarkTheme() ? MyTheme.darkTheme : MyTheme.lightTheme;
}
Future<void> initEnv(String appType) async { Future<void> initEnv(String appType) async {
await platformFFI.init(appType); await platformFFI.init(appType);
// global FFI, use this **ONLY** for global configuration // global FFI, use this **ONLY** for global configuration
@ -77,6 +79,7 @@ Future<void> initEnv(String appType) async {
await initGlobalFFI(); await initGlobalFFI();
// await Firebase.initializeApp(); // await Firebase.initializeApp();
refreshCurrentUser(); refreshCurrentUser();
_registerEventHandler();
} }
void runMainApp(bool startService) async { void runMainApp(bool startService) async {
@ -111,7 +114,9 @@ void runRemoteScreen(Map<String, dynamic> argument) async {
navigatorKey: globalKey, navigatorKey: globalKey,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
title: 'RustDesk - Remote Desktop', title: 'RustDesk - Remote Desktop',
theme: getCurrentTheme(), theme: MyTheme.lightTheme,
darkTheme: MyTheme.darkTheme,
themeMode: MyTheme.initialThemeMode(),
home: DesktopRemoteScreen( home: DesktopRemoteScreen(
params: argument, params: argument,
), ),
@ -129,7 +134,9 @@ void runFileTransferScreen(Map<String, dynamic> argument) async {
navigatorKey: globalKey, navigatorKey: globalKey,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
title: 'RustDesk - File Transfer', title: 'RustDesk - File Transfer',
theme: getCurrentTheme(), theme: MyTheme.lightTheme,
darkTheme: MyTheme.darkTheme,
themeMode: MyTheme.initialThemeMode(),
home: DesktopFileTransferScreen(params: argument), home: DesktopFileTransferScreen(params: argument),
navigatorObservers: [ navigatorObservers: [
// FirebaseAnalyticsObserver(analytics: analytics), // FirebaseAnalyticsObserver(analytics: analytics),
@ -146,7 +153,9 @@ void runPortForwardScreen(Map<String, dynamic> argument) async {
navigatorKey: globalKey, navigatorKey: globalKey,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
title: 'RustDesk - Port Forward', title: 'RustDesk - Port Forward',
theme: getCurrentTheme(), theme: MyTheme.lightTheme,
darkTheme: MyTheme.darkTheme,
themeMode: MyTheme.initialThemeMode(),
home: DesktopPortForwardScreen(params: argument), home: DesktopPortForwardScreen(params: argument),
navigatorObservers: [ navigatorObservers: [
// FirebaseAnalyticsObserver(analytics: analytics), // FirebaseAnalyticsObserver(analytics: analytics),
@ -170,7 +179,9 @@ void runConnectionManagerScreen() async {
]); ]);
runApp(GetMaterialApp( runApp(GetMaterialApp(
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
theme: getCurrentTheme(), theme: MyTheme.lightTheme,
darkTheme: MyTheme.darkTheme,
themeMode: MyTheme.initialThemeMode(),
home: DesktopServerPage(), home: DesktopServerPage(),
builder: _keepScaleBuilder())); builder: _keepScaleBuilder()));
} }
@ -185,7 +196,26 @@ WindowOptions getHiddenTitleBarWindowOptions(Size size) {
); );
} }
class App extends StatelessWidget { class App extends StatefulWidget {
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.window.onPlatformBrightnessChanged = () {
WidgetsBinding.instance.handlePlatformBrightnessChanged();
var system =
WidgetsBinding.instance.platformDispatcher.platformBrightness;
var current = isDarkTheme() ? Brightness.dark : Brightness.light;
if (current != system) {
MyTheme.changeTo(system == Brightness.dark);
}
};
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// final analytics = FirebaseAnalytics.instance; // final analytics = FirebaseAnalytics.instance;
@ -204,7 +234,9 @@ class App extends StatelessWidget {
navigatorKey: globalKey, navigatorKey: globalKey,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
title: 'RustDesk', title: 'RustDesk',
theme: getCurrentTheme(), theme: MyTheme.lightTheme,
darkTheme: MyTheme.darkTheme,
themeMode: MyTheme.initialThemeMode(mainPage: true),
home: isDesktop home: isDesktop
? const DesktopTabPage() ? const DesktopTabPage()
: !isAndroid : !isAndroid
@ -238,3 +270,17 @@ _keepScaleBuilder() {
); );
}; };
} }
_registerEventHandler() {
if (desktopType != DesktopType.main) {
platformFFI.registerEventHandler('theme', 'theme', (evt) {
String? dark = evt['dark'];
if (dark != null) {
MyTheme.changeTo(dark == 'true');
}
});
platformFFI.registerEventHandler('language', 'language', (_) {
Get.forceAppUpdate();
});
}
}

View File

@ -1,7 +1,7 @@
#include <dlfcn.h> #include <dlfcn.h>
#include "my_application.h" #include "my_application.h"
#define RUSTDESK_LIB_PATH "ibrustdesk.so" #define RUSTDESK_LIB_PATH "librustdesk.so"
// #define RUSTDESK_LIB_PATH "/usr/lib/rustdesk/librustdesk.so" // #define RUSTDESK_LIB_PATH "/usr/lib/rustdesk/librustdesk.so"
typedef bool (*RustDeskCoreMain)(); typedef bool (*RustDeskCoreMain)();

View File

@ -17,6 +17,8 @@ use crate::{client::*, flutter_ffi::EventToUI};
pub(super) const APP_TYPE_MAIN: &str = "main"; pub(super) const APP_TYPE_MAIN: &str = "main";
pub(super) const APP_TYPE_DESKTOP_REMOTE: &str = "remote"; pub(super) const APP_TYPE_DESKTOP_REMOTE: &str = "remote";
pub(super) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer"; pub(super) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer";
pub(super) const APP_TYPE_DESKTOP_PORT_FORWARD: &str = "port forward";
pub(super) const APP_TYPE_DESKTOP_RDP: &str = "rdp";
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref SESSIONS: RwLock<HashMap<String,Session<FlutterHandler>>> = Default::default(); pub static ref SESSIONS: RwLock<HashMap<String,Session<FlutterHandler>>> = Default::default();
@ -376,6 +378,14 @@ pub mod connection_manager {
vec![("id", &id.to_string()), ("text", &text)], vec![("id", &id.to_string()), ("text", &text)],
); );
} }
fn change_theme(&self, dark: bool) {
self.push_event("theme", vec![("dark", &dark.to_string())]);
}
fn change_language(&self) {
self.push_event("language", vec![]);
}
} }
impl FlutterHandler { impl FlutterHandler {

View File

@ -23,7 +23,7 @@ use crate::ui_interface::{
get_app_name, get_async_job_status, get_connect_status, get_fav, get_id, get_lan_peers, get_app_name, get_async_job_status, get_connect_status, get_fav, get_id, get_lan_peers,
get_langs, get_license, get_local_option, get_mouse_time, get_option, get_options, get_peer, get_langs, get_license, get_local_option, get_mouse_time, get_option, get_options, get_peer,
get_peer_option, get_socks, get_sound_inputs, get_uuid, get_version, has_hwcodec, get_peer_option, get_socks, get_sound_inputs, get_uuid, get_version, has_hwcodec,
has_rendezvous_service, post_request, set_local_option, set_option, set_options, has_rendezvous_service, post_request, send_to_cm, set_local_option, set_option, set_options,
set_peer_option, set_permanent_password, set_socks, store_fav, test_if_valid_server, set_peer_option, set_permanent_password, set_socks, store_fav, test_if_valid_server,
update_temporary_password, using_public_server, update_temporary_password, using_public_server,
}; };
@ -659,6 +659,34 @@ pub fn main_load_lan_peers() {
}; };
} }
fn main_broadcast_message(data: &HashMap<&str, &str>) {
let apps = vec![
flutter::APP_TYPE_DESKTOP_REMOTE,
flutter::APP_TYPE_DESKTOP_FILE_TRANSFER,
flutter::APP_TYPE_DESKTOP_PORT_FORWARD,
flutter::APP_TYPE_DESKTOP_RDP,
];
for app in apps {
if let Some(s) = flutter::GLOBAL_EVENT_STREAM.read().unwrap().get(app) {
s.add(serde_json::ser::to_string(data).unwrap_or("".to_owned()));
};
}
}
pub fn main_change_theme(dark: bool) {
main_broadcast_message(&HashMap::from([
("name", "theme"),
("dark", &dark.to_string()),
]));
send_to_cm(&crate::ipc::Data::Theme(dark));
}
pub fn main_change_language(lang: String) {
main_broadcast_message(&HashMap::from([("name", "language"), ("lang", &lang)]));
send_to_cm(&crate::ipc::Data::Language(lang));
}
pub fn session_add_port_forward( pub fn session_add_port_forward(
id: String, id: String,
local_port: i32, local_port: i32,

View File

@ -182,6 +182,8 @@ pub enum Data {
#[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli")))] #[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli")))]
Mouse(DataMouse), Mouse(DataMouse),
Control(DataControl), Control(DataControl),
Theme(bool),
Language(String),
Empty, Empty,
} }

View File

@ -47,6 +47,14 @@ impl InvokeUiCM for SciterHandler {
fn new_message(&self, id: i32, text: String) { fn new_message(&self, id: i32, text: String) {
self.call("newMessage", &make_args!(id, text)); self.call("newMessage", &make_args!(id, text));
} }
fn change_theme(&self, _dark: bool) {
// TODO
}
fn change_language(&self) {
// TODO
}
} }
impl SciterHandler { impl SciterHandler {

View File

@ -63,7 +63,7 @@ class MsgboxComponent: Reactor.Component {
var ts = this.auto_login ? { checked: true } : {}; var ts = this.auto_login ? { checked: true } : {};
return <div .form> return <div .form>
<PasswordComponent value={this.content} /> <PasswordComponent value={this.content} />
<div><button|checkbox(auto_login) {ts}>{translate('Auto Login')}</button></div> <div><button|checkbox(auto_login) {ts} style="width: *; word-wrap: break-word; overflow-wrap: break-word; white-space: normal; height: auto; overflow: hidden;">{translate('Auto Login')}</button></div>
</div>; </div>;
} }
return this.content; return this.content;

View File

@ -60,6 +60,10 @@ pub trait InvokeUiCM: Send + Clone + 'static + Sized {
fn remove_connection(&self, id: i32); fn remove_connection(&self, id: i32);
fn new_message(&self, id: i32, text: String); fn new_message(&self, id: i32, text: String);
fn change_theme(&self, dark: bool);
fn change_language(&self);
} }
impl<T: InvokeUiCM> Deref for ConnectionManager<T> { impl<T: InvokeUiCM> Deref for ConnectionManager<T> {
@ -198,6 +202,8 @@ pub enum ClipboardFileData {
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) { pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
use hbb_common::config::LocalConfig;
let (tx_file, _rx_file) = mpsc::unbounded_channel::<ClipboardFileData>(); let (tx_file, _rx_file) = mpsc::unbounded_channel::<ClipboardFileData>();
#[cfg(windows)] #[cfg(windows)]
let cm_clip = cm.clone(); let cm_clip = cm.clone();
@ -280,6 +286,13 @@ pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
.send(ClipboardFileData::Enable((conn_id, enabled))) .send(ClipboardFileData::Enable((conn_id, enabled)))
.ok(); .ok();
} }
Data::Theme(dark) => {
cm.change_theme(dark);
}
Data::Language(lang) => {
LocalConfig::set_option("lang".to_owned(), lang);
cm.change_language();
}
_ => { _ => {
} }

View File

@ -373,7 +373,8 @@ pub fn get_mouse_time() -> f64 {
} }
pub fn check_mouse_time() { pub fn check_mouse_time() {
#[cfg(not(any(target_os = "android", target_os = "ios")))]{ #[cfg(not(any(target_os = "android", target_os = "ios")))]
{
let sender = SENDER.lock().unwrap(); let sender = SENDER.lock().unwrap();
allow_err!(sender.send(ipc::Data::MouseMoveTime(0))); allow_err!(sender.send(ipc::Data::MouseMoveTime(0)));
} }
@ -779,6 +780,13 @@ pub(crate) async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedRe
} }
} }
#[tokio::main(flavor = "current_thread")]
pub(crate) async fn send_to_cm(data: &ipc::Data) {
if let Ok(mut c) = ipc::connect(1000, "_cm").await {
c.send(data).await.ok();
}
}
const INVALID_FORMAT: &'static str = "Invalid format"; const INVALID_FORMAT: &'static str = "Invalid format";
const UNKNOWN_ERROR: &'static str = "Unknown error"; const UNKNOWN_ERROR: &'static str = "Unknown error";