210 Zeilen
5.0 KiB
JavaScript
210 Zeilen
5.0 KiB
JavaScript
const { app, BrowserWindow, ipcMain, Menu, Tray } = require('electron')
|
|
const path = require('path')
|
|
const { spawn } = require('child_process')
|
|
const isDev = process.env.NODE_ENV === 'development' || (!app.isPackaged && !process.env.NODE_ENV)
|
|
|
|
let mainWindow
|
|
let tray
|
|
let backendProcess
|
|
|
|
function createWindow() {
|
|
mainWindow = new BrowserWindow({
|
|
width: 1400,
|
|
height: 900,
|
|
minWidth: 1200,
|
|
minHeight: 700,
|
|
webPreferences: {
|
|
nodeIntegration: false,
|
|
contextIsolation: true,
|
|
preload: path.join(__dirname, 'preload.js')
|
|
},
|
|
icon: path.join(__dirname, '../public/icon.png'),
|
|
titleBarStyle: 'hiddenInset',
|
|
frame: process.platform !== 'win32',
|
|
backgroundColor: '#F8FAFC'
|
|
})
|
|
|
|
if (isDev) {
|
|
mainWindow.loadURL('http://localhost:5173')
|
|
mainWindow.webContents.openDevTools()
|
|
} else {
|
|
// In production, load the built files
|
|
const indexPath = path.join(__dirname, '../dist/index.html')
|
|
console.log('Loading:', indexPath)
|
|
mainWindow.loadFile(indexPath)
|
|
|
|
// DevTools nur öffnen wenn explizit gewünscht
|
|
// mainWindow.webContents.openDevTools()
|
|
|
|
// Log any errors
|
|
mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription) => {
|
|
console.error('Failed to load:', errorCode, errorDescription)
|
|
})
|
|
|
|
mainWindow.webContents.on('console-message', (event, level, message) => {
|
|
console.log('Console:', message)
|
|
})
|
|
|
|
// Warte bis Seite geladen ist
|
|
mainWindow.webContents.on('did-finish-load', () => {
|
|
console.log('Page loaded successfully')
|
|
})
|
|
}
|
|
|
|
mainWindow.on('closed', () => {
|
|
mainWindow = null
|
|
})
|
|
|
|
// Custom window controls for Windows
|
|
if (process.platform === 'win32') {
|
|
mainWindow.on('maximize', () => {
|
|
mainWindow.webContents.send('window-maximized')
|
|
})
|
|
|
|
mainWindow.on('unmaximize', () => {
|
|
mainWindow.webContents.send('window-unmaximized')
|
|
})
|
|
}
|
|
}
|
|
|
|
function createTray() {
|
|
// Tray-Funktion vorerst deaktiviert, da Icon fehlt
|
|
// TODO: Tray-Icon hinzufügen
|
|
return
|
|
|
|
tray = new Tray(path.join(__dirname, '../public/tray-icon.png'))
|
|
|
|
const contextMenu = Menu.buildFromTemplate([
|
|
{
|
|
label: 'SkillMate öffnen',
|
|
click: () => {
|
|
if (mainWindow) {
|
|
mainWindow.show()
|
|
} else {
|
|
createWindow()
|
|
}
|
|
}
|
|
},
|
|
{ type: 'separator' },
|
|
{
|
|
label: 'Beenden',
|
|
click: () => {
|
|
app.quit()
|
|
}
|
|
}
|
|
])
|
|
|
|
tray.setToolTip('SkillMate')
|
|
tray.setContextMenu(contextMenu)
|
|
|
|
tray.on('click', () => {
|
|
if (mainWindow) {
|
|
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show()
|
|
} else {
|
|
createWindow()
|
|
}
|
|
})
|
|
}
|
|
|
|
function startBackend() {
|
|
// Backend nur im Development-Modus automatisch starten
|
|
// In Production wird es extern gestartet
|
|
return
|
|
|
|
if (!isDev) {
|
|
// In production, backend is bundled with the app
|
|
const backendPath = app.isPackaged
|
|
? path.join(process.resourcesPath, 'backend', 'index.js')
|
|
: path.join(__dirname, '../../backend/dist/index.js')
|
|
|
|
console.log('Starting backend from:', backendPath)
|
|
|
|
// Check if backend exists
|
|
const fs = require('fs')
|
|
if (!fs.existsSync(backendPath)) {
|
|
console.error('Backend not found at:', backendPath)
|
|
// Try alternative path
|
|
const altPath = path.join(__dirname, '../backend/index.js')
|
|
console.log('Trying alternative path:', altPath)
|
|
if (fs.existsSync(altPath)) {
|
|
backendPath = altPath
|
|
}
|
|
}
|
|
|
|
backendProcess = spawn('node', [backendPath], {
|
|
env: {
|
|
...process.env,
|
|
NODE_ENV: 'production',
|
|
PORT: '3001',
|
|
DATABASE_PATH: path.join(app.getPath('userData'), 'skillmate.db'),
|
|
LOG_PATH: path.join(app.getPath('userData'), 'logs')
|
|
},
|
|
stdio: ['pipe', 'pipe', 'pipe']
|
|
})
|
|
|
|
backendProcess.stdout.on('data', (data) => {
|
|
console.log(`Backend: ${data}`)
|
|
})
|
|
|
|
backendProcess.stderr.on('data', (data) => {
|
|
console.error(`Backend Error: ${data}`)
|
|
})
|
|
|
|
backendProcess.on('error', (error) => {
|
|
console.error('Failed to start backend:', error)
|
|
})
|
|
|
|
backendProcess.on('exit', (code) => {
|
|
console.log(`Backend exited with code ${code}`)
|
|
})
|
|
}
|
|
}
|
|
|
|
app.whenReady().then(() => {
|
|
createWindow()
|
|
createTray()
|
|
startBackend()
|
|
})
|
|
|
|
app.on('window-all-closed', () => {
|
|
if (process.platform !== 'darwin') {
|
|
app.quit()
|
|
}
|
|
})
|
|
|
|
app.on('before-quit', () => {
|
|
if (backendProcess) {
|
|
backendProcess.kill()
|
|
}
|
|
})
|
|
|
|
app.on('activate', () => {
|
|
if (mainWindow === null) {
|
|
createWindow()
|
|
}
|
|
})
|
|
|
|
// IPC handlers
|
|
ipcMain.handle('app:minimize', () => {
|
|
mainWindow.minimize()
|
|
})
|
|
|
|
ipcMain.handle('app:maximize', () => {
|
|
if (mainWindow.isMaximized()) {
|
|
mainWindow.unmaximize()
|
|
} else {
|
|
mainWindow.maximize()
|
|
}
|
|
})
|
|
|
|
ipcMain.handle('app:close', () => {
|
|
mainWindow.close()
|
|
})
|
|
|
|
ipcMain.handle('app:getVersion', () => {
|
|
return app.getVersion()
|
|
})
|
|
|
|
ipcMain.handle('app:getPath', (event, name) => {
|
|
return app.getPath(name)
|
|
}) |