const { app, BrowserWindow, dialog, ipcMain, Menu, nativeImage, Tray, } = require('electron'); const AutoLaunch = require('auto-launch'); const Constants = require('../src/constants'); const fs = require('fs'); const helpers = require('../src/helpers'); const os = require('os'); const path = require('path'); const url = require('url'); const debug = require('electron-debug'); debug({ devToolsMode: 'undocked', isEnabled: true, showDevTools: !!process.env.ELECTRON_START_URL, }); require.extensions['.sh'] = function (module, filename) { module.exports = fs.readFileSync(filename, 'utf8'); }; const detectScript = require('./detect_linux.sh'); const AppIPC = require('../src/renderer/ipc/AppIPC'); const ConfigIPC = require('../src/renderer/ipc/ConfigIPC'); const DaemonIPC = require('../src/renderer/ipc/DaemonIPC'); const DependencyIPC = require('../src/renderer/ipc/DependencyIPC'); const DownloadIPC = require('../src/renderer/ipc/DownloadIPC'); const FilesystemIPC = require('../src/renderer/ipc/FilesystemIPC'); const MountsIPC = require('../src/renderer/ipc/MountsIPC'); const PinnedIPC = require('../src/renderer/ipc/PinnedIPC'); const PlatformIPC = require('../src/renderer/ipc/PlatformIPC'); const ReleaseIPC = require('../src/renderer/ipc/ReleaseIPC'); const SkynetIPC = require('../src/renderer/ipc/SkynetIPC'); const StateIPC = require('../src/renderer/ipc/StateIPC'); const SystemIPC = require('../src/renderer/ipc/SystemIPC'); const UpgradeIPC = require('../src/renderer/ipc/UpgradeIPC'); const platform = os.platform(); const dimensions = { height: platform === 'win32' ? 326 : platform === 'darwin' ? 322 : 400, width: platform === 'win32' ? 468 : 628, }; let isShutdown = false; let isQuitting = false; let isInstalling = false; let launchHidden = false; let cleanupReleases = false; let mainWindow; let mainWindowTray; let trayContextMenu; const closeApplication = () => { if (!isShutdown) { isShutdown = true; if (mainWindowTray) { mainWindowTray.destroy(); } app.quit(); } }; const configurePrimaryApp = () => { app.on('second-instance', () => { if (!isInstalling && mainWindow) { setWindowVisibility(true); } }); app.on('ready', createWindow); app.on('window-all-closed', () => { closeApplication(); }); }; const createWindow = () => { loadUiSettings(); let extra = {}; if (platform === 'linux') { extra = { icon: path.join(__dirname, '../build/', 'logo.png'), }; } // Create the browser window. mainWindow = new BrowserWindow({ height: dimensions.height, width: dimensions.width, fullscreen: false, resizable: false, show: !launchHidden, title: 'Repertory UI', ...extra, webPreferences: { nodeIntegration: true, webSecurity: !process.env.ELECTRON_START_URL, }, }); if (platform === 'linux') { mainWindow.setMenuBarVisibility(false); } else { mainWindow.removeMenu(); } if (platform === 'darwin' && launchHidden) { app.dock.hide(); } // and load the index.html of the app. const startUrl = process.env.ELECTRON_START_URL || url.format({ pathname: path.join(__dirname, '../build/index.html'), protocol: 'file:', slashes: true, }); mainWindow.on('close', function (event) { if (!isQuitting) { event.preventDefault(); if (mainWindow.isVisible()) { setWindowVisibility(false); } event.returnValue = false; } }); mainWindow.on('closed', function () { // Dereference the window object, usually you would store windows // in an array if your app supports multi windows, this is the time // when you should delete the corresponding element. mainWindow = null; MountsIPC.unmountAllDrives(); }); const appPath = platform === 'win32' ? path.resolve(path.join(app.getAppPath(), '..\\..\\repertory-ui.exe')) : platform === 'darwin' ? path.resolve( path.join(path.dirname(app.getAppPath()), '../MacOS/repertory-ui') ) : process.env.APPIMAGE; const autoLauncher = new AutoLaunch({ name: 'Repertory UI', path: appPath, }); trayContextMenu = Menu.buildFromTemplate([ { label: 'Visible', type: 'checkbox', click(item) { setWindowVisibility(item.checked); }, checked: !launchHidden, }, { type: 'separator' }, { label: 'Auto-start', type: 'checkbox', click(item) { if (item.checked) { autoLauncher.enable(); } else { autoLauncher.disable(); } }, }, { label: 'Launch Hidden', type: 'checkbox', click(item) { launchHidden = !!item.checked; saveUiSettings(); }, checked: launchHidden, }, { type: 'separator' }, { label: 'Delete Old Releases', type: 'checkbox', click(item) { cleanupReleases = !!item.checked; saveUiSettings(); }, checked: cleanupReleases, }, { type: 'separator' }, { label: 'Exit and Unmount', click() { closeApplication(); }, }, ]); const image = nativeImage.createFromPath( path.join( __dirname, platform === 'darwin' ? '../build/logo_mac.png' : '../build/logo.png' ) ); mainWindowTray = new Tray(image); autoLauncher .isEnabled() .then((enabled) => { trayContextMenu.items[2].checked = enabled; mainWindowTray.setToolTip('Repertory UI'); mainWindowTray.setContextMenu(trayContextMenu); }) .catch(() => { closeApplication(); }); mainWindow.loadURL(startUrl); }; const getMainWindow = () => { return mainWindow; }; const loadUiSettings = () => { const settingFile = path.join( helpers.resolvePath(Constants.DATA_LOCATIONS[platform]), 'ui.json' ); try { if (fs.statSync(settingFile).isFile()) { const settings = JSON.parse(fs.readFileSync(settingFile, 'utf8')); launchHidden = !!settings.launch_hidden; cleanupReleases = !!settings.cleanup_releases; PlatformIPC.setPlatformOverride(settings.platform_override); } } catch (e) {} }; const saveUiSettings = () => { const settingFile = path.join(helpers.getDataDirectory(), 'ui.json'); try { fs.writeFileSync( settingFile, JSON.stringify({ cleanup_releases: cleanupReleases, launch_hidden: launchHidden, platform_override: PlatformIPC.getPlatformOverride(), }), 'utf-8' ); } catch (e) {} }; const setIsInstalling = (installing) => { isInstalling = installing; }; const setTrayImage = (driveInUse) => { let image; if (driveInUse) { image = nativeImage.createFromPath( path.join( __dirname, platform === 'darwin' ? '../build/logo_both_mac.png' : '../build/logo_both.png' ) ); } else { image = nativeImage.createFromPath( path.join( __dirname, platform === 'darwin' ? '../build/logo_mac.png' : '../build/logo.png' ) ); } mainWindowTray.setImage(image); }; const setWindowVisibility = (show) => { if (show) { mainWindow.show(); if (platform === 'darwin') { app.dock.show(); } else if (platform === 'linux') { mainWindow.setSize(dimensions.width, dimensions.height); } if (mainWindow.isMinimized()) { mainWindow.restore(); } mainWindow.focus(); } else { mainWindow.hide(); if (platform === 'darwin') { app.dock.hide(); } } if (trayContextMenu && mainWindowTray) { trayContextMenu.items[0].checked = show; mainWindowTray.setContextMenu(trayContextMenu); } }; const standardIPCReply = (event, channel, data, error) => { if (mainWindow) { event.sender.send(channel, { data: { ...data, Error: error instanceof Error ? error.toString() : error, Success: !error, }, }); } }; app.on('before-quit', function () { isQuitting = true; }); let instanceLock = app.requestSingleInstanceLock(); if (!instanceLock) { setTimeout(() => { if ((instanceLock = app.requestSingleInstanceLock())) { configurePrimaryApp(); } else { closeApplication(); } }, 3000); } else { configurePrimaryApp(); } const AppFunctions = { closeApplication, detectScript, dialog, getCleanupReleases: () => cleanupReleases, getMainWindow, saveUiSettings, setIsInstalling, setTrayImage, setWindowVisibility, standardIPCReply, unmountAllDrives: MountsIPC.unmountAllDrives, }; AppIPC.addListeners(ipcMain, AppFunctions); ConfigIPC.addListeners(ipcMain, AppFunctions); DaemonIPC.addListeners(ipcMain, AppFunctions); DependencyIPC.addListeners(ipcMain, AppFunctions); DownloadIPC.addListeners(ipcMain, AppFunctions); FilesystemIPC.addListeners(ipcMain, AppFunctions); MountsIPC.addListeners(ipcMain, AppFunctions); PinnedIPC.addListeners(ipcMain, AppFunctions); PlatformIPC.addListeners(ipcMain, AppFunctions); ReleaseIPC.addListeners(ipcMain, AppFunctions); SkynetIPC.addListeners(ipcMain, AppFunctions); StateIPC.addListeners(ipcMain, AppFunctions); SystemIPC.addListeners(ipcMain, AppFunctions); UpgradeIPC.addListeners(ipcMain, AppFunctions);