Files
koring-launcher/electron/handlers/background.ts
T
dream_pep fad8f612bf feat: 重构背景图处理体系,优化用户UX体验
- 重构背景图全链路处理:改用文件路径存储而非base64,新增`koring-res://`自定义协议流式加载本地壁纸,大幅降低内存占用
- 调整配置文件存储路径至userData目录,解决NSIS重装/升级时配置被清空的问题
- 新增路由调试页面,支持快速跳转所有已注册的应用页面
- 优化OOBE引导和更新完成页的「前往首页」按钮,添加4秒延迟渐入动画
- 自动迁移旧版配置:将安装目录的配置文件迁移至userData,同时将base64格式的背景配置自动转换为文件路径存储
- 重构预加载脚本、主进程IPC处理器与前端页面的背景图相关逻辑
- 更新AGENTS.md开发文档,修正路径与逻辑说明
- 更新应用背景图资源文件
2026-09-04 19:34:58 +08:00

165 lines
6.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import electron from 'electron';
import fs from 'fs';
import path from 'path';
import { loadConfig, saveConfig } from '../config';
import { importUserBackground, isManagedBackgroundFile, isPathInside } from '../core/background-image';
import { backgroundResourceUrl } from '../resource-protocol';
const { ipcMain } = electron;
export function registerBackgroundHandlers() {
ipcMain.handle('background:set-image', async (_event, payload: { url: string; blur?: number; opacity?: number }) => {
try {
const config = loadConfig();
config.background.bgType = 'image';
config.background.image = payload.url;
if (payload.blur !== undefined) config.background.blur = payload.blur;
if (payload.opacity !== undefined) config.background.opacity = payload.opacity;
saveConfig(config);
return { success: true, data: config.background, error: null };
} catch (e: unknown) {
return { success: false, data: null, error: String(e) };
}
});
ipcMain.handle('background:set-color', async (_event, payload: { color: string }) => {
try {
const config = loadConfig();
config.background.bgType = 'color';
config.background.image = payload.color;
saveConfig(config);
return { success: true, data: config.background, error: null };
} catch (e: unknown) {
return { success: false, data: null, error: String(e) };
}
});
ipcMain.handle('background:set-blur', async (_event, payload: { blur: number }) => {
try {
const config = loadConfig();
config.background.blur = payload.blur;
saveConfig(config);
return { success: true, data: config.background, error: null };
} catch (e: unknown) {
return { success: false, data: null, error: String(e) };
}
});
ipcMain.handle('background:set-opacity', async (_event, payload: { opacity: number }) => {
try {
const config = loadConfig();
config.background.opacity = payload.opacity;
saveConfig(config);
return { success: true, data: config.background, error: null };
} catch (e: unknown) {
return { success: false, data: null, error: String(e) };
}
});
ipcMain.handle('background:set-animation', async (_event, payload: { type: string; speed?: number }) => {
try {
// Animation config is not persisted in current design, return defaults
return { success: true, data: { bgType: 'image', image: '/background.png', blur: 0, opacity: 100 }, error: null };
} catch (e: unknown) {
return { success: false, data: null, error: String(e) };
}
});
ipcMain.handle('background:get', async () => {
try {
const config = loadConfig();
return { success: true, data: config.background, error: null };
} catch (e: unknown) {
return { success: false, data: null, error: String(e) };
}
});
ipcMain.handle('background:set-theme', async (_event, payload: { theme: string }) => {
try {
const config = loadConfig();
config.theme.darkMode = payload.theme;
saveConfig(config);
return { success: true, data: config.background, error: null };
} catch (e: unknown) {
return { success: false, data: null, error: String(e) };
}
});
ipcMain.handle('background:reset', async () => {
try {
const config = loadConfig();
config.background = { bgType: 'image', image: '/background.png', blur: 0, opacity: 100 };
saveConfig(config);
return { success: true, data: config.background, error: null };
} catch (e: unknown) {
return { success: false, data: null, error: String(e) };
}
});
// Copy file to userData and return the destination path
ipcMain.handle('background:copyToUserData', async (_event, srcPath: string, ext: string) => {
try {
const userDataPath = electron.app.getPath('userData');
const destPath = path.join(userDataPath, `background-custom${ext}`);
fs.copyFileSync(srcPath, destPath);
return destPath;
} catch {
return null;
}
});
// Get cached background file path from userData
ipcMain.handle('background:getCachedPath', async () => {
try {
const userDataPath = electron.app.getPath('userData');
const files = fs.readdirSync(userDataPath).filter(f => f.startsWith('background-custom'));
if (files.length === 0) return null;
return path.join(userDataPath, files[0]);
} catch {
return null;
}
});
// 导入自选壁纸:复制到 userData → 按屏幕所需尺寸降采样落盘,
// 返回【文件路径】(配置文件以路径存储,不再使用 BASE64 dataURL
ipcMain.handle('background:import', async (_event, payload: { srcPath: string; maxEdge?: number }) => {
try {
const result = importUserBackground(payload.srcPath, payload.maxEdge || 4096);
return { success: true, data: result, error: null };
} catch (e: unknown) {
return { success: false, data: null, error: String(e) };
}
});
// 把配置/Store 中的「壁纸值」解析为可显示的资源引用:
// - data:/http(s):/file: 及 /、./ 相对 URL → 原样返回(本身可直接用于 CSS);
// - userData 内的受管壁纸文件路径 → koring-res:// 协议 URL(流式读取,全程无 base64 副本);
// - 其它(越权路径/不存在等)→ data:null,调用方回退默认背景。
ipcMain.handle('background:resolve', async (_event, payload: { value?: string }) => {
try {
const value = typeof payload?.value === 'string' ? payload.value.trim() : '';
if (!value) return { success: true, data: null, error: null };
if (/^(data:|https?:|file:|\.\.\/|\/|\.\/)/i.test(value)) {
return { success: true, data: { url: value, bytes: 0 }, error: null };
}
const userDataDir = electron.app.getPath('userData');
if (!path.isAbsolute(value) || !isPathInside(userDataDir, value)) {
return { success: true, data: null, error: null };
}
const fileName = path.basename(value);
if (!isManagedBackgroundFile(fileName)) {
return { success: true, data: null, error: null };
}
const stat = fs.statSync(value);
if (!stat.isFile()) return { success: true, data: null, error: null };
return {
success: true,
data: { url: backgroundResourceUrl(fileName), bytes: stat.size },
error: null,
};
} catch (e: unknown) {
return { success: false, data: null, error: String(e) };
}
});
}