diff --git a/desktop/crates/cloudreve-sync/src/config.rs b/desktop/crates/cloudreve-sync/src/config.rs index a9813804..9fbf4fa1 100644 --- a/desktop/crates/cloudreve-sync/src/config.rs +++ b/desktop/crates/cloudreve-sync/src/config.rs @@ -62,6 +62,8 @@ pub struct AppConfig { pub log_max_files: usize, /// Delay before starting upload after file stops changing (seconds). 0 disables the delay. pub sync_delay_seconds: u64, + /// Whether to hide the system tray icon (popup stays reachable via shortcuts/relaunch) + pub hide_tray_icon: bool, /// Language/locale setting (e.g., "en-US", "zh-CN"). None means use system default. pub language: Option, } @@ -77,6 +79,7 @@ impl Default for AppConfig { log_level: LogLevel::Debug, log_max_files: 5, sync_delay_seconds: 0, + hide_tray_icon: false, language: None, } } @@ -299,6 +302,21 @@ impl ConfigManager { }) } + /// Whether the system tray icon is hidden + pub fn hide_tray_icon(&self) -> bool { + self.config + .read() + .map(|c| c.hide_tray_icon) + .unwrap_or(false) + } + + /// Set whether the system tray icon is hidden + pub fn set_hide_tray_icon(&self, hide: bool) -> Result<()> { + self.update(|config| { + config.hide_tray_icon = hide; + }) + } + /// Get the language setting pub fn language(&self) -> Option { self.config.read().ok().and_then(|c| c.language.clone()) diff --git a/desktop/src-tauri/src/commands.rs b/desktop/src-tauri/src/commands.rs index f05fbfaf..0ff98a30 100644 --- a/desktop/src-tauri/src/commands.rs +++ b/desktop/src-tauri/src/commands.rs @@ -10,6 +10,7 @@ use tauri::utils::{config::WindowEffectsConfig, WindowEffect}; #[cfg(target_os = "macos")] use tauri::TitleBarStyle; use tauri::{ + tray::TrayIcon, utils::config::Color, webview::{WebviewWindow, WebviewWindowBuilder}, AppHandle, Manager, State, WebviewUrl, @@ -1200,6 +1201,7 @@ pub async fn get_general_settings() -> CommandResult { log_level: config.log_level.as_str().to_string(), log_max_files: config.log_max_files, sync_delay_seconds: config.sync_delay_seconds, + hide_tray_icon: config.hide_tray_icon, log_dir: ConfigManager::get_log_dir().display().to_string(), language: config.language, }) @@ -1214,6 +1216,7 @@ pub struct GeneralSettings { pub log_level: String, pub log_max_files: usize, pub sync_delay_seconds: u64, + pub hide_tray_icon: bool, pub log_dir: String, pub language: Option, } @@ -1253,6 +1256,18 @@ pub async fn set_sync_delay_seconds(seconds: u64) -> CommandResult<()> { .map_err(|e| e.to_string()) } +/// Set whether the system tray icon is hidden and apply it live +#[tauri::command] +pub async fn set_hide_tray_icon(app: AppHandle, hide: bool) -> CommandResult<()> { + ConfigManager::get() + .set_hide_tray_icon(hide) + .map_err(|e| e.to_string())?; + if let Some(tray) = app.try_state::() { + tray.set_visible(!hide).map_err(|e| e.to_string())?; + } + Ok(()) +} + /// Set language setting and update rust_i18n locale #[tauri::command] pub async fn set_language(app: AppHandle, language: Option) -> CommandResult<()> { diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index 2020205f..603fae00 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -366,6 +366,12 @@ fn setup_tray(app: &tauri::App) -> anyhow::Result<()> { }) .build(app)?; + // Honour the hide-tray-icon setting (TrayIconBuilder has no visibility + // option, so it is applied right after construction). + if ConfigManager::get().hide_tray_icon() { + let _ = tray.set_visible(false); + } + // Keep the tray icon in Tauri's managed state so we can update its menu // when the language changes. app.manage(tray); @@ -475,6 +481,7 @@ pub fn run() { commands::set_log_level, commands::set_log_max_files, commands::set_sync_delay_seconds, + commands::set_hide_tray_icon, commands::set_language, commands::open_log_folder, ]) diff --git a/desktop/ui/public/locales/de/common.json b/desktop/ui/public/locales/de/common.json index 6ec830f2..c4c7ce12 100644 --- a/desktop/ui/public/locales/de/common.json +++ b/desktop/ui/public/locales/de/common.json @@ -91,6 +91,8 @@ "experimentalFeatures": "Experimentelle Funktionen", "delaySync": "Synchronisierung verzögern", "delaySyncDescription": "Die Synchronisierungsaufgabe wartet, bis die Datei nicht mehr geändert wird", + "hideTrayIcon": "Infobereichssymbol ausblenden", + "hideTrayIconDescription": "Im Hintergrund ohne Infobereichssymbol ausführen", "storage": "Speicher", "openFolder": "Ordner öffnen", "openSite": "Website öffnen", diff --git a/desktop/ui/public/locales/en-US/common.json b/desktop/ui/public/locales/en-US/common.json index 296a2ea9..af5050b8 100644 --- a/desktop/ui/public/locales/en-US/common.json +++ b/desktop/ui/public/locales/en-US/common.json @@ -91,6 +91,8 @@ "experimentalFeatures": "Experimental features", "delaySync": "Delay sync", "delaySyncDescription": "Sync task wait until file stop changing", + "hideTrayIcon": "Hide tray icon", + "hideTrayIconDescription": "Run in the background without a system tray icon", "storage": "Storage", "openFolder": "Open folder", "openSite": "Open site", diff --git a/desktop/ui/public/locales/es/common.json b/desktop/ui/public/locales/es/common.json index 0081f32e..a3d8628d 100644 --- a/desktop/ui/public/locales/es/common.json +++ b/desktop/ui/public/locales/es/common.json @@ -91,6 +91,8 @@ "experimentalFeatures": "Funciones experimentales", "delaySync": "Retrasar sincronización", "delaySyncDescription": "La tarea de sincronización espera hasta que el archivo deje de cambiar", + "hideTrayIcon": "Ocultar icono de bandeja", + "hideTrayIconDescription": "Ejecutar en segundo plano sin icono en la bandeja del sistema", "storage": "Almacenamiento", "openFolder": "Abrir carpeta", "openSite": "Abrir sitio", diff --git a/desktop/ui/public/locales/fr/common.json b/desktop/ui/public/locales/fr/common.json index 16b8310c..cd2adc26 100644 --- a/desktop/ui/public/locales/fr/common.json +++ b/desktop/ui/public/locales/fr/common.json @@ -91,6 +91,8 @@ "experimentalFeatures": "Fonctionnalités expérimentales", "delaySync": "Retarder la synchronisation", "delaySyncDescription": "La tâche de synchronisation attend que le fichier cesse d'être modifié", + "hideTrayIcon": "Masquer l'icône de la zone de notification", + "hideTrayIconDescription": "S'exécuter en arrière-plan sans icône dans la zone de notification", "storage": "Stockage", "openFolder": "Ouvrir le dossier", "openSite": "Ouvrir le site", diff --git a/desktop/ui/public/locales/it/common.json b/desktop/ui/public/locales/it/common.json index 3bb814a5..c50d694a 100644 --- a/desktop/ui/public/locales/it/common.json +++ b/desktop/ui/public/locales/it/common.json @@ -91,6 +91,8 @@ "experimentalFeatures": "Funzionalità sperimentali", "delaySync": "Ritarda sincronizzazione", "delaySyncDescription": "L'attività di sincronizzazione attende che il file smetta di cambiare", + "hideTrayIcon": "Nascondi icona nella barra delle applicazioni", + "hideTrayIconDescription": "Esegui in background senza icona nell'area di notifica", "storage": "Archiviazione", "openFolder": "Apri cartella", "openSite": "Apri sito", diff --git a/desktop/ui/public/locales/ja/common.json b/desktop/ui/public/locales/ja/common.json index 25bcd436..37974b71 100644 --- a/desktop/ui/public/locales/ja/common.json +++ b/desktop/ui/public/locales/ja/common.json @@ -91,6 +91,8 @@ "experimentalFeatures": "実験的な機能", "delaySync": "同期を遅延", "delaySyncDescription": "同期タスクはファイルの変更が止まるまで待機します", + "hideTrayIcon": "トレイアイコンを非表示", + "hideTrayIconDescription": "システムトレイアイコンなしでバックグラウンド実行", "storage": "ストレージ", "openFolder": "フォルダを開く", "openSite": "サイトを開く", diff --git a/desktop/ui/public/locales/ko/common.json b/desktop/ui/public/locales/ko/common.json index 0a1ef64c..913cb36a 100644 --- a/desktop/ui/public/locales/ko/common.json +++ b/desktop/ui/public/locales/ko/common.json @@ -91,6 +91,8 @@ "experimentalFeatures": "실험적 기능", "delaySync": "동기화 지연", "delaySyncDescription": "동기화 작업은 파일 변경이 멈출 때까지 기다립니다", + "hideTrayIcon": "트레이 아이콘 숨기기", + "hideTrayIconDescription": "시스템 트레이 아이콘 없이 백그라운드에서 실행", "storage": "저장소", "openFolder": "폴더 열기", "openSite": "사이트 열기", diff --git a/desktop/ui/public/locales/pl/common.json b/desktop/ui/public/locales/pl/common.json index df2bb978..d07128d1 100644 --- a/desktop/ui/public/locales/pl/common.json +++ b/desktop/ui/public/locales/pl/common.json @@ -91,6 +91,8 @@ "experimentalFeatures": "Funkcje eksperymentalne", "delaySync": "Opóźnij synchronizację", "delaySyncDescription": "Zadanie synchronizacji czeka, aż plik przestanie się zmieniać", + "hideTrayIcon": "Ukryj ikonę w zasobniku", + "hideTrayIconDescription": "Działaj w tle bez ikony w zasobniku systemowym", "storage": "Pamięć", "openFolder": "Otwórz folder", "openSite": "Otwórz witrynę", diff --git a/desktop/ui/public/locales/ru/common.json b/desktop/ui/public/locales/ru/common.json index c965ea1e..3cb5fa0c 100644 --- a/desktop/ui/public/locales/ru/common.json +++ b/desktop/ui/public/locales/ru/common.json @@ -91,6 +91,8 @@ "experimentalFeatures": "Экспериментальные функции", "delaySync": "Задержка синхронизации", "delaySyncDescription": "Задача синхронизации ждёт, пока файл перестанет изменяться", + "hideTrayIcon": "Скрыть значок в трее", + "hideTrayIconDescription": "Работать в фоне без значка в системном трее", "storage": "Хранилище", "openFolder": "Открыть папку", "openSite": "Открыть сайт", diff --git a/desktop/ui/public/locales/zh-CN/common.json b/desktop/ui/public/locales/zh-CN/common.json index 92e43e8d..03ded996 100644 --- a/desktop/ui/public/locales/zh-CN/common.json +++ b/desktop/ui/public/locales/zh-CN/common.json @@ -91,6 +91,8 @@ "experimentalFeatures": "实验性功能", "delaySync": "延迟同步", "delaySyncDescription": "同步任务等待文件停止更改后再上传", + "hideTrayIcon": "隐藏托盘图标", + "hideTrayIconDescription": "在后台运行而不显示系统托盘图标", "storage": "存储空间", "openFolder": "打开文件夹", "openSite": "打开站点", diff --git a/desktop/ui/public/locales/zh-TW/common.json b/desktop/ui/public/locales/zh-TW/common.json index 331e95f3..b7f4f17b 100644 --- a/desktop/ui/public/locales/zh-TW/common.json +++ b/desktop/ui/public/locales/zh-TW/common.json @@ -91,6 +91,8 @@ "experimentalFeatures": "實驗性功能", "delaySync": "延遲同步", "delaySyncDescription": "同步任務會等待檔案停止變更", + "hideTrayIcon": "隱藏系統匣圖示", + "hideTrayIconDescription": "在背景執行而不顯示系統匣圖示", "storage": "儲存空間", "openFolder": "開啟資料夾", "openSite": "開啟網站", diff --git a/desktop/ui/src/pages/settings/GeneralSection.tsx b/desktop/ui/src/pages/settings/GeneralSection.tsx index d2d76671..64a555c0 100644 --- a/desktop/ui/src/pages/settings/GeneralSection.tsx +++ b/desktop/ui/src/pages/settings/GeneralSection.tsx @@ -211,6 +211,7 @@ interface GeneralSettings { log_level: string; log_max_files: number; sync_delay_seconds: number; + hide_tray_icon: boolean; log_dir: string; language: string | null; } @@ -249,6 +250,7 @@ export default function GeneralSection() { const [logLevel, setLogLevel] = useState("info"); const [logMaxFiles, setLogMaxFiles] = useState(5); const [syncDelaySeconds, setSyncDelaySeconds] = useState(0); + const [hideTrayIcon, setHideTrayIcon] = useState(false); const [logDir, setLogDir] = useState(""); const [language, setLanguage] = useState(null); const [loading, setLoading] = useState(true); @@ -268,6 +270,7 @@ export default function GeneralSection() { setLogLevel(settings.log_level); setLogMaxFiles(settings.log_max_files); setSyncDelaySeconds(settings.sync_delay_seconds); + setHideTrayIcon(settings.hide_tray_icon); setLogDir(settings.log_dir); setLanguage(settings.language); } catch (error) { @@ -293,6 +296,17 @@ export default function GeneralSection() { } }; + const handleHideTrayIconChange = async (checked: boolean) => { + const previousValue = hideTrayIcon; + setHideTrayIcon(checked); + try { + await invoke("set_hide_tray_icon", { hide: checked }); + } catch (error) { + console.error("Failed to change tray icon setting:", error); + setHideTrayIcon(previousValue); + } + }; + const handleNotifyCredentialExpiredChange = async (checked: boolean) => { const previousValue = notifyCredentialExpired; setNotifyCredentialExpired(checked); @@ -417,6 +431,14 @@ export default function GeneralSection() { checked={fastPopupLaunch} onChange={handleFastPopupLaunchChange} disabled={loading} + isLast={false} + /> +