Files
dream_pep 8fc6fcaf05 feat(update): 实现更新通道管理系统与更新调试页面
本次提交完成以下变更:
1. 实现完整的更新通道管理功能,支持慢走/跑步两种更新模式,可在设置页切换且配置持久化生效
2. 新增更新调试页面,集成检查更新、版本比对、设置测试版本等调试工具
3. 新增快速打开Chromium DevTools的按钮,方便开发调试
4. 完善自动更新后端逻辑,新增版本比对、测试版本覆盖、通道动态获取等IPC接口
5. 调整GitHub Release构建脚本,修复prerelease版本的命名与发布问题
6. 添加semver依赖与类型定义,完善全量类型声明
7. 更新自动更新文档,补充更新通道相关的设计说明
8. 微调默认配置,添加主题暗黑模式的初始配置
2026-08-31 02:20:25 +08:00

124 lines
3.3 KiB
TypeScript

import electron from 'electron';
import path from 'path';
const { ipcMain, dialog, shell } = electron;
const isDev = !electron.app.isPackaged;
interface WinRef {
mainWindow: electron.BrowserWindow | null;
splashWindow: electron.BrowserWindow | null;
}
const MIME_MAP: Record<string, string> = {
png: 'image/png',
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
webp: 'image/webp',
gif: 'image/gif',
bmp: 'image/bmp',
svg: 'image/svg+xml',
};
function createSplashWindow(): electron.BrowserWindow {
const splash = new electron.BrowserWindow({
width: 480,
height: 320,
transparent: true,
frame: false,
resizable: false,
skipTaskbar: true,
alwaysOnTop: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
},
});
if (isDev) {
splash.loadURL('http://localhost:1420/splash.html');
} else {
splash.loadFile(path.join(__dirname, '../dist/splash.html'));
}
return splash;
}
export function registerWindowHandlers(win: WinRef) {
ipcMain.handle('window:minimize', () => {
win.mainWindow?.minimize();
});
ipcMain.handle('window:maximize', () => {
if (win.mainWindow?.isMaximized()) {
win.mainWindow.unmaximize();
} else {
win.mainWindow?.maximize();
}
});
ipcMain.handle('window:close', () => {
win.mainWindow?.close();
});
ipcMain.handle('window:isMaximized', () => {
return win.mainWindow?.isMaximized() ?? false;
});
ipcMain.handle('window:getTheme', () => {
return (win.mainWindow as any)?.themeSource ?? null;
});
// 打开浏览器调试工具(DevTools,开发者工具测试用)
ipcMain.handle('window:openDevTools', () => {
win.mainWindow?.webContents.openDevTools({ mode: 'detach' });
return { success: true };
});
// Splash window management
ipcMain.handle('window:openSplash', () => {
if (win.splashWindow && !win.splashWindow.isDestroyed()) {
win.splashWindow.focus();
return { success: true };
}
win.splashWindow = createSplashWindow();
return { success: true };
});
ipcMain.handle('window:closeSplash', () => {
if (win.splashWindow && !win.splashWindow.isDestroyed()) {
win.splashWindow.close();
win.splashWindow = null;
}
return { success: true };
});
// File dialog — returns source path and extension for preload to handle
ipcMain.handle('dialog:openFile', async (_event, payload: {
filters?: { name: string; extensions: string[] }[];
}) => {
const result = await dialog.showOpenDialog(win.mainWindow!, {
properties: ['openFile'],
filters: payload.filters,
});
if (result.canceled || result.filePaths.length === 0) return null;
const srcPath = result.filePaths[0];
const ext = path.extname(srcPath).toLowerCase() || '.png';
return { srcPath, ext };
});
// Open external URL in system browser
ipcMain.handle('shell:openExternal', async (_event, url: string) => {
await shell.openExternal(url);
});
// Folder dialog — select a directory
ipcMain.handle('dialog:openFolder', async () => {
const result = await dialog.showOpenDialog(win.mainWindow!, {
properties: ['openDirectory'],
});
if (result.canceled || result.filePaths.length === 0) return null;
return { folderPath: result.filePaths[0] };
});
}