diff --git a/package.json b/package.json index 8b0e5e7..5b608bc 100644 --- a/package.json +++ b/package.json @@ -24,11 +24,13 @@ "@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/utils": "^3.0.0", "@nextui-org/react": "^2.4.6", + "axios": "^1.7.2", "electron-updater": "^6.2.1", "framer-motion": "^11.3.19", "next-themes": "^0.3.0", "react-icons": "^5.2.1", - "react-router-dom": "^6.25.1" + "react-router-dom": "^6.25.1", + "swr": "^2.2.5" }, "devDependencies": { "@electron-toolkit/eslint-config-prettier": "^2.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 23a1462..7497521 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@nextui-org/react': specifier: ^2.4.6 version: 2.4.6(@types/react@18.3.3)(framer-motion@11.3.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.7) + axios: + specifier: ^1.7.2 + version: 1.7.2 electron-updater: specifier: ^6.2.1 version: 6.2.1 @@ -32,6 +35,9 @@ importers: react-router-dom: specifier: ^6.25.1 version: 6.25.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + swr: + specifier: ^2.2.5 + version: 2.2.5(react@18.3.1) devDependencies: '@electron-toolkit/eslint-config-prettier': specifier: ^2.0.0 @@ -1959,6 +1965,9 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + axios@1.7.2: + resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2086,6 +2095,9 @@ packages: resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} engines: {node: '>=8'} + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -2529,6 +2541,15 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -3458,6 +3479,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} @@ -3822,6 +3846,11 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + swr@2.2.5: + resolution: {integrity: sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 + synckit@0.9.1: resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} @@ -4004,6 +4033,11 @@ packages: '@types/react': optional: true + use-sync-external-store@1.2.2: + resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + utf8-byte-length@1.0.5: resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} @@ -6973,6 +7007,14 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 + axios@1.7.2: + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + balanced-match@1.0.2: {} base64-js@1.5.1: {} @@ -7152,6 +7194,8 @@ snapshots: string-width: 4.2.3 optional: true + client-only@0.0.1: {} + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -7759,6 +7803,8 @@ snapshots: flatted@3.3.1: {} + follow-redirects@1.15.6: {} + for-each@0.3.3: dependencies: is-callable: 1.2.7 @@ -8675,6 +8721,8 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + proxy-from-env@1.1.0: {} + pump@3.0.0: dependencies: end-of-stream: 1.4.4 @@ -9114,6 +9162,12 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + swr@2.2.5(react@18.3.1): + dependencies: + client-only: 0.0.1 + react: 18.3.1 + use-sync-external-store: 1.2.2(react@18.3.1) + synckit@0.9.1: dependencies: '@pkgr/core': 0.1.1 @@ -9319,6 +9373,10 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 + use-sync-external-store@1.2.2(react@18.3.1): + dependencies: + react: 18.3.1 + utf8-byte-length@1.0.5: {} util-deprecate@1.0.2: {} diff --git a/src/main/index.ts b/src/main/index.ts index cf03a7a..f15decc 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,7 +1,9 @@ import { app, shell, BrowserWindow, Tray, Menu } from 'electron' import { join } from 'path' import { electronApp, optimizer, is } from '@electron-toolkit/utils' -import icon from '../../resources/icon.png?asset' +import pngIcon from '../../resources/icon.png?asset' +import icoIcon from '../../resources/icon.ico?asset' +import { registerIpcMainHandlers } from './mihomo-api' let window: BrowserWindow | null = null let tray: Tray | null = null @@ -16,7 +18,7 @@ function createWindow(): void { height: 600, show: false, autoHideMenuBar: true, - ...(process.platform === 'linux' ? { icon } : {}), + ...(process.platform === 'linux' ? { icon: pngIcon } : {}), webPreferences: { preload: join(__dirname, '../preload/index.js'), sandbox: false @@ -48,7 +50,11 @@ function createWindow(): void { } function createTray(): void { - tray = new Tray(icon) + if (process.platform === 'linux') { + tray = new Tray(pngIcon) + } else { + tray = new Tray(icoIcon) + } trayContextMenu = Menu.buildFromTemplate([ { label: '显示窗口', @@ -92,7 +98,7 @@ app.whenReady().then(() => { app.on('browser-window-created', (_, window) => { optimizer.watchWindowShortcuts(window) }) - + registerIpcMainHandlers() createWindow() createTray() diff --git a/src/main/mihomo-api.ts b/src/main/mihomo-api.ts new file mode 100644 index 0000000..e4b5b2b --- /dev/null +++ b/src/main/mihomo-api.ts @@ -0,0 +1,31 @@ +import { ipcMain } from 'electron' +import axios, { AxiosInstance } from 'axios' + +let axiosIns: AxiosInstance = null! + +/// initialize some information +/// enable force update axiosIns +export const getAxios = async (force: boolean = false): Promise => { + if (axiosIns && !force) return axiosIns + + const server = '127.0.0.1:9097' + const secret = '' + + axiosIns = axios.create({ + baseURL: `http://${server}`, + proxy: false, + headers: secret ? { Authorization: `Bearer ${secret}` } : {}, + timeout: 15000 + }) + axiosIns.interceptors.response.use((r) => r.data) + return axiosIns +} + +async function mihomoVersion(): Promise { + const instance = await getAxios() + return instance.get('/version') as Promise +} + +export function registerIpcMainHandlers(): void { + ipcMain.handle('mihomoVersion', mihomoVersion) +} diff --git a/src/renderer/src/pages/settings.tsx b/src/renderer/src/pages/settings.tsx index f851b6b..7d0ccfa 100644 --- a/src/renderer/src/pages/settings.tsx +++ b/src/renderer/src/pages/settings.tsx @@ -1,3 +1,17 @@ +import { Button } from '@nextui-org/react' +import { mihomoVersion } from '@renderer/utils/api' + +import useSWR from 'swr' + export default function Settings(): JSX.Element { - return
Settings
+ const { data, error, isLoading, mutate } = useSWR('mihomoVersion', mihomoVersion) + + if (error) return
failed to load
+ if (isLoading) return
loading...
+ return ( +
+ {data?.version} + +
+ ) } diff --git a/src/renderer/src/utils/api.ts b/src/renderer/src/utils/api.ts new file mode 100644 index 0000000..aca2ede --- /dev/null +++ b/src/renderer/src/utils/api.ts @@ -0,0 +1,3 @@ +export async function mihomoVersion(): Promise { + return await window.electron.ipcRenderer.invoke('mihomoVersion') +} diff --git a/src/renderer/src/utils/types.d.ts b/src/renderer/src/utils/types.d.ts deleted file mode 100644 index fd2a435..0000000 --- a/src/renderer/src/utils/types.d.ts +++ /dev/null @@ -1 +0,0 @@ -type OutboundMode = 'rule' | 'global' | 'direct' diff --git a/src/shared/types.d.ts b/src/shared/types.d.ts new file mode 100644 index 0000000..fe7fe01 --- /dev/null +++ b/src/shared/types.d.ts @@ -0,0 +1,6 @@ +type OutboundMode = 'rule' | 'global' | 'direct' + +interface IMihomoVersion { + version: string + meta: boolean +} diff --git a/tsconfig.node.json b/tsconfig.node.json index db23a68..8d0edf2 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -1,6 +1,6 @@ { "extends": "@electron-toolkit/tsconfig/tsconfig.node.json", - "include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*"], + "include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*", "src/shared/**/*.d.ts"], "compilerOptions": { "composite": true, "types": ["electron-vite/node"] diff --git a/tsconfig.web.json b/tsconfig.web.json index 7ce117a..311e44e 100644 --- a/tsconfig.web.json +++ b/tsconfig.web.json @@ -4,7 +4,8 @@ "src/renderer/src/utils/env.d.ts", "src/renderer/src/**/*", "src/renderer/src/**/*.tsx", - "src/preload/*.d.ts" + "src/preload/*.d.ts", + "src/shared/**/*.d.ts" ], "compilerOptions": { "composite": true,