feat: add lightweight mode (#1739)

This commit is contained in:
ruokeqx
2026-03-29 18:35:23 +08:00
committed by GitHub
parent 210bff96c2
commit b1c7fe5563
5 changed files with 180 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
#[tauri::command]
pub fn enter_lightweight_mode(app: tauri::AppHandle) -> Result<(), String> {
crate::lightweight::enter_lightweight_mode(&app)
}
#[tauri::command]
pub fn exit_lightweight_mode(app: tauri::AppHandle) -> Result<(), String> {
crate::lightweight::exit_lightweight_mode(&app)
}
#[tauri::command]
pub fn is_lightweight_mode() -> bool {
crate::lightweight::is_lightweight_mode()
}
+2
View File
@@ -25,6 +25,7 @@ mod sync_support;
mod usage;
mod webdav_sync;
mod workspace;
mod lightweight;
pub use auth::*;
pub use config::*;
@@ -50,3 +51,4 @@ pub use stream_check::*;
pub use usage::*;
pub use webdav_sync::*;
pub use workspace::*;
pub use lightweight::*;
+28
View File
@@ -12,6 +12,7 @@ mod error;
mod gemini_config;
mod gemini_mcp;
mod init_status;
mod lightweight;
mod mcp;
mod openclaw_config;
mod opencode_config;
@@ -204,6 +205,12 @@ pub fn run() {
log::debug!(" arg[{i}]: {}", redact_url_for_log(arg));
}
if crate::lightweight::is_lightweight_mode() {
if let Err(e) = crate::lightweight::exit_lightweight_mode(app) {
log::error!("退出轻量模式重建窗口失败: {e}");
}
}
// Check for deep link URL in args (mainly for Windows/Linux command line)
let mut found_deeplink = false;
for arg in &args {
@@ -615,6 +622,12 @@ pub fn run() {
let urls = event.urls();
log::info!("Received {} URL(s)", urls.len());
if crate::lightweight::is_lightweight_mode() {
if let Err(e) = crate::lightweight::exit_lightweight_mode(&app_handle) {
log::error!("退出轻量模式重建窗口失败: {e}");
}
}
for (i, url) in urls.iter().enumerate() {
let url_str = url.as_str();
log::debug!(" URL[{i}]: {}", redact_url_for_log(url_str));
@@ -1085,6 +1098,10 @@ pub fn run() {
commands::delete_daily_memory_file,
commands::search_daily_memory_files,
commands::open_workspace_directory,
// lightweight mode (for testing or low-resource environments)
commands::enter_lightweight_mode,
commands::exit_lightweight_mode,
commands::is_lightweight_mode,
]);
let app = builder
@@ -1135,6 +1152,10 @@ pub fn run() {
let _ = window.show();
let _ = window.set_focus();
tray::apply_tray_policy(app_handle, true);
} else if crate::lightweight::is_lightweight_mode() {
if let Err(e) = crate::lightweight::exit_lightweight_mode(app_handle) {
log::error!("退出轻量模式重建窗口失败: {e}");
}
}
}
// 处理通过自定义 URL 协议触发的打开事件(例如 ccswitch://...
@@ -1144,6 +1165,13 @@ pub fn run() {
log::info!("RunEvent::Opened with URL: {url_str}");
if url_str.starts_with("ccswitch://") {
if crate::lightweight::is_lightweight_mode() {
if let Err(e) = crate::lightweight::exit_lightweight_mode(app_handle)
{
log::error!("退出轻量模式重建窗口失败: {e}");
}
}
// 解析并广播深链接事件,复用与 single_instance 相同的逻辑
match crate::deeplink::parse_deeplink_url(&url_str) {
Ok(request) => {
+90
View File
@@ -0,0 +1,90 @@
use std::sync::atomic::{AtomicBool, Ordering};
use tauri::Manager;
static LIGHTWEIGHT_MODE: AtomicBool = AtomicBool::new(false);
pub fn enter_lightweight_mode(app: &tauri::AppHandle) -> Result<(), String> {
#[cfg(target_os = "windows")]
{
if let Some(window) = app.get_webview_window("main") {
let _ = window.set_skip_taskbar(true);
}
}
#[cfg(target_os = "macos")]
{
crate::tray::apply_tray_policy(app, false);
}
if let Some(window) = app.get_webview_window("main") {
window
.destroy()
.map_err(|e| format!("销毁主窗口失败: {e}"))?;
}
// else: already in lightweight mode or window not found, just set the flag
LIGHTWEIGHT_MODE.store(true, Ordering::Release);
crate::tray::refresh_tray_menu(app);
log::info!("进入轻量模式");
Ok(())
}
pub fn exit_lightweight_mode(app: &tauri::AppHandle) -> Result<(), String> {
use tauri::WebviewWindowBuilder;
if let Some(window) = app.get_webview_window("main") {
let _ = window.unminimize();
let _ = window.show();
let _ = window.set_focus();
#[cfg(target_os = "windows")]
{
let _ = window.set_skip_taskbar(false);
}
#[cfg(target_os = "macos")]
{
crate::tray::apply_tray_policy(app, true);
}
LIGHTWEIGHT_MODE.store(false, Ordering::Release);
crate::tray::refresh_tray_menu(app);
log::info!("退出轻量模式");
return Ok(());
}
let window_config = app
.config()
.app
.windows
.iter()
.find(|w| w.label == "main")
.ok_or("主窗口配置未找到")?;
WebviewWindowBuilder::from_config(app, window_config)
.map_err(|e| format!("加载主窗口配置失败: {e}"))?
.visible(true)
.build()
.map_err(|e| format!("创建主窗口失败: {e}"))?;
if let Some(window) = app.get_webview_window("main") {
let _ = window.set_focus();
}
#[cfg(target_os = "windows")]
{
if let Some(window) = app.get_webview_window("main") {
let _ = window.set_skip_taskbar(false);
}
}
#[cfg(target_os = "macos")]
{
crate::tray::apply_tray_policy(app, true);
}
LIGHTWEIGHT_MODE.store(false, Ordering::Release);
crate::tray::refresh_tray_menu(app);
log::info!("退出轻量模式");
Ok(())
}
pub fn is_lightweight_mode() -> bool {
LIGHTWEIGHT_MODE.load(Ordering::Acquire)
}
+46
View File
@@ -14,6 +14,7 @@ use crate::store::AppState;
pub struct TrayTexts {
pub show_main: &'static str,
pub no_provider_hint: &'static str,
pub lightweight_mode: &'static str,
pub quit: &'static str,
pub _auto_label: &'static str,
}
@@ -24,6 +25,7 @@ impl TrayTexts {
"en" => Self {
show_main: "Open main window",
no_provider_hint: " (No providers yet, please add them from the main window)",
lightweight_mode: "Lightweight Mode",
quit: "Quit",
_auto_label: "Auto (Failover)",
},
@@ -31,12 +33,14 @@ impl TrayTexts {
show_main: "メインウィンドウを開く",
no_provider_hint:
" (プロバイダーがまだありません。メイン画面から追加してください)",
lightweight_mode: "軽量モード",
quit: "終了",
_auto_label: "自動 (フェイルオーバー)",
},
_ => Self {
show_main: "打开主界面",
no_provider_hint: " (无供应商,请在主界面添加)",
lightweight_mode: "轻量模式",
quit: "退出",
_auto_label: "自动 (故障转移)",
},
@@ -382,6 +386,19 @@ pub fn create_tray_menu(
menu_builder = menu_builder.separator();
}
let lightweight_item = CheckMenuItem::with_id(
app,
"lightweight_mode",
tray_texts.lightweight_mode,
true,
crate::lightweight::is_lightweight_mode(),
None::<&str>,
).map_err(|e| AppError::Message(format!("创建轻量模式菜单失败: {e}")))?;
menu_builder = menu_builder
.item(&lightweight_item)
.separator();
// 退出菜单(分隔符已在上面的 section 循环中添加)
let quit_item = MenuItem::with_id(app, "quit", tray_texts.quit, true, None::<&str>)
.map_err(|e| AppError::Message(format!("创建退出菜单失败: {e}")))?;
@@ -393,6 +410,20 @@ pub fn create_tray_menu(
.map_err(|e| AppError::Message(format!("构建菜单失败: {e}")))
}
pub fn refresh_tray_menu(app: &tauri::AppHandle) {
use crate::store::AppState;
if let Some(state) = app.try_state::<AppState>() {
if let Ok(new_menu) = create_tray_menu(app, state.inner()) {
if let Some(tray) = app.tray_by_id("main") {
if let Err(e) = tray.set_menu(Some(new_menu)) {
log::error!("刷新托盘菜单失败: {e}");
}
}
}
}
}
#[cfg(target_os = "macos")]
pub fn apply_tray_policy(app: &tauri::AppHandle, dock_visible: bool) {
use tauri::ActivationPolicy;
@@ -430,6 +461,21 @@ pub fn handle_tray_menu_event(app: &tauri::AppHandle, event_id: &str) {
{
apply_tray_policy(app, true);
}
} else if crate::lightweight::is_lightweight_mode() {
if let Err(e) = crate::lightweight::exit_lightweight_mode(app) {
log::error!("退出轻量模式重建窗口失败: {e}");
}
}
}
"lightweight_mode" => {
if crate::lightweight::is_lightweight_mode() {
if let Err(e) = crate::lightweight::exit_lightweight_mode(app) {
log::error!("退出轻量模式失败: {e}");
}
} else {
if let Err(e) = crate::lightweight::enter_lightweight_mode(app) {
log::error!("进入轻量模式失败: {e}");
}
}
}
"quit" => {