diff --git a/apps/desktop/package.json b/apps/desktop/package.json index c9adfde33..679eb5453 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -31,6 +31,7 @@ "@mqttx/ui": "workspace:*", "better-sqlite3": "^11.6.0", "drizzle-orm": "^0.36.4", + "electron-store": "^10.0.0", "electron-updater": "^6.3.9", "element-plus": "^2.8.7", "markdown-it": "^14.1.0", diff --git a/apps/desktop/src/main/index.ts b/apps/desktop/src/main/index.ts index 6fad19815..6afc39435 100644 --- a/apps/desktop/src/main/index.ts +++ b/apps/desktop/src/main/index.ts @@ -9,17 +9,18 @@ import { useAppUpdater } from './update' // const IsMacOS = process.platform === 'darwin' +let existingSettings: SelectSettings | undefined + async function createWindow() { - let data: SelectSettings | undefined - data = await db.query.settings.findFirst() - if (!data) { + existingSettings = await db.query.settings.findFirst() + if (!existingSettings) { await db.insert(settings).values({}) } - data = await db.query.settings.findFirst() as SelectSettings + existingSettings = await db.query.settings.findFirst() as SelectSettings - const width = data.width || 1024 - const height = data.height || 749 - const currentTheme = data.currentTheme || 'light' + const width = existingSettings.width || 1024 + const height = existingSettings.height || 749 + const currentTheme = existingSettings.currentTheme || 'light' const bgColor = { dark: '#232323', night: '#212328', @@ -94,7 +95,7 @@ app.whenReady().then(async () => { await createWindow() - useAppUpdater() + useAppUpdater(existingSettings!) app.on('activate', () => { // On macOS it's common to re-create a window in the app when the diff --git a/apps/desktop/src/main/update.ts b/apps/desktop/src/main/update.ts index 84bd36fe7..9ad368607 100644 --- a/apps/desktop/src/main/update.ts +++ b/apps/desktop/src/main/update.ts @@ -1,7 +1,12 @@ +import type { Lang } from 'mqttx' +import type { SelectSettings } from '../database/schemas/settings' import type { UpdateEvent } from '../preload/index.d' -import { BrowserWindow, ipcMain } from 'electron' +import { app, BrowserWindow, ipcMain } from 'electron' +import Store from 'electron-store' import pkg from 'electron-updater' +// FIXME: https://github.com/sindresorhus/electron-store/issues/276 +const store = new Store() as any const { autoUpdater } = pkg if (process.env.NODE_ENV === 'development') { @@ -9,10 +14,7 @@ if (process.env.NODE_ENV === 'development') { } autoUpdater.autoDownload = false - -// autoUpdater.checkForUpdates() -// autoUpdater.downloadUpdate() -// autoUpdater.quitAndInstall() +autoUpdater.autoInstallOnAppQuit = false autoUpdater.on('checking-for-update', () => { sendUpdateStatus({ status: 'checking-for-update' }) @@ -52,6 +54,27 @@ async function fetchReleaseNotes(version: string): Promise { }) } +async function showReleaseNotesWindow(lang: Lang) { + const language = ['en', 'zh', 'ja'].includes(lang) ? lang : 'en' + const version = app.getVersion() + const link = `https://mqttx.app/${language}/changelogs/v${version}` + + try { + const response = await fetch(link, { method: 'GET', signal: AbortSignal.timeout(5000) }) + if (response.status !== 200) { + return + } + const releaseNotesWindow = new BrowserWindow({ + width: 600, + height: 500, + alwaysOnTop: true, + }) + releaseNotesWindow.loadURL(link) + } catch (e) { + console.error(e) + } +} + function sendUpdateStatus(updateEvent: UpdateEvent) { const windows = BrowserWindow.getAllWindows() windows.forEach((window) => { @@ -63,7 +86,12 @@ function sendUpdateStatus(updateEvent: UpdateEvent) { }) } -function useAppUpdater() { +function useAppUpdater(settings: SelectSettings) { + const version = app.getVersion() + if (store.get('version') !== version) { + showReleaseNotesWindow(settings.currentLang) + store.set('version', version) + } ipcMain.handle('check-for-updates', async () => { return await autoUpdater.checkForUpdates() }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1d6823e99..e46cc9b65 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,6 +135,9 @@ importers: drizzle-orm: specifier: ^0.36.4 version: 0.36.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.6.0) + electron-store: + specifier: ^10.0.0 + version: 10.0.0 electron-updater: specifier: ^6.3.9 version: 6.3.9 @@ -3867,6 +3870,17 @@ packages: ajv: 8.13.0 dev: true + /ajv-formats@3.0.1(ajv@8.17.1): + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.17.1 + dev: false + /ajv-keywords@3.5.2(ajv@6.12.6): resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} peerDependencies: @@ -4137,6 +4151,13 @@ packages: engines: {node: '>= 4.0.0'} dev: true + /atomically@2.0.3: + resolution: {integrity: sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw==} + dependencies: + stubborn-fs: 1.2.5 + when-exit: 2.1.3 + dev: false + /autoprefixer@10.4.20(postcss@8.4.48): resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} engines: {node: ^10 || ^12 || >=14} @@ -4695,6 +4716,21 @@ packages: typedarray: 0.0.6 dev: false + /conf@13.1.0: + resolution: {integrity: sha512-Bi6v586cy1CoTFViVO4lGTtx780lfF96fUmS1lSX6wpZf6330NvHUu6fReVuDP1de8Mg0nkZb01c8tAQdz1o3w==} + engines: {node: '>=18'} + dependencies: + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + atomically: 2.0.3 + debounce-fn: 6.0.0 + dot-prop: 9.0.0 + env-paths: 3.0.0 + json-schema-typed: 8.0.1 + semver: 7.6.3 + uint8array-extras: 1.4.0 + dev: false + /confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} dev: true @@ -4915,6 +4951,13 @@ packages: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} dev: true + /debounce-fn@6.0.0: + resolution: {integrity: sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ==} + engines: {node: '>=18'} + dependencies: + mimic-function: 5.0.1 + dev: false + /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -5118,6 +5161,13 @@ packages: domhandler: 5.0.3 dev: true + /dot-prop@9.0.0: + resolution: {integrity: sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==} + engines: {node: '>=18'} + dependencies: + type-fest: 4.30.2 + dev: false + /dotenv-expand@11.0.6: resolution: {integrity: sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g==} engines: {node: '>=12'} @@ -5315,6 +5365,14 @@ packages: - supports-color dev: true + /electron-store@10.0.0: + resolution: {integrity: sha512-BU/QZh+5twHBprRdLu3YZX/rIarmZzhTNpJvAvqG1/yN0mNCrsMh0kl7bM4xaUKDNRiHz1r7wP/7Prjh7cleIw==} + engines: {node: '>=20'} + dependencies: + conf: 13.1.0 + type-fest: 4.30.2 + dev: false + /electron-to-chromium@1.5.55: resolution: {integrity: sha512-6maZ2ASDOTBtjt9FhqYPRnbvKU5tjG0IN9SztUOWYw2AzNDNpKJYLJmlK0/En4Hs/aiWnB+JZ+gW19PIGszgKg==} dev: true @@ -5433,6 +5491,11 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + /env-paths@3.0.0: + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + /environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} @@ -7220,6 +7283,10 @@ packages: /json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + /json-schema-typed@8.0.1: + resolution: {integrity: sha512-XQmWYj2Sm4kn4WeTYvmpKEbyPsL7nBsb647c7pMe6l02/yx2+Jfc4dT6UZkEXnIUb5LhD55r2HPsJ1milQ4rDg==} + dev: false + /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true @@ -8028,7 +8095,6 @@ packages: /mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} - dev: true /mimic-response@1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} @@ -9995,6 +10061,10 @@ packages: js-tokens: 9.0.0 dev: true + /stubborn-fs@1.2.5: + resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==} + dev: false + /stylehacks@7.0.4(postcss@8.4.48): resolution: {integrity: sha512-i4zfNrGMt9SB4xRK9L83rlsFCgdGANfeDAYacO1pkqcE7cRHPdWHwnKZVz7WY17Veq/FvyYsRAU++Ga+qDFIww==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} @@ -10384,6 +10454,11 @@ packages: engines: {node: '>=8'} dev: true + /type-fest@4.30.2: + resolution: {integrity: sha512-UJShLPYi1aWqCdq9HycOL/gwsuqda1OISdBO3t8RlXQC4QvtuIz4b5FCfe2dQIWEpmlRExKmcTBfP1r9bhY7ig==} + engines: {node: '>=16'} + dev: false + /typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: false @@ -10406,6 +10481,11 @@ packages: resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} dev: true + /uint8array-extras@1.4.0: + resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==} + engines: {node: '>=18'} + dev: false + /undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} @@ -10969,6 +11049,10 @@ packages: tr46: 5.0.0 webidl-conversions: 7.0.0 + /when-exit@2.1.3: + resolution: {integrity: sha512-uVieSTccFIr/SFQdFWN/fFaQYmV37OKtuaGphMAzi4DmmUlrvRBJW5WSLkHyjNQY/ePJMz3LoiX9R3yy1Su6Hw==} + dev: false + /which-typed-array@1.1.15: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'}