mirror of
https://github.com/dream-pep/koring-launcher.git
synced 2026-09-12 05:45:18 +08:00
- 重构背景图全链路处理:改用文件路径存储而非base64,新增`koring-res://`自定义协议流式加载本地壁纸,大幅降低内存占用 - 调整配置文件存储路径至userData目录,解决NSIS重装/升级时配置被清空的问题 - 新增路由调试页面,支持快速跳转所有已注册的应用页面 - 优化OOBE引导和更新完成页的「前往首页」按钮,添加4秒延迟渐入动画 - 自动迁移旧版配置:将安装目录的配置文件迁移至userData,同时将base64格式的背景配置自动转换为文件路径存储 - 重构预加载脚本、主进程IPC处理器与前端页面的背景图相关逻辑 - 更新AGENTS.md开发文档,修正路径与逻辑说明 - 更新应用背景图资源文件
118 lines
5.4 KiB
TypeScript
118 lines
5.4 KiB
TypeScript
import electron from 'electron';
|
|
const { contextBridge, ipcRenderer } = electron;
|
|
|
|
// 按当前窗口实际像素需求计算壁纸长边上限(含高分屏余量),
|
|
// 主进程据此把大图压到「屏幕可见」尺寸后落盘(配置只存文件路径,不存 BASE64)。
|
|
function computeMaxEdge(): number {
|
|
const dpr = window.devicePixelRatio || 1;
|
|
const css = Math.max(window.innerWidth || 1280, window.innerHeight || 800);
|
|
const target = Math.round(Math.max(css, 1920) * dpr * 1.1);
|
|
return Math.min(4096, Math.max(1920, target));
|
|
}
|
|
|
|
contextBridge.exposeInMainWorld('electronAPI', {
|
|
// Generic IPC
|
|
invoke: (channel: string, ...args: unknown[]) =>
|
|
ipcRenderer.invoke(channel, ...args),
|
|
|
|
on: (channel: string, callback: (...args: unknown[]) => void) => {
|
|
const handler = (_event: Electron.IpcRendererEvent, ...args: unknown[]) => callback(...args);
|
|
ipcRenderer.on(channel, handler);
|
|
return () => ipcRenderer.removeListener(channel, handler);
|
|
},
|
|
|
|
send: (channel: string, ...args: unknown[]) =>
|
|
ipcRenderer.send(channel, ...args),
|
|
|
|
// Window controls
|
|
minimize: () => ipcRenderer.invoke('window:minimize'),
|
|
maximize: () => ipcRenderer.invoke('window:maximize'),
|
|
close: () => ipcRenderer.invoke('window:close'),
|
|
isMaximized: () => ipcRenderer.invoke('window:isMaximized'),
|
|
openDevTools: () => ipcRenderer.invoke('window:openDevTools'),
|
|
onResized: (callback: () => void) => {
|
|
const handler = () => callback();
|
|
ipcRenderer.on('window:resized', handler);
|
|
return () => ipcRenderer.removeListener('window:resized', handler);
|
|
},
|
|
|
|
// Theme
|
|
getTheme: () => ipcRenderer.invoke('window:getTheme'),
|
|
|
|
// Config preloading
|
|
onConfigPreload: (callback: (data: { config: unknown; isFirstLaunch: boolean }) => void) => {
|
|
const handler = (_event: Electron.IpcRendererEvent, data: { config: unknown; isFirstLaunch: boolean }) => callback(data);
|
|
ipcRenderer.on('config:preload', handler);
|
|
return () => ipcRenderer.removeListener('config:preload', handler);
|
|
},
|
|
|
|
// Config changed broadcast (authoritative full config from main process)
|
|
onConfigChanged: (callback: (config: unknown) => void) => {
|
|
const handler = (_event: Electron.IpcRendererEvent, config: unknown) => callback(config);
|
|
ipcRenderer.on('config:changed', handler);
|
|
return () => ipcRenderer.removeListener('config:changed', handler);
|
|
},
|
|
|
|
// 背景图 — 选择本地图片:主进程复制到 userData、按窗口尺寸优化并落盘,
|
|
// 返回【文件路径】(配置/Store 以路径保存,不使用 BASE64)。
|
|
pickBackgroundImage: async (): Promise<string | null> => {
|
|
const result = await ipcRenderer.invoke('dialog:openFile', {
|
|
filters: [{ name: '图片', extensions: ['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp'] }],
|
|
});
|
|
if (!result) return null;
|
|
const { srcPath } = result as { srcPath: string };
|
|
const imported = await ipcRenderer.invoke('background:import', {
|
|
srcPath,
|
|
maxEdge: computeMaxEdge(),
|
|
});
|
|
if (imported && imported.success && typeof imported.data?.filePath === 'string' && imported.data.filePath) {
|
|
return imported.data.filePath;
|
|
}
|
|
return null;
|
|
},
|
|
|
|
// 把配置文件/Store 中的壁纸值解析为可显示的资源引用:
|
|
// data:/http(s):/file: 及 /、./ 相对 URL → 原样返回;
|
|
// userData 内受管壁纸文件路径 → koring-res:// 协议 URL(流式读取,无 base64 副本)。
|
|
resolveBackgroundResource: async (value: string): Promise<{ url: string | null; bytes: number }> => {
|
|
try {
|
|
const result = await ipcRenderer.invoke('background:resolve', { value });
|
|
if (result && result.success && typeof result.data?.url === 'string' && result.data.url) {
|
|
return { url: result.data.url, bytes: typeof result.data.bytes === 'number' ? result.data.bytes : 0 };
|
|
}
|
|
} catch {
|
|
// fallthrough
|
|
}
|
|
return { url: null, bytes: 0 };
|
|
},
|
|
|
|
// Open external URL in system browser
|
|
openExternal: (url: string) => ipcRenderer.invoke('shell:openExternal', url),
|
|
|
|
// Crash monitoring — devtools only
|
|
simulateCrash: () => ipcRenderer.invoke('crash:simulate'),
|
|
testCrashDialog: () => ipcRenderer.invoke('crash:testDialog'),
|
|
|
|
// Config reset
|
|
resetConfig: () => ipcRenderer.invoke('config:reset'),
|
|
|
|
// Auto-update (main process: electron/updater.ts)
|
|
checkForUpdates: (manual = false) => ipcRenderer.invoke('update:check', { manual }),
|
|
downloadUpdate: () => ipcRenderer.invoke('update:download'),
|
|
pauseUpdate: () => ipcRenderer.invoke('update:pause'),
|
|
resumeUpdate: () => ipcRenderer.invoke('update:resume'),
|
|
cancelUpdate: () => ipcRenderer.invoke('update:cancel'),
|
|
quitAndInstall: () => ipcRenderer.invoke('update:quitAndInstall'),
|
|
getUpdateState: () => ipcRenderer.invoke('update:getState'),
|
|
getReleaseNotes: (tag?: string) => ipcRenderer.invoke('update:getReleaseNotes', { tag }),
|
|
getUpdateChannels: () => ipcRenderer.invoke('update:getChannels'),
|
|
setUpdateChannel: (channel: string) => ipcRenderer.invoke('update:setChannel', { channel }),
|
|
setTestVersion: (version: string) => ipcRenderer.invoke('update:setTestVersion', { version }),
|
|
compareVersions: (a: string, b: string) => ipcRenderer.invoke('update:compareVersions', { a, b }),
|
|
onUpdateStatus: (callback: (data: unknown) => void) => {
|
|
const handler = (_event: Electron.IpcRendererEvent, data: unknown) => callback(data);
|
|
ipcRenderer.on('update:status', handler);
|
|
return () => ipcRenderer.removeListener('update:status', handler);
|
|
},
|
|
});
|