Files
rmtPocketWatcher/electron-app/src/main/index.ts

176 lines
4.5 KiB
TypeScript

import { app, BrowserWindow, Tray, Menu, nativeImage } from 'electron';
import * as path from 'path';
import { fileURLToPath } from 'url';
import * as dotenv from 'dotenv';
import { setupIpcHandlers, cleanupIpcHandlers } from './ipc-handlers.js';
import { initDatabase, closeDatabase } from './database.js';
// ES module equivalent of __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Load environment variables from .env file
// In dev: __dirname = dist/main, so go up to electron-app root
// In prod: __dirname = resources/app.asar/dist/main, .env should be in resources
const envPath = process.env.NODE_ENV === 'development'
? path.join(__dirname, '../../.env')
: path.join(process.resourcesPath, '.env');
dotenv.config({ path: envPath });
console.log('Loading .env from:', envPath);
console.log('WS_URL:', process.env.WS_URL);
console.log('API_URL:', process.env.API_URL);
let mainWindow: BrowserWindow | null = null;
let tray: Tray | null = null;
const isDev = process.env.NODE_ENV === 'development';
function getIconPath(): string {
if (isDev) {
return process.platform === 'win32'
? path.join(__dirname, '../../resources/icons/icon.ico')
: path.join(__dirname, '../../resources/icons/logo.png');
}
return process.platform === 'win32'
? path.join(process.resourcesPath, 'icons', 'icon.ico')
: path.join(process.resourcesPath, 'icons', 'logo.png');
}
function createWindow(): void {
const iconPath = getIconPath();
console.log('Window icon path:', iconPath);
mainWindow = new BrowserWindow({
width: 1400,
height: 900,
minWidth: 1000,
minHeight: 700,
frame: false,
backgroundColor: '#0a0e27',
icon: iconPath,
show: false, // Don't show until loaded
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false,
contextIsolation: true,
sandbox: true,
devTools: true, // Enable dev tools in production for debugging
},
title: 'rmtPocketWatcher',
});
// Setup IPC handlers for WebSocket communication
setupIpcHandlers(mainWindow);
// Load the app
if (isDev) {
mainWindow.loadURL('http://localhost:5173');
mainWindow.webContents.openDevTools();
} else {
const rendererPath = path.join(__dirname, '../renderer/index.html');
console.log('Loading renderer from:', rendererPath);
mainWindow.loadFile(rendererPath).catch(err => {
console.error('Failed to load renderer:', err);
});
}
// Show window and open dev tools to see errors
mainWindow.webContents.on('did-fail-load', (_event, errorCode, errorDescription) => {
console.error('Failed to load:', errorCode, errorDescription);
});
mainWindow.webContents.on('did-finish-load', () => {
console.log('Window loaded successfully');
mainWindow?.show();
});
mainWindow.on('closed', () => {
cleanupIpcHandlers();
mainWindow = null;
});
}
function createTray(): void {
// In dev: __dirname = dist/main, logo is at root
// In prod: __dirname = resources/app.asar/dist/main
const iconPath = getIconPath();
console.log('Tray icon path:', iconPath);
let icon = nativeImage.createFromPath(iconPath);
if (process.platform !== 'win32') {
icon = icon.resize({ width: 16, height: 16 });
}
tray = new Tray(icon);
const contextMenu = Menu.buildFromTemplate([
{
label: 'Show rmtPocketWatcher',
click: () => {
if (mainWindow) {
mainWindow.show();
mainWindow.focus();
}
}
},
{
label: 'Open DevTools',
click: () => {
if (mainWindow) {
mainWindow.webContents.openDevTools();
}
}
},
{
label: 'Reload',
click: () => {
if (mainWindow) {
mainWindow.reload();
}
}
},
{
label: 'Quit',
click: () => {
app.quit();
}
}
]);
tray.setToolTip('rmtPocketWatcher');
tray.setContextMenu(contextMenu);
// Double-click to show window
tray.on('double-click', () => {
if (mainWindow) {
mainWindow.show();
mainWindow.focus();
}
});
}
app.whenReady().then(() => {
initDatabase();
createTray();
createWindow();
});
app.on('window-all-closed', () => {
// Quit the app when all windows are closed
app.quit();
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
app.on('before-quit', () => {
cleanupIpcHandlers();
closeDatabase();
});