From 9468f3b5112ad3fbb7c12c7bde236956c268a887 Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Sat, 2 Nov 2024 23:29:16 +0800 Subject: [PATCH] refactor: main code --- src/main/config.ts | 18 ++------ src/main/index.ts | 2 +- src/main/ipc.ts | 44 +++++++++---------- src/main/services/ConfigManager.ts | 19 ++++++++ src/main/services/ExportService.ts | 6 +-- .../{FileManager.ts => FileStorage.ts} | 16 +++---- .../ShortcutService.ts} | 0 src/main/utils/index.ts | 9 ++++ src/main/window.ts | 5 ++- src/preload/index.d.ts | 6 ++- src/preload/index.ts | 16 ++++--- src/renderer/src/assets/styles/index.scss | 1 - src/renderer/src/services/BackupService.ts | 2 +- 13 files changed, 81 insertions(+), 63 deletions(-) create mode 100644 src/main/services/ConfigManager.ts rename src/main/services/{FileManager.ts => FileStorage.ts} (96%) rename src/main/{shortcut.ts => services/ShortcutService.ts} (100%) diff --git a/src/main/config.ts b/src/main/config.ts index 75a908bff..73025d102 100644 --- a/src/main/config.ts +++ b/src/main/config.ts @@ -1,25 +1,15 @@ -import fs from 'node:fs' - import { app } from 'electron' -import Store from 'electron-store' -import path from 'path' -const isDev = process.env.NODE_ENV === 'development' +import { getDataPath } from './utils' -isDev && app.setPath('userData', app.getPath('userData') + 'Dev') +const isDev = process.env.NODE_ENV === 'development' -const getDataPath = () => { - const dataPath = path.join(app.getPath('userData'), 'Data') - if (!fs.existsSync(dataPath)) { - fs.mkdirSync(dataPath, { recursive: true }) - } - return dataPath +if (isDev) { + app.setPath('userData', app.getPath('userData') + 'Dev') } export const DATA_PATH = getDataPath() -export const appConfig = new Store() - export const titleBarOverlayDark = { height: 40, color: '#00000000', diff --git a/src/main/index.ts b/src/main/index.ts index c2c0f7d20..35de52f8d 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -3,7 +3,7 @@ import { app, BrowserWindow } from 'electron' import installExtension, { REDUX_DEVTOOLS } from 'electron-devtools-installer' import { registerIpc } from './ipc' -import { registerZoomShortcut } from './shortcut' +import { registerZoomShortcut } from './services/ShortcutService' import { updateUserDataPath } from './utils/upgrade' import { createMainWindow } from './window' diff --git a/src/main/ipc.ts b/src/main/ipc.ts index cb03797f7..e3592eff7 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -2,15 +2,16 @@ import path from 'node:path' import { BrowserWindow, ipcMain, session, shell } from 'electron' -import { appConfig, titleBarOverlayDark, titleBarOverlayLight } from './config' +import { titleBarOverlayDark, titleBarOverlayLight } from './config' import AppUpdater from './services/AppUpdater' import BackupManager from './services/BackupManager' +import { configManager } from './services/ConfigManager' import { ExportService } from './services/ExportService' -import FileManager from './services/FileManager' +import FileStorage from './services/FileStorage' import { compress, decompress } from './utils/zip' import { createMinappWindow } from './window' -const fileManager = new FileManager() +const fileManager = new FileStorage() const backupManager = new BackupManager() const exportService = new ExportService(fileManager) @@ -24,15 +25,24 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) { filesPath: path.join(app.getPath('userData'), 'Data', 'Files') })) - ipcMain.handle('open-website', (_, url: string) => { - shell.openExternal(url) - }) + ipcMain.handle('app:proxy', (_, proxy: string) => session.defaultSession.setProxy(proxy ? { proxyRules: proxy } : {})) + ipcMain.handle('app:reload', () => mainWindow.reload()) + ipcMain.handle('open:website', (_, url: string) => shell.openExternal(url)) - ipcMain.handle('set-proxy', (_, proxy: string) => { - session.defaultSession.setProxy(proxy ? { proxyRules: proxy } : {}) + // theme + ipcMain.handle('app:set-theme', (_, theme: 'light' | 'dark') => { + configManager.setTheme(theme) + mainWindow?.setTitleBarOverlay && + mainWindow.setTitleBarOverlay(theme === 'dark' ? titleBarOverlayDark : titleBarOverlayLight) }) - ipcMain.handle('reload', () => mainWindow.reload()) + // check for update + ipcMain.handle('app:check-for-update', async () => { + return { + currentVersion: autoUpdater.currentVersion, + update: await autoUpdater.checkForUpdates() + } + }) // zip ipcMain.handle('zip:compress', (_, text: string) => compress(text)) @@ -73,20 +83,6 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) { }) }) - // theme - ipcMain.handle('set-theme', (_, theme: 'light' | 'dark') => { - appConfig.set('theme', theme) - mainWindow?.setTitleBarOverlay && - mainWindow.setTitleBarOverlay(theme === 'dark' ? titleBarOverlayDark : titleBarOverlayLight) - }) - - // 触发检查更新(此方法用于被渲染线程调用,例如页面点击检查更新按钮来调用此方法) - ipcMain.handle('check-for-update', async () => { - return { - currentVersion: autoUpdater.currentVersion, - update: await autoUpdater.checkForUpdates() - } - }) - + // export ipcMain.handle('export:word', exportService.exportToWord) } diff --git a/src/main/services/ConfigManager.ts b/src/main/services/ConfigManager.ts new file mode 100644 index 000000000..a6bb22011 --- /dev/null +++ b/src/main/services/ConfigManager.ts @@ -0,0 +1,19 @@ +import Store from 'electron-store' + +export class ConfigManager { + private store: Store + + constructor() { + this.store = new Store() + } + + getTheme(): 'light' | 'dark' { + return this.store.get('theme', 'light') as 'light' | 'dark' + } + + setTheme(theme: 'light' | 'dark') { + this.store.set('theme', theme) + } +} + +export const configManager = new ConfigManager() diff --git a/src/main/services/ExportService.ts b/src/main/services/ExportService.ts index bf2636bda..94d8b357b 100644 --- a/src/main/services/ExportService.ts +++ b/src/main/services/ExportService.ts @@ -6,13 +6,13 @@ import { dialog } from 'electron' import Logger from 'electron-log' import MarkdownIt from 'markdown-it' -import FileManager from './FileManager' +import FileStorage from './FileStorage' export class ExportService { - private fileManager: FileManager + private fileManager: FileStorage private md: MarkdownIt - constructor(fileManager: FileManager) { + constructor(fileManager: FileStorage) { this.fileManager = fileManager this.md = new MarkdownIt() } diff --git a/src/main/services/FileManager.ts b/src/main/services/FileStorage.ts similarity index 96% rename from src/main/services/FileManager.ts rename to src/main/services/FileStorage.ts index 991ca48af..410a4119c 100644 --- a/src/main/services/FileManager.ts +++ b/src/main/services/FileStorage.ts @@ -20,7 +20,7 @@ import { chdir } from 'process' import sharp from 'sharp' import { v4 as uuidv4 } from 'uuid' -class FileManager { +class FileStorage { private storageDir = path.join(app.getPath('userData'), 'Data', 'Files') private tempDir = path.join(app.getPath('temp'), 'CherryStudio') @@ -135,13 +135,13 @@ class FileManager { .jpeg({ quality: 80 }) .toFile(destPath) - logger.info('[FileManager] Image compressed successfully:', sourcePath) + logger.info('[FileStorage] Image compressed successfully:', sourcePath) } else { // 小图片直接复制 await fs.promises.copyFile(sourcePath, destPath) } } catch (error) { - logger.error('[FileManager] Image compression failed:', error) + logger.error('[FileStorage] Image compression failed:', error) // 压缩失败时直接复制原文件 await fs.promises.copyFile(sourcePath, destPath) } @@ -159,7 +159,7 @@ class FileManager { const ext = path.extname(origin_name).toLowerCase() const destPath = path.join(this.storageDir, uuid + ext) - logger.info('[FileManager] Uploading file:', file.path) + logger.info('[FileStorage] Uploading file:', file.path) // 根据文件类型选择处理方式 if (imageExts.includes(ext)) { @@ -411,7 +411,7 @@ class FileManager { return fileMetadata } catch (error) { - logger.error('[FileManager] Download file error:', error) + logger.error('[FileStorage] Download file error:', error) throw error } } @@ -447,12 +447,12 @@ class FileManager { // 复制文件 await fs.promises.copyFile(sourcePath, destPath) - logger.info('[FileManager] File copied successfully:', { from: sourcePath, to: destPath }) + logger.info('[FileStorage] File copied successfully:', { from: sourcePath, to: destPath }) } catch (error) { - logger.error('[FileManager] Copy file failed:', error) + logger.error('[FileStorage] Copy file failed:', error) throw error } } } -export default FileManager +export default FileStorage diff --git a/src/main/shortcut.ts b/src/main/services/ShortcutService.ts similarity index 100% rename from src/main/shortcut.ts rename to src/main/services/ShortcutService.ts diff --git a/src/main/utils/index.ts b/src/main/utils/index.ts index 42008fee0..07ee7d11a 100644 --- a/src/main/utils/index.ts +++ b/src/main/utils/index.ts @@ -1,3 +1,4 @@ +import fs from 'node:fs' import path from 'node:path' import { app } from 'electron' @@ -5,3 +6,11 @@ import { app } from 'electron' export function getResourcePath() { return path.join(app.getAppPath(), 'resources') } + +export function getDataPath() { + const dataPath = path.join(app.getPath('userData'), 'Data') + if (!fs.existsSync(dataPath)) { + fs.mkdirSync(dataPath, { recursive: true }) + } + return dataPath +} diff --git a/src/main/window.ts b/src/main/window.ts index dc0972735..3014dcf47 100644 --- a/src/main/window.ts +++ b/src/main/window.ts @@ -4,7 +4,8 @@ import windowStateKeeper from 'electron-window-state' import { join } from 'path' import icon from '../../build/icon.png?asset' -import { appConfig, titleBarOverlayDark, titleBarOverlayLight } from './config' +import { titleBarOverlayDark, titleBarOverlayLight } from './config' +import { configManager } from './services/ConfigManager' export function createMainWindow() { // Load the previous state with fallback to defaults @@ -13,7 +14,7 @@ export function createMainWindow() { defaultHeight: 670 }) - const theme = appConfig.get('theme') || 'light' + const theme = configManager.getTheme() // Create the browser window. const isMac = process.platform === 'darwin' diff --git a/src/preload/index.d.ts b/src/preload/index.d.ts index ab0051cc8..245afac70 100644 --- a/src/preload/index.d.ts +++ b/src/preload/index.d.ts @@ -20,8 +20,10 @@ declare global { setTheme: (theme: 'light' | 'dark') => void minApp: (options: { url: string; windowOptions?: Electron.BrowserWindowConstructorOptions }) => void reload: () => void - compress: (text: string) => Promise - decompress: (text: Buffer) => Promise + zip: { + compress: (text: string) => Promise + decompress: (text: Buffer) => Promise + } backup: { backup: (fileName: string, data: string, destinationPath?: string) => Promise restore: (backupPath: string) => Promise diff --git a/src/preload/index.ts b/src/preload/index.ts index 1933df84e..76e4fc2eb 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -5,14 +5,16 @@ import { contextBridge, ipcRenderer, OpenDialogOptions } from 'electron' // Custom APIs for renderer const api = { getAppInfo: () => ipcRenderer.invoke('app:info'), - checkForUpdate: () => ipcRenderer.invoke('check-for-update'), - openWebsite: (url: string) => ipcRenderer.invoke('open-website', url), - setProxy: (proxy: string) => ipcRenderer.invoke('set-proxy', proxy), - setTheme: (theme: 'light' | 'dark') => ipcRenderer.invoke('set-theme', theme), + reload: () => ipcRenderer.invoke('app:reload'), + setProxy: (proxy: string) => ipcRenderer.invoke('app:proxy', proxy), + checkForUpdate: () => ipcRenderer.invoke('app:check-for-update'), + setTheme: (theme: 'light' | 'dark') => ipcRenderer.invoke('app:set-theme', theme), + openWebsite: (url: string) => ipcRenderer.invoke('open:website', url), minApp: (url: string) => ipcRenderer.invoke('minapp', url), - reload: () => ipcRenderer.invoke('reload'), - compress: (text: string) => ipcRenderer.invoke('zip:compress', text), - decompress: (text: Buffer) => ipcRenderer.invoke('zip:decompress', text), + zip: { + compress: (text: string) => ipcRenderer.invoke('zip:compress', text), + decompress: (text: Buffer) => ipcRenderer.invoke('zip:decompress', text) + }, backup: { backup: (fileName: string, data: string, destinationPath?: string) => ipcRenderer.invoke('backup:backup', fileName, data, destinationPath), diff --git a/src/renderer/src/assets/styles/index.scss b/src/renderer/src/assets/styles/index.scss index 4df3a4143..116ae16aa 100644 --- a/src/renderer/src/assets/styles/index.scss +++ b/src/renderer/src/assets/styles/index.scss @@ -168,7 +168,6 @@ body, body[os='mac'] { #content-container { border-top-left-radius: 10px; - border-bottom-left-radius: 10px; border-left: 0.5px solid var(--color-border); box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.05); } diff --git a/src/renderer/src/services/BackupService.ts b/src/renderer/src/services/BackupService.ts index e9dce88db..2b4378336 100644 --- a/src/renderer/src/services/BackupService.ts +++ b/src/renderer/src/services/BackupService.ts @@ -26,7 +26,7 @@ export async function restore() { const restoreData = await window.api.backup.restore(file.filePath) data = JSON.parse(restoreData) } else { - data = JSON.parse(await window.api.decompress(file.content)) + data = JSON.parse(await window.api.zip.decompress(file.content)) } await handleData(data)