2023-09-25 14:41:13 +02:00

214 lines
5.2 KiB
TypeScript

import type { HandlerDetails } from 'electron';
import {
app, BrowserWindow, ipcMain, shell, systemPreferences,
} from 'electron';
import path from 'path';
import type { TrafficLightPosition } from '../types/electron';
import { ElectronAction, ElectronEvent } from '../types/electron';
import setupAutoUpdates from './autoUpdates';
import { processDeeplink } from './deeplink';
import tray from './tray';
import {
forceQuit, getAppTitle, getCurrentWindow, getLastWindow, hasExtraWindows, IS_MAC_OS, IS_WINDOWS,
TRAFFIC_LIGHT_POSITION, windows,
} from './utils';
import windowStateKeeper from './windowState';
const ALLOWED_DEVICE_ORIGINS = ['http://localhost:1234', 'file://'];
export function createWindow(url?: string) {
const windowState = windowStateKeeper({
defaultWidth: 1088,
defaultHeight: 700,
});
let x;
let y;
const currentWindow = getCurrentWindow();
if (currentWindow) {
const [currentWindowX, currentWindowY] = currentWindow.getPosition();
x = currentWindowX + 24;
y = currentWindowY + 24;
} else {
x = windowState.x;
y = windowState.y;
}
let width;
let height;
if (currentWindow) {
const bounds = currentWindow.getBounds();
width = bounds.width;
height = bounds.height;
} else {
width = windowState.width;
height = windowState.height;
}
const window = new BrowserWindow({
show: false,
x,
y,
minWidth: 360,
width,
height,
title: getAppTitle(),
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
devTools: process.env.APP_ENV !== 'production',
},
...(IS_MAC_OS && {
titleBarStyle: 'hidden',
trafficLightPosition: TRAFFIC_LIGHT_POSITION.standard,
}),
});
window.on('page-title-updated', (event: Event) => {
event.preventDefault();
});
windowState.manage(window);
window.webContents.setWindowOpenHandler((details: HandlerDetails) => {
shell.openExternal(details.url);
return { action: 'deny' };
});
window.webContents.session.setDevicePermissionHandler(({ deviceType, origin }) => {
return deviceType === 'hid' && ALLOWED_DEVICE_ORIGINS.includes(origin);
});
window.on('enter-full-screen', () => {
window.webContents.send(ElectronEvent.FULLSCREEN_CHANGE, true);
});
window.on('leave-full-screen', () => {
window.webContents.send(ElectronEvent.FULLSCREEN_CHANGE, false);
});
window.on('close', (event) => {
if (IS_MAC_OS || IS_WINDOWS) {
if (forceQuit.isEnabled) {
app.exit(0);
forceQuit.disable();
} else if (hasExtraWindows()) {
windows.delete(window);
windowState.unmanage();
} else {
event.preventDefault();
window.hide();
}
}
});
if (url) {
window.loadURL(url);
} else if (app.isPackaged) {
window.loadURL(`file://${__dirname}/index.html${windowState.urlHash}`);
} else {
window.loadURL(`http://localhost:1234${windowState.urlHash}`);
window.webContents.openDevTools();
}
windowState.clearLastUrlHash();
if (!IS_MAC_OS) {
window.removeMenu();
}
if (IS_WINDOWS && tray.isEnabled) {
tray.setupListeners(window);
tray.create();
}
window.webContents.once('dom-ready', () => {
window.show();
processDeeplink();
if (process.env.APP_ENV === 'production') {
setupAutoUpdates(window, windowState);
}
});
windows.add(window);
}
export function setupElectronActionHandlers() {
ipcMain.handle(ElectronAction.OPEN_NEW_WINDOW, (_, url: string) => {
createWindow(url);
});
ipcMain.handle(ElectronAction.SET_WINDOW_TITLE, (_, newTitle?: string) => {
getCurrentWindow()?.setTitle(getAppTitle(newTitle));
});
ipcMain.handle(ElectronAction.GET_IS_FULLSCREEN, () => {
getCurrentWindow()?.isFullScreen();
});
ipcMain.handle(ElectronAction.HANDLE_DOUBLE_CLICK, () => {
const currentWindow = getCurrentWindow();
const doubleClickAction = systemPreferences.getUserDefault('AppleActionOnDoubleClick', 'string');
if (doubleClickAction === 'Minimize') {
currentWindow?.minimize();
} else if (doubleClickAction === 'Maximize') {
if (!currentWindow?.isMaximized()) {
currentWindow?.maximize();
} else {
currentWindow?.unmaximize();
}
}
});
ipcMain.handle(ElectronAction.SET_TRAFFIC_LIGHT_POSITION, (_, position: TrafficLightPosition) => {
if (!IS_MAC_OS) {
return;
}
getCurrentWindow()?.setTrafficLightPosition(TRAFFIC_LIGHT_POSITION[position]);
});
ipcMain.handle(ElectronAction.SET_IS_TRAY_ICON_ENABLED, (_, value: boolean) => {
if (value) {
tray.enable();
} else {
tray.disable();
}
});
ipcMain.handle(ElectronAction.GET_IS_TRAY_ICON_ENABLED, () => tray.isEnabled);
}
export function setupCloseHandlers() {
app.on('window-all-closed', () => {
if (!IS_MAC_OS) {
app.quit();
}
});
app.on('before-quit', (event) => {
if (IS_MAC_OS && !forceQuit.isEnabled) {
event.preventDefault();
forceQuit.enable();
app.quit();
}
});
app.on('activate', () => {
const hasActiveWindow = BrowserWindow.getAllWindows().length > 0;
if (!hasActiveWindow) {
createWindow();
} else if (IS_MAC_OS) {
forceQuit.disable();
getLastWindow()?.show();
}
});
}