synced tray menu

This commit is contained in:
pompurin404 2024-08-01 11:31:46 +08:00
parent 3dd436d837
commit 8463175779
No known key found for this signature in database
4 changed files with 120 additions and 49 deletions

View File

@ -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
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()
})

View File

@ -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 {

View File

@ -10,6 +10,12 @@ const OutboundModeSwitcher: React.FC = () => {
const onChangeMode = async (mode: OutboundMode): Promise<void> => {
await patchControledMihomoConfig({ mode })
await patchMihomoConfig({ mode })
window.electron.ipcRenderer.send(mode)
window.electron.ipcRenderer.send('test')
}
if (!mode) {
return null
}
return (

View File

@ -1,5 +1,6 @@
import useSWR from 'swr'
import { getControledMihomoConfig, setControledMihomoConfig } from '@renderer/utils/ipc'
import { useEffect } from 'react'
interface RetuenType {
controledMihomoConfig: Partial<IMihomoConfig> | undefined
@ -15,9 +16,18 @@ export const useControledMihomoConfig = (): RetuenType => {
const patchControledMihomoConfig = async (value: Partial<IMihomoConfig>): Promise<void> => {
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,