chore: restructure project and add i18n support
- Reorganize project structure with new electron and shared directories - Add comprehensive i18n support with Chinese, English, and Japanese locales - Update build configurations and TypeScript paths for new structure - Add various UI components including chat interface and task management - Include Windows release binaries and localization files - Update dependencies and fix import paths throughout the codebase
This commit is contained in:
126
electron/service/config-service/index.ts
Normal file
126
electron/service/config-service/index.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import { app, BrowserWindow, ipcMain } from 'electron'
|
||||
import type { ConfigKeys, IConfig } from '@lib/types'
|
||||
import { CONFIG_KEYS, IPC_EVENTS } from '@lib/constants'
|
||||
import { debounce, simpleCloneDeep } from '@lib/utils'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
import logManager from '@electron/service/logger'
|
||||
|
||||
const DEFAULT_CONFIG: IConfig = {
|
||||
[CONFIG_KEYS.THEME_MODE]: 'system',
|
||||
[CONFIG_KEYS.PRIMARY_COLOR]: '#BB5BE7',
|
||||
[CONFIG_KEYS.LANGUAGE]: 'zh',
|
||||
[CONFIG_KEYS.FONT_SIZE]: 14,
|
||||
[CONFIG_KEYS.MINIMIZE_TO_TRAY]: false,
|
||||
[CONFIG_KEYS.PROVIDER]: '',
|
||||
[CONFIG_KEYS.DEFAULT_MODEL]: null,
|
||||
}
|
||||
|
||||
export class ConfigService {
|
||||
private static _instance: ConfigService;
|
||||
private _config: IConfig;
|
||||
private _configPath: string;
|
||||
private _defaultConfig: IConfig = DEFAULT_CONFIG;
|
||||
|
||||
private _listeners: Array<(config: IConfig) => void> = [];
|
||||
|
||||
|
||||
private constructor() {
|
||||
// 获取配置文件路径
|
||||
this._configPath = path.join(app.getPath('userData'), 'config.json');
|
||||
// 加载配置
|
||||
this._config = this._loadConfig();
|
||||
// 设置 IPC 事件
|
||||
this._setupIpcEvents();
|
||||
logManager.info('ConfigService initialized successfully.')
|
||||
}
|
||||
|
||||
private _setupIpcEvents() {
|
||||
const duration = 200;
|
||||
const handelUpdate = debounce((val) => this.update(val), duration);
|
||||
|
||||
ipcMain.handle(IPC_EVENTS.GET_CONFIG, (_, key) => this.get(key));
|
||||
ipcMain.on(IPC_EVENTS.SET_CONFIG, (_, key, val) => this.set(key, val));
|
||||
ipcMain.on(IPC_EVENTS.UPDATE_CONFIG, (_, updates) => handelUpdate(updates));
|
||||
}
|
||||
|
||||
public static getInstance(): ConfigService {
|
||||
if (!this._instance) {
|
||||
this._instance = new ConfigService();
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
private _loadConfig(): IConfig {
|
||||
try {
|
||||
if (fs.existsSync(this._configPath)) {
|
||||
const configContent = fs.readFileSync(this._configPath, 'utf-8');
|
||||
const config = { ...this._defaultConfig, ...JSON.parse(configContent) };
|
||||
logManager.info('Config loaded successfully from:', this._configPath);
|
||||
return config;
|
||||
}
|
||||
} catch (error) {
|
||||
logManager.error('Failed to load config:', error);
|
||||
}
|
||||
return { ...this._defaultConfig };
|
||||
}
|
||||
|
||||
private _saveConfig(): void {
|
||||
try {
|
||||
// 确保目录存在
|
||||
fs.mkdirSync(path.dirname(this._configPath), { recursive: true });
|
||||
// 写入
|
||||
fs.writeFileSync(this._configPath, JSON.stringify(this._config, null, 2), 'utf-8');
|
||||
// 通知监听者
|
||||
this._notifyListeners();
|
||||
|
||||
logManager.info('Config saved successfully to:', this._configPath);
|
||||
} catch (error) {
|
||||
logManager.error('Failed to save config:', error);
|
||||
}
|
||||
}
|
||||
|
||||
private _notifyListeners(): void {
|
||||
BrowserWindow.getAllWindows().forEach(win => win.webContents.send(IPC_EVENTS.CONFIG_UPDATED, this._config));
|
||||
this._listeners.forEach(listener => listener({ ...this._config }));
|
||||
}
|
||||
|
||||
public getConfig(): IConfig {
|
||||
return simpleCloneDeep(this._config);
|
||||
}
|
||||
|
||||
public get<T = any>(key: ConfigKeys): T {
|
||||
return this._config[key] as T
|
||||
}
|
||||
|
||||
public set(key: ConfigKeys, value: unknown, autoSave: boolean = true): void {
|
||||
if (!(key in this._config)) return;
|
||||
const oldValue = this._config[key];
|
||||
if (oldValue === value) return;
|
||||
this._config[key] = value as never;
|
||||
logManager.debug(`Config set: ${key} = ${value}`);
|
||||
autoSave && this._saveConfig();
|
||||
}
|
||||
|
||||
public update(updates: Partial<IConfig>, autoSave: boolean = true): void {
|
||||
this._config = { ...this._config, ...updates };
|
||||
autoSave && this._saveConfig();
|
||||
}
|
||||
|
||||
public resetToDefault(): void {
|
||||
this._config = { ...this._defaultConfig };
|
||||
logManager.info('Config reset to default.');
|
||||
this._saveConfig();
|
||||
}
|
||||
|
||||
public onConfigChange(listener: ((config: IConfig) => void)): () => void {
|
||||
this._listeners.push(listener);
|
||||
|
||||
return () => this._listeners = this._listeners.filter(l => l !== listener);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const configManager = ConfigService.getInstance();
|
||||
export default configManager;
|
||||
Reference in New Issue
Block a user