hydra/src/main/services/window-manager.ts

216 lines
5.5 KiB
TypeScript
Raw Normal View History

import {
BrowserWindow,
Menu,
MenuItem,
MenuItemConstructorOptions,
Tray,
app,
shell,
} from "electron";
2024-04-25 07:52:19 +03:00
import { is } from "@electron-toolkit/utils";
2024-04-21 08:26:29 +03:00
import { t } from "i18next";
import path from "node:path";
2024-04-29 13:01:34 +03:00
import icon from "@resources/icon.png?asset";
import trayIcon from "@resources/tray-icon.png?asset";
import { gameRepository, userPreferencesRepository } from "@main/repository";
import { IsNull, Not } from "typeorm";
2024-04-21 08:26:29 +03:00
export class WindowManager {
public static mainWindow: Electron.BrowserWindow | null = null;
2024-05-18 06:13:43 +03:00
public static splashWindow: Electron.BrowserWindow | null = null;
public static isReadyToShowMainWindow = false;
2024-04-21 08:26:29 +03:00
2024-04-25 07:52:19 +03:00
private static loadURL(hash = "") {
// 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"]) {
2024-04-25 22:54:38 +03:00
this.mainWindow?.loadURL(
2024-04-25 07:52:19 +03:00
`${process.env["ELECTRON_RENDERER_URL"]}#/${hash}`
);
} else {
2024-04-25 22:54:38 +03:00
this.mainWindow?.loadFile(
path.join(__dirname, "../renderer/index.html"),
{
hash,
}
);
2024-04-25 07:52:19 +03:00
}
}
2024-05-18 06:13:43 +03:00
private static loadSplashURL() {
// 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"]) {
this.splashWindow?.loadURL(
2024-05-19 07:39:50 +03:00
`${process.env["ELECTRON_RENDERER_URL"]}#/splash`
2024-05-18 06:13:43 +03:00
);
} else {
this.splashWindow?.loadFile(
2024-05-19 07:39:50 +03:00
path.join(__dirname, "../renderer/index.html"),
{
hash: "splash",
}
2024-05-18 06:13:43 +03:00
);
}
}
public static createSplashScreen() {
if (this.splashWindow) return;
2024-05-18 06:13:43 +03:00
this.splashWindow = new BrowserWindow({
width: 380,
height: 380,
2024-05-19 20:15:07 +03:00
frame: false,
resizable: false,
backgroundColor: "#1c1c1c",
2024-05-19 07:39:50 +03:00
webPreferences: {
preload: path.join(__dirname, "../preload/index.mjs"),
sandbox: false,
},
2024-05-18 06:13:43 +03:00
});
this.loadSplashURL();
2024-05-19 04:29:11 +03:00
this.splashWindow.removeMenu();
2024-05-18 06:13:43 +03:00
}
public static createMainWindow() {
if (this.mainWindow || !this.isReadyToShowMainWindow) return;
2024-04-21 08:26:29 +03:00
this.mainWindow = new BrowserWindow({
width: 1200,
height: 720,
minWidth: 1024,
minHeight: 540,
backgroundColor: "#1c1c1c",
2024-04-21 08:26:29 +03:00
titleBarStyle: "hidden",
2024-05-03 19:17:53 +03:00
...(process.platform === "linux" ? { icon } : {}),
trafficLightPosition: { x: 16, y: 16 },
2024-04-21 08:26:29 +03:00
titleBarOverlay: {
symbolColor: "#DADBE1",
color: "#151515",
height: 34,
},
webPreferences: {
preload: path.join(__dirname, "../preload/index.mjs"),
sandbox: false,
},
});
2024-04-25 07:52:19 +03:00
this.loadURL();
2024-04-21 08:26:29 +03:00
this.mainWindow.removeMenu();
this.mainWindow.on("ready-to-show", () => {
if (!app.isPackaged) WindowManager.mainWindow?.webContents.openDevTools();
});
this.mainWindow.on("close", async () => {
const userPreferences = await userPreferencesRepository.findOne({
where: { id: 1 },
});
if (userPreferences?.preferQuitInsteadOfHiding) {
app.quit();
}
WindowManager.mainWindow?.setProgressBar(-1);
2024-04-21 08:26:29 +03:00
});
}
public static prepareMainWindowAndCloseSplash() {
this.isReadyToShowMainWindow = true;
this.splashWindow?.close();
this.createMainWindow();
}
2024-04-25 07:52:19 +03:00
public static redirect(hash: string) {
2024-04-21 08:26:29 +03:00
if (!this.mainWindow) this.createMainWindow();
2024-04-25 07:52:19 +03:00
this.loadURL(hash);
2024-04-21 08:26:29 +03:00
2024-04-25 22:54:38 +03:00
if (this.mainWindow?.isMinimized()) this.mainWindow.restore();
this.mainWindow?.focus();
2024-04-21 08:26:29 +03:00
}
public static createSystemTray(language: string) {
2024-04-25 07:52:19 +03:00
const tray = new Tray(trayIcon);
2024-04-21 08:26:29 +03:00
const updateSystemTray = async () => {
const games = await gameRepository.find({
where: {
isDeleted: false,
executablePath: Not(IsNull()),
lastTimePlayed: Not(IsNull()),
2024-04-21 08:26:29 +03:00
},
take: 5,
order: {
updatedAt: "DESC",
},
});
const recentlyPlayedGames: Array<MenuItemConstructorOptions | MenuItem> =
games.map(({ title, executablePath }) => ({
label: title,
type: "normal",
click: async () => {
if (!executablePath) return;
shell.openPath(executablePath);
},
}));
const contextMenu = Menu.buildFromTemplate([
{
label: t("open", {
ns: "system_tray",
lng: language,
}),
type: "normal",
click: () => {
if (this.mainWindow) {
this.mainWindow.show();
} else {
this.createMainWindow();
}
},
},
{
type: "separator",
},
...recentlyPlayedGames,
{
type: "separator",
},
{
label: t("quit", {
ns: "system_tray",
lng: language,
}),
type: "normal",
click: () => app.quit(),
},
]);
return contextMenu;
};
2024-04-21 08:26:29 +03:00
tray.setToolTip("Hydra");
if (process.platform === "win32" || process.platform === "linux") {
2024-04-21 08:26:29 +03:00
tray.addListener("click", () => {
if (this.mainWindow) {
2024-04-25 22:54:38 +03:00
if (WindowManager.mainWindow?.isMinimized())
2024-04-21 08:26:29 +03:00
WindowManager.mainWindow.restore();
2024-04-25 22:54:38 +03:00
WindowManager.mainWindow?.focus();
2024-04-21 08:26:29 +03:00
return;
}
this.createMainWindow();
});
tray.addListener("right-click", async () => {
const contextMenu = await updateSystemTray();
tray.popUpContextMenu(contextMenu);
});
2024-04-21 08:26:29 +03:00
}
}
}