From 9a5776d5864eefd442b487c1490c1e74e66476ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A2=E4=BA=9A=E6=98=95?= <1549469775@qq.com> Date: Fri, 25 Jul 2025 15:57:15 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=BA=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E4=B8=BB=E8=BF=9B=E7=A8=8B=E5=92=8C=E6=B8=B2=E6=9F=93?= =?UTF-8?q?=E8=BF=9B=E7=A8=8B=E4=BA=A4=E4=BA=92=E6=96=B9=E5=BC=8F=E4=B8=8D?= =?UTF-8?q?=E5=8F=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- electron.vite.config.ts | 4 +- packages/base/api/abstract.ts | 71 +++++++++ packages/base/api/browser.ts | 34 +++++ packages/base/api/electron.ts | 27 ++++ src/common/_ioc.main.ts | 50 ------- src/common/event/PlatForm/hook.ts | 41 ----- src/common/event/PlatForm/index.ts | 58 -------- src/common/event/PlatForm/main/command.ts | 116 --------------- src/common/event/Setting/hook.ts | 63 -------- src/common/event/Setting/index.ts | 23 --- src/common/event/Setting/main/command.ts | 13 -- src/common/event/Snippet/hook.ts | 5 - src/common/event/Snippet/index.ts | 18 --- src/common/event/Snippet/main/command.ts | 44 ------ src/common/event/Updater/hook.ts | 70 --------- src/common/event/Updater/index.ts | 13 -- src/common/event/Updater/main/command.ts | 23 --- src/common/lib/abstract.ts | 70 --------- src/common/lib/browser.ts | 34 ----- src/common/lib/electron.ts | 25 ---- src/common/readme.md | 7 - src/main/App copy.ts | 165 --------------------- src/main/_ioc.ts | 2 +- src/main/command/PlatForm/command.ts | 116 +++++++++++++++ src/main/command/Setting/command.ts | 13 ++ src/main/command/Snippet/command.ts | 44 ++++++ src/main/command/Updater/command.ts | 23 +++ src/main/command/_ioc.ts | 50 +++++++ src/preload/plugin.ts | 0 src/renderer/auto-imports.d.ts | 10 +- .../src/composables/Api/Platform/_/index.ts | 58 ++++++++ .../src/composables/Api/Platform/useApiPlatForm.ts | 41 +++++ .../src/composables/Api/Setting/_/index.ts | 23 +++ .../src/composables/Api/Setting/useApiSetting.ts | 63 ++++++++ .../src/composables/Api/Updater/_/index.ts | 13 ++ .../src/composables/Api/Updater/useApiUpdater.ts | 70 +++++++++ src/renderer/src/composables/useTest.ts | 3 - src/renderer/src/pages/index/index copy.vue | 48 +++--- src/renderer/src/pages/index/index.vue | 7 +- src/renderer/src/pages/setting/index.vue | 5 +- src/renderer/src/ui/NavBar.vue | 4 +- src/renderer/src/ui/Update.vue | 16 +- tsconfig.node.json | 10 +- tsconfig.web.json | 7 - 44 files changed, 696 insertions(+), 904 deletions(-) create mode 100644 packages/base/api/abstract.ts create mode 100644 packages/base/api/browser.ts create mode 100644 packages/base/api/electron.ts delete mode 100644 src/common/_ioc.main.ts delete mode 100644 src/common/event/PlatForm/hook.ts delete mode 100644 src/common/event/PlatForm/index.ts delete mode 100644 src/common/event/PlatForm/main/command.ts delete mode 100644 src/common/event/Setting/hook.ts delete mode 100644 src/common/event/Setting/index.ts delete mode 100644 src/common/event/Setting/main/command.ts delete mode 100644 src/common/event/Snippet/hook.ts delete mode 100644 src/common/event/Snippet/index.ts delete mode 100644 src/common/event/Snippet/main/command.ts delete mode 100644 src/common/event/Updater/hook.ts delete mode 100644 src/common/event/Updater/index.ts delete mode 100644 src/common/event/Updater/main/command.ts delete mode 100644 src/common/lib/abstract.ts delete mode 100644 src/common/lib/browser.ts delete mode 100644 src/common/lib/electron.ts delete mode 100644 src/common/readme.md delete mode 100644 src/main/App copy.ts create mode 100644 src/main/command/PlatForm/command.ts create mode 100644 src/main/command/Setting/command.ts create mode 100644 src/main/command/Snippet/command.ts create mode 100644 src/main/command/Updater/command.ts create mode 100644 src/main/command/_ioc.ts delete mode 100644 src/preload/plugin.ts create mode 100644 src/renderer/src/composables/Api/Platform/_/index.ts create mode 100644 src/renderer/src/composables/Api/Platform/useApiPlatForm.ts create mode 100644 src/renderer/src/composables/Api/Setting/_/index.ts create mode 100644 src/renderer/src/composables/Api/Setting/useApiSetting.ts create mode 100644 src/renderer/src/composables/Api/Updater/_/index.ts create mode 100644 src/renderer/src/composables/Api/Updater/useApiUpdater.ts delete mode 100644 src/renderer/src/composables/useTest.ts diff --git a/electron.vite.config.ts b/electron.vite.config.ts index eb97550..529acc3 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -31,7 +31,7 @@ export default defineConfig({ lib: { entry: { index: resolve(__dirname, "./src/preload/index.ts"), - plugin: resolve(__dirname, "./src/preload/plugin.ts"), + // plugin: resolve(__dirname, "./src/preload/plugin.ts"), }, }, }, @@ -101,7 +101,7 @@ export default defineConfig({ "vue-i18n", ], dts: true, - dirs: ["src/composables"], + dirs: ["src/composables/**/*.ts", "!src/composables/**/_/**/*.ts"], vueTemplate: true, }), // https://github.com/antfu/vite-plugin-components diff --git a/packages/base/api/abstract.ts b/packages/base/api/abstract.ts new file mode 100644 index 0000000..5e1e323 --- /dev/null +++ b/packages/base/api/abstract.ts @@ -0,0 +1,71 @@ +import { ElectronApiClient } from "./electron" +import { BrowserApiClient } from "./browser" +import { BaseSingleton } from "base/index" + +// 定义抽象 API 接口 +export interface IApiClient { + call(command: string, ...args: any[]): Promise + callSync(command: string, ...args: any[]): void + on(channel: K, callback: (...args: any[]) => void): void + off(channel: K, callback: (...args: any[]) => void): void + offAll(channel: K): void +} + +class NullApiClient implements IApiClient { + async call(command: string, ...args: any[]): Promise { + args + console.warn(`API call to ${command} failed: API client not initialized`) + return undefined as any + } + callSync(command: string, ...args: any[]): void { + args + console.warn(`API callSync to ${command} failed: API client not initialized`) + return undefined as any + } + + on(channel: K, callback: (...args: any[]) => void): void { + callback + console.warn(`Failed to register listener for ${channel}: API client not initialized`) + } + + off(channel: K, callback: (...args: any[]) => void): void { + callback + console.warn(`Failed to unregister listener for ${channel}: API client not initialized`) + } + + offAll(channel: K): void { + console.warn(`Failed to unregister all listeners for ${channel}: API client not initialized`) + } +} + +// 创建 API 工厂 +export class ApiFactory { + private static instance: IApiClient = new NullApiClient() // 默认使用空实现 + + static setApiClient(client: IApiClient) { + this.instance = client + } + + static getApiClient(): IApiClient { + if (this.instance instanceof NullApiClient) { + // 根据环境选择合适的 API 客户端 + // @ts-ignore 忽略类型检查 + if (window.api && window.electron) { + this.instance = new ElectronApiClient() + } else { + this.instance = new BrowserApiClient() + } + } + return this.instance + } +} + +export class BaseEvent extends BaseSingleton { + constructor() { + super() + } + + public get api() { + return ApiFactory.getApiClient() + } +} diff --git a/packages/base/api/browser.ts b/packages/base/api/browser.ts new file mode 100644 index 0000000..035a71b --- /dev/null +++ b/packages/base/api/browser.ts @@ -0,0 +1,34 @@ +import { IApiClient } from "./abstract" + +export class BrowserApiClient implements IApiClient { + call(command: string, ...args: any[]): Promise { + // 浏览器特定实现,可能使用 fetch 或其他方式 + const [service, method] = command.split(".") + return fetch(`/api/${service}/${method}`, { + method: "POST", + body: JSON.stringify(args), + headers: { "Content-Type": "application/json" }, + }).then(res => res.json()) + } + + callSync(): void { + // 浏览器特定实现,可能使用 fetch 或其他方式 + console.log("不支持 callSync 方法") + } + + // 实现其他方法... + on(channel: K, callback: (...args: any[]) => void): void { + // 浏览器中可能使用 WebSocket 或其他方式 + console.log("不支持 on 方法", channel, callback) + } + + off(channel: K, callback: (...args: any[]) => void): void { + // 相应的解绑实现 + console.log("不支持 on 方法", channel, callback) + } + + offAll(channel: K): void { + // 相应的全部解绑实现 + console.log("不支持 on 方法", channel) + } +} diff --git a/packages/base/api/electron.ts b/packages/base/api/electron.ts new file mode 100644 index 0000000..5e907d7 --- /dev/null +++ b/packages/base/api/electron.ts @@ -0,0 +1,27 @@ +// @ts-nocheck window.api 不需要检查 + +import { IApiClient } from "./abstract" + +export class ElectronApiClient implements IApiClient { + call(command: string, ...args: any[]): Promise { + // Electron 特定实现 + return window.api.call(command, ...args) + } + + callSync(command: string, ...args: any[]): Promise { + // Electron 特定实现 + return window.api.callSync(command, ...args) + } + + on(channel: K, callback: (...args: any[]) => void): void { + window.api.on(channel, callback) + } + + off(channel: K, callback: (...args: any[]) => void): void { + window.api.off(channel, callback) + } + + offAll(channel: K): void { + window.api.offAll(channel) + } +} diff --git a/src/common/_ioc.main.ts b/src/common/_ioc.main.ts deleted file mode 100644 index bb057db..0000000 --- a/src/common/_ioc.main.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Container, ContainerModule } from "inversify" -import _logger from "logger/main" - -const logger = _logger.createNamespace("command") - -/** - * 自动加载所有命令模块 - */ -const commandModules = import.meta.glob("./event/**/main/command.{ts,js}", { eager: true }) - -const modules = new ContainerModule(bind => { - // 自动绑定所有命令类 - Object.values(commandModules).forEach(module => { - // 由于 module 类型为 unknown,先进行类型断言为包含 default 属性的对象 - const CommandClass = (module as { default: any }).default - if (CommandClass) { - const className = CommandClass.name.replace("Command", "") - logger.debug(`绑定命令类: ${className}Command`) - if (CommandClass["init"]) { - CommandClass["init"]() - } - bind(className + "Command") - .to(CommandClass) - .inSingletonScope() - } - }) -}) - -/** - * 销毁所有命令绑定 - * @param ioc - Inversify 容器实例 - */ -async function destroyAllCommand(ioc: Container) { - const allIOC: any[] = [] - Object.values(commandModules).forEach(module => { - const CommandClass = (module as { default: any }).default - if (CommandClass) { - const className = CommandClass.name.replace("Command", "") - const m = ioc.get(className + "Command") as any - if (m && m.destroy) { - allIOC.push(m.destroy()) - } - } - }) - await Promise.all(allIOC) - await ioc.unloadAsync(modules) -} - -export { modules, destroyAllCommand } -export default modules diff --git a/src/common/event/PlatForm/hook.ts b/src/common/event/PlatForm/hook.ts deleted file mode 100644 index 2441319..0000000 --- a/src/common/event/PlatForm/hook.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { LogLevel } from "logger/common" -import { PlatForm } from "." - -export function usePlatForm() { - const plat = PlatForm.getInstance() - - // 全屏状态 - const isFullScreen = ref(false) - ;(async () => { - isFullScreen.value = await plat.isFullScreen() - })() - - const toggleFullScreen = async () => { - await plat.toggleFullScreen() - isFullScreen.value = !isFullScreen.value - } - // 全屏状态 END - - const curLogLevel = ref() - ;(async () => { - curLogLevel.value = await plat.logGetLevel() - })() - const isOpenDebug = computed(() => curLogLevel.value === LogLevel.TRACE) - const toggleDebugMode = async () => { - if (curLogLevel.value === LogLevel.TRACE) { - await plat.logSetLevel(LogLevel.INFO) - curLogLevel.value = LogLevel.INFO - return - } - await plat.logSetLevel(LogLevel.TRACE) - curLogLevel.value = LogLevel.TRACE - } - - return { - power: plat, - isOpenDebug, - toggleDebugMode, - toggleFullScreen, - isFullScreen, - } -} diff --git a/src/common/event/PlatForm/index.ts b/src/common/event/PlatForm/index.ts deleted file mode 100644 index 423d0b9..0000000 --- a/src/common/event/PlatForm/index.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { ApiFactory } from "common/lib/abstract" -import { BaseSingleton } from "base" -import { LogLevel } from "packages/logger/common" - -class PlatForm extends BaseSingleton { - constructor() { - super() - } - - private get api() { - return ApiFactory.getApiClient() - } - - async logSetLevel(level: LogLevel) { - return this.api.call("PlatFormCommand.logSetLevel", level) - } - - async logGetLevel() { - return this.api.call("PlatFormCommand.logGetLevel") - } - - async showAbout() { - // return this.api.call("BasicService.showAbout") - return this.api.call("PlatFormCommand.showAbout") - } - - async showSrd() { - // return this.api.call("BasicService.showAbout") - return this.api.call("PlatFormCommand.showSrd") - } - - async getSrdCookie() { - // return this.api.call("BasicService.showAbout") - return this.api.call("PlatFormCommand.getSrdCookie") - } - - async crash() { - return this.api.call("PlatFormCommand.crash") - } - - async isFullScreen() { - return this.api.call("PlatFormCommand.isFullscreen") - } - - async toggleFullScreen() { - return this.api.call("PlatFormCommand.fullscreen") - } - - async reload() { - return this.api.call("PlatFormCommand.reload") - } - - async toggleDevTools() { - return this.api.call("PlatFormCommand.toggleDevTools") - } -} - -export { PlatForm } diff --git a/src/common/event/PlatForm/main/command.ts b/src/common/event/PlatForm/main/command.ts deleted file mode 100644 index 0555b9b..0000000 --- a/src/common/event/PlatForm/main/command.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { app, dialog, nativeTheme, TitleBarOverlayOptions } from "electron" -import { inject } from "inversify" -import errorHandler from "logger/main-error" -import WindowManager from "main/modules/window-manager" -import icon from "@res/icon.png?asset" -import setting from "setting/main" -import { LogLevel } from "logger/common" -import { getFileUrl } from "utils/main" - -export default class PlatFormCommand { - constructor(@inject(WindowManager) private _WindowManager: WindowManager) {} - - setTheme(theme: typeof nativeTheme.themeSource) { - nativeTheme.themeSource = theme - } - - logSetLevel(level: LogLevel) { - return setting.set("dev:debug", level) - } - - logGetLevel() { - return setting.values("dev:debug") - } - - setTitlBar(options: TitleBarOverlayOptions) { - const mainWindow = this._WindowManager.getMainWindow() - if (mainWindow) { - mainWindow.setTitleBarOverlay(options) - } - } - - showAbout() { - this._WindowManager.createWindow("about", { - url: getFileUrl("about.html"), - overideWindowOpts: true, - confrimWindowClose: false, - type: "info", - windowOpts: { - width: 600, - height: 400, - minimizable: false, - darkTheme: true, - modal: true, - title: "关于我", - show: true, - resizable: false, - icon: icon, - webPreferences: { - devTools: false, - sandbox: false, - nodeIntegration: false, - contextIsolation: true, - }, - }, - }) - } - - toggleDevTools() { - const focusedWindow = this._WindowManager.getFocusWindow() - if (focusedWindow) { - // @ts-ignore ... - focusedWindow.toggleDevTools() - } - } - fullscreen() { - const focusedWindow = this._WindowManager.getFocusWindow() - if (focusedWindow) { - const isFullScreen = focusedWindow!.isFullScreen() - focusedWindow!.setFullScreen(!isFullScreen) - } - } - - crash() { - errorHandler.captureError(new Error("手动触发的崩溃")) - process.crash() - } - - isFullscreen() { - const focusedWindow = this._WindowManager.getFocusWindow() - if (focusedWindow) { - return focusedWindow!.isFullScreen() - } - return false - } - - relunch() { - app.relaunch() - app.exit() - } - - reload() { - const focusedWindow = this._WindowManager.getFocusWindow() - // 重载之后, 刷新并关闭所有的次要窗体 - if (this._WindowManager.length() > 1 && focusedWindow && focusedWindow.$$opts!.name === this._WindowManager.mainInfo.name) { - const choice = dialog.showMessageBoxSync(focusedWindow, { - type: "question", - buttons: ["取消", "是的,继续", "不,算了"], - title: "警告", - defaultId: 2, - cancelId: 0, - message: "警告", - detail: "重载主窗口将关闭所有子窗口,是否继续", - }) - if (choice == 1) { - this._WindowManager.getWndows().forEach(win => { - if (win.$$opts!.name !== this._WindowManager.mainInfo.name) { - win.close() - } - }) - } else { - return - } - } - focusedWindow!.reload() - } -} diff --git a/src/common/event/Setting/hook.ts b/src/common/event/Setting/hook.ts deleted file mode 100644 index 8456d3a..0000000 --- a/src/common/event/Setting/hook.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { defineStore } from "pinia" -import { Setting } from "." -import type { IConfig } from "config" - -let rawConfig: IConfig = Setting.getInstance().sync() as unknown as IConfig - -export const useSettingStore = defineStore( - "Setting", - () => { - const config = ref(JSON.parse(JSON.stringify(rawConfig))) - const diffKeys = ref<(keyof IConfig)[]>([]) - const isSame = computed(() => { - return diffKeys.value.length === 0 - }) - watch( - () => config.value, - () => { - diffKeys.value = [] - ;(Object.keys(config.value) as (keyof IConfig)[]).forEach((key: keyof IConfig) => { - if (config.value[key] !== rawConfig[key]) { - diffKeys.value.push(key) - } - }) - }, - { - deep: true, - immediate: true, - }, - ) - const reset = () => { - const tempConfig = JSON.parse(JSON.stringify(rawConfig)) - config.value = tempConfig - } - const isSaving = ref(false) - const save = async () => { - if (isSaving.value) { - return - } - isSaving.value = true - try { - const tempConfig = JSON.parse(JSON.stringify(unref(config))) - await Setting.getInstance().save(tempConfig) - isSaving.value = false - rawConfig = JSON.parse(JSON.stringify(tempConfig)) - config.value = tempConfig - } catch (error) { - isSaving.value = false - throw error - } - } - return { - config, - isSame, - isSaving, - diffKeys, - reset, - save, - } - }, - { - persist: false, - }, -) diff --git a/src/common/event/Setting/index.ts b/src/common/event/Setting/index.ts deleted file mode 100644 index 7abe0cc..0000000 --- a/src/common/event/Setting/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ApiFactory } from "common/lib/abstract" -import { BaseSingleton } from "base" -import { IConfig } from "config" - -class Setting extends BaseSingleton { - constructor() { - super() - } - - private get api() { - return ApiFactory.getApiClient() - } - - sync() { - return this.api.callSync("SettingCommand.sync") - } - - save(config: IConfig) { - return this.api.call("SettingCommand.save", config) - } -} - -export { Setting } diff --git a/src/common/event/Setting/main/command.ts b/src/common/event/Setting/main/command.ts deleted file mode 100644 index 6c9afd6..0000000 --- a/src/common/event/Setting/main/command.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Setting, { IConfig } from "setting/main" - -export default class SettingCommand { - static init() { - console.log("SettingCommand init") - } - sync() { - return Setting.config() - } - save(config: IConfig) { - return Setting.set(config) - } -} diff --git a/src/common/event/Snippet/hook.ts b/src/common/event/Snippet/hook.ts deleted file mode 100644 index 3a89407..0000000 --- a/src/common/event/Snippet/hook.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Snippet } from "." - -export function useSnippet() { - return Snippet.getInstance() -} diff --git a/src/common/event/Snippet/index.ts b/src/common/event/Snippet/index.ts deleted file mode 100644 index 5cf9945..0000000 --- a/src/common/event/Snippet/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { BaseSingleton } from "base" -import { ApiFactory } from "common/lib/abstract" - -class Snippet extends BaseSingleton { - constructor() { - super() - } - - private get api() { - return ApiFactory.getApiClient() - } - - getTree = async () => { - return this.api.call("SnippetCommand.getTree") - } -} - -export { Snippet } diff --git a/src/common/event/Snippet/main/command.ts b/src/common/event/Snippet/main/command.ts deleted file mode 100644 index 5361c2d..0000000 --- a/src/common/event/Snippet/main/command.ts +++ /dev/null @@ -1,44 +0,0 @@ -// import fs from "fs-extra" -// import path from "path/posix" -// import Setting from "setting/main" - -// 代码片段命令处理器 -// base/__snippet__.json 基础信息 -// 路径做为ID, 当前文件夹的信息 - -export default class SnippetCommand { - // storagePath: string = Setting.values("snippet.storagePath") - - constructor() { - const handler = { - get: function (target, prop, receiver) { - if (!target["check"]()) { - throw new Error(`代码片段路径存在问题`) - } - const value = target[prop] - if (typeof value === "function") { - return (...args) => Reflect.apply(value, receiver, args) - } - return value - }, - } - return new Proxy(this, handler) - } - - async check() { - // const stat = await fs.statSync(this.storagePath) - // const inforFile = path.resolve(this.storagePath, "__snippet__.json") - // if (stat.isDirectory() && stat.size == 0) { - // await fs.writeJSON(inforFile, {}) - // // 空文件夹, 初始化信息 - // return true - // } else { - // const isExist = await fs.pathExists(inforFile) - // return isExist - // } - } - - getTree() { - // return this.storagePath - } -} diff --git a/src/common/event/Updater/hook.ts b/src/common/event/Updater/hook.ts deleted file mode 100644 index 4249f57..0000000 --- a/src/common/event/Updater/hook.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { EventMaps, UpdaterCommand } from "helper/updater/common" -import { defineStore } from "pinia" - -export const enum UpdaterStatus { - Idle = "idle", - Checking = "checking", - StartChecking = "start-checking", - UpdateAvailable = "update-available", - UpdateNotAvailable = "update-not-available", - Downloading = "downloading", - Error = "error", -} - -export const useUpdaterStore = defineStore( - "Updater", - () => { - const curStatus = ref(UpdaterStatus.Idle) - const speed = ref(0) - const percent = ref(0) - const all = ref(0) - const now = ref(0) - - const isNeedUpdate = ref(false) - - const api = getApi() - api.on("error", (_, data) => { - curStatus.value = UpdaterStatus.Error - console.log(data) - }) - api.on("update-not-available", () => { - curStatus.value = UpdaterStatus.UpdateNotAvailable - isNeedUpdate.value = false - }) - api.on("update-available", () => { - curStatus.value = UpdaterStatus.UpdateAvailable - isNeedUpdate.value = true - }) - api.on("update-progress", (_, data) => { - curStatus.value = UpdaterStatus.Downloading - speed.value = +(data.speed / 1000).toFixed(2) // Convert to KB/s - percent.value = data.percent - all.value = data.all - now.value = data.now - isNeedUpdate.value = false - }) - api.on("checking-for-update", () => { - curStatus.value = UpdaterStatus.Checking - }) - if (import.meta.env.PROD) { - api.callLong("UpdaterCommand.checkForUpdates") - } - return { - status: curStatus, - speed: speed, - percent: percent, - all: all, - now: now, - isNeedUpdate, - checkForUpdates() { - if (curStatus.value === UpdaterStatus.Checking) return - if (curStatus.value === UpdaterStatus.Downloading) return - curStatus.value = UpdaterStatus.StartChecking - api.callLong("UpdaterCommand.checkForUpdates") - }, - } - }, - { - persist: false, - }, -) diff --git a/src/common/event/Updater/index.ts b/src/common/event/Updater/index.ts deleted file mode 100644 index 2b23ee4..0000000 --- a/src/common/event/Updater/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { BaseEvent } from "common/lib/abstract" - -class Updater extends BaseEvent { - constructor() { - super() - } - - test() { - this.api - } -} - -export { Updater } diff --git a/src/common/event/Updater/main/command.ts b/src/common/event/Updater/main/command.ts deleted file mode 100644 index 277e33a..0000000 --- a/src/common/event/Updater/main/command.ts +++ /dev/null @@ -1,23 +0,0 @@ -import Updater from "helper/updater/main" -import _logger from "logger/main" -import { broadcast } from "utils/main" - -const logger = _logger.createNamespace("UpdaterCommand") - -export default class UpdaterCommand { - static init() { - // 命令初始化 - logger.debug("UpdaterCommand init") - Updater.events.on("*", (name, ...argus) => { - broadcast(name, ...argus) - }) - } - - async triggerHotUpdate() { - Updater.triggerHotUpdate() - } - - checkForUpdates() { - return Updater.checkForUpdates() - } -} diff --git a/src/common/lib/abstract.ts b/src/common/lib/abstract.ts deleted file mode 100644 index 981d02e..0000000 --- a/src/common/lib/abstract.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { ElectronApiClient } from "common/lib/electron" -import { BrowserApiClient } from "common/lib/browser" -import { BaseSingleton } from "base/index" - -// 定义抽象 API 接口 -export interface IApiClient { - call(command: string, ...args: any[]): Promise - callSync(command: string, ...args: any[]): void - on(channel: K, callback: (...args: any[]) => void): void - off(channel: K, callback: (...args: any[]) => void): void - offAll(channel: K): void -} - -class NullApiClient implements IApiClient { - async call(command: string, ...args: any[]): Promise { - args - console.warn(`API call to ${command} failed: API client not initialized`) - return undefined as any - } - callSync(command: string, ...args: any[]): void { - args - console.warn(`API callSync to ${command} failed: API client not initialized`) - return undefined as any - } - - on(channel: K, callback: (...args: any[]) => void): void { - callback - console.warn(`Failed to register listener for ${channel}: API client not initialized`) - } - - off(channel: K, callback: (...args: any[]) => void): void { - callback - console.warn(`Failed to unregister listener for ${channel}: API client not initialized`) - } - - offAll(channel: K): void { - console.warn(`Failed to unregister all listeners for ${channel}: API client not initialized`) - } -} - -// 创建 API 工厂 -export class ApiFactory { - private static instance: IApiClient = new NullApiClient() // 默认使用空实现 - - static setApiClient(client: IApiClient) { - this.instance = client - } - - static getApiClient(): IApiClient { - if (this.instance instanceof NullApiClient) { - // 根据环境选择合适的 API 客户端 - if (window.api && window.electron) { - this.instance = new ElectronApiClient() - } else { - this.instance = new BrowserApiClient() - } - } - return this.instance - } -} - -export class BaseEvent extends BaseSingleton { - constructor() { - super() - } - - public get api() { - return ApiFactory.getApiClient() - } -} diff --git a/src/common/lib/browser.ts b/src/common/lib/browser.ts deleted file mode 100644 index 035a71b..0000000 --- a/src/common/lib/browser.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { IApiClient } from "./abstract" - -export class BrowserApiClient implements IApiClient { - call(command: string, ...args: any[]): Promise { - // 浏览器特定实现,可能使用 fetch 或其他方式 - const [service, method] = command.split(".") - return fetch(`/api/${service}/${method}`, { - method: "POST", - body: JSON.stringify(args), - headers: { "Content-Type": "application/json" }, - }).then(res => res.json()) - } - - callSync(): void { - // 浏览器特定实现,可能使用 fetch 或其他方式 - console.log("不支持 callSync 方法") - } - - // 实现其他方法... - on(channel: K, callback: (...args: any[]) => void): void { - // 浏览器中可能使用 WebSocket 或其他方式 - console.log("不支持 on 方法", channel, callback) - } - - off(channel: K, callback: (...args: any[]) => void): void { - // 相应的解绑实现 - console.log("不支持 on 方法", channel, callback) - } - - offAll(channel: K): void { - // 相应的全部解绑实现 - console.log("不支持 on 方法", channel) - } -} diff --git a/src/common/lib/electron.ts b/src/common/lib/electron.ts deleted file mode 100644 index 05609d2..0000000 --- a/src/common/lib/electron.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { IApiClient } from "./abstract" - -export class ElectronApiClient implements IApiClient { - call(command: string, ...args: any[]): Promise { - // Electron 特定实现 - return window.api.call(command, ...args) - } - - callSync(command: string, ...args: any[]): Promise { - // Electron 特定实现 - return window.api.callSync(command, ...args) - } - - on(channel: K, callback: (...args: any[]) => void): void { - window.api.on(channel, callback) - } - - off(channel: K, callback: (...args: any[]) => void): void { - window.api.off(channel, callback) - } - - offAll(channel: K): void { - window.api.offAll(channel) - } -} diff --git a/src/common/readme.md b/src/common/readme.md deleted file mode 100644 index 51c0c10..0000000 --- a/src/common/readme.md +++ /dev/null @@ -1,7 +0,0 @@ -## event - -通用事件处理模块 - -- main/**/* 处理主进程的模块 -- main/command.ts 会通过ioc收集,进入依赖管理中 -- 其他 处理渲染进程的模块 \ No newline at end of file diff --git a/src/main/App copy.ts b/src/main/App copy.ts deleted file mode 100644 index 220ca22..0000000 --- a/src/main/App copy.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { inject, injectable } from "inversify" -// import Setting from "./modules/setting" -// import DB from "./modules/db" -import Api from "./modules/api" -import WindowManager from "./modules/window-manager" -import { app, nativeTheme, protocol, WebContentsView } from "electron" -import { electronApp } from "@electron-toolkit/utils" -// import Tabs from "./modules/tabs/Tabs" -import { getFileUrl } from "./utils" -import BaseClass from "./base/base" - -protocol.registerSchemesAsPrivileged([ - // { - // scheme: "http", - // privileges: { standard: true, bypassCSP: true, allowServiceWorkers: true, supportFetchAPI: true, corsEnabled: true, stream: true }, - // }, - // { - // scheme: "https", - // privileges: { standard: true, bypassCSP: true, allowServiceWorkers: true, supportFetchAPI: true, corsEnabled: true, stream: true }, - // }, - // { scheme: "mailto", privileges: { standard: true } }, - { - scheme: "api", - privileges: { - standard: true, - secure: true, - supportFetchAPI: true, - }, - }, -]) - -@injectable() -class App extends BaseClass { - destroy() { - // destroyAll() - // 这里是应用正常退出 - } - // private _setting: Setting - // private _db: DB - private _Api: Api - private _windowManager: WindowManager - // private _tabs: Tabs - - constructor( - // @inject(Setting) setting: Setting, - // @inject(DB) db: DB, - @inject(Api) Api: Api, - @inject(WindowManager) windowManager: WindowManager, - // @inject(Tabs) tabs: Tabs, - ) { - super() - // this._setting = setting - // this._db = db - this._Api = Api - this._windowManager = windowManager - // this._tabs = tabs - } - - async init() { - this._windowManager.init() - app.whenReady().then(() => { - electronApp.setAppUserModelId("top.xieyaxin") - this.create() - this._Api.init() - }) - app.on("window-all-closed", () => { - if (process.platform !== "darwin") { - app.quit() - } - }) - app.on("will-quit", () => { - this.destroy() - }) - } - - create() { - this._windowManager.showMainWindow() - const mainWindow = this._windowManager.getMainWindow() - if (mainWindow) { - nativeTheme.themeSource = "light" - mainWindow.setTitleBarOverlay({ - height: 29, // the smallest size of the title bar on windows accounting for the border on windows 11 - color: "#F8F8F8", - symbolColor: "#000000", - }) - this._windowManager.showWindow("main-top") - const mainTopWindow = this._windowManager.get("main-top") - setTimeout(() => { - // console.log(mainWindow.getParentWindow()); - setTimeout(() => { - mainWindow.contentView.children.length = 0 - const view = new WebContentsView() - view.addChildView(mainTopWindow!.contentView) - view.webContents.loadURL(getFileUrl("about.html")) - // mainTopWindow!.contentView.setBounds({ x: 0, y: 0, width: 100, height: 30 }) - // view.setBounds({ x: 0, y: 0, width: 100, height: 30 }) - mainWindow.contentView.addChildView(view) - // mainWindow.contentView.children.sort() - console.log(mainWindow.contentView.children) - }, 5000) - // mainWindow.webContents = mainTopWindow!.webContents - mainWindow.reload() - console.log(mainWindow.webContents.getURL()) - - // mainTopWindow?.destroy() - // mainWindow.contentView.addChildView(mainWindow.contentView) - console.log(`child count: `, mainWindow.contentView.children.length) - }, 2000) - // if (mainTopWindow) { - // mainTopWindow.setParentWindow(mainWindow) - // mainTopWindow.setIgnoreMouseEvents(true, { forward: false }) - // const listenMove = () => { - // if (mainWindow && mainTopWindow) { - // const pos = mainWindow.getPosition() - // mainTopWindow.setPosition(pos[0], pos[1]) - // } - // } - // mainWindow?.on("move", listenMove) - // const listenResize = () => { - // if (mainWindow && mainTopWindow) { - // const size = mainWindow.getSize() - // console.log(size) - // mainTopWindow.setSize(size[0], size[1]) - // const pos = mainWindow.getPosition() - // mainTopWindow.setPosition(pos[0], pos[1]) - // } - // } - // listenResize() - // mainWindow?.on("resize", listenResize) - // } - } - // 考虑双browserwindow模式 - /** - * 因为browserwindow可以设置穿透,考虑将tab放在底层window上,其他组件放在上层window上。 - */ - // const webContentsView = new WebContentsView({ - // webPreferences: { - // preload: join(__dirname, "../preload/index.mjs"), - // transparent: true, - // nodeIntegration: true, - // spellcheck: false, - // contextIsolation: true, - // }, - // }) - // // mainWindow!.contentView = webContentsView - // // setTimeout(() => { - // mainWindow!.contentView.addChildView(webContentsView) - // // mainWindow?.setIgnoreMouseEvents(true, { forward: true }) - // // }, 2000); - // webContentsView.webContents.loadURL(getFileUrl("index.html")) - // const listenResize = () => { - // const size = mainWindow!.getSize() - // webContentsView.setBounds({ x: 0, y: 0, width: size[0], height: size[1] }) - // } - // listenResize() - // mainWindow!.addListener("resize", listenResize) - - // this._tabs.add("https://baidu.com", true) - // this._tabs.add("https://zhihu.com") - return mainWindow - } -} - -export default App -export { App } diff --git a/src/main/_ioc.ts b/src/main/_ioc.ts index fa0689e..ad2f3fa 100644 --- a/src/main/_ioc.ts +++ b/src/main/_ioc.ts @@ -2,7 +2,7 @@ import IOC from "./_iocClass" import { Container } from "inversify" import iocModules, { destroyAllModules } from "./modules/_ioc" import iocController, { destroyAllController } from "./controller/_ioc" -import iocCommand, { destroyAllCommand } from "common/_ioc.main" +import iocCommand, { destroyAllCommand } from "./command/_ioc" import App from "./App" async function destroyAll() { diff --git a/src/main/command/PlatForm/command.ts b/src/main/command/PlatForm/command.ts new file mode 100644 index 0000000..0555b9b --- /dev/null +++ b/src/main/command/PlatForm/command.ts @@ -0,0 +1,116 @@ +import { app, dialog, nativeTheme, TitleBarOverlayOptions } from "electron" +import { inject } from "inversify" +import errorHandler from "logger/main-error" +import WindowManager from "main/modules/window-manager" +import icon from "@res/icon.png?asset" +import setting from "setting/main" +import { LogLevel } from "logger/common" +import { getFileUrl } from "utils/main" + +export default class PlatFormCommand { + constructor(@inject(WindowManager) private _WindowManager: WindowManager) {} + + setTheme(theme: typeof nativeTheme.themeSource) { + nativeTheme.themeSource = theme + } + + logSetLevel(level: LogLevel) { + return setting.set("dev:debug", level) + } + + logGetLevel() { + return setting.values("dev:debug") + } + + setTitlBar(options: TitleBarOverlayOptions) { + const mainWindow = this._WindowManager.getMainWindow() + if (mainWindow) { + mainWindow.setTitleBarOverlay(options) + } + } + + showAbout() { + this._WindowManager.createWindow("about", { + url: getFileUrl("about.html"), + overideWindowOpts: true, + confrimWindowClose: false, + type: "info", + windowOpts: { + width: 600, + height: 400, + minimizable: false, + darkTheme: true, + modal: true, + title: "关于我", + show: true, + resizable: false, + icon: icon, + webPreferences: { + devTools: false, + sandbox: false, + nodeIntegration: false, + contextIsolation: true, + }, + }, + }) + } + + toggleDevTools() { + const focusedWindow = this._WindowManager.getFocusWindow() + if (focusedWindow) { + // @ts-ignore ... + focusedWindow.toggleDevTools() + } + } + fullscreen() { + const focusedWindow = this._WindowManager.getFocusWindow() + if (focusedWindow) { + const isFullScreen = focusedWindow!.isFullScreen() + focusedWindow!.setFullScreen(!isFullScreen) + } + } + + crash() { + errorHandler.captureError(new Error("手动触发的崩溃")) + process.crash() + } + + isFullscreen() { + const focusedWindow = this._WindowManager.getFocusWindow() + if (focusedWindow) { + return focusedWindow!.isFullScreen() + } + return false + } + + relunch() { + app.relaunch() + app.exit() + } + + reload() { + const focusedWindow = this._WindowManager.getFocusWindow() + // 重载之后, 刷新并关闭所有的次要窗体 + if (this._WindowManager.length() > 1 && focusedWindow && focusedWindow.$$opts!.name === this._WindowManager.mainInfo.name) { + const choice = dialog.showMessageBoxSync(focusedWindow, { + type: "question", + buttons: ["取消", "是的,继续", "不,算了"], + title: "警告", + defaultId: 2, + cancelId: 0, + message: "警告", + detail: "重载主窗口将关闭所有子窗口,是否继续", + }) + if (choice == 1) { + this._WindowManager.getWndows().forEach(win => { + if (win.$$opts!.name !== this._WindowManager.mainInfo.name) { + win.close() + } + }) + } else { + return + } + } + focusedWindow!.reload() + } +} diff --git a/src/main/command/Setting/command.ts b/src/main/command/Setting/command.ts new file mode 100644 index 0000000..6c9afd6 --- /dev/null +++ b/src/main/command/Setting/command.ts @@ -0,0 +1,13 @@ +import Setting, { IConfig } from "setting/main" + +export default class SettingCommand { + static init() { + console.log("SettingCommand init") + } + sync() { + return Setting.config() + } + save(config: IConfig) { + return Setting.set(config) + } +} diff --git a/src/main/command/Snippet/command.ts b/src/main/command/Snippet/command.ts new file mode 100644 index 0000000..5361c2d --- /dev/null +++ b/src/main/command/Snippet/command.ts @@ -0,0 +1,44 @@ +// import fs from "fs-extra" +// import path from "path/posix" +// import Setting from "setting/main" + +// 代码片段命令处理器 +// base/__snippet__.json 基础信息 +// 路径做为ID, 当前文件夹的信息 + +export default class SnippetCommand { + // storagePath: string = Setting.values("snippet.storagePath") + + constructor() { + const handler = { + get: function (target, prop, receiver) { + if (!target["check"]()) { + throw new Error(`代码片段路径存在问题`) + } + const value = target[prop] + if (typeof value === "function") { + return (...args) => Reflect.apply(value, receiver, args) + } + return value + }, + } + return new Proxy(this, handler) + } + + async check() { + // const stat = await fs.statSync(this.storagePath) + // const inforFile = path.resolve(this.storagePath, "__snippet__.json") + // if (stat.isDirectory() && stat.size == 0) { + // await fs.writeJSON(inforFile, {}) + // // 空文件夹, 初始化信息 + // return true + // } else { + // const isExist = await fs.pathExists(inforFile) + // return isExist + // } + } + + getTree() { + // return this.storagePath + } +} diff --git a/src/main/command/Updater/command.ts b/src/main/command/Updater/command.ts new file mode 100644 index 0000000..277e33a --- /dev/null +++ b/src/main/command/Updater/command.ts @@ -0,0 +1,23 @@ +import Updater from "helper/updater/main" +import _logger from "logger/main" +import { broadcast } from "utils/main" + +const logger = _logger.createNamespace("UpdaterCommand") + +export default class UpdaterCommand { + static init() { + // 命令初始化 + logger.debug("UpdaterCommand init") + Updater.events.on("*", (name, ...argus) => { + broadcast(name, ...argus) + }) + } + + async triggerHotUpdate() { + Updater.triggerHotUpdate() + } + + checkForUpdates() { + return Updater.checkForUpdates() + } +} diff --git a/src/main/command/_ioc.ts b/src/main/command/_ioc.ts new file mode 100644 index 0000000..a30e368 --- /dev/null +++ b/src/main/command/_ioc.ts @@ -0,0 +1,50 @@ +import { Container, ContainerModule } from "inversify" +import _logger from "logger/main" + +const logger = _logger.createNamespace("command") + +/** + * 自动加载所有命令模块 + */ +const commandModules = import.meta.glob("./**/command.{ts,js}", { eager: true }) + +const modules = new ContainerModule(bind => { + // 自动绑定所有命令类 + Object.values(commandModules).forEach(module => { + // 由于 module 类型为 unknown,先进行类型断言为包含 default 属性的对象 + const CommandClass = (module as { default: any }).default + if (CommandClass) { + const className = CommandClass.name.replace("Command", "") + logger.debug(`绑定命令类: ${className}Command`) + if (CommandClass["init"]) { + CommandClass["init"]() + } + bind(className + "Command") + .to(CommandClass) + .inSingletonScope() + } + }) +}) + +/** + * 销毁所有命令绑定 + * @param ioc - Inversify 容器实例 + */ +async function destroyAllCommand(ioc: Container) { + const allIOC: any[] = [] + Object.values(commandModules).forEach(module => { + const CommandClass = (module as { default: any }).default + if (CommandClass) { + const className = CommandClass.name.replace("Command", "") + const m = ioc.get(className + "Command") as any + if (m && m.destroy) { + allIOC.push(m.destroy()) + } + } + }) + await Promise.all(allIOC) + await ioc.unloadAsync(modules) +} + +export { modules, destroyAllCommand } +export default modules diff --git a/src/preload/plugin.ts b/src/preload/plugin.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/renderer/auto-imports.d.ts b/src/renderer/auto-imports.d.ts index ce4d49e..6249747 100644 --- a/src/renderer/auto-imports.d.ts +++ b/src/renderer/auto-imports.d.ts @@ -6,6 +6,7 @@ // biome-ignore lint: disable export {} declare global { + const ApiUpdaterStatus: typeof import('./src/composables/Api/Updater/useApiUpdater')['ApiUpdaterStatus'] const EffectScope: typeof import('vue')['EffectScope'] const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] const autoResetRef: typeof import('@vueuse/core')['autoResetRef'] @@ -111,6 +112,9 @@ declare global { const until: typeof import('@vueuse/core')['until'] const useActiveElement: typeof import('@vueuse/core')['useActiveElement'] const useAnimate: typeof import('@vueuse/core')['useAnimate'] + const useApiPlatForm: typeof import('./src/composables/Api/Platform/useApiPlatForm')['useApiPlatForm'] + const useApiSetting: typeof import('./src/composables/Api/Setting/useApiSetting')['useApiSetting'] + const useApiUpdater: typeof import('./src/composables/Api/Updater/useApiUpdater')['useApiUpdater'] const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference'] const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery'] const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter'] @@ -247,7 +251,6 @@ declare global { const useSwipe: typeof import('@vueuse/core')['useSwipe'] const useTemplateRef: typeof import('vue')['useTemplateRef'] const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] - const useTest: typeof import('./src/composables/useTest')['useTest'] const useTextDirection: typeof import('@vueuse/core')['useTextDirection'] const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize'] @@ -307,6 +310,7 @@ import { UnwrapRef } from 'vue' declare module 'vue' { interface GlobalComponents {} interface ComponentCustomProperties { + readonly ApiUpdaterStatus: UnwrapRef readonly EffectScope: UnwrapRef readonly asyncComputed: UnwrapRef readonly autoResetRef: UnwrapRef @@ -412,6 +416,9 @@ declare module 'vue' { readonly until: UnwrapRef readonly useActiveElement: UnwrapRef readonly useAnimate: UnwrapRef + readonly useApiPlatForm: UnwrapRef + readonly useApiSetting: UnwrapRef + readonly useApiUpdater: UnwrapRef readonly useArrayDifference: UnwrapRef readonly useArrayEvery: UnwrapRef readonly useArrayFilter: UnwrapRef @@ -548,7 +555,6 @@ declare module 'vue' { readonly useSwipe: UnwrapRef readonly useTemplateRef: UnwrapRef readonly useTemplateRefsList: UnwrapRef - readonly useTest: UnwrapRef readonly useTextDirection: UnwrapRef readonly useTextSelection: UnwrapRef readonly useTextareaAutosize: UnwrapRef diff --git a/src/renderer/src/composables/Api/Platform/_/index.ts b/src/renderer/src/composables/Api/Platform/_/index.ts new file mode 100644 index 0000000..7e3930e --- /dev/null +++ b/src/renderer/src/composables/Api/Platform/_/index.ts @@ -0,0 +1,58 @@ +import { ApiFactory } from "base/api/abstract" +import { BaseSingleton } from "base" +import { LogLevel } from "packages/logger/common" + +class PlatForm extends BaseSingleton { + constructor() { + super() + } + + private get api() { + return ApiFactory.getApiClient() + } + + async logSetLevel(level: LogLevel) { + return this.api.call("PlatFormCommand.logSetLevel", level) + } + + async logGetLevel() { + return this.api.call("PlatFormCommand.logGetLevel") + } + + async showAbout() { + // return this.api.call("BasicService.showAbout") + return this.api.call("PlatFormCommand.showAbout") + } + + async showSrd() { + // return this.api.call("BasicService.showAbout") + return this.api.call("PlatFormCommand.showSrd") + } + + async getSrdCookie() { + // return this.api.call("BasicService.showAbout") + return this.api.call("PlatFormCommand.getSrdCookie") + } + + async crash() { + return this.api.call("PlatFormCommand.crash") + } + + async isFullScreen() { + return this.api.call("PlatFormCommand.isFullscreen") + } + + async toggleFullScreen() { + return this.api.call("PlatFormCommand.fullscreen") + } + + async reload() { + return this.api.call("PlatFormCommand.reload") + } + + async toggleDevTools() { + return this.api.call("PlatFormCommand.toggleDevTools") + } +} + +export { PlatForm } diff --git a/src/renderer/src/composables/Api/Platform/useApiPlatForm.ts b/src/renderer/src/composables/Api/Platform/useApiPlatForm.ts new file mode 100644 index 0000000..87de469 --- /dev/null +++ b/src/renderer/src/composables/Api/Platform/useApiPlatForm.ts @@ -0,0 +1,41 @@ +import { LogLevel } from "logger/common" +import { PlatForm } from "./_" + +export function useApiPlatForm() { + const plat = PlatForm.getInstance() + + // 全屏状态 + const isFullScreen = ref(false) + ;(async () => { + isFullScreen.value = await plat.isFullScreen() + })() + + const toggleFullScreen = async () => { + await plat.toggleFullScreen() + isFullScreen.value = !isFullScreen.value + } + // 全屏状态 END + + const curLogLevel = ref() + ;(async () => { + curLogLevel.value = await plat.logGetLevel() + })() + const isOpenDebug = computed(() => curLogLevel.value === LogLevel.TRACE) + const toggleDebugMode = async () => { + if (curLogLevel.value === LogLevel.TRACE) { + await plat.logSetLevel(LogLevel.INFO) + curLogLevel.value = LogLevel.INFO + return + } + await plat.logSetLevel(LogLevel.TRACE) + curLogLevel.value = LogLevel.TRACE + } + + return { + power: plat, + isOpenDebug, + toggleDebugMode, + toggleFullScreen, + isFullScreen, + } +} diff --git a/src/renderer/src/composables/Api/Setting/_/index.ts b/src/renderer/src/composables/Api/Setting/_/index.ts new file mode 100644 index 0000000..1e7690f --- /dev/null +++ b/src/renderer/src/composables/Api/Setting/_/index.ts @@ -0,0 +1,23 @@ +import { ApiFactory } from "base/api/abstract" +import { BaseSingleton } from "base" +import { IConfig } from "config" + +class Setting extends BaseSingleton { + constructor() { + super() + } + + private get api() { + return ApiFactory.getApiClient() + } + + sync() { + return this.api.callSync("SettingCommand.sync") + } + + save(config: IConfig) { + return this.api.call("SettingCommand.save", config) + } +} + +export { Setting } diff --git a/src/renderer/src/composables/Api/Setting/useApiSetting.ts b/src/renderer/src/composables/Api/Setting/useApiSetting.ts new file mode 100644 index 0000000..b6f5ddb --- /dev/null +++ b/src/renderer/src/composables/Api/Setting/useApiSetting.ts @@ -0,0 +1,63 @@ +import { defineStore } from "pinia" +import { Setting } from "./_" +import type { IConfig } from "config" + +let rawConfig: IConfig = Setting.getInstance().sync() as unknown as IConfig + +export const useApiSetting = defineStore( + "Setting", + () => { + const config = ref(JSON.parse(JSON.stringify(rawConfig))) + const diffKeys = ref<(keyof IConfig)[]>([]) + const isSame = computed(() => { + return diffKeys.value.length === 0 + }) + watch( + () => config.value, + () => { + diffKeys.value = [] + ;(Object.keys(config.value) as (keyof IConfig)[]).forEach((key: keyof IConfig) => { + if (config.value[key] !== rawConfig[key]) { + diffKeys.value.push(key) + } + }) + }, + { + deep: true, + immediate: true, + }, + ) + const reset = () => { + const tempConfig = JSON.parse(JSON.stringify(rawConfig)) + config.value = tempConfig + } + const isSaving = ref(false) + const save = async () => { + if (isSaving.value) { + return + } + isSaving.value = true + try { + const tempConfig = JSON.parse(JSON.stringify(unref(config))) + await Setting.getInstance().save(tempConfig) + isSaving.value = false + rawConfig = JSON.parse(JSON.stringify(tempConfig)) + config.value = tempConfig + } catch (error) { + isSaving.value = false + throw error + } + } + return { + config, + isSame, + isSaving, + diffKeys, + reset, + save, + } + }, + { + persist: false, + }, +) diff --git a/src/renderer/src/composables/Api/Updater/_/index.ts b/src/renderer/src/composables/Api/Updater/_/index.ts new file mode 100644 index 0000000..7838a68 --- /dev/null +++ b/src/renderer/src/composables/Api/Updater/_/index.ts @@ -0,0 +1,13 @@ +import { BaseEvent } from "base/api/abstract" + +class Updater extends BaseEvent { + constructor() { + super() + } + + test() { + this.api + } +} + +export { Updater } diff --git a/src/renderer/src/composables/Api/Updater/useApiUpdater.ts b/src/renderer/src/composables/Api/Updater/useApiUpdater.ts new file mode 100644 index 0000000..a86ef7c --- /dev/null +++ b/src/renderer/src/composables/Api/Updater/useApiUpdater.ts @@ -0,0 +1,70 @@ +import { EventMaps, UpdaterCommand } from "helper/updater/common" +import { defineStore } from "pinia" + +export const enum ApiUpdaterStatus { + Idle = "idle", + Checking = "checking", + StartChecking = "start-checking", + UpdateAvailable = "update-available", + UpdateNotAvailable = "update-not-available", + Downloading = "downloading", + Error = "error", +} + +export const useApiUpdater = defineStore( + "Updater", + () => { + const curStatus = ref(ApiUpdaterStatus.Idle) + const speed = ref(0) + const percent = ref(0) + const all = ref(0) + const now = ref(0) + + const isNeedUpdate = ref(false) + + const api = getApi() + api.on("error", (_, data) => { + curStatus.value = ApiUpdaterStatus.Error + console.log(data) + }) + api.on("update-not-available", () => { + curStatus.value = ApiUpdaterStatus.UpdateNotAvailable + isNeedUpdate.value = false + }) + api.on("update-available", () => { + curStatus.value = ApiUpdaterStatus.UpdateAvailable + isNeedUpdate.value = true + }) + api.on("update-progress", (_, data) => { + curStatus.value = ApiUpdaterStatus.Downloading + speed.value = +(data.speed / 1000).toFixed(2) // Convert to KB/s + percent.value = data.percent + all.value = data.all + now.value = data.now + isNeedUpdate.value = false + }) + api.on("checking-for-update", () => { + curStatus.value = ApiUpdaterStatus.Checking + }) + if (import.meta.env.PROD) { + api.callLong("UpdaterCommand.checkForUpdates") + } + return { + status: curStatus, + speed: speed, + percent: percent, + all: all, + now: now, + isNeedUpdate, + checkForUpdates() { + if (curStatus.value === ApiUpdaterStatus.Checking) return + if (curStatus.value === ApiUpdaterStatus.Downloading) return + curStatus.value = ApiUpdaterStatus.StartChecking + api.callLong("UpdaterCommand.checkForUpdates") + }, + } + }, + { + persist: false, + }, +) diff --git a/src/renderer/src/composables/useTest.ts b/src/renderer/src/composables/useTest.ts deleted file mode 100644 index c272572..0000000 --- a/src/renderer/src/composables/useTest.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function useTest() { - console.log("test") -} diff --git a/src/renderer/src/pages/index/index copy.vue b/src/renderer/src/pages/index/index copy.vue index af32e5f..fc3060c 100644 --- a/src/renderer/src/pages/index/index copy.vue +++ b/src/renderer/src/pages/index/index copy.vue @@ -1,34 +1,34 @@ diff --git a/src/renderer/src/pages/index/index.vue b/src/renderer/src/pages/index/index.vue index 4fa148b..3a29644 100644 --- a/src/renderer/src/pages/index/index.vue +++ b/src/renderer/src/pages/index/index.vue @@ -1,7 +1,7 @@ diff --git a/src/renderer/src/pages/setting/index.vue b/src/renderer/src/pages/setting/index.vue index 49eb09b..4bf7bd9 100644 --- a/src/renderer/src/pages/setting/index.vue +++ b/src/renderer/src/pages/setting/index.vue @@ -1,9 +1,6 @@