feat: implement tray functionality with status updates and localization support
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { BrowserWindow } from 'electron';
|
import { BrowserWindow } from 'electron';
|
||||||
import { windowManager } from '@electron/service/window-service';
|
import { windowManager } from '@electron/service/window-service';
|
||||||
import logManager from '@electron/service/logger';
|
import logManager from '@electron/service/logger';
|
||||||
|
import { updateTrayStatus } from '@electron/main/tray';
|
||||||
import type { GatewayEvent, RuntimeRefreshTopic } from './types';
|
import type { GatewayEvent, RuntimeRefreshTopic } from './types';
|
||||||
import * as chatHandlers from './handlers/chat';
|
import * as chatHandlers from './handlers/chat';
|
||||||
import * as providerHandlers from './handlers/provider';
|
import * as providerHandlers from './handlers/provider';
|
||||||
@@ -20,15 +21,15 @@ class GatewayManager {
|
|||||||
|
|
||||||
private setStatus(status: 'connected' | 'disconnected' | 'reconnecting'): void {
|
private setStatus(status: 'connected' | 'disconnected' | 'reconnecting'): void {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
|
updateTrayStatus(status);
|
||||||
this.broadcast({ type: 'gateway:status', status });
|
this.broadcast({ type: 'gateway:status', status });
|
||||||
}
|
}
|
||||||
|
|
||||||
async init(): Promise<void> {
|
async init(): Promise<void> {
|
||||||
if (this.initialized) return;
|
if (this.initialized) return;
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
this.status = 'connected';
|
|
||||||
logManager.info('GatewayManager initialized');
|
logManager.info('GatewayManager initialized');
|
||||||
this.broadcast({ type: 'gateway:status', status: 'connected' });
|
this.setStatus('connected');
|
||||||
}
|
}
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
|
|||||||
@@ -31,6 +31,17 @@ export const runtimeLocaleMessages: Record<'en' | 'zh' | 'th', RuntimeMessageTre
|
|||||||
tray: {
|
tray: {
|
||||||
tooltip: 'ZN-AI',
|
tooltip: 'ZN-AI',
|
||||||
showWindow: 'Show Window',
|
showWindow: 'Show Window',
|
||||||
|
gatewayStatus: 'Gateway Status',
|
||||||
|
status: {
|
||||||
|
running: 'Running',
|
||||||
|
stopped: 'Stopped',
|
||||||
|
restarting: 'Restarting',
|
||||||
|
},
|
||||||
|
quickActions: 'Quick Actions',
|
||||||
|
openChat: 'Open Chat',
|
||||||
|
openSettings: 'Open Settings',
|
||||||
|
checkForUpdates: 'Check for Updates...',
|
||||||
|
quit: 'Quit ZN-AI',
|
||||||
exit: 'Exit',
|
exit: 'Exit',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -62,6 +73,17 @@ export const runtimeLocaleMessages: Record<'en' | 'zh' | 'th', RuntimeMessageTre
|
|||||||
tray: {
|
tray: {
|
||||||
tooltip: 'ZN-AI',
|
tooltip: 'ZN-AI',
|
||||||
showWindow: '显示窗口',
|
showWindow: '显示窗口',
|
||||||
|
gatewayStatus: '网关状态',
|
||||||
|
status: {
|
||||||
|
running: '运行中',
|
||||||
|
stopped: '已停止',
|
||||||
|
restarting: '重启中',
|
||||||
|
},
|
||||||
|
quickActions: '快捷操作',
|
||||||
|
openChat: '打开聊天',
|
||||||
|
openSettings: '打开设置',
|
||||||
|
checkForUpdates: '检查更新...',
|
||||||
|
quit: '退出 ZN-AI',
|
||||||
exit: '退出',
|
exit: '退出',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -93,6 +115,17 @@ export const runtimeLocaleMessages: Record<'en' | 'zh' | 'th', RuntimeMessageTre
|
|||||||
tray: {
|
tray: {
|
||||||
tooltip: 'ZN-AI',
|
tooltip: 'ZN-AI',
|
||||||
showWindow: 'แสดงหน้าต่าง',
|
showWindow: 'แสดงหน้าต่าง',
|
||||||
|
gatewayStatus: 'สถานะเกตเวย์',
|
||||||
|
status: {
|
||||||
|
running: 'กำลังทำงาน',
|
||||||
|
stopped: 'หยุดทำงาน',
|
||||||
|
restarting: 'กำลังรีสตาร์ต',
|
||||||
|
},
|
||||||
|
quickActions: 'การดำเนินการด่วน',
|
||||||
|
openChat: 'เปิดแชท',
|
||||||
|
openSettings: 'เปิดการตั้งค่า',
|
||||||
|
checkForUpdates: 'ตรวจสอบการอัปเดต...',
|
||||||
|
quit: 'ออกจาก ZN-AI',
|
||||||
exit: 'ออก',
|
exit: 'ออก',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
286
electron/main/tray.ts
Normal file
286
electron/main/tray.ts
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
import { app, BrowserWindow, Menu, Tray, nativeImage } from 'electron';
|
||||||
|
import { join } from 'node:path';
|
||||||
|
import { pathToFileURL } from 'node:url';
|
||||||
|
import { appUpdater } from '@electron/service/updater';
|
||||||
|
import configManager from '@electron/service/config-service';
|
||||||
|
import logManager from '@electron/service/logger';
|
||||||
|
import { windowManager } from '@electron/service/window-service';
|
||||||
|
import { createTranslator } from '@electron/utils';
|
||||||
|
import { CONFIG_KEYS, MAIN_WIN_SIZE, WINDOW_NAMES } from '@runtime/lib/constants';
|
||||||
|
|
||||||
|
declare const MAIN_WINDOW_VITE_DEV_SERVER_URL: string | undefined;
|
||||||
|
|
||||||
|
type GatewayStatus = 'connected' | 'disconnected' | 'reconnecting';
|
||||||
|
|
||||||
|
let tray: Tray | null = null;
|
||||||
|
let mainWindowRef: BrowserWindow | null = null;
|
||||||
|
let gatewayStatus: GatewayStatus = 'disconnected';
|
||||||
|
let removeLanguageListener: (() => void) | null = null;
|
||||||
|
let quitHookBound = false;
|
||||||
|
let t: ReturnType<typeof createTranslator> = createTranslator();
|
||||||
|
|
||||||
|
function getIconsDir(): string {
|
||||||
|
if (app.isPackaged) {
|
||||||
|
return join(process.resourcesPath, 'resources', 'icons');
|
||||||
|
}
|
||||||
|
|
||||||
|
return join(app.getAppPath(), 'resources', 'icons');
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveTrayIcon() {
|
||||||
|
const iconsDir = getIconsDir();
|
||||||
|
const iconPath = process.platform === 'win32'
|
||||||
|
? join(iconsDir, 'icon.ico')
|
||||||
|
: process.platform === 'darwin'
|
||||||
|
? join(iconsDir, 'icon.png')
|
||||||
|
: join(iconsDir, '32x32.png');
|
||||||
|
|
||||||
|
let icon = nativeImage.createFromPath(iconPath);
|
||||||
|
if (icon.isEmpty()) {
|
||||||
|
icon = nativeImage.createFromPath(join(iconsDir, 'icon.png'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.platform === 'darwin' && !icon.isEmpty()) {
|
||||||
|
icon.setTemplateImage(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGatewayStatusLabelKey(status: GatewayStatus): string {
|
||||||
|
switch (status) {
|
||||||
|
case 'connected':
|
||||||
|
return 'tray.status.running';
|
||||||
|
case 'reconnecting':
|
||||||
|
return 'tray.status.restarting';
|
||||||
|
case 'disconnected':
|
||||||
|
default:
|
||||||
|
return 'tray.status.stopped';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rememberMainWindow(window: BrowserWindow | null | undefined): BrowserWindow | null {
|
||||||
|
if (!window || window.isDestroyed()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindowRef = window;
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildMainWindowUrl(route: string): string {
|
||||||
|
const normalizedHash = route.startsWith('#') ? route.slice(1) : route;
|
||||||
|
|
||||||
|
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
|
||||||
|
const url = new URL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
|
||||||
|
url.pathname = '/';
|
||||||
|
url.hash = normalizedHash;
|
||||||
|
return url.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = pathToFileURL(join(app.getAppPath(), 'dist', 'index.html'));
|
||||||
|
url.hash = normalizedHash;
|
||||||
|
return url.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveMainWindow(): BrowserWindow | null {
|
||||||
|
const trackedWindow = rememberMainWindow(mainWindowRef);
|
||||||
|
if (trackedWindow) {
|
||||||
|
return trackedWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentWindow = rememberMainWindow(windowManager.get(WINDOW_NAMES.MAIN));
|
||||||
|
if (currentWindow) {
|
||||||
|
return currentWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rememberMainWindow(windowManager.create(WINDOW_NAMES.MAIN, MAIN_WIN_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMainWindow(): BrowserWindow | null {
|
||||||
|
const mainWindow = resolveMainWindow();
|
||||||
|
if (!mainWindow) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainWindow.isMinimized()) {
|
||||||
|
mainWindow.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mainWindow.isVisible()) {
|
||||||
|
mainWindow.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow.focus();
|
||||||
|
return mainWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateMainWindow(route: string): void {
|
||||||
|
const mainWindow = showMainWindow();
|
||||||
|
if (!mainWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hashRoute = route.startsWith('#') ? route : `#${route}`;
|
||||||
|
const applyRoute = () => {
|
||||||
|
if (mainWindow.isDestroyed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainWindow.webContents.executeJavaScript(
|
||||||
|
`window.location.hash = ${JSON.stringify(hashRoute)};`,
|
||||||
|
true,
|
||||||
|
).catch((error) => {
|
||||||
|
logManager.warn(`Tray navigation fallback reload for ${hashRoute}`, error);
|
||||||
|
void mainWindow.loadURL(buildMainWindowUrl(hashRoute));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mainWindow.webContents.isLoadingMainFrame()) {
|
||||||
|
mainWindow.webContents.once('did-finish-load', applyRoute);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyRoute();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMainWindow(): void {
|
||||||
|
const mainWindow = resolveMainWindow();
|
||||||
|
if (!mainWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainWindow.isVisible()) {
|
||||||
|
mainWindow.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showMainWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildContextMenu() {
|
||||||
|
const gatewayStatusLabel = t(getGatewayStatusLabelKey(gatewayStatus)) ?? gatewayStatus;
|
||||||
|
|
||||||
|
return Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
label: t('tray.showWindow') ?? 'Show Window',
|
||||||
|
click: () => {
|
||||||
|
showMainWindow();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: t('tray.gatewayStatus') ?? 'Gateway Status',
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: gatewayStatusLabel,
|
||||||
|
type: 'checkbox',
|
||||||
|
checked: gatewayStatus === 'connected',
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: t('tray.quickActions') ?? 'Quick Actions',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: t('tray.openChat') ?? 'Open Chat',
|
||||||
|
click: () => {
|
||||||
|
navigateMainWindow('/home');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('tray.openSettings') ?? 'Open Settings',
|
||||||
|
click: () => {
|
||||||
|
navigateMainWindow('/setting?view=general');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: t('tray.checkForUpdates') ?? 'Check for Updates...',
|
||||||
|
click: () => {
|
||||||
|
void appUpdater.checkForUpdates();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: t('tray.quit') ?? 'Quit ZN-AI',
|
||||||
|
click: () => {
|
||||||
|
app.quit();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshTray(): void {
|
||||||
|
if (!tray) {
|
||||||
|
tray = new Tray(resolveTrayIcon());
|
||||||
|
}
|
||||||
|
|
||||||
|
const tooltip = [t('tray.tooltip') ?? 'ZN-AI', t(getGatewayStatusLabelKey(gatewayStatus)) ?? gatewayStatus]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(' - ');
|
||||||
|
|
||||||
|
tray.setToolTip(tooltip);
|
||||||
|
tray.setContextMenu(buildContextMenu());
|
||||||
|
|
||||||
|
tray.removeAllListeners('click');
|
||||||
|
tray.removeAllListeners('double-click');
|
||||||
|
tray.on('click', toggleMainWindow);
|
||||||
|
tray.on('double-click', () => {
|
||||||
|
showMainWindow();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureLanguageListener(): void {
|
||||||
|
if (removeLanguageListener) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeLanguageListener = configManager.onConfigChange((config) => {
|
||||||
|
if (!config[CONFIG_KEYS.LANGUAGE]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = createTranslator();
|
||||||
|
if (tray) {
|
||||||
|
refreshTray();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createTray(mainWindow: BrowserWindow): Tray {
|
||||||
|
rememberMainWindow(mainWindow);
|
||||||
|
ensureLanguageListener();
|
||||||
|
refreshTray();
|
||||||
|
|
||||||
|
if (!quitHookBound) {
|
||||||
|
quitHookBound = true;
|
||||||
|
app.once('before-quit', () => {
|
||||||
|
destroyTray();
|
||||||
|
quitHookBound = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return tray as Tray;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateTrayStatus(status: GatewayStatus): void {
|
||||||
|
gatewayStatus = status;
|
||||||
|
if (tray) {
|
||||||
|
refreshTray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function destroyTray(): void {
|
||||||
|
tray?.destroy();
|
||||||
|
tray = null;
|
||||||
|
mainWindowRef = null;
|
||||||
|
|
||||||
|
if (removeLanguageListener) {
|
||||||
|
removeLanguageListener();
|
||||||
|
removeLanguageListener = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
import { Tray, Menu, ipcMain, app } from 'electron'
|
|
||||||
import { createTranslator, createLogo } from '@electron/utils'
|
|
||||||
import { CONFIG_KEYS, IPC_EVENTS, WINDOW_NAMES, MAIN_WIN_SIZE } from '@runtime/lib/constants'
|
|
||||||
|
|
||||||
import logManager from '@electron/service/logger'
|
|
||||||
// TODO: shortcutManager
|
|
||||||
import windowManager from '@electron/service/window-service'
|
|
||||||
import configManager from '@electron/service/config-service'
|
|
||||||
|
|
||||||
let t: ReturnType<typeof createTranslator> = createTranslator();
|
|
||||||
|
|
||||||
class TrayService {
|
|
||||||
private static _instance: TrayService;
|
|
||||||
private _tray: Tray | null = null;
|
|
||||||
private _removeLanguageListener?: () => void;
|
|
||||||
|
|
||||||
private _setupLanguageChangeListener() {
|
|
||||||
this._removeLanguageListener = configManager.onConfigChange((config) => {
|
|
||||||
if (!config[CONFIG_KEYS.LANGUAGE]) return;
|
|
||||||
|
|
||||||
// 切换语言后,重新创建翻译器
|
|
||||||
t = createTranslator();
|
|
||||||
|
|
||||||
|
|
||||||
if (this._tray) {
|
|
||||||
this._updateTray();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateTray() {
|
|
||||||
if (!this._tray) {
|
|
||||||
this._tray = new Tray(createLogo());
|
|
||||||
}
|
|
||||||
|
|
||||||
const showWindow = () => {
|
|
||||||
const mainWindow = windowManager.get(WINDOW_NAMES.MAIN);
|
|
||||||
|
|
||||||
if (mainWindow && !mainWindow?.isDestroyed() && mainWindow?.isVisible() && !mainWindow?.isFocused()) {
|
|
||||||
return mainWindow.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainWindow?.isMinimized()) {
|
|
||||||
return mainWindow?.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainWindow?.isVisible() && mainWindow?.isFocused()) return;
|
|
||||||
|
|
||||||
windowManager.create(WINDOW_NAMES.MAIN, MAIN_WIN_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._tray.setToolTip(t('tray.tooltip') ?? 'Diona Application');
|
|
||||||
|
|
||||||
// TODO: 依赖快捷键Service
|
|
||||||
this._tray.setContextMenu(Menu.buildFromTemplate([
|
|
||||||
{ label: t('tray.showWindow'), accelerator: 'CmdOrCtrl+N', click: showWindow },
|
|
||||||
{ type: 'separator' },
|
|
||||||
{ label: t('settings.title'), click: () => ipcMain.emit(`${IPC_EVENTS.OPEN_WINDOW}:${WINDOW_NAMES.SETTING}`) },
|
|
||||||
{ role: 'quit', label: t('tray.exit') }
|
|
||||||
]));
|
|
||||||
|
|
||||||
this._tray.removeAllListeners('click');
|
|
||||||
this._tray.on('click', showWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
private constructor() {
|
|
||||||
this._setupLanguageChangeListener();
|
|
||||||
logManager.info('TrayService initialized successfully.');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static getInstance() {
|
|
||||||
if (!this._instance) {
|
|
||||||
this._instance = new TrayService();
|
|
||||||
}
|
|
||||||
return this._instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public create() {
|
|
||||||
if (this._tray) return;
|
|
||||||
this._updateTray();
|
|
||||||
app.on('quit', () => {
|
|
||||||
this.destroy();
|
|
||||||
//TODO: 移除快捷键
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
public destroy() {
|
|
||||||
this._tray?.destroy();
|
|
||||||
this._tray = null;
|
|
||||||
//TODO: 移除快捷键
|
|
||||||
if (this._removeLanguageListener) {
|
|
||||||
this._removeLanguageListener();
|
|
||||||
this._removeLanguageListener = void 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const trayManager = TrayService.getInstance();
|
|
||||||
export default trayManager;
|
|
||||||
|
|
||||||
@@ -47,18 +47,7 @@ export class AppUpdater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private registerHandlers() {
|
private registerHandlers() {
|
||||||
ipcMain.handle(IPC_EVENTS.UPDATE_CHECK, () => {
|
ipcMain.handle(IPC_EVENTS.UPDATE_CHECK, () => this.checkForUpdates());
|
||||||
if (app.isPackaged) {
|
|
||||||
return autoUpdater.checkForUpdates();
|
|
||||||
} else {
|
|
||||||
// 在开发环境下模拟
|
|
||||||
this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: 'checking' });
|
|
||||||
setTimeout(() => {
|
|
||||||
this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: 'not-available' });
|
|
||||||
}, 1500);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.handle(IPC_EVENTS.UPDATE_DOWNLOAD, () => {
|
ipcMain.handle(IPC_EVENTS.UPDATE_DOWNLOAD, () => {
|
||||||
if (app.isPackaged) {
|
if (app.isPackaged) {
|
||||||
@@ -78,6 +67,18 @@ export class AppUpdater {
|
|||||||
return app.getVersion();
|
return app.getVersion();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public checkForUpdates() {
|
||||||
|
if (app.isPackaged) {
|
||||||
|
return autoUpdater.checkForUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: 'checking' });
|
||||||
|
setTimeout(() => {
|
||||||
|
this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: 'not-available' });
|
||||||
|
}, 1500);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const appUpdater = AppUpdater.getInstance();
|
export const appUpdater = AppUpdater.getInstance();
|
||||||
|
|||||||
@@ -5,17 +5,17 @@ import { windowManager } from '@electron/service/window-service'
|
|||||||
import { menuManager } from '@electron/service/menu-service'
|
import { menuManager } from '@electron/service/menu-service'
|
||||||
import { logManager } from '@electron/service/logger'
|
import { logManager } from '@electron/service/logger'
|
||||||
import { configManager } from '@electron/service/config-service'
|
import { configManager } from '@electron/service/config-service'
|
||||||
import { trayManager } from '@electron/service/tray-service'
|
|
||||||
import { TabManager } from '@service/tab-manager'
|
import { TabManager } from '@service/tab-manager'
|
||||||
import { registerWindowHandlers } from '@electron/ipc/window-handlers'
|
import { registerWindowHandlers } from '@electron/ipc/window-handlers'
|
||||||
|
import { createTray, destroyTray } from '@electron/main/tray'
|
||||||
|
|
||||||
const handleTray = (minimizeToTray: boolean) => {
|
const handleTray = (minimizeToTray: boolean, mainWindow: BrowserWindow) => {
|
||||||
if (minimizeToTray) {
|
if (minimizeToTray) {
|
||||||
trayManager.create();
|
createTray(mainWindow);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
trayManager.destroy();
|
destroyTray();
|
||||||
}
|
}
|
||||||
|
|
||||||
const registerMenus = (window: BrowserWindow) => {
|
const registerMenus = (window: BrowserWindow) => {
|
||||||
@@ -105,10 +105,10 @@ export function setupMainWindow() {
|
|||||||
configManager.onConfigChange((config) => {
|
configManager.onConfigChange((config) => {
|
||||||
if (minimizeToTray === config[CONFIG_KEYS.MINIMIZE_TO_TRAY]) return;
|
if (minimizeToTray === config[CONFIG_KEYS.MINIMIZE_TO_TRAY]) return;
|
||||||
minimizeToTray = config[CONFIG_KEYS.MINIMIZE_TO_TRAY];
|
minimizeToTray = config[CONFIG_KEYS.MINIMIZE_TO_TRAY];
|
||||||
handleTray(minimizeToTray);
|
handleTray(minimizeToTray, mainWindow);
|
||||||
});
|
});
|
||||||
|
|
||||||
handleTray(minimizeToTray);
|
handleTray(minimizeToTray, mainWindow);
|
||||||
registerMenus(mainWindow);
|
registerMenus(mainWindow);
|
||||||
registerWindowHandlers(mainWindow);
|
registerWindowHandlers(mainWindow);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user