update tracjer

This commit is contained in:
2026-01-21 23:29:52 +07:00
parent 9f79daf796
commit 765da3c37f
7 changed files with 64 additions and 37 deletions

4
desktop/.gitignore vendored
View File

@@ -14,6 +14,7 @@ npm-debug.log*
.vscode/ .vscode/
*.swp *.swp
*.swo *.swo
.claude/
# OS # OS
.DS_Store .DS_Store
@@ -26,3 +27,6 @@ Thumbs.db
# Electron # Electron
*.asar *.asar
# Lock files (optional - remove if you want to commit)
package-lock.json

View File

@@ -1,6 +1,6 @@
{ {
"name": "game-marathon-tracker", "name": "game-marathon-tracker",
"version": "1.0.0", "version": "1.0.1",
"description": "Desktop app for tracking game time in Game Marathon", "description": "Desktop app for tracking game time in Game Marathon",
"main": "dist/main/main/index.js", "main": "dist/main/main/index.js",
"author": "Game Marathon", "author": "Game Marathon",
@@ -54,13 +54,20 @@
"output": "release" "output": "release"
}, },
"files": [ "files": [
"dist/**/*", "dist/**/*"
"resources/**/*" ],
"extraResources": [
{
"from": "resources",
"to": "resources"
}
], ],
"win": { "win": {
"target": [ "target": [
"nsis", {
"portable" "target": "nsis",
"arch": ["x64"]
}
], ],
"icon": "resources/icon.ico", "icon": "resources/icon.ico",
"signAndEditExecutable": false "signAndEditExecutable": false
@@ -69,7 +76,9 @@
"oneClick": false, "oneClick": false,
"allowToChangeInstallationDirectory": true, "allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true, "createDesktopShortcut": true,
"createStartMenuShortcut": true "createStartMenuShortcut": true,
"runAfterFinish": false,
"artifactName": "Game-Marathon-Tracker-Setup-${version}.${ext}"
}, },
"publish": { "publish": {
"provider": "github", "provider": "github",

View File

@@ -34,12 +34,23 @@ const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged
// Prevent multiple instances // Prevent multiple instances
const gotTheLock = app.requestSingleInstanceLock() const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) { if (!gotTheLock) {
app.quit() app.exit(0)
} }
// Someone tried to run a second instance, focus our window
app.on('second-instance', () => {
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore()
mainWindow.show()
mainWindow.focus()
}
})
function createWindow() { function createWindow() {
// __dirname is dist/main/main/ in both dev and prod // In dev: use project resources folder, in prod: use app resources
const iconPath = path.join(__dirname, '../../../resources/icon.ico') const iconPath = isDev
? path.join(__dirname, '../../../resources/icon.ico')
: path.join(process.resourcesPath, 'resources/icon.ico')
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
width: 450, width: 450,
@@ -149,6 +160,11 @@ ipcMain.on('minimize-to-tray', () => {
mainWindow?.hide() mainWindow?.hide()
}) })
ipcMain.on('close-window', () => {
// This triggers the 'close' event handler which checks minimizeToTray setting
mainWindow?.close()
})
ipcMain.on('quit-app', () => { ipcMain.on('quit-app', () => {
app.isQuitting = true app.isQuitting = true
app.quit() app.quit()

View File

@@ -10,10 +10,10 @@ export function setupTray(
) { ) {
const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged
// In dev: __dirname is dist/main/main/, in prod: same // In dev: use project resources folder, in prod: use app resources
const iconPath = isDev const iconPath = isDev
? path.join(__dirname, '../../../resources/icon.ico') ? path.join(__dirname, '../../../resources/icon.ico')
: path.join(__dirname, '../../../resources/icon.ico') : path.join(process.resourcesPath, 'resources/icon.ico')
// Create tray icon // Create tray icon
let trayIcon: NativeImage let trayIcon: NativeImage

View File

@@ -53,15 +53,20 @@ function sendProgressToSplash(percent: number) {
export function setupAutoUpdater(onComplete: () => void) { export function setupAutoUpdater(onComplete: () => void) {
const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged
let hasCompleted = false
const safeComplete = () => {
if (hasCompleted) return
hasCompleted = true
closeSplashWindow()
onComplete()
}
// In development, skip update check // In development, skip update check
if (isDev) { if (isDev) {
console.log('[Updater] Skipping update check in development mode') console.log('[Updater] Skipping update check in development mode')
sendStatusToSplash('Режим разработки') sendStatusToSplash('Режим разработки')
setTimeout(() => { setTimeout(safeComplete, 1500)
closeSplashWindow()
onComplete()
}, 1500)
return return
} }
@@ -69,24 +74,21 @@ export function setupAutoUpdater(onComplete: () => void) {
autoUpdater.autoDownload = true autoUpdater.autoDownload = true
autoUpdater.autoInstallOnAppQuit = true autoUpdater.autoInstallOnAppQuit = true
// Check for updates // Check for updates (use 'once' to prevent handlers from triggering on manual update checks)
autoUpdater.on('checking-for-update', () => { autoUpdater.once('checking-for-update', () => {
console.log('[Updater] Checking for updates...') console.log('[Updater] Checking for updates...')
sendStatusToSplash('Проверка обновлений...') sendStatusToSplash('Проверка обновлений...')
}) })
autoUpdater.on('update-available', (info) => { autoUpdater.once('update-available', (info) => {
console.log('[Updater] Update available:', info.version) console.log('[Updater] Update available:', info.version)
sendStatusToSplash(`Найдено обновление v${info.version}`) sendStatusToSplash(`Найдено обновление v${info.version}`)
}) })
autoUpdater.on('update-not-available', () => { autoUpdater.once('update-not-available', () => {
console.log('[Updater] No updates available') console.log('[Updater] No updates available')
sendStatusToSplash('Актуальная версия') sendStatusToSplash('Актуальная версия')
setTimeout(() => { setTimeout(safeComplete, 1000)
closeSplashWindow()
onComplete()
}, 1000)
}) })
autoUpdater.on('download-progress', (progress) => { autoUpdater.on('download-progress', (progress) => {
@@ -96,7 +98,7 @@ export function setupAutoUpdater(onComplete: () => void) {
sendProgressToSplash(percent) sendProgressToSplash(percent)
}) })
autoUpdater.on('update-downloaded', (info) => { autoUpdater.once('update-downloaded', (info) => {
console.log('[Updater] Update downloaded:', info.version) console.log('[Updater] Update downloaded:', info.version)
sendStatusToSplash('Установка обновления...') sendStatusToSplash('Установка обновления...')
// Install and restart // Install and restart
@@ -105,23 +107,18 @@ export function setupAutoUpdater(onComplete: () => void) {
}, 1500) }, 1500)
}) })
autoUpdater.on('error', (error) => { autoUpdater.once('error', (error) => {
console.error('[Updater] Error:', error) console.error('[Updater] Error:', error.message)
sendStatusToSplash('Ошибка проверки обновлений') console.error('[Updater] Error stack:', error.stack)
setTimeout(() => { sendStatusToSplash('Запуск...')
closeSplashWindow() setTimeout(safeComplete, 1500)
onComplete()
}, 2000)
}) })
// Start checking // Start checking
autoUpdater.checkForUpdates().catch((error) => { autoUpdater.checkForUpdates().catch((error) => {
console.error('[Updater] Failed to check for updates:', error) console.error('[Updater] Failed to check for updates:', error)
sendStatusToSplash('Не удалось проверить обновления') sendStatusToSplash('Запуск...')
setTimeout(() => { setTimeout(safeComplete, 1500)
closeSplashWindow()
onComplete()
}, 2000)
}) })
} }

View File

@@ -52,6 +52,7 @@ const electronAPI = {
// Window controls // Window controls
minimizeToTray: (): void => ipcRenderer.send('minimize-to-tray'), minimizeToTray: (): void => ipcRenderer.send('minimize-to-tray'),
closeWindow: (): void => ipcRenderer.send('close-window'),
quitApp: (): void => ipcRenderer.send('quit-app'), quitApp: (): void => ipcRenderer.send('quit-app'),
// Monitoring control // Monitoring control

View File

@@ -32,7 +32,7 @@ export function Layout({ children }: LayoutProps) {
<Minus className="w-4 h-4 text-gray-400" /> <Minus className="w-4 h-4 text-gray-400" />
</button> </button>
<button <button
onClick={() => window.electronAPI.quitApp()} onClick={() => window.electronAPI.closeWindow()}
className="w-8 h-8 flex items-center justify-center hover:bg-red-600 transition-colors" className="w-8 h-8 flex items-center justify-center hover:bg-red-600 transition-colors"
> >
<X className="w-4 h-4 text-gray-400" /> <X className="w-4 h-4 text-gray-400" />