import { electronApp, is, optimizer } from '@electron-toolkit/utils' import { app, BrowserWindow, ipcMain, safeStorage, shell } from 'electron' import { join } from 'path' import icon from '../../resources/icon.png?asset' import { NostrService } from './services/nostr.service' import { StorageService } from './services/storage.service' import { ThemeService } from './services/theme.service' import { TSendToRenderer } from './types' let mainWindow: BrowserWindow | null = null function createWindow(): void { // Create the browser window. mainWindow = new BrowserWindow({ width: 900, height: 670, show: false, autoHideMenuBar: true, ...(process.platform === 'linux' ? { icon } : {}), webPreferences: { preload: join(__dirname, '../preload/index.js'), sandbox: false }, titleBarStyle: process.platform === 'darwin' ? 'hiddenInset' : undefined }) mainWindow.on('ready-to-show', () => { mainWindow?.show() }) mainWindow.on('closed', () => { mainWindow = null }) mainWindow.webContents.setWindowOpenHandler((details) => { shell.openExternal(details.url) return { action: 'deny' } }) // HMR for renderer base on electron-vite cli. // Load the remote URL for development or the local html file for production. if (is.dev && process.env['ELECTRON_RENDERER_URL']) { mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']) } else { mainWindow.loadFile(join(__dirname, '../renderer/index.html')) } if (is.dev) { mainWindow.webContents.openDevTools() } } // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.whenReady().then(async () => { // Set app user model id for windows electronApp.setAppUserModelId('com.jumble') // Default open or close DevTools by F12 in development // and ignore CommandOrControl + R in production. // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils app.on('browser-window-created', (_, window) => { optimizer.watchWindowShortcuts(window) }) const sendToRenderer: TSendToRenderer = (channel, ...args) => { mainWindow?.webContents.send(channel, ...args) } const storageService = new StorageService() storageService.init() const themeService = new ThemeService(sendToRenderer) themeService.init() const nostrService = new NostrService() nostrService.init() ipcMain.handle('system:isEncryptionAvailable', () => safeStorage.isEncryptionAvailable()) ipcMain.handle('system:getSelectedStorageBackend', () => { if (process.platform === 'darwin') { return 'keychain' } if (process.platform === 'win32') { return 'dpapi' } return safeStorage.getSelectedStorageBackend() }) createWindow() app.on('activate', function () { // On macOS it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (BrowserWindow.getAllWindows().length === 0) createWindow() }) }) // Quit when all windows are closed, except on macOS. There, it's common // for applications and their menu bar to stay active until the user quits // explicitly with Cmd + Q. app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) // In this file you can include the rest of your app"s specific main process // code. You can also put them in separate files and require them here.