refactor: TrayService & ConfigManager (#6526)

* refactor: TrayService

- Removed the App_RestartTray channel from IpcChannel and its usage in ipc.ts and preload/index.ts.
- Updated TrayService to handle configuration changes without the need for a restart.
- Enhanced ConfigManager to notify subscribers on language and quick assistant settings changes.
- Adjusted QuickAssistantSettings to close the mini window based on the quick assistant's enable state.

* refactor: enhance configuration management

- Updated ConfigManager to consolidate setting and notification logic into a single method, setAndNotify.
- Modified IPC handler to accept an additional parameter for notification control.
- Adjusted QuickAssistantSettings to utilize the new parameter for enabling notifications during configuration changes.
This commit is contained in:
fullex 2025-05-27 21:11:49 +08:00 committed by GitHub
parent af6145600a
commit 80c09a07dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 60 additions and 58 deletions

View File

@ -11,7 +11,6 @@ export enum IpcChannel {
App_SetLaunchToTray = 'app:set-launch-to-tray', App_SetLaunchToTray = 'app:set-launch-to-tray',
App_SetTray = 'app:set-tray', App_SetTray = 'app:set-tray',
App_SetTrayOnClose = 'app:set-tray-on-close', App_SetTrayOnClose = 'app:set-tray-on-close',
App_RestartTray = 'app:restart-tray',
App_SetTheme = 'app:set-theme', App_SetTheme = 'app:set-theme',
App_SetAutoUpdate = 'app:set-auto-update', App_SetAutoUpdate = 'app:set-auto-update',
App_HandleZoomFactor = 'app:handle-zoom-factor', App_HandleZoomFactor = 'app:handle-zoom-factor',

View File

@ -28,7 +28,6 @@ import { searchService } from './services/SearchService'
import { SelectionService } from './services/SelectionService' import { SelectionService } from './services/SelectionService'
import { registerShortcuts, unregisterAllShortcuts } from './services/ShortcutService' import { registerShortcuts, unregisterAllShortcuts } from './services/ShortcutService'
import storeSyncService from './services/StoreSyncService' import storeSyncService from './services/StoreSyncService'
import { TrayService } from './services/TrayService'
import { setOpenLinkExternal } from './services/WebviewService' import { setOpenLinkExternal } from './services/WebviewService'
import { windowService } from './services/WindowService' import { windowService } from './services/WindowService'
import { calculateDirectorySize, getResourcePath } from './utils' import { calculateDirectorySize, getResourcePath } from './utils'
@ -113,10 +112,8 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
configManager.setAutoUpdate(isActive) configManager.setAutoUpdate(isActive)
}) })
ipcMain.handle(IpcChannel.App_RestartTray, () => TrayService.getInstance().restartTray()) ipcMain.handle(IpcChannel.Config_Set, (_, key: string, value: any, isNotify: boolean = false) => {
configManager.set(key, value, isNotify)
ipcMain.handle(IpcChannel.Config_Set, (_, key: string, value: any) => {
configManager.set(key, value)
}) })
ipcMain.handle(IpcChannel.Config_Get, (_, key: string) => { ipcMain.handle(IpcChannel.Config_Get, (_, key: string) => {

View File

@ -35,8 +35,8 @@ export class ConfigManager {
return this.get(ConfigKeys.Language, locale) as LanguageVarious return this.get(ConfigKeys.Language, locale) as LanguageVarious
} }
setLanguage(theme: LanguageVarious) { setLanguage(lang: LanguageVarious) {
this.set(ConfigKeys.Language, theme) this.setAndNotify(ConfigKeys.Language, lang)
} }
getTheme(): ThemeMode { getTheme(): ThemeMode {
@ -60,8 +60,7 @@ export class ConfigManager {
} }
setTray(value: boolean) { setTray(value: boolean) {
this.set(ConfigKeys.Tray, value) this.setAndNotify(ConfigKeys.Tray, value)
this.notifySubscribers(ConfigKeys.Tray, value)
} }
getTrayOnClose(): boolean { getTrayOnClose(): boolean {
@ -77,8 +76,7 @@ export class ConfigManager {
} }
setZoomFactor(factor: number) { setZoomFactor(factor: number) {
this.set(ConfigKeys.ZoomFactor, factor) this.setAndNotify(ConfigKeys.ZoomFactor, factor)
this.notifySubscribers(ConfigKeys.ZoomFactor, factor)
} }
subscribe<T>(key: string, callback: (newValue: T) => void) { subscribe<T>(key: string, callback: (newValue: T) => void) {
@ -110,11 +108,10 @@ export class ConfigManager {
} }
setShortcuts(shortcuts: Shortcut[]) { setShortcuts(shortcuts: Shortcut[]) {
this.set( this.setAndNotify(
ConfigKeys.Shortcuts, ConfigKeys.Shortcuts,
shortcuts.filter((shortcut) => shortcut.system) shortcuts.filter((shortcut) => shortcut.system)
) )
this.notifySubscribers(ConfigKeys.Shortcuts, shortcuts)
} }
getClickTrayToShowQuickAssistant(): boolean { getClickTrayToShowQuickAssistant(): boolean {
@ -130,7 +127,7 @@ export class ConfigManager {
} }
setEnableQuickAssistant(value: boolean) { setEnableQuickAssistant(value: boolean) {
this.set(ConfigKeys.EnableQuickAssistant, value) this.setAndNotify(ConfigKeys.EnableQuickAssistant, value)
} }
getAutoUpdate(): boolean { getAutoUpdate(): boolean {
@ -155,8 +152,7 @@ export class ConfigManager {
} }
setSelectionAssistantEnabled(value: boolean) { setSelectionAssistantEnabled(value: boolean) {
this.set(ConfigKeys.SelectionAssistantEnabled, value) this.setAndNotify(ConfigKeys.SelectionAssistantEnabled, value)
this.notifySubscribers(ConfigKeys.SelectionAssistantEnabled, value)
} }
// Selection Assistant: trigger mode (selected, ctrlkey) // Selection Assistant: trigger mode (selected, ctrlkey)
@ -165,8 +161,7 @@ export class ConfigManager {
} }
setSelectionAssistantTriggerMode(value: string) { setSelectionAssistantTriggerMode(value: string) {
this.set(ConfigKeys.SelectionAssistantTriggerMode, value) this.setAndNotify(ConfigKeys.SelectionAssistantTriggerMode, value)
this.notifySubscribers(ConfigKeys.SelectionAssistantTriggerMode, value)
} }
// Selection Assistant: if action window position follow toolbar // Selection Assistant: if action window position follow toolbar
@ -175,12 +170,16 @@ export class ConfigManager {
} }
setSelectionAssistantFollowToolbar(value: boolean) { setSelectionAssistantFollowToolbar(value: boolean) {
this.set(ConfigKeys.SelectionAssistantFollowToolbar, value) this.setAndNotify(ConfigKeys.SelectionAssistantFollowToolbar, value)
this.notifySubscribers(ConfigKeys.SelectionAssistantFollowToolbar, value)
} }
set(key: string, value: unknown) { setAndNotify(key: string, value: unknown) {
this.set(key, value, true)
}
set(key: string, value: unknown, isNotify: boolean = false) {
this.store.set(key, value) this.store.set(key, value)
isNotify && this.notifySubscribers(key, value)
} }
get<T>(key: string, defaultValue?: T) { get<T>(key: string, defaultValue?: T) {

View File

@ -5,16 +5,17 @@ import { app, Menu, MenuItemConstructorOptions, nativeImage, nativeTheme, Tray }
import icon from '../../../build/tray_icon.png?asset' import icon from '../../../build/tray_icon.png?asset'
import iconDark from '../../../build/tray_icon_dark.png?asset' import iconDark from '../../../build/tray_icon_dark.png?asset'
import iconLight from '../../../build/tray_icon_light.png?asset' import iconLight from '../../../build/tray_icon_light.png?asset'
import { configManager } from './ConfigManager' import { ConfigKeys, configManager } from './ConfigManager'
import { windowService } from './WindowService' import { windowService } from './WindowService'
export class TrayService { export class TrayService {
private static instance: TrayService private static instance: TrayService
private tray: Tray | null = null private tray: Tray | null = null
private contextMenu: Menu | null = null
constructor() { constructor() {
this.watchConfigChanges()
this.updateTray() this.updateTray()
this.watchTrayChanges()
TrayService.instance = this TrayService.instance = this
} }
@ -43,6 +44,30 @@ export class TrayService {
this.tray = tray this.tray = tray
this.updateContextMenu()
if (process.platform === 'linux') {
this.tray.setContextMenu(this.contextMenu)
}
this.tray.setToolTip('Cherry Studio')
this.tray.on('right-click', () => {
if (this.contextMenu) {
this.tray?.popUpContextMenu(this.contextMenu)
}
})
this.tray.on('click', () => {
if (configManager.getEnableQuickAssistant() && configManager.getClickTrayToShowQuickAssistant()) {
windowService.showMiniWindow()
} else {
windowService.showMainWindow()
}
})
}
private updateContextMenu() {
const locale = locales[configManager.getLanguage()] const locale = locales[configManager.getLanguage()]
const { tray: trayLocale } = locale.translation const { tray: trayLocale } = locale.translation
@ -64,25 +89,7 @@ export class TrayService {
} }
].filter(Boolean) as MenuItemConstructorOptions[] ].filter(Boolean) as MenuItemConstructorOptions[]
const contextMenu = Menu.buildFromTemplate(template) this.contextMenu = Menu.buildFromTemplate(template)
if (process.platform === 'linux') {
this.tray.setContextMenu(contextMenu)
}
this.tray.setToolTip('Cherry Studio')
this.tray.on('right-click', () => {
this.tray?.popUpContextMenu(contextMenu)
})
this.tray.on('click', () => {
if (enableQuickAssistant && configManager.getClickTrayToShowQuickAssistant()) {
windowService.showMiniWindow()
} else {
windowService.showMainWindow()
}
})
} }
private updateTray() { private updateTray() {
@ -94,13 +101,6 @@ export class TrayService {
} }
} }
public restartTray() {
if (configManager.getTray()) {
this.destroyTray()
this.createTray()
}
}
private destroyTray() { private destroyTray() {
if (this.tray) { if (this.tray) {
this.tray.destroy() this.tray.destroy()
@ -108,8 +108,16 @@ export class TrayService {
} }
} }
private watchTrayChanges() { private watchConfigChanges() {
configManager.subscribe<boolean>('tray', () => this.updateTray()) configManager.subscribe(ConfigKeys.Tray, () => this.updateTray())
configManager.subscribe(ConfigKeys.Language, () => {
this.updateContextMenu()
})
configManager.subscribe(ConfigKeys.EnableQuickAssistant, () => {
this.updateContextMenu()
})
} }
private quit() { private quit() {

View File

@ -20,7 +20,6 @@ const api = {
setLaunchToTray: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetLaunchToTray, isActive), setLaunchToTray: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetLaunchToTray, isActive),
setTray: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetTray, isActive), setTray: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetTray, isActive),
setTrayOnClose: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetTrayOnClose, isActive), setTrayOnClose: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetTrayOnClose, isActive),
restartTray: () => ipcRenderer.invoke(IpcChannel.App_RestartTray),
setTheme: (theme: 'light' | 'dark' | 'auto') => ipcRenderer.invoke(IpcChannel.App_SetTheme, theme), setTheme: (theme: 'light' | 'dark' | 'auto') => ipcRenderer.invoke(IpcChannel.App_SetTheme, theme),
handleZoomFactor: (delta: number, reset: boolean = false) => handleZoomFactor: (delta: number, reset: boolean = false) =>
ipcRenderer.invoke(IpcChannel.App_HandleZoomFactor, delta, reset), ipcRenderer.invoke(IpcChannel.App_HandleZoomFactor, delta, reset),
@ -128,7 +127,8 @@ const api = {
deleteFile: (fileId: string, apiKey: string) => ipcRenderer.invoke(IpcChannel.Gemini_DeleteFile, fileId, apiKey) deleteFile: (fileId: string, apiKey: string) => ipcRenderer.invoke(IpcChannel.Gemini_DeleteFile, fileId, apiKey)
}, },
config: { config: {
set: (key: string, value: any) => ipcRenderer.invoke(IpcChannel.Config_Set, key, value), set: (key: string, value: any, isNotify: boolean = false) =>
ipcRenderer.invoke(IpcChannel.Config_Set, key, value, isNotify),
get: (key: string) => ipcRenderer.invoke(IpcChannel.Config_Get, key) get: (key: string) => ipcRenderer.invoke(IpcChannel.Config_Get, key)
}, },
miniWindow: { miniWindow: {

View File

@ -23,10 +23,9 @@ const QuickAssistantSettings: FC = () => {
const handleEnableQuickAssistant = async (enable: boolean) => { const handleEnableQuickAssistant = async (enable: boolean) => {
dispatch(setEnableQuickAssistant(enable)) dispatch(setEnableQuickAssistant(enable))
await window.api.config.set('enableQuickAssistant', enable) await window.api.config.set('enableQuickAssistant', enable, true)
window.api.restartTray()
const disable = !enable !enable && window.api.miniWindow.close()
disable && window.api.miniWindow.close()
if (enable && !clickTrayToShowQuickAssistant) { if (enable && !clickTrayToShowQuickAssistant) {
window.message.info({ window.message.info({