From 8463175779f376d854e316e1817ac1e1bac27351 Mon Sep 17 00:00:00 2001 From: pompurin404 Date: Thu, 1 Aug 2024 11:31:46 +0800 Subject: [PATCH] synced tray menu --- src/main/index.ts | 147 ++++++++++++------ src/main/manager.ts | 4 +- .../sider/outbound-mode-switcher.tsx | 6 + .../src/hooks/use-controled-mihomo-config.tsx | 12 +- 4 files changed, 120 insertions(+), 49 deletions(-) diff --git a/src/main/index.ts b/src/main/index.ts index b50d8ea..830ed5d 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,20 +1,71 @@ -import { app, shell, BrowserWindow, Tray, Menu } from 'electron' +import { app, shell, BrowserWindow, Tray, Menu, ipcMain } from 'electron' import { join } from 'path' import { electronApp, optimizer, is } from '@electron-toolkit/utils' import pngIcon from '../../resources/icon.png?asset' import icoIcon from '../../resources/icon.ico?asset' import { registerIpcMainHandlers } from './cmds' -import { initConfig, appConfig } from './config' +import { initConfig, appConfig, controledMihomoConfig, setControledMihomoConfig } from './config' import { stopCore, startCore } from './manager' import { initDirs } from './dirs' +import { patchMihomoConfig } from './mihomo-api' let window: BrowserWindow | null = null let tray: Tray | null = null let trayContextMenu: Menu | null = null -initDirs() -initConfig() -startCore() +const gotTheLock = app.requestSingleInstanceLock() + +if (!gotTheLock) { + app.quit() +} else { + initDirs() + initConfig() + startCore() + + app.on('second-instance', () => { + window?.show() + window?.focusOnWebView() + }) + + // Quit when all windows are closed, except on macOS. There, it's common + // for applications and their menu bar to stay active until the user quits + // explicitly with Cmd + Q. + app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } + }) + + app.on('before-quit', () => { + stopCore() + app.exit() + }) + + // This method will be called when Electron has finished + // initialization and is ready to create browser windows. + // Some APIs can only be used after this event occurs. + app.whenReady().then(() => { + // Set app user model id for windows + electronApp.setAppUserModelId('party.mihomo.app') + + // Default open or close DevTools by F12 in development + // and ignore CommandOrControl + R in production. + // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils + app.on('browser-window-created', (_, window) => { + optimizer.watchWindowShortcuts(window) + }) + registerIpcMainHandlers() + createWindow() + createTray() + + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) + }) +} + function createWindow(): void { // Create the browser window. window = new BrowserWindow({ @@ -65,6 +116,7 @@ function createTray(): void { } trayContextMenu = Menu.buildFromTemplate([ { + id: 'show', label: '显示窗口', type: 'normal', click: (): void => { @@ -73,6 +125,43 @@ function createTray(): void { } }, { + id: 'rule', + label: '规则模式', + type: 'radio', + checked: controledMihomoConfig.mode === 'rule', + click: (): void => { + setControledMihomoConfig({ mode: 'rule' }) + patchMihomoConfig({ mode: 'rule' }) + window?.webContents.send('controledMihomoConfigUpdated') + } + }, + { + id: 'global', + label: '全局模式', + type: 'radio', + checked: controledMihomoConfig.mode === 'global', + click: (): void => { + setControledMihomoConfig({ mode: 'global' }) + patchMihomoConfig({ mode: 'global' }) + window?.webContents.send('controledMihomoConfigUpdated') + } + }, + { + id: 'direct', + label: '直连模式', + type: 'radio', + checked: controledMihomoConfig.mode === 'direct', + click: (): void => { + setControledMihomoConfig({ mode: 'direct' }) + patchMihomoConfig({ mode: 'direct' }) + window?.webContents.send('controledMihomoConfigUpdated') + } + }, + { type: 'separator' }, + { id: 'version', label: app.getVersion(), type: 'normal', enabled: false }, + { type: 'separator' }, + { + id: 'restart', label: '重启应用', type: 'normal', click: (): void => { @@ -80,10 +169,16 @@ function createTray(): void { app.quit() } }, - { type: 'separator' }, - { label: '退出应用', type: 'normal', click: (): void => app.quit() } + { id: 'quit', label: '退出应用', type: 'normal', click: (): void => app.quit() } ]) + ipcMain.on('controledMihomoConfigUpdated', () => { + const { mode } = controledMihomoConfig + if (mode) { + trayContextMenu?.getMenuItemById(mode)?.click() + } + }) + tray.setContextMenu(trayContextMenu) tray.setIgnoreDoubleClickEvents(true) tray.setToolTip('Another Mihomo GUI.') @@ -92,41 +187,3 @@ function createTray(): void { window?.isVisible() ? window?.hide() : window?.show() }) } - -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. -app.whenReady().then(() => { - // Set app user model id for windows - electronApp.setAppUserModelId('party.mihomo.app') - - // Default open or close DevTools by F12 in development - // and ignore CommandOrControl + R in production. - // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils - app.on('browser-window-created', (_, window) => { - optimizer.watchWindowShortcuts(window) - }) - registerIpcMainHandlers() - createWindow() - createTray() - - app.on('activate', function () { - // On macOS it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (BrowserWindow.getAllWindows().length === 0) createWindow() - }) -}) - -// Quit when all windows are closed, except on macOS. There, it's common -// for applications and their menu bar to stay active until the user quits -// explicitly with Cmd + Q. -app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit() - } -}) - -app.on('before-quit', () => { - stopCore() - app.exit() -}) diff --git a/src/main/manager.ts b/src/main/manager.ts index e26ccf0..837853e 100644 --- a/src/main/manager.ts +++ b/src/main/manager.ts @@ -9,9 +9,7 @@ export function startCore(): void { const corePath = mihomoCorePath(appConfig.core ?? 'mihomo') generateProfile() stopCore() - child = execFile(corePath, ['-d', mihomoWorkDir()], (error, stdout) => { - console.log(stdout) - }) + child = execFile(corePath, ['-d', mihomoWorkDir()], () => {}) } export function stopCore(): void { diff --git a/src/renderer/src/components/sider/outbound-mode-switcher.tsx b/src/renderer/src/components/sider/outbound-mode-switcher.tsx index b15e129..801a25f 100644 --- a/src/renderer/src/components/sider/outbound-mode-switcher.tsx +++ b/src/renderer/src/components/sider/outbound-mode-switcher.tsx @@ -10,6 +10,12 @@ const OutboundModeSwitcher: React.FC = () => { const onChangeMode = async (mode: OutboundMode): Promise => { await patchControledMihomoConfig({ mode }) await patchMihomoConfig({ mode }) + window.electron.ipcRenderer.send(mode) + window.electron.ipcRenderer.send('test') + } + + if (!mode) { + return null } return ( diff --git a/src/renderer/src/hooks/use-controled-mihomo-config.tsx b/src/renderer/src/hooks/use-controled-mihomo-config.tsx index dd4dfb7..40f5d37 100644 --- a/src/renderer/src/hooks/use-controled-mihomo-config.tsx +++ b/src/renderer/src/hooks/use-controled-mihomo-config.tsx @@ -1,5 +1,6 @@ import useSWR from 'swr' import { getControledMihomoConfig, setControledMihomoConfig } from '@renderer/utils/ipc' +import { useEffect } from 'react' interface RetuenType { controledMihomoConfig: Partial | undefined @@ -15,9 +16,18 @@ export const useControledMihomoConfig = (): RetuenType => { const patchControledMihomoConfig = async (value: Partial): Promise => { await setControledMihomoConfig(value) - mutateControledMihomoConfig() + window.electron.ipcRenderer.send('controledMihomoConfigUpdated') } + useEffect(() => { + window.electron.ipcRenderer.on('controledMihomoConfigUpdated', () => { + mutateControledMihomoConfig() + }) + return (): void => { + window.electron.ipcRenderer.removeAllListeners('controledMihomoConfigUpdated') + } + }, []) + return { controledMihomoConfig, mutateControledMihomoConfig,