From bc4e9125048b976b6436edca0e11f2f0c26da8f8 Mon Sep 17 00:00:00 2001 From: vrustx <279631638@qq.com> Date: Sun, 31 May 2026 10:15:59 +0800 Subject: [PATCH] Add configurable black app icons and logo (#564) --- apps/desktop/public/logo-black.png | Bin 0 -> 29484 bytes .../desktop/src/components/auth/LoginPage.vue | 3 +- .../editor/EditorSettingsDialog.vue | 51 ++++++++- apps/desktop/src/components/icons/AppLogo.vue | 12 +++ apps/desktop/src/i18n/locales/en.ts | 5 + apps/desktop/src/i18n/locales/es.ts | 5 + apps/desktop/src/i18n/locales/zh-CN.ts | 5 + apps/desktop/src/lib/http.ts | 2 +- apps/desktop/src/lib/tauri.ts | 1 + apps/desktop/src/stores/settingsStore.ts | 18 +++- crates/dbx-core/src/storage.rs | 62 +++++++++-- src-tauri/icons/icon-black.png | Bin 0 -> 29484 bytes src-tauri/src/commands/app_settings.rs | 6 +- src-tauri/src/lib.rs | 99 ++++++++++++++++-- 14 files changed, 240 insertions(+), 29 deletions(-) create mode 100644 apps/desktop/public/logo-black.png create mode 100644 apps/desktop/src/components/icons/AppLogo.vue create mode 100644 src-tauri/icons/icon-black.png diff --git a/apps/desktop/public/logo-black.png b/apps/desktop/public/logo-black.png new file mode 100644 index 0000000000000000000000000000000000000000..c016b386b28981a530c73b93d3c60259aa0d07e2 GIT binary patch literal 29484 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 literal 0 HcmV?d00001 diff --git a/apps/desktop/src/components/auth/LoginPage.vue b/apps/desktop/src/components/auth/LoginPage.vue index 62b94f07d..ab6e916ca 100644 --- a/apps/desktop/src/components/auth/LoginPage.vue +++ b/apps/desktop/src/components/auth/LoginPage.vue @@ -4,6 +4,7 @@ import { useI18n } from "vue-i18n"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Lock, Loader2, ShieldCheck } from "lucide-vue-next"; +import AppLogo from "@/components/icons/AppLogo.vue"; const props = withDefaults( defineProps<{ @@ -55,7 +56,7 @@ async function submit() { >
- DBX +

DBX

diff --git a/apps/desktop/src/components/editor/EditorSettingsDialog.vue b/apps/desktop/src/components/editor/EditorSettingsDialog.vue index 01b25a08b..0f1a7f633 100644 --- a/apps/desktop/src/components/editor/EditorSettingsDialog.vue +++ b/apps/desktop/src/components/editor/EditorSettingsDialog.vue @@ -36,6 +36,7 @@ import { type AiProvider, type AiApiStyle, type EditorTheme, + type DesktopIconTheme, } from "@/stores/settingsStore"; import { loadEditorTheme, editorFontTheme } from "@/lib/editorThemes"; import { isTauriRuntime } from "@/lib/tauriRuntime"; @@ -66,6 +67,7 @@ import type { SqlSnippet } from "@/types/database"; import { uuid } from "@/lib/utils"; import { DEFAULT_SQL_SNIPPETS } from "@/lib/sqlCompletion"; import AiProviderLogo from "@/components/icons/AiProviderLogo.vue"; +import AppLogo from "@/components/icons/AppLogo.vue"; import type { AppThemeAppearance } from "@/lib/appTheme"; import { useConnectionStore } from "@/stores/connectionStore"; @@ -93,6 +95,7 @@ const editExecuteMode = ref(settingsStore.editorSettings.executeMode); const editWordWrap = ref(settingsStore.editorSettings.wordWrap); const editAppLayout = ref(settingsStore.editorSettings.appLayout); const editShowTrayIcon = ref(settingsStore.desktopSettings.show_tray_icon); +const editIconTheme = ref(settingsStore.desktopSettings.icon_theme); const editShowColumnCommentsInHeader = ref(settingsStore.editorSettings.showColumnCommentsInHeader); const editCompactColumnHeaderActions = ref(settingsStore.editorSettings.compactColumnHeaderActions); const editRedisScanPageSize = ref(settingsStore.editorSettings.redisScanPageSize); @@ -228,6 +231,7 @@ watch( editWordWrap.value = settingsStore.editorSettings.wordWrap; editAppLayout.value = settingsStore.editorSettings.appLayout; editShowTrayIcon.value = settingsStore.desktopSettings.show_tray_icon; + editIconTheme.value = settingsStore.desktopSettings.icon_theme; editShowColumnCommentsInHeader.value = settingsStore.editorSettings.showColumnCommentsInHeader; editCompactColumnHeaderActions.value = settingsStore.editorSettings.compactColumnHeaderActions; editRedisScanPageSize.value = settingsStore.editorSettings.redisScanPageSize; @@ -266,6 +270,7 @@ function hasChanges(): boolean { editWordWrap.value !== settingsStore.editorSettings.wordWrap || editAppLayout.value !== settingsStore.editorSettings.appLayout || editShowTrayIcon.value !== settingsStore.desktopSettings.show_tray_icon || + editIconTheme.value !== settingsStore.desktopSettings.icon_theme || editShowColumnCommentsInHeader.value !== settingsStore.editorSettings.showColumnCommentsInHeader || editCompactColumnHeaderActions.value !== settingsStore.editorSettings.compactColumnHeaderActions || editRedisScanPageSize.value !== settingsStore.editorSettings.redisScanPageSize || @@ -305,6 +310,7 @@ async function persistSettings() { }); await settingsStore.updateDesktopSettings({ show_tray_icon: editShowTrayIcon.value, + icon_theme: editIconTheme.value, }); if (sidebarObjectDisplayChanged) { await connectionStore.refreshAllTree(); @@ -329,6 +335,7 @@ function resetDefaults() { editWordWrap.value = DEFAULT_EDITOR_SETTINGS.wordWrap; editAppLayout.value = DEFAULT_EDITOR_SETTINGS.appLayout; editShowTrayIcon.value = DEFAULT_DESKTOP_SETTINGS.show_tray_icon; + editIconTheme.value = DEFAULT_DESKTOP_SETTINGS.icon_theme; editShowColumnCommentsInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnCommentsInHeader; editCompactColumnHeaderActions.value = DEFAULT_EDITOR_SETTINGS.compactColumnHeaderActions; editRedisScanPageSize.value = DEFAULT_EDITOR_SETTINGS.redisScanPageSize; @@ -362,6 +369,10 @@ function setSidebarObjectDisplay(value: "grouped" | "simple") { editSidebarObjectDisplay.value = value; } +function setIconTheme(value: DesktopIconTheme) { + editIconTheme.value = value; +} + function onShortcutChange(actionId: ShortcutActionId, value: any) { if (typeof value !== "string") return; const definition = SHORTCUT_DEFINITIONS.find((item) => item.id === actionId); @@ -591,6 +602,7 @@ watch( await settingsStore.initAiConfig(); await settingsStore.initDesktopSettings(); editShowTrayIcon.value = settingsStore.desktopSettings.show_tray_icon; + editIconTheme.value = settingsStore.desktopSettings.icon_theme; webdavPassword.value = ""; await refreshWebDavPasswordStatus(); syncAiEditState(); @@ -1164,6 +1176,43 @@ watch(

+ +
+ +
+ + +
+
+
- DBX + {{ t("settings.officialDocs") }}
diff --git a/apps/desktop/src/components/icons/AppLogo.vue b/apps/desktop/src/components/icons/AppLogo.vue new file mode 100644 index 000000000..d25684c0a --- /dev/null +++ b/apps/desktop/src/components/icons/AppLogo.vue @@ -0,0 +1,12 @@ + + + diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts index 629d77686..8f4f1c864 100644 --- a/apps/desktop/src/i18n/locales/en.ts +++ b/apps/desktop/src/i18n/locales/en.ts @@ -1456,6 +1456,11 @@ export default { appLayoutSeparatedDescription: "Clear panel separation with block-style tabs.", appLayoutClassic: "Classic compact", appLayoutClassicDescription: "Continuous tab bar with compact panel headers.", + iconTheme: "Icon and logo style", + iconThemeDefault: "Default", + iconThemeDefaultDescription: "Use the color DBX app icon.", + iconThemeBlack: "Black", + iconThemeBlackDescription: "Use the black DBX mark for the window, tray, and logo.", showTrayIcon: "Show tray/menu bar icon", showTrayIconDescription: "When disabled, no icon is shown, but closing the window still hides DBX in the background as before.", diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts index e525cf1ea..9aba0e583 100644 --- a/apps/desktop/src/i18n/locales/es.ts +++ b/apps/desktop/src/i18n/locales/es.ts @@ -1349,6 +1349,11 @@ export default { appLayoutSeparatedDescription: "Separación clara de paneles con pestañas en bloque.", appLayoutClassic: "Clásico compacto", appLayoutClassicDescription: "Barra de pestañas continua con encabezados de panel compactos.", + iconTheme: "Estilo de icono y logo", + iconThemeDefault: "Predeterminado", + iconThemeDefaultDescription: "Usar el icono de color de DBX.", + iconThemeBlack: "Negro", + iconThemeBlackDescription: "Usar la marca negra de DBX en ventana, bandeja y logo.", showTrayIcon: "Mostrar icono en bandeja/barra de menú", showTrayIconDescription: "Si está desactivado, no se muestra el icono, pero cerrar la ventana sigue ocultando DBX en segundo plano como antes.", diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts index 0b887adf0..20825570c 100644 --- a/apps/desktop/src/i18n/locales/zh-CN.ts +++ b/apps/desktop/src/i18n/locales/zh-CN.ts @@ -1430,6 +1430,11 @@ export default { appLayoutSeparatedDescription: "面板分隔更清晰,标签页为块状样式。", appLayoutClassic: "经典紧凑", appLayoutClassicDescription: "使用连续标签栏和更紧凑的面板标题。", + iconTheme: "图标与 Logo 样式", + iconThemeDefault: "默认", + iconThemeDefaultDescription: "使用彩色 DBX 应用图标。", + iconThemeBlack: "黑色", + iconThemeBlackDescription: "窗口、托盘和 Logo 都使用黑色 DBX 标识。", showTrayIcon: "显示系统托盘/菜单栏图标", showTrayIconDescription: "关闭后不显示图标,但关闭窗口仍会像之前一样隐藏到后台。", dataGridDisplay: "数据表格显示", diff --git a/apps/desktop/src/lib/http.ts b/apps/desktop/src/lib/http.ts index c03d83f73..5a36f0543 100644 --- a/apps/desktop/src/lib/http.ts +++ b/apps/desktop/src/lib/http.ts @@ -789,7 +789,7 @@ export async function loadAiConfig(): Promise { } export async function loadDesktopSettings(): Promise { - return { show_tray_icon: true }; + return { show_tray_icon: true, icon_theme: "default" }; } export async function saveDesktopSettings(_settings: DesktopSettings): Promise { diff --git a/apps/desktop/src/lib/tauri.ts b/apps/desktop/src/lib/tauri.ts index 01a2604fa..a6dfa05ac 100644 --- a/apps/desktop/src/lib/tauri.ts +++ b/apps/desktop/src/lib/tauri.ts @@ -97,6 +97,7 @@ export interface DriverStoreUsage { export interface DesktopSettings { show_tray_icon: boolean; + icon_theme: "default" | "black"; } export interface WebDavConfig { diff --git a/apps/desktop/src/stores/settingsStore.ts b/apps/desktop/src/stores/settingsStore.ts index 51c7b8302..8152cd884 100644 --- a/apps/desktop/src/stores/settingsStore.ts +++ b/apps/desktop/src/stores/settingsStore.ts @@ -38,12 +38,24 @@ export interface AiConfig { export interface DesktopSettings { show_tray_icon: boolean; + icon_theme: DesktopIconTheme; } +export type DesktopIconTheme = "default" | "black"; + export const DEFAULT_DESKTOP_SETTINGS: DesktopSettings = { show_tray_icon: true, + icon_theme: "default", }; +function normalizeDesktopSettings(settings: Partial | null | undefined): DesktopSettings { + const iconTheme = settings?.icon_theme === "black" ? "black" : DEFAULT_DESKTOP_SETTINGS.icon_theme; + return { + show_tray_icon: settings?.show_tray_icon ?? DEFAULT_DESKTOP_SETTINGS.show_tray_icon, + icon_theme: iconTheme, + }; +} + export interface AiProviderPreset extends Omit { label: string; iconSlug?: string; @@ -415,7 +427,7 @@ export const useSettingsStore = defineStore("settings", () => { async function initDesktopSettings() { if (isDesktopSettingsLoaded.value) return; - desktopSettings.value = await api.loadDesktopSettings().catch(() => ({ ...DEFAULT_DESKTOP_SETTINGS })); + desktopSettings.value = normalizeDesktopSettings(await api.loadDesktopSettings().catch(() => null)); isDesktopSettingsLoaded.value = true; } @@ -425,9 +437,9 @@ export const useSettingsStore = defineStore("settings", () => { ...desktopSettings.value, ...partial, }; - desktopSettings.value = next; + desktopSettings.value = normalizeDesktopSettings(next); try { - await api.saveDesktopSettings(next); + await api.saveDesktopSettings(desktopSettings.value); } catch (error) { desktopSettings.value = previous; throw error; diff --git a/crates/dbx-core/src/storage.rs b/crates/dbx-core/src/storage.rs index 8bf30874e..a0d040a0b 100644 --- a/crates/dbx-core/src/storage.rs +++ b/crates/dbx-core/src/storage.rs @@ -18,11 +18,28 @@ pub struct Storage { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct DesktopSettings { pub show_tray_icon: bool, + pub icon_theme: DesktopIconTheme, } impl Default for DesktopSettings { fn default() -> Self { - Self { show_tray_icon: true } + Self { show_tray_icon: true, icon_theme: DesktopIconTheme::Default } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum DesktopIconTheme { + Default, + Black, +} + +impl DesktopIconTheme { + fn from_settings_value(value: Option<&serde_json::Value>) -> Self { + match value.and_then(|value| value.as_str()) { + Some("black") => Self::Black, + _ => Self::Default, + } } } @@ -326,6 +343,10 @@ impl Storage { let mut settings = self.load_app_settings_json().await?; settings.remove("run_in_background"); settings.insert("show_tray_icon".to_string(), serde_json::Value::Bool(desktop_settings.show_tray_icon)); + settings.insert( + "icon_theme".to_string(), + serde_json::to_value(desktop_settings.icon_theme).map_err(|e| e.to_string())?, + ); self.save_app_settings_json(&settings).await } @@ -337,6 +358,7 @@ impl Storage { .and_then(|value| value.as_bool()) .or_else(|| settings.get("run_in_background").and_then(|value| value.as_bool())) .unwrap_or_else(|| DesktopSettings::default().show_tray_icon), + icon_theme: DesktopIconTheme::from_settings_value(settings.get("icon_theme")), }) } @@ -1063,7 +1085,7 @@ fn map_from_sql_err(err: serde_json::Error) -> rusqlite::Error { #[cfg(test)] mod tests { - use super::{DesktopSettings, Storage}; + use super::{DesktopIconTheme, DesktopSettings, Storage}; use std::time::{SystemTime, UNIX_EPOCH}; fn temp_db_path(name: &str) -> std::path::PathBuf { @@ -1076,7 +1098,7 @@ mod tests { let path = temp_db_path("desktop-settings-default"); let storage = Storage::open(&path).await.unwrap(); - assert_eq!(storage.load_desktop_settings().await.unwrap(), DesktopSettings { show_tray_icon: true }); + assert_eq!(storage.load_desktop_settings().await.unwrap(), DesktopSettings::default()); } #[tokio::test] @@ -1087,7 +1109,10 @@ mod tests { settings.insert("run_in_background".to_string(), serde_json::Value::Bool(false)); storage.save_app_settings_json(&settings).await.unwrap(); - assert_eq!(storage.load_desktop_settings().await.unwrap(), DesktopSettings { show_tray_icon: false }); + assert_eq!( + storage.load_desktop_settings().await.unwrap(), + DesktopSettings { show_tray_icon: false, ..DesktopSettings::default() } + ); } #[tokio::test] @@ -1096,10 +1121,16 @@ mod tests { let storage = Storage::open(&path).await.unwrap(); storage.save_password_hash("hash-1").await.unwrap(); - storage.save_desktop_settings(&DesktopSettings { show_tray_icon: false }).await.unwrap(); + storage + .save_desktop_settings(&DesktopSettings { show_tray_icon: false, icon_theme: DesktopIconTheme::Black }) + .await + .unwrap(); assert_eq!(storage.load_password_hash().await.unwrap(), Some("hash-1".to_string())); - assert_eq!(storage.load_desktop_settings().await.unwrap(), DesktopSettings { show_tray_icon: false }); + assert_eq!( + storage.load_desktop_settings().await.unwrap(), + DesktopSettings { show_tray_icon: false, icon_theme: DesktopIconTheme::Black } + ); } #[tokio::test] @@ -1110,11 +1141,18 @@ mod tests { settings.insert("run_in_background".to_string(), serde_json::Value::Bool(false)); storage.save_app_settings_json(&settings).await.unwrap(); - storage.save_desktop_settings(&DesktopSettings { show_tray_icon: true }).await.unwrap(); + storage + .save_desktop_settings(&DesktopSettings { + icon_theme: DesktopIconTheme::Black, + ..DesktopSettings::default() + }) + .await + .unwrap(); let settings = storage.load_app_settings_json().await.unwrap(); assert_eq!(settings.get("run_in_background"), None); assert_eq!(settings.get("show_tray_icon").and_then(|value| value.as_bool()), Some(true)); + assert_eq!(settings.get("icon_theme").and_then(|value| value.as_str()), Some("black")); } #[tokio::test] @@ -1122,11 +1160,17 @@ mod tests { let path = temp_db_path("password-preserve-desktop-settings"); let storage = Storage::open(&path).await.unwrap(); - storage.save_desktop_settings(&DesktopSettings { show_tray_icon: false }).await.unwrap(); + storage + .save_desktop_settings(&DesktopSettings { show_tray_icon: false, icon_theme: DesktopIconTheme::Black }) + .await + .unwrap(); storage.save_password_hash("hash-2").await.unwrap(); assert_eq!(storage.load_password_hash().await.unwrap(), Some("hash-2".to_string())); - assert_eq!(storage.load_desktop_settings().await.unwrap(), DesktopSettings { show_tray_icon: false }); + assert_eq!( + storage.load_desktop_settings().await.unwrap(), + DesktopSettings { show_tray_icon: false, icon_theme: DesktopIconTheme::Black } + ); } #[tokio::test] diff --git a/src-tauri/icons/icon-black.png b/src-tauri/icons/icon-black.png new file mode 100644 index 0000000000000000000000000000000000000000..c016b386b28981a530c73b93d3c60259aa0d07e2 GIT binary patch literal 29484 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 literal 0 HcmV?d00001 diff --git a/src-tauri/src/commands/app_settings.rs b/src-tauri/src/commands/app_settings.rs index 28a003167..3a4144009 100644 --- a/src-tauri/src/commands/app_settings.rs +++ b/src-tauri/src/commands/app_settings.rs @@ -4,7 +4,7 @@ use dbx_core::storage::DesktopSettings; use tauri::{AppHandle, State}; use super::connection::AppState; -use crate::apply_desktop_tray_preference; +use crate::apply_desktop_settings; #[tauri::command] pub async fn load_desktop_settings(state: State<'_, Arc>) -> Result { @@ -18,8 +18,8 @@ pub async fn save_desktop_settings( settings: DesktopSettings, ) -> Result<(), String> { state.storage.save_desktop_settings(&settings).await?; - if let Err(err) = apply_desktop_tray_preference(&app, settings.show_tray_icon) { - eprintln!("Failed to apply desktop tray preference: {err}"); + if let Err(err) = apply_desktop_settings(&app, &settings) { + eprintln!("Failed to apply desktop settings: {err}"); } Ok(()) } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index f04cb46b5..2d2e481b5 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -5,7 +5,7 @@ mod models; mod window_state_guard; use commands::connection::AppState; -use dbx_core::storage::Storage; +use dbx_core::storage::{DesktopIconTheme, DesktopSettings, Storage}; use std::sync::Arc; use std::time::Instant; #[cfg(target_os = "macos")] @@ -21,6 +21,7 @@ use tauri_plugin_deep_link::DeepLinkExt; const DESKTOP_TRAY_ID: &str = "main-tray"; #[cfg(target_os = "macos")] const MACOS_TRAY_ICON: tauri::image::Image<'_> = tauri::include_image!("icons/tray-macos-template.png"); +const BLACK_APP_ICON: tauri::image::Image<'_> = tauri::include_image!("icons/icon-black.png"); fn should_hide_window_on_close(target_os: &str) -> bool { matches!(target_os, "macos" | "windows") @@ -54,15 +55,35 @@ fn open_connection_deep_links(app: &tauri::AppHandle, links: Vec) { } #[cfg_attr(not(any(target_os = "macos", target_os = "windows")), allow(dead_code))] -fn setup_desktop_tray>(manager: &M) -> tauri::Result<()> { +fn setup_desktop_tray>( + manager: &M, + icon_theme: DesktopIconTheme, +) -> tauri::Result<()> { let menu = MenuBuilder::new(manager).text("show", "Show DBX").separator().text("quit", "Quit DBX").build()?; let mut tray = TrayIconBuilder::::with_id(DESKTOP_TRAY_ID).tooltip("DBX").menu(&menu).show_menu_on_left_click(false); #[cfg(target_os = "macos")] { - tray = tray.icon(MACOS_TRAY_ICON).icon_as_template(true); + match icon_theme { + DesktopIconTheme::Default => { + tray = tray.icon(MACOS_TRAY_ICON).icon_as_template(true); + } + DesktopIconTheme::Black => { + tray = tray.icon(BLACK_APP_ICON).icon_as_template(false); + } + } } - #[cfg(not(target_os = "macos"))] + #[cfg(target_os = "windows")] + { + let icon = match icon_theme { + DesktopIconTheme::Default => manager.app_handle().default_window_icon().cloned(), + DesktopIconTheme::Black => Some(BLACK_APP_ICON), + }; + if let Some(icon) = icon { + tray = tray.icon(icon); + } + } + #[cfg(not(any(target_os = "macos", target_os = "windows")))] { if let Some(icon) = manager.app_handle().default_window_icon().cloned() { tray = tray.icon(icon); @@ -86,12 +107,59 @@ fn setup_desktop_tray>(manager: &M) -> tauri::R Ok(()) } -pub(crate) fn apply_desktop_tray_preference(app: &tauri::AppHandle, show_tray_icon: bool) -> tauri::Result<()> { +fn apply_desktop_icon_theme(app: &tauri::AppHandle, icon_theme: DesktopIconTheme) -> tauri::Result<()> { + if let Some(window) = app.get_webview_window("main") { + match icon_theme { + DesktopIconTheme::Default => { + if let Some(icon) = app.default_window_icon().cloned() { + window.set_icon(icon)?; + } + } + DesktopIconTheme::Black => window.set_icon(BLACK_APP_ICON)?, + } + } + Ok(()) +} + +fn apply_desktop_tray_icon_theme(app: &tauri::AppHandle, icon_theme: DesktopIconTheme) -> tauri::Result<()> { + if let Some(tray) = app.tray_by_id(DESKTOP_TRAY_ID) { + #[cfg(target_os = "macos")] + { + match icon_theme { + DesktopIconTheme::Default => { + tray.set_icon(Some(MACOS_TRAY_ICON))?; + tray.set_icon_as_template(true)?; + } + DesktopIconTheme::Black => { + tray.set_icon(Some(BLACK_APP_ICON))?; + tray.set_icon_as_template(false)?; + } + } + } + #[cfg(target_os = "windows")] + { + let icon = match icon_theme { + DesktopIconTheme::Default => app.default_window_icon().cloned(), + DesktopIconTheme::Black => Some(BLACK_APP_ICON), + }; + tray.set_icon(icon)?; + } + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + { + let _ = (tray, icon_theme); + } + } + Ok(()) +} + +pub(crate) fn apply_desktop_settings(app: &tauri::AppHandle, desktop_settings: &DesktopSettings) -> tauri::Result<()> { + apply_desktop_icon_theme(app, desktop_settings.icon_theme)?; if matches!(std::env::consts::OS, "macos" | "windows") { if let Some(tray) = app.tray_by_id(DESKTOP_TRAY_ID) { - tray.set_visible(show_tray_icon)?; - } else if show_tray_icon { - setup_desktop_tray(app)?; + tray.set_visible(desktop_settings.show_tray_icon)?; + apply_desktop_tray_icon_theme(app, desktop_settings.icon_theme)?; + } else if desktop_settings.show_tray_icon { + setup_desktop_tray(app, desktop_settings.icon_theme)?; } } Ok(()) @@ -121,7 +189,7 @@ mod tests { assert!(!should_setup_desktop_tray("linux", true)); let source = include_str!("lib.rs"); assert!(source.contains( - "if should_setup_desktop_tray(std::env::consts::OS, desktop_settings.show_tray_icon) {\n setup_desktop_tray(app)?;" + "if should_setup_desktop_tray(std::env::consts::OS, desktop_settings.show_tray_icon) {\n setup_desktop_tray(app, desktop_settings.icon_theme)?;" )); } @@ -133,10 +201,18 @@ mod tests { assert!(!source.contains(remove_call)); } + #[test] + fn can_apply_black_logo_icon_theme() { + let source = include_str!("lib.rs"); + assert!(source.contains("const BLACK_APP_ICON")); + assert!(source.contains("DesktopIconTheme::Black => window.set_icon(BLACK_APP_ICON)?")); + assert!(source.contains("DesktopIconTheme::Black => Some(BLACK_APP_ICON)")); + } + #[test] fn desktop_settings_save_treats_runtime_tray_update_as_best_effort() { let source = include_str!("commands/app_settings.rs"); - assert!(source.contains("if let Err(err) = apply_desktop_tray_preference")); + assert!(source.contains("if let Err(err) = apply_desktop_settings")); assert!(!source.contains("map_err(|err| err.to_string())")); } @@ -233,8 +309,9 @@ pub fn run() { } } if should_setup_desktop_tray(std::env::consts::OS, desktop_settings.show_tray_icon) { - setup_desktop_tray(app)?; + setup_desktop_tray(app, desktop_settings.icon_theme)?; } + apply_desktop_icon_theme(app.handle(), desktop_settings.icon_theme)?; window_state_guard::enforce_main_window_bounds(app.handle()); if should_show_main_window_after_setup() { show_main_window(app.handle());