1
0
mirror of https://github.com/TheFunny/ArisuAutoSweeper synced 2026-01-01 15:05:20 +00:00
ArisuAutoSweeper/webapp/packages/main/src/mainWindow.ts
2023-11-01 15:33:35 +08:00

271 lines
7.3 KiB
TypeScript

import {
app,
BrowserWindow,
globalShortcut,
ipcMain,
Menu,
nativeTheme,
Tray,
nativeImage,
} from 'electron';
import {URL} from 'node:url';
import {PyShell} from '/@/pyshell';
import {
dpiScaling,
webuiTheme,
webuiArgs,
webuiPath,
installerPath,
installerArgs,
} from '/@/config';
import {isMacintosh} from '@common/utils/env';
import relaunchApp from '/@/relaunchApp';
import {ALAS_LOG, UPDATE_APP} from '@common/constant/eventNames';
const path = require('path');
/**
* Load deploy settings and start Alas web server.
*/
let installer: PyShell | null = null;
let alas: PyShell | null = null;
let browserWindow: BrowserWindow | null = null;
nativeTheme.themeSource = webuiTheme;
export async function createWindow() {
browserWindow = new BrowserWindow({
width: 1280,
height: 880,
show: false, // Use 'ready-to-show' event to show window
frame: false,
icon: path.join(__dirname, './icon.png'),
webPreferences: {
nodeIntegration: true,
contextIsolation: true,
sandbox: false, // Sandbox disabled because the demo of preload script depend on the Node.js api
webviewTag: false, // The webview tag is not recommended. Consider alternatives like an iframe or Electron's BrowserView. @see https://www.electronjs.org/docs/latest/api/webview-tag#warning
preload: path.join(app.getAppPath(), 'packages/preload/dist/index.cjs'),
},
});
/**
* If the 'show' property of the BrowserWindow's constructor is omitted from the initialization options,
* it then defaults to 'true'. This can cause flickering as the window loads the html content,
* and it also has show problematic behaviour with the closing of the window.
* Use `show: false` and listen to the `ready-to-show` event to show the window.
*
* @see https://github.com/electron/electron/issues/25012 for the afford mentioned issue.
*/
browserWindow.on('ready-to-show', () => {
browserWindow?.show();
// Hide menu
const {Menu} = require('electron');
Menu.setApplicationMenu(null);
if (import.meta.env.DEV) {
browserWindow?.webContents.openDevTools();
}
});
browserWindow.on('focus', function () {
// Dev tools
globalShortcut.register('Ctrl+Shift+I', function () {
if (browserWindow?.webContents.isDevToolsOpened()) {
browserWindow?.webContents.closeDevTools();
} else {
browserWindow?.webContents.openDevTools();
}
});
// Refresh
globalShortcut.register('Ctrl+R', function () {
browserWindow?.reload();
});
globalShortcut.register('Ctrl+Shift+R', function () {
browserWindow?.reload();
});
});
browserWindow.on('blur', function () {
globalShortcut.unregisterAll();
});
ipcMain.on('window-ready', async function (_, args) {
args && (await initWindowEvents());
});
/*
* Fix oversize icon on bar in macOS
*/
const icon = nativeImage.createFromPath(path.join(__dirname, './icon.png'));
const dockerIcon = icon.resize({width: 16, height: 16});
// Tray
const tray = new Tray(isMacintosh ? dockerIcon : icon);
const contextMenu = Menu.buildFromTemplate([
{
label: 'Show',
click: function () {
browserWindow?.show();
},
},
{
label: 'Hide',
click: function () {
browserWindow?.hide();
},
},
{
label: 'Exit',
click: function () {
alas?.kill(function () {
browserWindow?.close();
});
},
},
]);
tray.setToolTip('AAS');
tray.setContextMenu(contextMenu);
tray.on('click', () => {
if (browserWindow?.isVisible()) {
if (browserWindow?.isMinimized()) {
browserWindow?.show();
} else {
browserWindow?.hide();
}
} else {
browserWindow?.show();
}
});
tray.on('right-click', () => {
tray.popUpContextMenu(contextMenu);
});
return browserWindow;
}
// No DPI scaling
if (!dpiScaling) {
app.commandLine.appendSwitch('high-dpi-support', '1');
app.commandLine.appendSwitch('force-device-scale-factor', '1');
}
export function loadURL() {
/**
* URL for main window.
* Vite dev server for development.
* `file://../renderer/index.html` for production and test
*/
const pageUrl =
import.meta.env.DEV && import.meta.env.VITE_DEV_SERVER_URL !== undefined
? import.meta.env.VITE_DEV_SERVER_URL
: new URL('../renderer/dist/index.html', 'file://' + __dirname).toString();
browserWindow?.loadURL(pageUrl);
}
// Minimize, maximize, close window.
ipcMain.on('window-tray', function () {
browserWindow?.hide();
});
ipcMain.on('window-min', function () {
browserWindow?.minimize();
});
ipcMain.on('window-max', function () {
browserWindow?.isMaximized() ? browserWindow?.restore() : browserWindow?.maximize();
});
ipcMain.on('window-close', function () {
if (installer) {
installer?.removeAllListeners('stderr');
installer?.removeAllListeners('message');
installer?.removeAllListeners('stdout');
installer?.kill(function () {
browserWindow?.close();
browserWindow = null;
installer = null;
});
return;
}
alas?.removeAllListeners('stderr');
alas?.removeAllListeners('message');
alas?.removeAllListeners('stdout');
alas?.kill(function () {
browserWindow?.close();
browserWindow = null;
});
browserWindow?.close();
});
async function initWindowEvents() {
// Start installer and wait for it to finish.
await runInstaller();
ipcMain.on('install-success', async function () {
installer = null;
// Start Alas web server.
runAlas();
});
}
async function runInstaller() {
installer = new PyShell(installerPath, installerArgs);
installer?.end(function (err: string) {
sendLaunchLog(err);
if (err) throw err;
});
installer?.on('stdout', function (message) {
sendLaunchLog(message);
});
installer?.on('message', function (message) {
sendLaunchLog(message);
});
installer?.on('stderr', function (message: string) {
sendLaunchLog(message);
});
}
function runAlas() {
alas = new PyShell(webuiPath, webuiArgs);
alas?.end(function (err: string) {
sendLaunchLog(err);
if (err) throw err;
});
alas?.on('stdout', function (message) {
sendLaunchLog(message);
});
alas?.on('message', function (message) {
sendLaunchLog(message);
});
alas?.on('stderr', function (message: string) {
sendLaunchLog(message);
/**
* Receive logs, judge if Alas is ready
* For starlette backend, there will have:
* `INFO: Uvicorn running on http://0.0.0.0:22267 (Press CTRL+C to quit)`
* Or backend has started already
* `[Errno 10048] error while attempting to bind on address ('0.0.0.0', 22267): `
*/
if (message.includes('Application startup complete') || message.includes('bind on address')) {
alas?.removeAllListeners('stderr');
alas?.removeAllListeners('message');
alas?.removeAllListeners('stdout');
// loadURL();
}
});
}
function sendLaunchLog(message: string) {
message?.includes(UPDATE_APP) && relaunchApp();
browserWindow?.webContents.send(ALAS_LOG, message);
}
export async function restoreWindow() {
// Someone tried to run a second instance, we should focus our window.
if (browserWindow) {
if (browserWindow.isMinimized()) browserWindow.restore();
if (!browserWindow.isVisible()) browserWindow.show();
browserWindow.focus();
}
}