From 5075a03eac1c27b01ea4060f6c04061d3c4b148e Mon Sep 17 00:00:00 2001 From: ni00 Date: Fri, 3 Jan 2025 23:49:19 +0800 Subject: [PATCH 1/6] feat(desktop): save and restore window state --- src/background.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/background.ts b/src/background.ts index 8d81d78aa..24c912ddb 100644 --- a/src/background.ts +++ b/src/background.ts @@ -1,6 +1,6 @@ import 'reflect-metadata' // Required by TypoORM. ;('use strict') -import { app, protocol, BrowserWindow, ipcMain, shell, Menu } from 'electron' +import { app, protocol, BrowserWindow, ipcMain, shell, Menu, screen } from 'electron' import { createProtocol } from 'vue-cli-plugin-electron-builder/lib' import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer' import { quitAndRenameLogger } from './utils/logger' @@ -185,6 +185,22 @@ async function createWindow() { backgroundColor: theme === 'dark' ? '#232323' : theme === 'night' ? '#212328' : '#ffffff', icon: `${__static}/app.ico`, }) + + // Restore window state + const savedBounds = electronStore.get('bounds') + if (savedBounds !== undefined) { + const screenArea = screen.getDisplayMatching(savedBounds).workArea + // Check if the window is within the bounds of the screen + if ( + savedBounds.x >= screenArea.x && + savedBounds.x <= screenArea.x + screenArea.width && + savedBounds.y >= screenArea.y && + savedBounds.y <= screenArea.y + screenArea.height + ) { + win.setBounds(savedBounds) + } + } + // Theme change onSystemThemeChanged(async (theme) => { // @ts-ignore @@ -210,7 +226,11 @@ async function createWindow() { win.loadURL('app://./index.html') } - win.on('closed', () => { + win.on('close', () => { + if (win) { + // Save window bounds before closing + electronStore.set('bounds', win.getBounds()) + } win = null console.log('App closed') beforeAppQuit() From da57dade5a9361314b9c4137e4c5cba1d5dda9a8 Mon Sep 17 00:00:00 2001 From: ni00 Date: Mon, 20 Jan 2025 21:46:29 +0800 Subject: [PATCH 2/6] fix(desktop): optimize window state persistence with error handling --- src/background.ts | 33 ++++------------ src/utils/windowStateManager.ts | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 25 deletions(-) create mode 100644 src/utils/windowStateManager.ts diff --git a/src/background.ts b/src/background.ts index 24c912ddb..3a840fbc7 100644 --- a/src/background.ts +++ b/src/background.ts @@ -1,9 +1,10 @@ import 'reflect-metadata' // Required by TypoORM. ;('use strict') -import { app, protocol, BrowserWindow, ipcMain, shell, Menu, screen } from 'electron' +import { app, protocol, BrowserWindow, ipcMain, shell, Menu } from 'electron' import { createProtocol } from 'vue-cli-plugin-electron-builder/lib' import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer' import { quitAndRenameLogger } from './utils/logger' +import { defaultWindowSize, restoreWindowState, saveWindowState } from './utils/windowStateManager' import rebuildDatabase from './database/rebuildDatabase' import { createUpdateWindow, autoDownload } from './main/updateDownloader' import { getCurrentLang } from './main/updateChecker' @@ -26,10 +27,6 @@ const electronStore = new Store() let theme: Theme = 'light' let syncOsTheme = false let autoCheckUpdate: boolean = true -const windowSize = { - width: 1025, - height: 749, -} const isDevelopment: boolean = process.env.NODE_ENV !== 'production' const isMac: boolean = process.platform === 'darwin' @@ -138,8 +135,8 @@ async function createWindow() { theme = setting.currentTheme autoCheckUpdate = setting.autoCheck syncOsTheme = setting.syncOsTheme - windowSize.height = setting.height - windowSize.width = setting.width + defaultWindowSize.height = setting.height + defaultWindowSize.width = setting.width //@ts-ignore global.sharedData = { currentTheme: setting.currentTheme, @@ -171,9 +168,7 @@ async function createWindow() { } // Create the browser window. win = new BrowserWindow({ - ...windowSize, - minHeight: 650, - minWidth: 997, + ...defaultWindowSize, webPreferences: { devTools: isDevelopment, webSecurity: false, @@ -187,19 +182,7 @@ async function createWindow() { }) // Restore window state - const savedBounds = electronStore.get('bounds') - if (savedBounds !== undefined) { - const screenArea = screen.getDisplayMatching(savedBounds).workArea - // Check if the window is within the bounds of the screen - if ( - savedBounds.x >= screenArea.x && - savedBounds.x <= screenArea.x + screenArea.width && - savedBounds.y >= screenArea.y && - savedBounds.y <= screenArea.y + screenArea.height - ) { - win.setBounds(savedBounds) - } - } + restoreWindowState(win) // Theme change onSystemThemeChanged(async (theme) => { @@ -228,8 +211,8 @@ async function createWindow() { win.on('close', () => { if (win) { - // Save window bounds before closing - electronStore.set('bounds', win.getBounds()) + // Save window state before closing + saveWindowState(win) } win = null console.log('App closed') diff --git a/src/utils/windowStateManager.ts b/src/utils/windowStateManager.ts new file mode 100644 index 000000000..0d410748a --- /dev/null +++ b/src/utils/windowStateManager.ts @@ -0,0 +1,67 @@ +import { BrowserWindow, screen } from 'electron' +import Store from 'electron-store' + +const electronStore = new Store() + +interface WindowBounds { + x: number + y: number + width: number + height: number +} + +interface WindowState { + bounds: WindowBounds + isMaximized: boolean +} + +// Default window size +export const defaultWindowSize = { + width: 1025, + height: 749, + minHeight: 650, + minWidth: 997, +} + +// Restore window state +export function restoreWindowState(win: BrowserWindow): void { + try { + const savedState = electronStore.get('windowState') as WindowState | undefined + if (savedState && typeof savedState === 'object') { + const screenArea = screen.getDisplayMatching(savedState.bounds).workArea + // Check if the window is within the bounds of the screen + if ( + savedState.bounds.x >= screenArea.x && + savedState.bounds.x <= screenArea.x + screenArea.width && + savedState.bounds.y >= screenArea.y && + savedState.bounds.y <= screenArea.y + screenArea.height + ) { + try { + win.setBounds(savedState.bounds) + if (savedState.isMaximized) { + win.maximize() + } + } catch (error) { + console.error('Failed to restore window bounds:', error) + // Fallback to default window bounds + win.setBounds({ width: defaultWindowSize.width, height: defaultWindowSize.height }) + } + } + } + } catch (error) { + console.error('Failed to restore window state:', error) + } +} + +// Save window state +export function saveWindowState(win: BrowserWindow): void { + try { + const windowState = { + bounds: win.getBounds(), + isMaximized: win.isMaximized(), + } + electronStore.set('windowState', windowState) + } catch (error) { + console.error('Failed to save window state:', error) + } +} From aef6887fd0d510d0191fb2fba1d4ab132b372261 Mon Sep 17 00:00:00 2001 From: ni00 Date: Mon, 20 Jan 2025 22:19:28 +0800 Subject: [PATCH 3/6] fix(desktop): optimize window state setting service --- src/background.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/background.ts b/src/background.ts index 3a840fbc7..5ed59eb8f 100644 --- a/src/background.ts +++ b/src/background.ts @@ -135,8 +135,6 @@ async function createWindow() { theme = setting.currentTheme autoCheckUpdate = setting.autoCheck syncOsTheme = setting.syncOsTheme - defaultWindowSize.height = setting.height - defaultWindowSize.width = setting.width //@ts-ignore global.sharedData = { currentTheme: setting.currentTheme, From 78d1231c08b655998651fef8316a5f51b1182c05 Mon Sep 17 00:00:00 2001 From: Red-Asuka Date: Mon, 10 Feb 2025 16:47:26 +0800 Subject: [PATCH 4/6] fix(desktop): improve window state handling on close and restore --- src/background.ts | 25 ++++++++++---- src/utils/windowStateManager.ts | 61 ++++++++++++++++----------------- 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/src/background.ts b/src/background.ts index 5ed59eb8f..3eefac90d 100644 --- a/src/background.ts +++ b/src/background.ts @@ -207,14 +207,25 @@ async function createWindow() { win.loadURL('app://./index.html') } - win.on('close', () => { - if (win) { - // Save window state before closing - saveWindowState(win) + win.on('close', (e) => { + // When the window is in full-screen mode, exit full-screen before closing. + // This ensures that we save the normal (non-full-screen) window bounds. + // Otherwise, the saved state would be the full-screen bounds, + // causing the window to restore to full-screen dimensions (covering the entire screen) + // after leaving full-screen mode in a subsequent launch. + const mainWindow = win! + if (mainWindow.isFullScreen()) { + e.preventDefault() + mainWindow.once('leave-full-screen', () => { + saveWindowState(mainWindow) + mainWindow.close() + }) + mainWindow.setFullScreen(false) + } else { + saveWindowState(mainWindow) + console.log('App closed') + beforeAppQuit() } - win = null - console.log('App closed') - beforeAppQuit() }) handleIpcMessages() if (electronStore.get('isVersion') !== version) { diff --git a/src/utils/windowStateManager.ts b/src/utils/windowStateManager.ts index 0d410748a..aef4384d6 100644 --- a/src/utils/windowStateManager.ts +++ b/src/utils/windowStateManager.ts @@ -1,18 +1,13 @@ -import { BrowserWindow, screen } from 'electron' +import type { BrowserWindow, Rectangle } from 'electron' +import { screen } from 'electron' import Store from 'electron-store' -const electronStore = new Store() - -interface WindowBounds { - x: number - y: number - width: number - height: number -} +const store = new Store() interface WindowState { - bounds: WindowBounds + bounds: Rectangle isMaximized: boolean + isFullScreen: boolean } // Default window size @@ -26,27 +21,28 @@ export const defaultWindowSize = { // Restore window state export function restoreWindowState(win: BrowserWindow): void { try { - const savedState = electronStore.get('windowState') as WindowState | undefined - if (savedState && typeof savedState === 'object') { - const screenArea = screen.getDisplayMatching(savedState.bounds).workArea - // Check if the window is within the bounds of the screen - if ( - savedState.bounds.x >= screenArea.x && - savedState.bounds.x <= screenArea.x + screenArea.width && - savedState.bounds.y >= screenArea.y && - savedState.bounds.y <= screenArea.y + screenArea.height - ) { - try { - win.setBounds(savedState.bounds) - if (savedState.isMaximized) { - win.maximize() - } - } catch (error) { - console.error('Failed to restore window bounds:', error) - // Fallback to default window bounds - win.setBounds({ width: defaultWindowSize.width, height: defaultWindowSize.height }) - } - } + const savedState = store.get('windowState') as WindowState | undefined + if (!savedState || typeof savedState !== 'object') return + + const screenArea = screen.getDisplayMatching(savedState.bounds).workArea + if (savedState.bounds.width > screenArea.width) { + savedState.bounds.width = screenArea.width + } + if (savedState.bounds.height > screenArea.height) { + savedState.bounds.height = screenArea.height + } + if (savedState.bounds.x < screenArea.x) { + savedState.bounds.x = screenArea.x + } + if (savedState.bounds.y < screenArea.y) { + savedState.bounds.y = screenArea.y + } + win.setBounds(savedState.bounds) + if (savedState.isMaximized) { + win.maximize() + } + if (savedState.isFullScreen) { + win.setFullScreen(true) } } catch (error) { console.error('Failed to restore window state:', error) @@ -59,8 +55,9 @@ export function saveWindowState(win: BrowserWindow): void { const windowState = { bounds: win.getBounds(), isMaximized: win.isMaximized(), + isFullScreen: win.isFullScreen(), } - electronStore.set('windowState', windowState) + store.set('windowState', windowState) } catch (error) { console.error('Failed to save window state:', error) } From 9052ee0c7c5af4185db3f9529aadfa7142009340 Mon Sep 17 00:00:00 2001 From: Red-Asuka Date: Mon, 10 Feb 2025 16:48:07 +0800 Subject: [PATCH 5/6] chore(deps): update typescript to version 4.9.5 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0b71f4dfb..82014fd72 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "sass": "~1.32.13", "sass-loader": "^8.0.2", "typeorm-uml": "^1.6.4", - "typescript": "^3.7.4", + "typescript": "^4.9.5", "vue-cli-plugin-electron-builder": "^2.1.1", "vue-template-compiler": "^2.6.12" }, diff --git a/yarn.lock b/yarn.lock index e5ebcf736..a0e86c9ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12198,10 +12198,10 @@ typeorm@^0.2.34: yargs "^16.2.0" zen-observable-ts "^1.0.0" -typescript@^3.7.4: - version "3.9.9" - resolved "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674" - integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w== +typescript@^4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== uc.micro@^1.0.1: version "1.0.6" From 07c4770c7754d43264eae69a258a76e3eebdc5f6 Mon Sep 17 00:00:00 2001 From: Red-Asuka Date: Mon, 10 Feb 2025 16:48:52 +0800 Subject: [PATCH 6/6] fix(typescript): skip library check --- src/main/saveExcel.ts | 12 +++++++----- tsconfig.json | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/saveExcel.ts b/src/main/saveExcel.ts index 7528f6d5f..309f61e4c 100644 --- a/src/main/saveExcel.ts +++ b/src/main/saveExcel.ts @@ -14,11 +14,13 @@ const saveExcel = (win: BrowserWindow, filename: string, workbook: WorkBook) => try { xlsx.writeFile(workbook, filePath) } catch (err) { - dialog.showMessageBox({ - type: 'error', - title: 'System', - message: `An error ocurred creating the file ${err.toString()}`, - }) + if (err instanceof Error) { + dialog.showMessageBox({ + type: 'error', + title: 'System', + message: `An error ocurred creating the file ${err.toString()}`, + }) + } caughtError = true } if (!caughtError) { diff --git a/tsconfig.json b/tsconfig.json index 111fd44ac..343ae6e97 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,7 @@ "sourceMap": true, "emitDecoratorMetadata": true, "baseUrl": ".", + "skipLibCheck": true, "types": [ "webpack-env", "mocha",