From 5b79e89fde9ac4e2f1b6fea8abffc53fb16d101c Mon Sep 17 00:00:00 2001 From: lxien Date: Mon, 31 Aug 2026 18:09:47 +0800 Subject: [PATCH] feat(desktop): add system tray --- desktop/i18n/en_US.properties | 2 ++ desktop/i18n/zh_CN.properties | 2 ++ desktop/src/main.rs | 43 ++++++++++++++++++++++++++++------- desktop/ui/app.slint | 3 ++- desktop/ui/tray.slint | 17 ++++++++++++++ 5 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 desktop/ui/tray.slint diff --git a/desktop/i18n/en_US.properties b/desktop/i18n/en_US.properties index f1ee198..9abe602 100644 --- a/desktop/i18n/en_US.properties +++ b/desktop/i18n/en_US.properties @@ -115,6 +115,8 @@ menu-theme-light=Light menu-theme-dark=Dark menu-help=Help menu-about=About Orbien Desktop +tray-quit=Quit +tray-tooltip=Orbien about-window-title=About Orbien Desktop about-page-title=About about-tagline=Orbien intranet-penetration cross-platform native desktop client — visual config, ready out of the box diff --git a/desktop/i18n/zh_CN.properties b/desktop/i18n/zh_CN.properties index d4d1f18..cd903bf 100644 --- a/desktop/i18n/zh_CN.properties +++ b/desktop/i18n/zh_CN.properties @@ -110,6 +110,8 @@ menu-theme-light=白昼 menu-theme-dark=黑夜 menu-help=帮助 menu-about=关于 Orbien Desktop +tray-quit=退出 +tray-tooltip=Orbien about-window-title=关于 Orbien Desktop about-page-title=关于 about-tagline=Orbien内网穿透跨平台原生桌面客户端,可视化配置,开箱即用 diff --git a/desktop/src/main.rs b/desktop/src/main.rs index f61bf27..5a8d9ac 100644 --- a/desktop/src/main.rs +++ b/desktop/src/main.rs @@ -25,6 +25,13 @@ fn locale_of(ui: &AppWindow) -> Locale { Locale::from_index(ui.get_locale_index()) } +fn sync_tray_locale(tray: &OrbienTray, locale_index: i32) { + let tr = tray.global::(); + if tr.get_locale_index() != locale_index { + tr.set_locale_index(locale_index); + } +} + fn apply_theme(ui: &AppWindow, theme_index: i32) { ui.set_theme_index(theme_index); } @@ -671,6 +678,16 @@ fn main() -> Result<(), slint::PlatformError> { ui.set_locale_index(prefs.locale_index()); let _ = ui.global::().set_locale_index(ui.get_locale_index()); apply_theme(&ui, prefs.theme_index()); + + let tray = OrbienTray::new()?; + sync_tray_locale(&tray, ui.get_locale_index()); + let tray_weak = tray.as_weak(); + tray.on_quit(|| { + runtime::stop_async(|| { + let _ = slint::quit_event_loop(); + }); + }); + let default_path = config_bridge::default_config_path(); ui.set_config_file_path(config_bridge::path_display(&default_path).into()); @@ -912,7 +929,7 @@ fn main() -> Result<(), slint::PlatformError> { } }); - wire_tunnel_and_config(&ui, remotes_gen.clone()); + wire_tunnel_and_config(&ui, remotes_gen.clone(), tray_weak); let ui_weak = ui.as_weak(); ui.on_show_about(move || { @@ -946,7 +963,9 @@ fn main() -> Result<(), slint::PlatformError> { ui.show()?; center_window_on_screen(&ui); - ui.run() + let result = ui.run(); + drop(tray); + result } fn center_window_on_screen(ui: &AppWindow) { @@ -994,7 +1013,11 @@ fn open_url(url: &str) -> std::io::Result<()> { Ok(()) } -fn wire_tunnel_and_config(ui: &AppWindow, remotes_gen: Arc>) { +fn wire_tunnel_and_config( + ui: &AppWindow, + remotes_gen: Arc>, + tray_weak: slint::Weak, +) { let ui_weak = ui.as_weak(); ui.on_tunnel_add(move || { if let Some(ui) = ui_weak.upgrade() { @@ -1298,12 +1321,16 @@ fn wire_tunnel_and_config(ui: &AppWindow, remotes_gen: Arc>) { let ui_weak = ui.as_weak(); ui.on_locale_changed(move |index| { - if let Some(ui) = ui_weak.upgrade() { - ui.global::().set_locale_index(index); - let label = if index == 0 { "zh-CN" } else { "en-US" }; - push_log(&ui, &format!("INFO locale set to {label}")); - persist_prefs(&ui); + let Some(ui) = ui_weak.upgrade() else { + return; + }; + ui.global::().set_locale_index(index); + if let Some(tray) = tray_weak.upgrade() { + sync_tray_locale(&tray, index); } + let label = if index == 0 { "zh-CN" } else { "en-US" }; + push_log(&ui, &format!("INFO locale set to {label}")); + persist_prefs(&ui); }); let ui_weak = ui.as_weak(); diff --git a/desktop/ui/app.slint b/desktop/ui/app.slint index dab9690..b08ba10 100644 --- a/desktop/ui/app.slint +++ b/desktop/ui/app.slint @@ -12,8 +12,9 @@ import { AboutDialog } from "pages/about.slint"; import { ToastHost } from "toast.slint"; import { Tr } from "i18n.slint"; import { AppMeta } from "version.slint"; +import { OrbienTray } from "tray.slint"; -export { AppPage, TunnelRow, LogLine, Tr, AboutDialog, AppMeta, Theme } +export { AppPage, TunnelRow, LogLine, Tr, AboutDialog, AppMeta, Theme, OrbienTray } export component AppWindow inherits Window { title: "Orbien Desktop"; default-font-family: "Noto Sans SC"; diff --git a/desktop/ui/tray.slint b/desktop/ui/tray.slint new file mode 100644 index 0000000..c12065e --- /dev/null +++ b/desktop/ui/tray.slint @@ -0,0 +1,17 @@ +import { Tr } from "i18n.slint"; + +export component OrbienTray inherits SystemTrayIcon { + icon: @image-url("../assets/logo.png"); + tooltip: Tr.tray-tooltip; + + callback quit(); + + Menu { + MenuItem { + title: Tr.tray-quit; + activated => { + root.quit(); + } + } + } +}