import { app, BrowserWindow, ipcMain, dialog } from 'electron'; import { fileURLToPath } from 'url'; import { dirname, join, resolve } from 'path'; import { existsSync, readFileSync, writeFile, writeFileSync } from 'fs'; import pkg from 'electron-updater'; const { autoUpdater } = pkg; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); function getCarOptionsPath() { return app.isPackaged ? join(process.resourcesPath, 'carOptions.json') : resolve(__dirname, '..', 'src', 'frontend', 'carOptions.json'); } function getSharedCarsPath() { return join(getDefaultCarsFolder(), 'shared-cars.json'); } function getSettingsPath() { return join(app.getPath('userData'), 'kenteken-settings.json'); } function getDefaultCarsFolder() { return app.isPackaged ? app.getPath('userData') : resolve(__dirname, '..'); } function normalizeCarsFolder(folder) { if (!folder || typeof folder !== 'string') { return ''; } if (!existsSync(folder)) { return ''; } return folder; } function loadSettings() { // Persist the chosen cars folder so users can keep using the same location. try { const raw = readFileSync(getSettingsPath(), 'utf-8'); const parsed = JSON.parse(raw); const carsFolder = normalizeCarsFolder(parsed?.carsFolder); return { carsFolder }; } catch { return { carsFolder: '' }; } } function saveSettings(nextSettings) { writeFileSync(getSettingsPath(), JSON.stringify(nextSettings, null, 2)); } function getCarsFolder() { return settings.carsFolder || getDefaultCarsFolder(); } function setCarsFolder(folder) { const normalized = normalizeCarsFolder(folder); settings.carsFolder = normalized; saveSettings(settings); storeFile = join(getCarsFolder(), 'shared-cars.json'); } function loadBaseCarOptions() { const p = getCarOptionsPath(); const json = readFileSync(p, 'utf-8'); return JSON.parse(json); } function createWindow() { const win = new BrowserWindow({ width: 1024, height: 768, webPreferences: { contextIsolation: true, nodeIntegration: false, preload: join(__dirname, 'preload.cjs'), }, }); if (app.isPackaged) { win.loadFile(join(__dirname, '../dist/index.html')); } else { win.loadURL('http://localhost:5173'); win.webContents.openDevTools(); } } let storeFile; let cars = []; let saveTimer; let settings = { carsFolder: '' }; function loadCars() { try { const data = JSON.parse(readFileSync(storeFile, 'utf-8')); if (!Array.isArray(data)) throw new Error('Invalid data'); if ( !data.every( (c) => typeof c.name === 'string' && typeof c.width === 'number' && typeof c.height === 'number' ) ) { throw new Error('Invalid schema'); } cars = data; } catch { cars = loadBaseCarOptions(); saveCars(cars, true); } return cars; } function saveCars(newCars, immediate = false) { cars = newCars; const write = () => writeFile(storeFile, JSON.stringify(cars, null, 2), () => {}); if (immediate) { write(); } else { clearTimeout(saveTimer); saveTimer = setTimeout(write, 250); } } ipcMain.handle('cars:load', () => loadCars()); ipcMain.handle('cars:save', (_e, newCars) => { saveCars(newCars); return cars; }); ipcMain.handle('cars:folder:get', () => getCarsFolder()); ipcMain.handle('cars:folder:select', async () => { const result = await dialog.showOpenDialog({ properties: ['openDirectory', 'createDirectory'], }); if (result.canceled || !result.filePaths?.[0]) { return { canceled: true, folder: getCarsFolder(), cars }; } setCarsFolder(result.filePaths[0]); const updatedCars = loadCars(); return { canceled: false, folder: getCarsFolder(), cars: updatedCars }; }); ipcMain.handle('cars:folder:reset', () => { settings.carsFolder = ''; saveSettings(settings); storeFile = getSharedCarsPath(); const updatedCars = loadCars(); return { folder: getCarsFolder(), cars: updatedCars }; }); app.whenReady().then(() => { settings = loadSettings(); storeFile = settings.carsFolder ? join(getCarsFolder(), 'shared-cars.json') : getSharedCarsPath(); loadCars(); createWindow(); try { autoUpdater.checkForUpdatesAndNotify(); } catch (e) { // fail silently } app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } });