From 92ef0880f84fcbb954138ee8e7e93a42558d0dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E6=9F=B1?= Date: Tue, 10 Jun 2025 18:04:52 +0800 Subject: [PATCH] tray: Add unread count badge option for macOS tray icon Add a new configuration option 'trayBadgeCount' that allows users to display unread message count on the tray icon for macOS. When enabled, the tray icon shows the unread count as a title badge instead of modifying the icon image itself. This change: - Adds trayBadgeCount configuration option to config schema - Adds toggle-tray-badge-count IPC message for preference updates - Implements displayTrayIcon() function to handle platform-specific tray icon display logic - Updates preference UI to show the option only on macOS - Refactors tray logic to use consistent display methods across platforms The feature is macOS-specific because other platforms already use icon overlays to show unread counts, while macOS can use the cleaner title badge approach. --- app/common/config-schemata.ts | 1 + app/common/typed-ipc.ts | 1 + .../js/pages/preference/general-section.ts | 30 +++++++++++++ app/renderer/js/tray.ts | 44 +++++++++++++++---- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/app/common/config-schemata.ts b/app/common/config-schemata.ts index e2db7b80f..b7e89c3b1 100644 --- a/app/common/config-schemata.ts +++ b/app/common/config-schemata.ts @@ -33,6 +33,7 @@ export const configSchemata = { startAtLogin: z.boolean(), startMinimized: z.boolean(), trayIcon: z.boolean(), + trayBadgeCount: z.boolean(), useManualProxy: z.boolean(), useProxy: z.boolean(), useSystemProxy: z.boolean(), diff --git a/app/common/typed-ipc.ts b/app/common/typed-ipc.ts index 269f42984..df7e06435 100644 --- a/app/common/typed-ipc.ts +++ b/app/common/typed-ipc.ts @@ -73,6 +73,7 @@ export type RendererMessage = { "toggle-sidebar": (show: boolean) => void; "toggle-silent": (state: boolean) => void; "toggle-tray": (state: boolean) => void; + "toggle-tray-badge-count": (newValue: boolean) => void; toggletray: () => void; tray: (argument: number) => void; "update-realm-icon": (serverURL: string, iconURL: string) => void; diff --git a/app/renderer/js/pages/preference/general-section.ts b/app/renderer/js/pages/preference/general-section.ts index df48a5ab3..b400a8e6a 100644 --- a/app/renderer/js/pages/preference/general-section.ts +++ b/app/renderer/js/pages/preference/general-section.ts @@ -60,6 +60,16 @@ export function initGeneralSection({$root}: GeneralSectionProperties): void {
+
+
+ ${t.__("Show unread count on tray icon")} +
+
+
0 ? unread.toString() : ""); + } else { + const image = renderNativeImage(unread); + tray.setImage(image); + } + + tray.setToolTip(`${unread} unread messages`); +}; + export function initializeTray(serverManagerView: ServerManagerView) { ipcRenderer.on("destroytray", () => { if (!tray) { @@ -197,17 +221,15 @@ export function initializeTray(serverManagerView: ServerManagerView) { return; } - // We don't want to create tray from unread messages on macOS since it already has dock badges. - if (process.platform === "linux" || process.platform === "win32") { + if (shouldShowTrayIcon()) { if (argument === 0) { unread = argument; tray.setImage(iconPath()); + tray.setTitle(""); tray.setToolTip("No unread messages"); } else { unread = argument; - const image = renderNativeImage(argument); - tray.setImage(image); - tray.setToolTip(`${argument} unread messages`); + displayTrayIcon(tray); } } }); @@ -225,10 +247,8 @@ export function initializeTray(serverManagerView: ServerManagerView) { } else { state = true; createTray(); - if (process.platform === "linux" || process.platform === "win32") { - const image = renderNativeImage(unread); - tray!.setImage(image); - tray!.setToolTip(`${unread} unread messages`); + if (shouldShowTrayIcon()) { + displayTrayIcon(tray!); } ConfigUtil.setConfigItem("trayIcon", true); @@ -239,6 +259,12 @@ export function initializeTray(serverManagerView: ServerManagerView) { ipcRenderer.on("toggletray", toggleTray); + ipcRenderer.on("toggle-tray-badge-count", () => { + if (tray && shouldShowTrayIcon()) { + displayTrayIcon(tray); + } + }); + if (ConfigUtil.getConfigItem("trayIcon", true)) { createTray(); }