diff --git a/changelog.md b/changelog.md index e007480..4391d5d 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,7 @@ +### New Features + +- 允许在开启悬浮窗的情况下禁用托盘图标 + ### Bug Fixes - 修复开启轻量模式后 TrafficMonitor 重复启动的问题 diff --git a/src/main/index.ts b/src/main/index.ts index b6cb95f..253cab5 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -150,13 +150,15 @@ app.whenReady().then(async () => { app.on('browser-window-created', (_, window) => { optimizer.watchWindowShortcuts(window) }) - const { showFloatingWindow: showFloating = false } = await getAppConfig() + const { showFloatingWindow: showFloating = false, disableTray = false } = await getAppConfig() registerIpcMainHandlers() await createWindow() if (showFloating) { showFloatingWindow() } - await createTray() + if (!disableTray) { + await createTray() + } await initShortcut() app.on('activate', function () { // On macOS it's common to re-create a window in the app when the diff --git a/src/main/resolve/floatingWindow.ts b/src/main/resolve/floatingWindow.ts index 967f62f..1ad23a1 100644 --- a/src/main/resolve/floatingWindow.ts +++ b/src/main/resolve/floatingWindow.ts @@ -4,7 +4,7 @@ import windowStateKeeper from 'electron-window-state' import { join } from 'path' import { getAppConfig, patchAppConfig } from '../config' import { applyTheme } from './theme' -import { buildContextMenu } from './tray' +import { buildContextMenu, showTrayIcon } from './tray' export let floatingWindow: BrowserWindow | null = null @@ -55,7 +55,7 @@ async function createFloatingWindow(): Promise { } } -export function showFloatingWindow(): void { +export async function showFloatingWindow(): Promise { if (floatingWindow) { floatingWindow.show() } else { @@ -66,19 +66,21 @@ export function showFloatingWindow(): void { export async function triggerFloatingWindow(): Promise { if (floatingWindow?.isVisible()) { await patchAppConfig({ showFloatingWindow: false }) - closeFloatingWindow() + await closeFloatingWindow() } else { await patchAppConfig({ showFloatingWindow: true }) - showFloatingWindow() + await showFloatingWindow() } } -export function closeFloatingWindow(): void { +export async function closeFloatingWindow(): Promise { if (floatingWindow) { floatingWindow.close() floatingWindow.destroy() floatingWindow = null } + await showTrayIcon() + await patchAppConfig({ disableTray: false }) } export async function showContextMenu(): Promise { diff --git a/src/main/resolve/tray.ts b/src/main/resolve/tray.ts index 0d4e2e3..b0f29f6 100644 --- a/src/main/resolve/tray.ts +++ b/src/main/resolve/tray.ts @@ -365,3 +365,16 @@ export async function copyEnv(type: 'bash' | 'cmd' | 'powershell'): Promise { + if (!tray) { + await createTray() + } +} + +export async function closeTrayIcon(): Promise { + if (tray) { + tray.destroy() + } + tray = null +} diff --git a/src/main/utils/init.ts b/src/main/utils/init.ts index a2ff6d8..8d15be9 100644 --- a/src/main/utils/init.ts +++ b/src/main/utils/init.ts @@ -148,7 +148,9 @@ async function migration(): Promise { ], appTheme = 'system', envType = [process.platform === 'win32' ? 'powershell' : 'bash'], - useSubStore = true + useSubStore = true, + showFloatingWindow = false, + disableTray = false } = await getAppConfig() const { 'external-controller-pipe': externalControllerPipe, @@ -208,6 +210,9 @@ async function migration(): Promise { if (externalController === undefined) { await patchControledMihomoConfig({ 'external-controller': '' }) } + if (!showFloatingWindow && disableTray) { + await patchAppConfig({ disableTray: false }) + } } function initDeeplink(): void { diff --git a/src/main/utils/ipc.ts b/src/main/utils/ipc.ts index 54882e8..dc81812 100644 --- a/src/main/utils/ipc.ts +++ b/src/main/utils/ipc.ts @@ -63,7 +63,7 @@ import { import { getRuntimeConfig, getRuntimeConfigStr } from '../core/factory' import { listWebdavBackups, webdavBackup, webdavDelete, webdavRestore } from '../resolve/backup' import { getInterfaces } from '../sys/interface' -import { copyEnv } from '../resolve/tray' +import { closeTrayIcon, copyEnv, showTrayIcon } from '../resolve/tray' import { registerShortcut } from '../resolve/shortcut' import { closeMainWindow, mainWindow, showMainWindow, triggerMainWindow } from '..' import { @@ -210,11 +210,13 @@ export function registerIpcMainHandlers(): void { ipcMain.handle('isAlwaysOnTop', () => { return mainWindow?.isAlwaysOnTop() }) + ipcMain.handle('showTrayIcon', () => ipcErrorWrapper(showTrayIcon)()) + ipcMain.handle('closeTrayIcon', () => ipcErrorWrapper(closeTrayIcon)()) ipcMain.handle('showMainWindow', showMainWindow) ipcMain.handle('closeMainWindow', closeMainWindow) ipcMain.handle('triggerMainWindow', triggerMainWindow) - ipcMain.handle('showFloatingWindow', showFloatingWindow) - ipcMain.handle('closeFloatingWindow', closeFloatingWindow) + ipcMain.handle('showFloatingWindow', () => ipcErrorWrapper(showFloatingWindow)()) + ipcMain.handle('closeFloatingWindow', () => ipcErrorWrapper(closeFloatingWindow)()) ipcMain.handle('showContextMenu', () => ipcErrorWrapper(showContextMenu)()) ipcMain.handle('openFile', (_e, type, id, ext) => openFile(type, id, ext)) ipcMain.handle('openDevTools', () => { diff --git a/src/renderer/src/components/settings/general-config.tsx b/src/renderer/src/components/settings/general-config.tsx index 808943b..1e036e8 100644 --- a/src/renderer/src/components/settings/general-config.tsx +++ b/src/renderer/src/components/settings/general-config.tsx @@ -8,6 +8,7 @@ import { applyTheme, checkAutoRun, closeFloatingWindow, + closeTrayIcon, copyEnv, disableAutoRun, enableAutoRun, @@ -17,6 +18,7 @@ import { relaunchApp, resolveThemes, showFloatingWindow, + showTrayIcon, startMonitor, writeTheme } from '@renderer/utils/ipc' @@ -39,6 +41,7 @@ const GeneralConfig: React.FC = () => { useDockIcon = true, showTraffic = true, proxyInTray = true, + disableTray = false, showFloatingWindow: showFloating = false, useWindowFrame = false, autoQuitWithoutCore = false, @@ -192,6 +195,22 @@ const GeneralConfig: React.FC = () => { }} /> + {showFloating && ( + + { + await patchAppConfig({ disableTray: v }) + if (v) { + closeTrayIcon() + } else { + showTrayIcon() + } + }} + /> + + )} {platform !== 'linux' && ( <> diff --git a/src/renderer/src/utils/ipc.ts b/src/renderer/src/utils/ipc.ts index 4dc979c..9903bde 100644 --- a/src/renderer/src/utils/ipc.ts +++ b/src/renderer/src/utils/ipc.ts @@ -327,6 +327,14 @@ export async function subStoreCollections(): Promise { return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('subStoreCollections')) } +export async function showTrayIcon(): Promise { + return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('showTrayIcon')) +} + +export async function closeTrayIcon(): Promise { + return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('closeTrayIcon')) +} + export async function showMainWindow(): Promise { return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('showMainWindow')) } diff --git a/src/shared/types.d.ts b/src/shared/types.d.ts index 5f80e52..91f1f5c 100644 --- a/src/shared/types.d.ts +++ b/src/shared/types.d.ts @@ -212,6 +212,7 @@ interface IAppConfig { proxyCols: 'auto' | '1' | '2' | '3' | '4' connectionDirection: 'asc' | 'desc' connectionOrderBy: 'time' | 'upload' | 'download' | 'uploadSpeed' | 'downloadSpeed' + disableTray?: boolean showFloatingWindow?: boolean connectionCardStatus?: CardStatus dnsCardStatus?: CardStatus