refactor: improve code formatting and consistency across components

- Updated button and span elements in ThemeToggle.vue and TopActions.vue for better readability.
- Enhanced UninstallConfirmModal.vue and UpdateAppsModal.vue with consistent indentation and spacing.
- Refactored downloadStatus.ts and storeConfig.ts for improved code clarity.
- Standardized string quotes and spacing in typedefinition.ts and processInstall.ts.
- Ensured consistent use of arrow functions and improved variable declarations throughout the codebase.
This commit is contained in:
Elysia
2026-02-12 18:32:41 +08:00
parent e11740ad4c
commit 6622e70033
29 changed files with 1681 additions and 1042 deletions

View File

@@ -1,11 +1,11 @@
import { ipcMain, WebContents } from 'electron';
import { spawn, ChildProcess, exec } from 'node:child_process';
import { promisify } from 'node:util';
import pino from 'pino';
import { ipcMain, WebContents } from "electron";
import { spawn, ChildProcess, exec } from "node:child_process";
import { promisify } from "node:util";
import pino from "pino";
import { ChannelPayload, InstalledAppInfo } from '../../typedefinition';
import { ChannelPayload, InstalledAppInfo } from "../../typedefinition";
const logger = pino({ 'name': 'install-manager' });
const logger = pino({ name: "install-manager" });
type InstallTask = {
id: number;
@@ -16,67 +16,69 @@ type InstallTask = {
webContents: WebContents | null;
};
const SHELL_CALLER_PATH = '/opt/apm-store/extras/shell-caller.sh';
const SHELL_CALLER_PATH = "/opt/apm-store/extras/shell-caller.sh";
export const tasks = new Map<number, InstallTask>();
let idle = true; // Indicates if the installation manager is idle
const checkSuperUserCommand = async (): Promise<string> => {
let superUserCmd = '';
let superUserCmd = "";
const execAsync = promisify(exec);
if (process.getuid && process.getuid() !== 0) {
const { stdout, stderr } = await execAsync('which /usr/bin/pkexec');
const { stdout, stderr } = await execAsync("which /usr/bin/pkexec");
if (stderr) {
logger.error('没有找到 pkexec 命令');
logger.error("没有找到 pkexec 命令");
return;
}
logger.info(`找到提升权限命令: ${stdout.trim()}`);
superUserCmd = stdout.trim();
if (superUserCmd.length === 0) {
logger.error('没有找到提升权限的命令 pkexec!');
logger.error("没有找到提升权限的命令 pkexec!");
}
}
return superUserCmd;
}
};
const runCommandCapture = async (execCommand: string, execParams: string[]) => {
return await new Promise<{ code: number; stdout: string; stderr: string }>((resolve) => {
const child = spawn(execCommand, execParams, {
shell: true,
env: process.env
});
return await new Promise<{ code: number; stdout: string; stderr: string }>(
(resolve) => {
const child = spawn(execCommand, execParams, {
shell: true,
env: process.env,
});
let stdout = '';
let stderr = '';
let stdout = "";
let stderr = "";
child.stdout?.on('data', (data) => {
stdout += data.toString();
});
child.stdout?.on("data", (data) => {
stdout += data.toString();
});
child.stderr?.on('data', (data) => {
stderr += data.toString();
});
child.stderr?.on("data", (data) => {
stderr += data.toString();
});
child.on('error', (err) => {
resolve({ code: -1, stdout, stderr: err.message });
});
child.on("error", (err) => {
resolve({ code: -1, stdout, stderr: err.message });
});
child.on('close', (code) => {
resolve({ code: typeof code === 'number' ? code : -1, stdout, stderr });
});
});
child.on("close", (code) => {
resolve({ code: typeof code === "number" ? code : -1, stdout, stderr });
});
},
);
};
const parseInstalledList = (output: string) => {
const apps: Array<InstalledAppInfo> = [];
const lines = output.split('\n');
const lines = output.split("\n");
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
if (trimmed.startsWith('Listing')) continue;
if (trimmed.startsWith('[INFO]')) continue;
if (trimmed.startsWith("Listing")) continue;
if (trimmed.startsWith("[INFO]")) continue;
const match = trimmed.match(/^(\S+)\/\S+,\S+\s+(\S+)\s+(\S+)\s+\[(.+)\]$/);
if (!match) continue;
@@ -85,32 +87,40 @@ const parseInstalledList = (output: string) => {
version: match[2],
arch: match[3],
flags: match[4],
raw: trimmed
raw: trimmed,
});
}
return apps;
};
const parseUpgradableList = (output: string) => {
const apps: Array<{ pkgname: string; newVersion: string; currentVersion: string; raw: string }> = [];
const lines = output.split('\n');
const apps: Array<{
pkgname: string;
newVersion: string;
currentVersion: string;
raw: string;
}> = [];
const lines = output.split("\n");
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
if (trimmed.startsWith('Listing')) continue;
if (trimmed.startsWith('[INFO]')) continue;
if (trimmed.includes('=') && !trimmed.includes('/')) continue;
if (trimmed.startsWith("Listing")) continue;
if (trimmed.startsWith("[INFO]")) continue;
if (trimmed.includes("=") && !trimmed.includes("/")) continue;
if (!trimmed.includes('/')) continue;
if (!trimmed.includes("/")) continue;
const tokens = trimmed.split(/\s+/);
if (tokens.length < 2) continue;
const pkgToken = tokens[0];
const pkgname = pkgToken.split('/')[0];
const newVersion = tokens[1] || '';
const currentMatch = trimmed.match(/\[(?:upgradable from|from):\s*([^\]\s]+)\]/i);
const currentToken = tokens[5] || '';
const currentVersion = currentMatch?.[1] || currentToken.replace('[', '').replace(']', '');
const pkgname = pkgToken.split("/")[0];
const newVersion = tokens[1] || "";
const currentMatch = trimmed.match(
/\[(?:upgradable from|from):\s*([^\]\s]+)\]/i,
);
const currentToken = tokens[5] || "";
const currentVersion =
currentMatch?.[1] || currentToken.replace("[", "").replace("]", "");
if (!pkgname) continue;
apps.push({ pkgname, newVersion, currentVersion, raw: trimmed });
@@ -119,30 +129,30 @@ const parseUpgradableList = (output: string) => {
};
// Listen for download requests from renderer process
ipcMain.on('queue-install', async (event, download_json) => {
ipcMain.on("queue-install", async (event, download_json) => {
const download = JSON.parse(download_json);
const { id, pkgname } = download || {};
if (!id || !pkgname) {
logger.warn('passed arguments missing id or pkgname');
logger.warn("passed arguments missing id or pkgname");
return;
}
logger.info(`收到下载任务: ${id}, 软件包名称: ${pkgname}`);
// 避免重复添加同一任务,但允许重试下载
if (tasks.has(id) && !download.retry) {
tasks.get(id)?.webContents.send('install-log', {
tasks.get(id)?.webContents.send("install-log", {
id,
time: Date.now(),
message: `任务id ${id} 已在列表中,忽略重复添加`
message: `任务id ${id} 已在列表中,忽略重复添加`,
});
tasks.get(id)?.webContents.send('install-complete', {
tasks.get(id)?.webContents.send("install-complete", {
id: id,
success: false,
time: Date.now(),
exitCode: -1,
message: `{"message":"任务id ${id} 已在列表中,忽略重复添加","stdout":"","stderr":""}`
message: `{"message":"任务id ${id} 已在列表中,忽略重复添加","stdout":"","stderr":""}`,
});
return;
}
@@ -151,7 +161,7 @@ ipcMain.on('queue-install', async (event, download_json) => {
// 开始组装安装命令
const superUserCmd = await checkSuperUserCommand();
let execCommand = '';
let execCommand = "";
const execParams = [];
if (superUserCmd.length > 0) {
execCommand = superUserCmd;
@@ -159,7 +169,7 @@ ipcMain.on('queue-install', async (event, download_json) => {
} else {
execCommand = SHELL_CALLER_PATH;
}
execParams.push('apm', 'install', '-y', pkgname);
execParams.push("apm", "install", "-y", pkgname);
const task: InstallTask = {
id,
@@ -167,7 +177,7 @@ ipcMain.on('queue-install', async (event, download_json) => {
execCommand,
execParams,
process: null,
webContents
webContents,
};
tasks.set(id, task);
if (idle) processNextInQueue(0);
@@ -179,53 +189,53 @@ function processNextInQueue(index: number) {
idle = false;
const task = Array.from(tasks.values())[index];
const webContents = task.webContents;
let stdoutData = '';
let stderrData = '';
let stdoutData = "";
let stderrData = "";
webContents.send('install-status', {
webContents.send("install-status", {
id: task.id,
time: Date.now(),
message: 'installing'
})
webContents.send('install-log', {
id: task.id,
time: Date.now(),
message: `开始执行: ${task.execCommand} ${task.execParams.join(' ')}`
message: "installing",
});
logger.info(`启动安装命令: ${task.execCommand} ${task.execParams.join(' ')}`);
webContents.send("install-log", {
id: task.id,
time: Date.now(),
message: `开始执行: ${task.execCommand} ${task.execParams.join(" ")}`,
});
logger.info(`启动安装命令: ${task.execCommand} ${task.execParams.join(" ")}`);
const child = spawn(task.execCommand, task.execParams, {
shell: true,
env: process.env
env: process.env,
});
task.process = child;
// 监听 stdout
child.stdout.on('data', (data) => {
child.stdout.on("data", (data) => {
stdoutData += data.toString();
webContents.send('install-log', {
webContents.send("install-log", {
id: task.id,
time: Date.now(),
message: data.toString()
message: data.toString(),
});
});
// 监听 stderr
child.stderr.on('data', (data) => {
child.stderr.on("data", (data) => {
stderrData += data.toString();
webContents.send('install-log', {
webContents.send("install-log", {
id: task.id,
time: Date.now(),
message: data.toString()
message: data.toString(),
});
});
child.on('close', (code) => {
child.on("close", (code) => {
const success = code === 0;
// 拼接json消息
const messageJSONObj = {
message: success ? '安装完成' : `安装失败,退出码 ${code}`,
message: success ? "安装完成" : `安装失败,退出码 ${code}`,
stdout: stdoutData,
stderr: stderrData
stderr: stderrData,
};
if (success) {
@@ -234,42 +244,45 @@ function processNextInQueue(index: number) {
logger.error(messageJSONObj);
}
webContents.send('install-complete', {
webContents.send("install-complete", {
id: task.id,
success: success,
time: Date.now(),
exitCode: code,
message: JSON.stringify(messageJSONObj)
message: JSON.stringify(messageJSONObj),
});
tasks.delete(task.id);
idle = true;
if (tasks.size > 0)
processNextInQueue(0);
if (tasks.size > 0) processNextInQueue(0);
});
}
ipcMain.handle('check-installed', async (_event, pkgname: string) => {
ipcMain.handle("check-installed", async (_event, pkgname: string) => {
if (!pkgname) {
logger.warn('check-installed missing pkgname');
logger.warn("check-installed missing pkgname");
return false;
}
let isInstalled = false;
logger.info(`检查应用是否已安装: ${pkgname}`);
const child = spawn(SHELL_CALLER_PATH, ['apm', 'list', '--installed', pkgname], {
shell: true,
env: process.env
});
const child = spawn(
SHELL_CALLER_PATH,
["apm", "list", "--installed", pkgname],
{
shell: true,
env: process.env,
},
);
let output = '';
child.stdout.on('data', (data) => {
let output = "";
child.stdout.on("data", (data) => {
output += data.toString();
});
await new Promise<void>((resolve) => {
child.on('close', (code) => {
child.on("close", (code) => {
if (code === 0 && output.includes(pkgname)) {
isInstalled = true;
logger.info(`应用已安装: ${pkgname}`);
@@ -282,16 +295,16 @@ ipcMain.handle('check-installed', async (_event, pkgname: string) => {
return isInstalled;
});
ipcMain.on('remove-installed', async (_event, pkgname: string) => {
ipcMain.on("remove-installed", async (_event, pkgname: string) => {
const webContents = _event.sender;
if (!pkgname) {
logger.warn('remove-installed missing pkgname');
logger.warn("remove-installed missing pkgname");
return;
}
logger.info(`卸载已安装应用: ${pkgname}`);
const superUserCmd = await checkSuperUserCommand();
let execCommand = '';
let execCommand = "";
const execParams = [];
if (superUserCmd.length > 0) {
execCommand = superUserCmd;
@@ -299,25 +312,29 @@ ipcMain.on('remove-installed', async (_event, pkgname: string) => {
} else {
execCommand = SHELL_CALLER_PATH;
}
const child = spawn(execCommand, [...execParams, 'apm', 'remove', '-y', pkgname], {
shell: true,
env: process.env
});
let output = '';
child.stdout.on('data', (data) => {
const child = spawn(
execCommand,
[...execParams, "apm", "remove", "-y", pkgname],
{
shell: true,
env: process.env,
},
);
let output = "";
child.stdout.on("data", (data) => {
const chunk = data.toString();
output += chunk;
webContents.send('remove-progress', chunk);
webContents.send("remove-progress", chunk);
});
child.on('close', (code) => {
child.on("close", (code) => {
const success = code === 0;
// 拼接json消息
const messageJSONObj = {
message: success ? '卸载完成' : `卸载失败,退出码 ${code}`,
message: success ? "卸载完成" : `卸载失败,退出码 ${code}`,
stdout: output,
stderr: ''
stderr: "",
};
if (success) {
@@ -326,26 +343,28 @@ ipcMain.on('remove-installed', async (_event, pkgname: string) => {
logger.error(messageJSONObj);
}
webContents.send('remove-complete', {
webContents.send("remove-complete", {
id: 0,
success: success,
time: Date.now(),
exitCode: code,
message: JSON.stringify(messageJSONObj)
message: JSON.stringify(messageJSONObj),
} satisfies ChannelPayload);
});
});
ipcMain.handle('list-upgradable', async () => {
const { code, stdout, stderr } = await runCommandCapture(
SHELL_CALLER_PATH,
['apm', 'list', '--upgradable']);
ipcMain.handle("list-upgradable", async () => {
const { code, stdout, stderr } = await runCommandCapture(SHELL_CALLER_PATH, [
"apm",
"list",
"--upgradable",
]);
if (code !== 0) {
logger.error(`list-upgradable failed: ${stderr || stdout}`);
return {
success: false,
message: stderr || stdout || `list-upgradable failed with code ${code}`,
apps: []
apps: [],
};
}
@@ -353,20 +372,25 @@ ipcMain.handle('list-upgradable', async () => {
return { success: true, apps };
});
ipcMain.handle('list-installed', async () => {
ipcMain.handle("list-installed", async () => {
const superUserCmd = await checkSuperUserCommand();
const execCommand = superUserCmd.length > 0 ? superUserCmd : SHELL_CALLER_PATH;
const execParams = superUserCmd.length > 0
? [SHELL_CALLER_PATH, 'apm', 'list', '--installed']
: ['apm', 'list', '--installed'];
const execCommand =
superUserCmd.length > 0 ? superUserCmd : SHELL_CALLER_PATH;
const execParams =
superUserCmd.length > 0
? [SHELL_CALLER_PATH, "apm", "list", "--installed"]
: ["apm", "list", "--installed"];
const { code, stdout, stderr } = await runCommandCapture(execCommand, execParams);
const { code, stdout, stderr } = await runCommandCapture(
execCommand,
execParams,
);
if (code !== 0) {
logger.error(`list-installed failed: ${stderr || stdout}`);
return {
success: false,
message: stderr || stdout || `list-installed failed with code ${code}`,
apps: []
apps: [],
};
}
@@ -374,19 +398,24 @@ ipcMain.handle('list-installed', async () => {
return { success: true, apps };
});
ipcMain.handle('uninstall-installed', async (_event, pkgname: string) => {
ipcMain.handle("uninstall-installed", async (_event, pkgname: string) => {
if (!pkgname) {
logger.warn('uninstall-installed missing pkgname');
return { success: false, message: 'missing pkgname' };
logger.warn("uninstall-installed missing pkgname");
return { success: false, message: "missing pkgname" };
}
const superUserCmd = await checkSuperUserCommand();
const execCommand = superUserCmd.length > 0 ? superUserCmd : SHELL_CALLER_PATH;
const execParams = superUserCmd.length > 0
? [SHELL_CALLER_PATH, 'apm', 'remove', '-y', pkgname]
: ['apm', 'remove', '-y', pkgname];
const execCommand =
superUserCmd.length > 0 ? superUserCmd : SHELL_CALLER_PATH;
const execParams =
superUserCmd.length > 0
? [SHELL_CALLER_PATH, "apm", "remove", "-y", pkgname]
: ["apm", "remove", "-y", pkgname];
const { code, stdout, stderr } = await runCommandCapture(execCommand, execParams);
const { code, stdout, stderr } = await runCommandCapture(
execCommand,
execParams,
);
const success = code === 0;
if (success) {
@@ -397,24 +426,28 @@ ipcMain.handle('uninstall-installed', async (_event, pkgname: string) => {
return {
success,
message: success ? '卸载完成' : (stderr || stdout || `卸载失败,退出码 ${code}`)
message: success
? "卸载完成"
: stderr || stdout || `卸载失败,退出码 ${code}`,
};
});
ipcMain.handle('launch-app', async (_event, pkgname: string) => {
ipcMain.handle("launch-app", async (_event, pkgname: string) => {
if (!pkgname) {
logger.warn('No pkgname provided for launch-app');
logger.warn("No pkgname provided for launch-app");
}
const execCommand = "/opt/apm-store/extras/host-spawn";
const execParams = ['/opt/apm-store/extras/apm-launcher', 'launch', pkgname ];
const execParams = ["/opt/apm-store/extras/apm-launcher", "launch", pkgname];
logger.info(`Launching app: ${pkgname} with command: ${execCommand} ${execParams.join(' ')}`);
logger.info(
`Launching app: ${pkgname} with command: ${execCommand} ${execParams.join(" ")}`,
);
spawn(execCommand, execParams, {
shell: false,
env: process.env,
detached: true,
stdio: 'ignore'
stdio: "ignore",
}).unref();
});
});

View File

@@ -5,7 +5,7 @@
import { app } from "electron";
import pino from "pino";
const logger = pino({ 'name': 'deeplink.ts' });
const logger = pino({ name: "deeplink.ts" });
type Query = Record<string, string>;
export type Listener = (query: Query) => void;
@@ -52,13 +52,13 @@ export const deepLink = {
on: (event: string, listener: Listener) => {
const count = listeners.add(event, listener);
logger.info(
`Deep link: listener added for event ${event}. Total event listeners: ${count}`
`Deep link: listener added for event ${event}. Total event listeners: ${count}`,
);
},
off: (event: string, listener: Listener) => {
const count = listeners.remove(event, listener);
logger.info(
`Deep link: listener removed for event ${event}. Total event listeners: ${count}`
`Deep link: listener removed for event ${event}. Total event listeners: ${count}`,
);
},
once: (event: string, listener: Listener) => {
@@ -72,7 +72,7 @@ export const deepLink = {
export function handleCommandLine(commandLine: string[]) {
const target = commandLine.find((arg) =>
protocols.some((protocol) => arg.startsWith(protocol + "://"))
protocols.some((protocol) => arg.startsWith(protocol + "://")),
);
if (!target) return;

View File

@@ -1,9 +1,9 @@
import { BrowserWindow } from 'electron';
import { deepLink } from './deeplink';
import { isLoaded } from '../global';
import pino from 'pino';
import { BrowserWindow } from "electron";
import { deepLink } from "./deeplink";
import { isLoaded } from "../global";
import pino from "pino";
const logger = pino({ 'name': 'handle-url-scheme.ts' });
const logger = pino({ name: "handle-url-scheme.ts" });
const pendingActions: Array<() => void> = [];
@@ -24,22 +24,26 @@ new Promise<void>((resolve) => {
});
deepLink.on("event", (query) => {
logger.info(`Deep link: event "event" fired with query: ${JSON.stringify(query)}`);
logger.info(
`Deep link: event "event" fired with query: ${JSON.stringify(query)}`,
);
});
deepLink.on("action", (query) => {
logger.info(`Deep link: event "action" fired with query: ${JSON.stringify(query)}`);
logger.info(
`Deep link: event "action" fired with query: ${JSON.stringify(query)}`,
);
const action = () => {
const win = BrowserWindow.getAllWindows()[0];
if (!win) return;
if (query.cmd === 'update') {
win.webContents.send('deep-link-update');
if (query.cmd === "update") {
win.webContents.send("deep-link-update");
if (win.isMinimized()) win.restore();
win.focus();
} else if (query.cmd === 'list') {
win.webContents.send('deep-link-installed');
} else if (query.cmd === "list") {
win.webContents.send("deep-link-installed");
if (win.isMinimized()) win.restore();
win.focus();
}
@@ -55,14 +59,16 @@ deepLink.on("action", (query) => {
});
deepLink.on("install", (query) => {
logger.info(`Deep link: event "install" fired with query: ${JSON.stringify(query)}`);
logger.info(
`Deep link: event "install" fired with query: ${JSON.stringify(query)}`,
);
const action = () => {
const win = BrowserWindow.getAllWindows()[0];
if (!win) return;
if (query.pkg) {
win.webContents.send('deep-link-install', query.pkg);
win.webContents.send("deep-link-install", query.pkg);
if (win.isMinimized()) win.restore();
win.focus();
}

View File

@@ -1,24 +1,23 @@
import { app, BrowserWindow, ipcMain, Menu, shell, Tray } from 'electron'
import { fileURLToPath } from 'node:url'
import path from 'node:path'
import os from 'node:os'
import fs from 'node:fs'
import pino from 'pino'
import { handleCommandLine } from './deeplink.js'
import { isLoaded } from '../global.js'
import { tasks } from './backend/install-manager.js'
import { app, BrowserWindow, ipcMain, Menu, shell, Tray } from "electron";
import { fileURLToPath } from "node:url";
import path from "node:path";
import os from "node:os";
import fs from "node:fs";
import pino from "pino";
import { handleCommandLine } from "./deeplink.js";
import { isLoaded } from "../global.js";
import { tasks } from "./backend/install-manager.js";
// Assure single instance application
if (!app.requestSingleInstanceLock()) {
app.exit(0);
}
import './backend/install-manager.js'
import './handle-url-scheme.js'
import "./backend/install-manager.js";
import "./handle-url-scheme.js";
const logger = pino({ 'name': 'index.ts' });
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const logger = pino({ name: "index.ts" });
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// The built directory structure
//
@@ -30,38 +29,38 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
// ├─┬ dist
// │ └── index.html > Electron-Renderer
//
process.env.APP_ROOT = path.join(__dirname, '../..')
process.env.APP_ROOT = path.join(__dirname, "../..");
export const MAIN_DIST = path.join(process.env.APP_ROOT, 'dist-electron')
export const RENDERER_DIST = path.join(process.env.APP_ROOT, 'dist')
export const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL
export const MAIN_DIST = path.join(process.env.APP_ROOT, "dist-electron");
export const RENDERER_DIST = path.join(process.env.APP_ROOT, "dist");
export const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL;
process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL
? path.join(process.env.APP_ROOT, 'public')
: RENDERER_DIST
? path.join(process.env.APP_ROOT, "public")
: RENDERER_DIST;
// Disable GPU Acceleration for Windows 7
if (os.release().startsWith('6.1')) app.disableHardwareAcceleration()
if (os.release().startsWith("6.1")) app.disableHardwareAcceleration();
// Set application name for Windows 10+ notifications
if (process.platform === 'win32') app.setAppUserModelId(app.getName())
if (process.platform === "win32") app.setAppUserModelId(app.getName());
if (!app.requestSingleInstanceLock()) {
app.quit()
process.exit(0)
app.quit();
process.exit(0);
}
let win: BrowserWindow | null = null
const preload = path.join(__dirname, '../preload/index.mjs')
const indexHtml = path.join(RENDERER_DIST, 'index.html')
let win: BrowserWindow | null = null;
const preload = path.join(__dirname, "../preload/index.mjs");
const indexHtml = path.join(RENDERER_DIST, "index.html");
async function createWindow() {
win = new BrowserWindow({
title: 'APM AppStore',
title: "APM AppStore",
width: 1366,
height: 768,
autoHideMenuBar: true,
icon: path.join(process.env.VITE_PUBLIC, 'favicon.ico'),
icon: path.join(process.env.VITE_PUBLIC, "favicon.ico"),
webPreferences: {
preload,
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
@@ -71,30 +70,31 @@ async function createWindow() {
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
// contextIsolation: false,
},
})
});
if (VITE_DEV_SERVER_URL) { // #298
win.loadURL(VITE_DEV_SERVER_URL)
if (VITE_DEV_SERVER_URL) {
// #298
win.loadURL(VITE_DEV_SERVER_URL);
// Open devTool if the app is not packaged
win.webContents.openDevTools({mode:'detach'})
win.webContents.openDevTools({ mode: "detach" });
} else {
win.loadFile(indexHtml)
win.loadFile(indexHtml);
}
// Test actively push message to the Electron-Renderer
win.webContents.on('did-finish-load', () => {
win?.webContents.send('main-process-message', new Date().toLocaleString())
logger.info('Renderer process is ready.');
})
win.webContents.on("did-finish-load", () => {
win?.webContents.send("main-process-message", new Date().toLocaleString());
logger.info("Renderer process is ready.");
});
// Make all links open with the browser, not with the application
win.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith('https:')) shell.openExternal(url)
return { action: 'deny' }
})
if (url.startsWith("https:")) shell.openExternal(url);
return { action: "deny" };
});
// win.webContents.on('will-navigate', (event, url) => { }) #344
win.on('close', (event) => {
win.on("close", (event) => {
// 截获 close 默认行为
event.preventDefault();
// 点击关闭时触发close事件我们按照之前的思路在关闭时隐藏窗口隐藏任务栏窗口
@@ -103,50 +103,52 @@ async function createWindow() {
win.setSkipTaskbar(true);
} else {
// 如果没有下载任务,才允许关闭窗口
win.destroy()
win.destroy();
}
})
});
}
ipcMain.on('renderer-ready', (event, args) => {
logger.info('Received renderer-ready event with args: ' + JSON.stringify(args));
ipcMain.on("renderer-ready", (event, args) => {
logger.info(
"Received renderer-ready event with args: " + JSON.stringify(args),
);
isLoaded.value = args.status;
logger.info(`isLoaded set to: ${isLoaded.value}`);
})
});
app.whenReady().then(() => {
createWindow()
handleCommandLine(process.argv)
})
createWindow();
handleCommandLine(process.argv);
});
app.on('window-all-closed', () => {
win = null
if (process.platform !== 'darwin') app.quit()
})
app.on("window-all-closed", () => {
win = null;
if (process.platform !== "darwin") app.quit();
});
app.on('second-instance', () => {
app.on("second-instance", () => {
if (win) {
// Focus on the main window if the user tried to open another
if (win.isMinimized()) win.restore()
win.focus()
if (win.isMinimized()) win.restore();
win.focus();
}
})
});
app.on('activate', () => {
const allWindows = BrowserWindow.getAllWindows()
app.on("activate", () => {
const allWindows = BrowserWindow.getAllWindows();
if (allWindows.length) {
allWindows[0].focus()
allWindows[0].focus();
} else {
createWindow()
createWindow();
}
})
});
// 设置托盘
// 获取图标路径
function getIconPath() {
let iconPath = "";
const iconFile = process.platform === "win32" ? "amber-pm-logo.ico" : "amber-pm-logo.png"; // 图标文件名linux下需要png格式不然会不显示
const iconFile =
process.platform === "win32" ? "amber-pm-logo.ico" : "amber-pm-logo.png"; // 图标文件名linux下需要png格式不然会不显示
// 判断是否在打包模式
if (app.isPackaged) {
// 打包模式
@@ -170,31 +172,35 @@ function getIconPath() {
let tray = null;
app.whenReady().then(() => {
tray = new Tray(getIconPath());
const contextMenu = Menu.buildFromTemplate([{
label: '显示主界面',
click: () => { win.show() }
tray = new Tray(getIconPath());
const contextMenu = Menu.buildFromTemplate([
{
label: "显示主界面",
click: () => {
win.show();
},
},
{
label: '退出程序',
click: () => { win.destroy() }
label: "退出程序",
click: () => {
win.destroy();
},
},
]);
tray.setToolTip("APM 应用商店");
tray.setContextMenu(contextMenu);
// 双击触发
tray.on("click", () => {
// 双击通知区图标实现应用的显示或隐藏
if (win.isVisible()) {
win.hide();
win.setSkipTaskbar(true);
} else {
win.show();
win.setSkipTaskbar(false);
}
]);
tray.setToolTip('APM 应用商店')
tray.setContextMenu(contextMenu)
// 双击触发
tray.on('click', () => {
// 双击通知区图标实现应用的显示或隐藏
if (win.isVisible()) {
win.hide();
win.setSkipTaskbar(true);
} else {
win.show();
win.setSkipTaskbar(false);
}
});
})
});
});
// New window example arg: new windows url
// ipcMain.handle('open-win', (_, arg) => {