From 403e6608d37755ef63537d594c1dff7391f0b6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A2=E4=BA=9A=E6=98=95?= <1549469775@qq.com> Date: Wed, 16 Jul 2025 16:56:48 +0800 Subject: [PATCH] ad --- .github/workflows/Build.yml | 113 ++++++++++++++++++++++++++++++ backup/Tabs/index.ts | 54 ++++++++++++++ backup/Tabs/main/command.ts | 65 +++++++++++++++++ changelog/0.0.1.md | 3 + packages/base/event/main/index.ts | 26 +++++-- packages/helper/db/custom.ts | 33 +++++++++ packages/helper/db/index.ts | 68 ++++++++++++++++++ packages/helper/updater/common.ts | 14 +++- packages/helper/updater/main/index.ts | 91 +++++++++++++++++------- packages/locales/main.ts | 3 +- packages/logger/main.ts | 3 + packages/logger/renderer-error.ts | 3 +- packages/setting/main.ts | 3 + packages/setting/main/event.ts | 1 + packages/utils/main/session/index.ts | 12 ++-- src/common/_ioc.main.ts | 16 +++++ src/common/event/PlatForm/hook.ts | 38 +++++++++- src/common/event/PlatForm/main/command.ts | 7 +- src/common/event/Tabs/index.ts | 54 -------------- src/common/event/Tabs/main/command.ts | 65 ----------------- src/common/event/Updater/hook.ts | 37 ++++++++-- src/common/event/Updater/main/command.ts | 8 +++ src/main/App.ts | 3 - src/main/controller/BasicService.ts | 6 +- src/main/modules/_ioc.ts | 9 +-- src/main/modules/db/custom.ts | 33 --------- src/main/modules/db/index.ts | 82 ---------------------- src/preload/index.ts | 3 + src/renderer/components.d.ts | 2 + src/renderer/src/App.vue | 1 - src/renderer/src/pages/index/index.vue | 20 +++++- src/renderer/src/ui/NavBar.vue | 52 ++++++++++---- src/types/global.d.ts | 14 ++-- temp/dev.yml | 3 + 34 files changed, 621 insertions(+), 324 deletions(-) create mode 100644 .github/workflows/Build.yml create mode 100644 backup/Tabs/index.ts create mode 100644 backup/Tabs/main/command.ts create mode 100644 changelog/0.0.1.md create mode 100644 packages/helper/db/custom.ts create mode 100644 packages/helper/db/index.ts delete mode 100644 src/common/event/Tabs/index.ts delete mode 100644 src/common/event/Tabs/main/command.ts delete mode 100644 src/main/modules/db/custom.ts delete mode 100644 src/main/modules/db/index.ts create mode 100644 temp/dev.yml diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml new file mode 100644 index 0000000..1cd8f2f --- /dev/null +++ b/.github/workflows/Build.yml @@ -0,0 +1,113 @@ +# https://zhuanlan.zhihu.com/p/164901026 +# https://www.antmoe.com/posts/18c087cf/ +# https://zhuanlan.zhihu.com/p/348712087 +# https://cloud.tencent.com/developer/article/1949574 +# 此工作流的名字 +name: Build +# 工作流的执行时机,可以设定为定时执行,每次push后执行,手动执行等 +on: + # workflow_dispatch为在Github仓库的Actions面板中手动执行 + # workflow_dispatch: + push: + branches: + - master +# 工作/任务,这里的工作是可以并行的。 +jobs: + # 工作的名称“编译windows版” + build: + # 运行的操作系统 windows + runs-on: ${{ matrix.os }} + env: + GH_TOKEN: ${{ secrets.ELECTRON_TOKEN }} + IS_ACTIONS: true + strategy: + matrix: + # https://www.likecs.com/ask-314443.html + node-version: [18.17.1] + os: [windows-2022, ubuntu-latest] + # 步骤 + steps: + # 使用预制action:拉取最新的代码 + - uses: actions/checkout@v3 + with: + ref: master + # https://pnpm.io/zh/continuous-integration/#github-actions + - uses: pnpm/action-setup@v2.2.4 + name: Install pnpm + id: pnpm-install + with: + version: 8.7.6 + # 安装node + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: 'pnpm' + - name: Install dependencies + run: pnpm install + # 安装python + - name: Use Python 3.9.13 + uses: actions/setup-python@v4 + with: + python-version: 3.9.13 + env: + PYTHON_VERSION: 3.9.13 + # https://docs.microsoft.com/zh-cn/visualstudio/releases/2017/vs2017-system-requirements-vs + # 将windows设置成windows-2016,2016要取消支持了,可换成2022 + # - name: set msvs + # run: npm config set msvs_version 2022 + # https://github.com/wxWidgets/wxWidgets/blob/master/.github/workflows/ci_msw.yml + # https://github.com/microsoft/setup-msbuild + - name: Add msbuild to PATH + if: matrix.os == 'windows-2022' + uses: microsoft/setup-msbuild@v1.1 + with: + vs-prerelease: true + # 步骤一的名称: + - name: Build + # 该步骤运行的终端命令,运行编译命令 + run: npm run build + # 步骤二的名称:将编译后的结果上传 + # - name: Upload File + # # 使用预制action:上传文件,可以将执行路径打包成zip上传 + # uses: actions/upload-artifact@v3 + # with: + # # 上传后文件的名称 + # name: windows + # # 打包的路径以及文件过滤,此为仅打包dist目录下的exe文件 + # path: out/*exe + - name: 读取当前版本号 + id: version + uses: ashley-taylor/read-json-property-action@v1.1 + with: + path: ./dist/package.json + property: version + - name: 读取描述文件 + id: description + uses: juliangruber/read-file-action@v1 + with: + path: ./changelog/${{steps.version.outputs.value}}.md + # step5: cleanup artifacts in dist_electron + # - name: 清理不必要的资产 + # run: | + # npx rimraf "out/!(*.exe|*.dmg)" + # - name: Generate release tag + # id: tag + # run: | + # echo "::set-output name=release_tag::UserBuild_$(date +"%Y.%m.%d_%H-%M")" + - name: Generate release tag + id: tag + run: | + echo "::set-output name=release_tag::v${{steps.version.outputs.value}}" + # echo "release_tag=v${{steps.version.outputs.value}}" >> $GITHUB_OUTPUT + - name: release # https://github.com/softprops/action-gh-release/issues/20 + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.tag.outputs.release_tag }} + name: ${{ steps.tag.outputs.release_tag }} + files: "out/*exe,out/*dmg,out/*AppImage,out/*yml" + body: ${{steps.description.outputs.content}} + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.ELECTRON_TOKEN }} diff --git a/backup/Tabs/index.ts b/backup/Tabs/index.ts new file mode 100644 index 0000000..de0025b --- /dev/null +++ b/backup/Tabs/index.ts @@ -0,0 +1,54 @@ +import { BaseSingleton } from "base" + +export class Tabs extends BaseSingleton { + constructor() { + super() + } + + private isListen: boolean = false + + private execUpdate = (...args) => { + this.#fnList.forEach(v => v(...args)) + } + + #fnList: ((...args) => void)[] = [] + listenUpdate(cb: (...args) => void) { + if (!this.isListen) { + api.on("main:TabsCommand.update", this.execUpdate) + this.isListen = true + } + this.#fnList.push(cb) + } + + unListenUpdate(fn: (...args) => void) { + this.#fnList = this.#fnList.filter(v => { + return v !== fn + }) + if (!this.#fnList.length) { + api.off("main:TabsCommand.update", this.execUpdate) + this.isListen = false + } + } + + bindPosition(data) { + api.call("TabsCommand.bindElement", data) + } + + closeAll() { + api.call("TabsCommand.closeAll") + } + + sync() { + api.call("TabsCommand.sync") + } + + unListenerAll() { + this.#fnList = [] + api.offAll("main:TabsCommand.update") + } + + async getAllTabs() { + const res = await api.call("TabsCommand.getAllTabs") + return res + } +} diff --git a/backup/Tabs/main/command.ts b/backup/Tabs/main/command.ts new file mode 100644 index 0000000..a9984d3 --- /dev/null +++ b/backup/Tabs/main/command.ts @@ -0,0 +1,65 @@ +import { inject } from "inversify" +import Tabs from "main/modules/tabs" +import WindowManager from "main/modules/window-manager" +import { broadcast } from "utils/main" + +class TabsCommand { + constructor( + @inject(Tabs) private _Tabs: Tabs, + @inject(WindowManager) private _WindowManager: WindowManager, + ) { + this._Tabs.events.on("update", this.listenerTabActive) + } + + listenerTabActive = () => { + broadcast("main:TabsCommand.update", this.getAllTabs()) + } + + bindElement(rect) { + this._Tabs.updateRect(rect) + } + + reload() { + this._WindowManager.getMainWindow()?.reload() + } + + sync() { + this.listenerTabActive() + if (!this.getAllTabs().length) { + this.add("about:blank") + } + } + + add(url) { + this._Tabs.add(url, true, this._WindowManager.getMainWindow()!) + } + + nagivate(index: number, url: string) { + this._Tabs.navigate(+index, url) + } + + closeAll() { + this._Tabs.closeAll() + } + + setActive(index) { + this._Tabs.changeActive(index) + } + + closeTab(e) { + this._Tabs.remove(e.body.active) + } + + getAllTabs() { + return this._Tabs._tabs.map(v => ({ + url: v.url, + showUrl: v.showUrl, + title: v.title, + favicons: v.favicons, + isActive: v.isActive, + })) + } +} + +export { TabsCommand } +export default TabsCommand diff --git a/changelog/0.0.1.md b/changelog/0.0.1.md new file mode 100644 index 0000000..ae0c63f --- /dev/null +++ b/changelog/0.0.1.md @@ -0,0 +1,3 @@ +## 0.0.1 + +第一个版本 \ No newline at end of file diff --git a/packages/base/event/main/index.ts b/packages/base/event/main/index.ts index 77949d6..6cd4f60 100644 --- a/packages/base/event/main/index.ts +++ b/packages/base/event/main/index.ts @@ -8,17 +8,31 @@ class FireEvent> { console.log(`${key}: ${this.#events[key]}\n`) }) } - on(name: S, fn: T[S]) { + on(name: S, fn: S extends "*" ? (...argus: [keyof T, T[keyof T]]) => void : T[S]) { if (!this.#events[name]) { this.#events[name] = [] } - this.#events[name].push(fn) + this.#events[name].push(fn as any) } - emit(name: S, ...argu: Parameters) { + async emit(name: S, ...argu: Parameters) { if (this.#events[name]) { - this.#events[name].forEach(fn => { - fn(...argu) - }) + const returnValues: any = [] + for (let i = 0; i < this.#events[name].length; i++) { + const fn = this.#events[name][i] + let r + if (Object.prototype.toString.call(fn) === "[object AsyncFunction]") { + r = await fn(...argu) + } else { + r = fn(...argu) + } + returnValues.push(r) + } + } + if (this.#events["*"]) { + for (let i = 0; i < this.#events["*"].length; i++) { + const fn = this.#events["*"][i] + fn(name, ...argu) + } } } off(name: S, fn?: T[S]) { diff --git a/packages/helper/db/custom.ts b/packages/helper/db/custom.ts new file mode 100644 index 0000000..a932712 --- /dev/null +++ b/packages/helper/db/custom.ts @@ -0,0 +1,33 @@ +import { JSONFile } from "lowdb/node" +import { Low } from "lowdb" +import fs from "fs-extra" + +export class CustomAdapter extends JSONFile { + constructor(filepath: string) { + super(filepath) + this.filepath = filepath + } + filepath: string = "" + async read() { + if (!fs.existsSync(this.filepath)) { + return null + } + const data = fs.readJSONSync(this.filepath, { throws: false }) + if (!data) { + return null + } + return data + } + + async write(data: T) { + fs.ensureFileSync(this.filepath) + await super.write(data) + } +} +export class CustomLow extends Low { + constructor(adapter: CustomAdapter, defaultData: T) { + super(adapter, defaultData) + this.filepath = adapter.filepath + } + filepath: string = "" +} diff --git a/packages/helper/db/index.ts b/packages/helper/db/index.ts new file mode 100644 index 0000000..7ad38cf --- /dev/null +++ b/packages/helper/db/index.ts @@ -0,0 +1,68 @@ +import Setting from "setting/main" +import { CustomAdapter, CustomLow } from "./custom" +import path from "node:path" +// import _logger from "logger/main" + +// const logger = _logger.createNamespace("db") + +class DB { + Modules: Record> = {} + + create(filepath) { + const adapter = new CustomAdapter(filepath) + const db = new CustomLow(adapter, {}) + db.filepath = filepath + return db + } + + getDB(dbName: string) { + if (this.Modules[dbName] === undefined) { + const filepath = path.resolve(Setting.values("storagePath"), "./db/" + dbName + ".json") + this.Modules[dbName] = this.create(filepath) + return this.Modules[dbName] + } else { + const cur = this.Modules[dbName] + const filepath = path.resolve(Setting.values("storagePath"), "./db/" + dbName + ".json") + if (cur.filepath != filepath) { + this.Modules[dbName] = this.create(filepath) + } + return this.Modules[dbName] + } + } + + async saveData(data: any): Promise + async saveData(dbName: string, data: any): Promise + async saveData(dbName: string, data?: any): Promise { + let db, rData + if (arguments.length === 2) { + db = this.getDB(dbName) + rData = data + } else { + db = this.getDB("db") + rData = dbName + } + if (db) { + db.data = rData + await db.write() + return db.data + } + return null + } + + async getData(dbName?: string) { + let db + if (dbName) { + db = this.getDB(dbName) + } else { + db = this.getDB("db") + } + if (db) { + await db.read() + return db.data + } + return null + } +} + +export default DB +export { DB } diff --git a/packages/helper/updater/common.ts b/packages/helper/updater/common.ts index b512f5f..2ec3840 100644 --- a/packages/helper/updater/common.ts +++ b/packages/helper/updater/common.ts @@ -1,3 +1,15 @@ +import { UpdateInfo } from "electron-updater" + +export interface UpdaterCommand { + checkForUpdates: () => void +} + export type EventMaps = { - "update-progress": (data: { percent: number; all: number; now: number }) => void + "update-progress": (data: { speed: number; percent: number; all: number; now: number }) => void + error: (err: any) => void + "updater:error": (info: UpdateInfo) => void + "checking-for-update": () => void + "update-available": (info: UpdateInfo) => void + "update-not-available": (info: UpdateInfo) => void + "updater:downloaded": (p: any) => void } diff --git a/packages/helper/updater/main/index.ts b/packages/helper/updater/main/index.ts index 82f211c..994c2a8 100644 --- a/packages/helper/updater/main/index.ts +++ b/packages/helper/updater/main/index.ts @@ -1,17 +1,19 @@ -import pkg from "electron-updater" -import { app, dialog } from "electron" +import { NsisUpdater } from "electron-updater" +import { app, BrowserWindow, dialog } from "electron" +import { is } from "@electron-toolkit/utils" import Setting from "setting/main" import { BaseSingleton } from "base" import { fetchHotUpdatePackage, flagNeedUpdate } from "./hot" import Locales from "locales/main" import _logger from "logger/main" import { buildEmitter } from "base/event/main" +import { EventMaps } from "../common" +import path from "path" const logger = _logger.createNamespace("updater") -const { autoUpdater } = pkg class _Updater extends BaseSingleton { - public events = buildEmitter() + public events = buildEmitter() private timer: ReturnType | null = null // autoReplace = false async triggerHotUpdate(autoReplace = false) { @@ -28,42 +30,83 @@ class _Updater extends BaseSingleton { } } + updateInfo: ConstructorParameters[0] + autoUpdater: NsisUpdater + constructor() { super() + + this.autoUpdater = new NsisUpdater({ + provider: "github", + owner: "npmrun", + repo: "electron-app", + }) + + Setting.onChange("update.allowDowngrade", () => { + this.autoUpdater.allowDowngrade = Setting.values("update.allowDowngrade") + }) + Setting.onChange("update.allowPrerelease", () => { + this.autoUpdater.allowPrerelease = Setting.values("update.allowPrerelease") + }) + Setting.onChange(["update.owner", "update.repo"], () => { + this.autoUpdater.setFeedURL({ + provider: "github", + owner: "npmrun", + repo: "electron-app", + }) + }) + // 配置自动更新 - autoUpdater.autoDownload = false - autoUpdater.autoInstallOnAppQuit = true + this.autoUpdater.autoDownload = false + this.autoUpdater.autoInstallOnAppQuit = true + + this.autoUpdater.allowPrerelease = true + this.autoUpdater.allowDowngrade = true + this.autoUpdater.forceDevUpdateConfig = is.dev + if (is.dev) { + this.autoUpdater.updateConfigPath = path.resolve(process.cwd(), "temp/dev.yml") + } // 检查更新错误 - autoUpdater.on("error", error => { + this.autoUpdater.on("error", error => { logger.debug("Update error:", error) + this.events.emit("error", error) }) // 检查更新 - autoUpdater.on("checking-for-update", () => { + this.autoUpdater.on("checking-for-update", () => { logger.debug("Checking for updates...") + this.events.emit("checking-for-update") }) // 有可用更新 - autoUpdater.on("update-available", info => { + this.autoUpdater.on("update-available", info => { logger.debug("Update available:", info) + this.events.emit("update-available", info) this.promptUserToUpdate() }) // 没有可用更新 - autoUpdater.on("update-not-available", info => { + this.autoUpdater.on("update-not-available", info => { logger.debug("Update not available:", info) + this.events.emit("update-not-available", info) }) // 更新下载进度 - autoUpdater.on("download-progress", progressObj => { + this.autoUpdater.on("download-progress", progressObj => { logger.debug( `Download speed: ${progressObj.bytesPerSecond} - Downloaded ${progressObj.percent}% (${progressObj.transferred}/${progressObj.total})`, ) + this.events.emit("update-progress", { + speed: progressObj.bytesPerSecond, + percent: progressObj.percent, + all: progressObj.total, + now: progressObj.transferred, + }) }) // 更新下载完成 - autoUpdater.on("update-downloaded", info => { + this.autoUpdater.on("update-downloaded", info => { logger.debug("Update downloaded:", info) this.promptUserToInstall() }) @@ -89,16 +132,12 @@ class _Updater extends BaseSingleton { } } - private async checkForUpdates() { - if (app.isPackaged) { - try { - await autoUpdater.checkForUpdates() - logger.debug("Updater初始化检查成功.") - } catch (error) { - logger.debug("Failed to check for updates:", error) - } - } else { - logger.debug("正在开发模式,跳过更新检查.") + async checkForUpdates() { + try { + this.autoUpdater.checkForUpdates() + logger.debug("Updater初始化检查成功.") + } catch (error) { + logger.debug("Failed to check for updates:", error) } } @@ -112,21 +151,21 @@ class _Updater extends BaseSingleton { }) if (result.response === 0) { - autoUpdater.downloadUpdate() + this.autoUpdater.downloadUpdate() } } private async promptUserToInstall() { - const result = await dialog.showMessageBox({ + const result = await dialog.showMessageBox(BrowserWindow.getFocusedWindow()!, { type: "info", title: "更新已就绪", message: "新版本已下载完成,是否立即安装?", - buttons: ["立即安装", "稍后安装"], + buttons: ["立即安装"], defaultId: 0, }) if (result.response === 0) { - autoUpdater.quitAndInstall(false, true) + this.autoUpdater.quitAndInstall(false, true) } } } diff --git a/packages/locales/main.ts b/packages/locales/main.ts index d49c0be..5bfb1f2 100644 --- a/packages/locales/main.ts +++ b/packages/locales/main.ts @@ -21,7 +21,7 @@ class Locale { try { this.locale = app.getLocale() } catch (e) { - console.log(e) + console.error(e) } } @@ -40,7 +40,6 @@ class Locale { if (replacements) { // 替换所有形如 {key} 的占位符 Object.entries(replacements).forEach(([key, value]) => { - console.log(text) text = text.replace(new RegExp(`{${key}}`, "g"), value) }) } diff --git a/packages/logger/main.ts b/packages/logger/main.ts index ba9ee66..9933646 100644 --- a/packages/logger/main.ts +++ b/packages/logger/main.ts @@ -260,6 +260,9 @@ export class Logger { // 默认实例 const logger = Logger.getInstance() logger.init() +emitter.on("init", setting => { + logger.setLevel(setting["dev:debug"]) +}) emitter.on("update", setting => { logger.setLevel(setting["dev:debug"]) }) diff --git a/packages/logger/renderer-error.ts b/packages/logger/renderer-error.ts index 4caea50..863a951 100644 --- a/packages/logger/renderer-error.ts +++ b/packages/logger/renderer-error.ts @@ -107,7 +107,7 @@ const formatError = (error: any, options: ErrorHandlerOptions): ErrorDetail => { return errorDetail } -// @ts-ignore +// @ts-ignore 忽略preload层不存在的问题 const preloadErrorHandler = window.preloadErrorHandler /** @@ -223,6 +223,7 @@ const errorHandler = createRendererErrorHandler() // 安装全局错误处理器 errorHandler.installGlobalHandlers() +// @ts-ignore 忽略全局问题 window.errorHandler = errorHandler /** diff --git a/packages/setting/main.ts b/packages/setting/main.ts index 9cdf609..875a667 100644 --- a/packages/setting/main.ts +++ b/packages/setting/main.ts @@ -5,6 +5,7 @@ import { cloneDeep } from "lodash" import Config from "config" import type { IConfig } from "config" import _logger from "logger/main" +import { emitter } from "./main/event" const logger = _logger.createNamespace("setting") @@ -137,6 +138,7 @@ class SettingClass { this.#sync() } init.call(this, this.#config) + emitter.emit("update", this.#config, this.#config) } config() { return this.#config @@ -215,6 +217,7 @@ class SettingClass { if (isChange) { this.#sync() this.#runCB(this.#config, oldMainConfig, changeKeys) + emitter.emit("update", this.#config, oldMainConfig, changeKeys) } } values(key: T): IConfig[T] { diff --git a/packages/setting/main/event.ts b/packages/setting/main/event.ts index bd109ef..8bc297d 100644 --- a/packages/setting/main/event.ts +++ b/packages/setting/main/event.ts @@ -2,5 +2,6 @@ import { buildEmitter } from "base/event/main" import type { IOnFunc } from "setting/main" export const emitter = buildEmitter<{ + init: IOnFunc update: IOnFunc }>() diff --git a/packages/utils/main/session/index.ts b/packages/utils/main/session/index.ts index 128df4f..c4451b4 100644 --- a/packages/utils/main/session/index.ts +++ b/packages/utils/main/session/index.ts @@ -11,7 +11,7 @@ function createLoginWin(partition) { partition = partition || `persist:${Math.random()}` // const charset = require("superagent-charset") // const request = charset(require("superagent")) // HTTP - let presWindow = new BrowserWindow({ + const presWindow = new BrowserWindow({ width: 1280, height: 768, title: "用户登陆", @@ -21,14 +21,14 @@ function createLoginWin(partition) { partition, }, }) - let webContents = presWindow.webContents - return new Promise(function (resove, _) { + const webContents = presWindow.webContents + return new Promise(function (resove) { // webContents.openDevTools(); presWindow.loadURL("https://login.taobao.com/member/login.jhtml") webContents.on("did-navigate-in-page", async function () { // 这里可以看情况进行参数的传递,获取制定的 cookies const cookies = await webContents.session.cookies.get({}) - let obj = { partition, cookies } + const obj = { partition, cookies } resove(obj) // webContents.session.cookies.get({}, function (err, cookies) { // if (err) { @@ -77,6 +77,4 @@ function createLoginWin(partition) { }) } -export { - createLoginWin -} +export { createLoginWin } diff --git a/src/common/_ioc.main.ts b/src/common/_ioc.main.ts index 067c1be..bb057db 100644 --- a/src/common/_ioc.main.ts +++ b/src/common/_ioc.main.ts @@ -1,4 +1,7 @@ import { Container, ContainerModule } from "inversify" +import _logger from "logger/main" + +const logger = _logger.createNamespace("command") /** * 自动加载所有命令模块 @@ -12,6 +15,7 @@ const modules = new ContainerModule(bind => { const CommandClass = (module as { default: any }).default if (CommandClass) { const className = CommandClass.name.replace("Command", "") + logger.debug(`绑定命令类: ${className}Command`) if (CommandClass["init"]) { CommandClass["init"]() } @@ -27,6 +31,18 @@ const modules = new ContainerModule(bind => { * @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) } diff --git a/src/common/event/PlatForm/hook.ts b/src/common/event/PlatForm/hook.ts index 0ebe033..2441319 100644 --- a/src/common/event/PlatForm/hook.ts +++ b/src/common/event/PlatForm/hook.ts @@ -1,5 +1,41 @@ +import { LogLevel } from "logger/common" import { PlatForm } from "." export function usePlatForm() { - return PlatForm.getInstance() + 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/main/command.ts b/src/common/event/PlatForm/main/command.ts index 97e09cd..0555b9b 100644 --- a/src/common/event/PlatForm/main/command.ts +++ b/src/common/event/PlatForm/main/command.ts @@ -1,7 +1,6 @@ import { app, dialog, nativeTheme, TitleBarOverlayOptions } from "electron" import { inject } from "inversify" import errorHandler from "logger/main-error" -import Tabs from "main/modules/tabs" import WindowManager from "main/modules/window-manager" import icon from "@res/icon.png?asset" import setting from "setting/main" @@ -9,10 +8,7 @@ import { LogLevel } from "logger/common" import { getFileUrl } from "utils/main" export default class PlatFormCommand { - constructor( - @inject(WindowManager) private _WindowManager: WindowManager, - @inject(Tabs) private _Tabs: Tabs, - ) {} + constructor(@inject(WindowManager) private _WindowManager: WindowManager) {} setTheme(theme: typeof nativeTheme.themeSource) { nativeTheme.themeSource = theme @@ -115,7 +111,6 @@ export default class PlatFormCommand { return } } - this._Tabs.closeAll() focusedWindow!.reload() } } diff --git a/src/common/event/Tabs/index.ts b/src/common/event/Tabs/index.ts deleted file mode 100644 index de0025b..0000000 --- a/src/common/event/Tabs/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { BaseSingleton } from "base" - -export class Tabs extends BaseSingleton { - constructor() { - super() - } - - private isListen: boolean = false - - private execUpdate = (...args) => { - this.#fnList.forEach(v => v(...args)) - } - - #fnList: ((...args) => void)[] = [] - listenUpdate(cb: (...args) => void) { - if (!this.isListen) { - api.on("main:TabsCommand.update", this.execUpdate) - this.isListen = true - } - this.#fnList.push(cb) - } - - unListenUpdate(fn: (...args) => void) { - this.#fnList = this.#fnList.filter(v => { - return v !== fn - }) - if (!this.#fnList.length) { - api.off("main:TabsCommand.update", this.execUpdate) - this.isListen = false - } - } - - bindPosition(data) { - api.call("TabsCommand.bindElement", data) - } - - closeAll() { - api.call("TabsCommand.closeAll") - } - - sync() { - api.call("TabsCommand.sync") - } - - unListenerAll() { - this.#fnList = [] - api.offAll("main:TabsCommand.update") - } - - async getAllTabs() { - const res = await api.call("TabsCommand.getAllTabs") - return res - } -} diff --git a/src/common/event/Tabs/main/command.ts b/src/common/event/Tabs/main/command.ts deleted file mode 100644 index a9984d3..0000000 --- a/src/common/event/Tabs/main/command.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { inject } from "inversify" -import Tabs from "main/modules/tabs" -import WindowManager from "main/modules/window-manager" -import { broadcast } from "utils/main" - -class TabsCommand { - constructor( - @inject(Tabs) private _Tabs: Tabs, - @inject(WindowManager) private _WindowManager: WindowManager, - ) { - this._Tabs.events.on("update", this.listenerTabActive) - } - - listenerTabActive = () => { - broadcast("main:TabsCommand.update", this.getAllTabs()) - } - - bindElement(rect) { - this._Tabs.updateRect(rect) - } - - reload() { - this._WindowManager.getMainWindow()?.reload() - } - - sync() { - this.listenerTabActive() - if (!this.getAllTabs().length) { - this.add("about:blank") - } - } - - add(url) { - this._Tabs.add(url, true, this._WindowManager.getMainWindow()!) - } - - nagivate(index: number, url: string) { - this._Tabs.navigate(+index, url) - } - - closeAll() { - this._Tabs.closeAll() - } - - setActive(index) { - this._Tabs.changeActive(index) - } - - closeTab(e) { - this._Tabs.remove(e.body.active) - } - - getAllTabs() { - return this._Tabs._tabs.map(v => ({ - url: v.url, - showUrl: v.showUrl, - title: v.title, - favicons: v.favicons, - isActive: v.isActive, - })) - } -} - -export { TabsCommand } -export default TabsCommand diff --git a/src/common/event/Updater/hook.ts b/src/common/event/Updater/hook.ts index 0cfc34a..9560262 100644 --- a/src/common/event/Updater/hook.ts +++ b/src/common/event/Updater/hook.ts @@ -1,14 +1,41 @@ -import { EventMaps } from "helper/updater/common" +import { EventMaps, UpdaterCommand } from "helper/updater/common" import { defineStore } from "pinia" -export const useSettingStore = defineStore( +export const useUpdaterStore = defineStore( "Updater", () => { - getApi().on("update-progress", (_, data) => { + const isNeedUpdate = ref(false) + const isChecking = ref(false) + + const api = getApi() + api.on("error", (_, data) => { + isChecking.value = false console.log(data) }) - - return {} + api.on("update-not-available", (_, data) => { + isChecking.value = false + console.log(data) + }) + api.on("update-available", (_, data) => { + isChecking.value = false + isNeedUpdate.value = true + console.log(data) + }) + api.on("update-progress", (_, data) => { + console.log(data) + }) + api.on("checking-for-update", () => { + isChecking.value = true + }) + api.call("UpdaterCommand.checkForUpdates") + return { + isChecking, + isNeedUpdate, + checkForUpdates() { + if (isChecking.value) return + api.call("UpdaterCommand.checkForUpdates") + }, + } }, { persist: false, diff --git a/src/common/event/Updater/main/command.ts b/src/common/event/Updater/main/command.ts index 8ba7617..277e33a 100644 --- a/src/common/event/Updater/main/command.ts +++ b/src/common/event/Updater/main/command.ts @@ -1,5 +1,6 @@ import Updater from "helper/updater/main" import _logger from "logger/main" +import { broadcast } from "utils/main" const logger = _logger.createNamespace("UpdaterCommand") @@ -7,9 +8,16 @@ 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/App.ts b/src/main/App.ts index 87a47ca..9bd0fe7 100644 --- a/src/main/App.ts +++ b/src/main/App.ts @@ -8,7 +8,6 @@ import { electronApp } from "@electron-toolkit/utils" import Command from "./modules/commands" import BaseClass from "./base/base" import IOC from "./_ioc" -import DB from "./modules/db" import Zephyr from "./modules/zephyr" import { crashHandler } from "logger/crash-handler" import logger from "logger/main" @@ -53,7 +52,6 @@ class App extends BaseClass { @inject(IOC) private _IOC: IOC, @inject(Api) private _Api: Api, @inject(Command) private _Command: Command, - @inject(DB) private _DB: DB, @inject(WindowManager) private _WindowManager: WindowManager, @inject(Zephyr) private _Zephyr: Zephyr, ) { @@ -68,7 +66,6 @@ class App extends BaseClass { // 开启硬件加速 app.disableHardwareAcceleration() crashHandler.init() - this._DB.init() this._Command.init() this._WindowManager.init() app.whenReady().then(() => { diff --git a/src/main/controller/BasicService.ts b/src/main/controller/BasicService.ts index 3668256..f25e582 100644 --- a/src/main/controller/BasicService.ts +++ b/src/main/controller/BasicService.ts @@ -1,13 +1,13 @@ import { inject, injectable } from "inversify" import BaseContainer from "main/base/baseContainer" -import Tabs from "main/modules/tabs" +// import Tabs from "main/modules/tabs" import WindowManager from "main/modules/window-manager" @injectable() class BasicService extends BaseContainer { constructor( @inject(WindowManager) private _WindowManager: WindowManager, - @inject(Tabs) private _Tabs: Tabs, + // @inject(Tabs) private _Tabs: Tabs, ) { super() } @@ -21,7 +21,7 @@ class BasicService extends BaseContainer { openTabDevtool() { // this._Tabs.reload(0) - this._Tabs.openDevtool(0) + // this._Tabs.openDevtool(0) } } diff --git a/src/main/modules/_ioc.ts b/src/main/modules/_ioc.ts index f46fcd1..7f63082 100644 --- a/src/main/modules/_ioc.ts +++ b/src/main/modules/_ioc.ts @@ -1,8 +1,7 @@ import { Container, ContainerModule } from "inversify" -import { DB } from "./db" import { Api } from "./api" import { WindowManager } from "./window-manager" -import { Tabs } from "./tabs" +// import { Tabs } from "./tabs" import Commands from "./commands" import Zephyr from "./zephyr" @@ -11,8 +10,7 @@ const modules = new ContainerModule(bind => { bind(Api).toSelf().inSingletonScope() bind(WindowManager).toSelf().inSingletonScope() bind(Commands).toSelf().inSingletonScope() - bind(Tabs).toSelf().inSingletonScope() - bind(DB).toSelf().inSingletonScope() + // bind(Tabs).toSelf().inSingletonScope() }) async function destroyAllModules(ioc: Container) { @@ -20,9 +18,8 @@ async function destroyAllModules(ioc: Container) { ioc.get(WindowManager).destroy(), ioc.get(Commands).destroy(), ioc.get(Zephyr).destroy(), - ioc.get(Tabs).destroy(), + // ioc.get(Tabs).destroy(), ioc.get(Api).destroy(), - ioc.get(DB).destroy(), ]) ioc.unloadAsync(modules) } diff --git a/src/main/modules/db/custom.ts b/src/main/modules/db/custom.ts deleted file mode 100644 index a932712..0000000 --- a/src/main/modules/db/custom.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { JSONFile } from "lowdb/node" -import { Low } from "lowdb" -import fs from "fs-extra" - -export class CustomAdapter extends JSONFile { - constructor(filepath: string) { - super(filepath) - this.filepath = filepath - } - filepath: string = "" - async read() { - if (!fs.existsSync(this.filepath)) { - return null - } - const data = fs.readJSONSync(this.filepath, { throws: false }) - if (!data) { - return null - } - return data - } - - async write(data: T) { - fs.ensureFileSync(this.filepath) - await super.write(data) - } -} -export class CustomLow extends Low { - constructor(adapter: CustomAdapter, defaultData: T) { - super(adapter, defaultData) - this.filepath = adapter.filepath - } - filepath: string = "" -} diff --git a/src/main/modules/db/index.ts b/src/main/modules/db/index.ts deleted file mode 100644 index 0d9d22e..0000000 --- a/src/main/modules/db/index.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { injectable } from "inversify" -import Setting from "setting/main" -import { CustomAdapter, CustomLow } from "./custom" -import path from "node:path" -import BaseClass from "main/base/base" -import _logger from "logger/main" - -const logger = _logger.createNamespace("db") - -@injectable() -class DB extends BaseClass { - destroy() { - logger.debug(`DB destroy`) - } - Modules: Record> = {} - - constructor() { - super() - } - - init() { - console.log("DB Init") - } - - create(filepath) { - const adapter = new CustomAdapter(filepath) - const db = new CustomLow(adapter, {}) - db.filepath = filepath - return db - } - - getDB(dbName: string) { - if (this.Modules[dbName] === undefined) { - const filepath = path.resolve(Setting.values("storagePath"), "./db/" + dbName + ".json") - this.Modules[dbName] = this.create(filepath) - return this.Modules[dbName] - } else { - const cur = this.Modules[dbName] - const filepath = path.resolve(Setting.values("storagePath"), "./db/" + dbName + ".json") - if (cur.filepath != filepath) { - this.Modules[dbName] = this.create(filepath) - } - return this.Modules[dbName] - } - } - - async saveData(data: any): Promise - async saveData(dbName: string, data: any): Promise - async saveData(dbName: string, data?: any): Promise { - let db, rData - if (arguments.length === 2) { - db = this.getDB(dbName) - rData = data - } else { - db = this.getDB("db") - rData = dbName - } - if (db) { - db.data = rData - await db.write() - return db.data - } - return null - } - - async getData(dbName?: string) { - let db - if (dbName) { - db = this.getDB(dbName) - } else { - db = this.getDB("db") - } - if (db) { - await db.read() - return db.data - } - return null - } -} - -export default DB -export { DB } diff --git a/src/preload/index.ts b/src/preload/index.ts index 58b2883..51e863b 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -67,6 +67,7 @@ ipcRenderer.once("bind-window-manager", (_, name: string) => { if (process.contextIsolated) { try { contextBridge.exposeInMainWorld("electron", electronAPI) + contextBridge.exposeInMainWorld("getApi", () => api) contextBridge.exposeInMainWorld("api", api) } catch (error) { console.error(error) @@ -76,4 +77,6 @@ if (process.contextIsolated) { window.electron = electronAPI // @ts-ignore (define in dts) window.api = api + // @ts-ignore (define in dts) + window.getApi = () => api } diff --git a/src/renderer/components.d.ts b/src/renderer/components.d.ts index 829b688..540eae5 100644 --- a/src/renderer/components.d.ts +++ b/src/renderer/components.d.ts @@ -11,8 +11,10 @@ declare module 'vue' { AdjustLine: typeof import('./src/components/AdjustLine.vue')['default'] CodeEditor: typeof import('./src/components/CodeEditor/code-editor.vue')['default'] IconFluentCollections24Regular: typeof import('~icons/fluent/collections24-regular')['default'] + 'IconGrommetIcons:update': typeof import('~icons/grommet-icons/update')['default'] IconHugeiconsInbox: typeof import('~icons/hugeicons/inbox')['default'] IconMynauiTrash: typeof import('~icons/mynaui/trash')['default'] + 'IconQlementineIcons:update16': typeof import('~icons/qlementine-icons/update16')['default'] IconSolarHome2Outline: typeof import('~icons/solar/home2-outline')['default'] 'IconStash:arrowReplyDuotone': typeof import('~icons/stash/arrow-reply-duotone')['default'] NavBar: typeof import('./src/ui/NavBar.vue')['default'] diff --git a/src/renderer/src/App.vue b/src/renderer/src/App.vue index 2ed6d22..6ce5d66 100644 --- a/src/renderer/src/App.vue +++ b/src/renderer/src/App.vue @@ -1,5 +1,4 @@