Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(desktop): save and restore window state #1852

Merged
merged 6 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
38 changes: 25 additions & 13 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ 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'
Expand All @@ -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'

Expand Down Expand Up @@ -138,8 +135,6 @@ async function createWindow() {
theme = setting.currentTheme
autoCheckUpdate = setting.autoCheck
syncOsTheme = setting.syncOsTheme
windowSize.height = setting.height
windowSize.width = setting.width
//@ts-ignore
global.sharedData = {
currentTheme: setting.currentTheme,
Expand Down Expand Up @@ -171,9 +166,7 @@ async function createWindow() {
}
// Create the browser window.
win = new BrowserWindow({
...windowSize,
minHeight: 650,
minWidth: 997,
...defaultWindowSize,
webPreferences: {
devTools: isDevelopment,
webSecurity: false,
Expand All @@ -185,6 +178,10 @@ async function createWindow() {
backgroundColor: theme === 'dark' ? '#232323' : theme === 'night' ? '#212328' : '#ffffff',
icon: `${__static}/app.ico`,
})

// Restore window state
restoreWindowState(win)

// Theme change
onSystemThemeChanged(async (theme) => {
// @ts-ignore
Expand All @@ -210,10 +207,25 @@ async function createWindow() {
win.loadURL('app://./index.html')
}

win.on('closed', () => {
win = null
console.log('App closed')
beforeAppQuit()
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()
}
})
handleIpcMessages()
if (electronStore.get('isVersion') !== version) {
Expand Down
12 changes: 7 additions & 5 deletions src/main/saveExcel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
64 changes: 64 additions & 0 deletions src/utils/windowStateManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type { BrowserWindow, Rectangle } from 'electron'
import { screen } from 'electron'
import Store from 'electron-store'

const store = new Store()

interface WindowState {
bounds: Rectangle
isMaximized: boolean
isFullScreen: 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 = 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)
}
}

// Save window state
export function saveWindowState(win: BrowserWindow): void {
try {
const windowState = {
bounds: win.getBounds(),
isMaximized: win.isMaximized(),
isFullScreen: win.isFullScreen(),
}
store.set('windowState', windowState)
} catch (error) {
console.error('Failed to save window state:', error)
}
}
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"sourceMap": true,
"emitDecoratorMetadata": true,
"baseUrl": ".",
"skipLibCheck": true,
"types": [
"webpack-env",
"mocha",
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down