mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-21 16:01:35 +08:00
refactor: main code
This commit is contained in:
parent
04af940144
commit
9468f3b511
@ -1,25 +1,15 @@
|
|||||||
import fs from 'node:fs'
|
|
||||||
|
|
||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
import Store from 'electron-store'
|
|
||||||
import path from 'path'
|
import { getDataPath } from './utils'
|
||||||
|
|
||||||
const isDev = process.env.NODE_ENV === 'development'
|
const isDev = process.env.NODE_ENV === 'development'
|
||||||
|
|
||||||
isDev && app.setPath('userData', app.getPath('userData') + 'Dev')
|
if (isDev) {
|
||||||
|
app.setPath('userData', app.getPath('userData') + 'Dev')
|
||||||
const getDataPath = () => {
|
|
||||||
const dataPath = path.join(app.getPath('userData'), 'Data')
|
|
||||||
if (!fs.existsSync(dataPath)) {
|
|
||||||
fs.mkdirSync(dataPath, { recursive: true })
|
|
||||||
}
|
|
||||||
return dataPath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DATA_PATH = getDataPath()
|
export const DATA_PATH = getDataPath()
|
||||||
|
|
||||||
export const appConfig = new Store()
|
|
||||||
|
|
||||||
export const titleBarOverlayDark = {
|
export const titleBarOverlayDark = {
|
||||||
height: 40,
|
height: 40,
|
||||||
color: '#00000000',
|
color: '#00000000',
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { app, BrowserWindow } from 'electron'
|
|||||||
import installExtension, { REDUX_DEVTOOLS } from 'electron-devtools-installer'
|
import installExtension, { REDUX_DEVTOOLS } from 'electron-devtools-installer'
|
||||||
|
|
||||||
import { registerIpc } from './ipc'
|
import { registerIpc } from './ipc'
|
||||||
import { registerZoomShortcut } from './shortcut'
|
import { registerZoomShortcut } from './services/ShortcutService'
|
||||||
import { updateUserDataPath } from './utils/upgrade'
|
import { updateUserDataPath } from './utils/upgrade'
|
||||||
import { createMainWindow } from './window'
|
import { createMainWindow } from './window'
|
||||||
|
|
||||||
|
|||||||
@ -2,15 +2,16 @@ import path from 'node:path'
|
|||||||
|
|
||||||
import { BrowserWindow, ipcMain, session, shell } from 'electron'
|
import { BrowserWindow, ipcMain, session, shell } from 'electron'
|
||||||
|
|
||||||
import { appConfig, titleBarOverlayDark, titleBarOverlayLight } from './config'
|
import { titleBarOverlayDark, titleBarOverlayLight } from './config'
|
||||||
import AppUpdater from './services/AppUpdater'
|
import AppUpdater from './services/AppUpdater'
|
||||||
import BackupManager from './services/BackupManager'
|
import BackupManager from './services/BackupManager'
|
||||||
|
import { configManager } from './services/ConfigManager'
|
||||||
import { ExportService } from './services/ExportService'
|
import { ExportService } from './services/ExportService'
|
||||||
import FileManager from './services/FileManager'
|
import FileStorage from './services/FileStorage'
|
||||||
import { compress, decompress } from './utils/zip'
|
import { compress, decompress } from './utils/zip'
|
||||||
import { createMinappWindow } from './window'
|
import { createMinappWindow } from './window'
|
||||||
|
|
||||||
const fileManager = new FileManager()
|
const fileManager = new FileStorage()
|
||||||
const backupManager = new BackupManager()
|
const backupManager = new BackupManager()
|
||||||
const exportService = new ExportService(fileManager)
|
const exportService = new ExportService(fileManager)
|
||||||
|
|
||||||
@ -24,16 +25,25 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
filesPath: path.join(app.getPath('userData'), 'Data', 'Files')
|
filesPath: path.join(app.getPath('userData'), 'Data', 'Files')
|
||||||
}))
|
}))
|
||||||
|
|
||||||
ipcMain.handle('open-website', (_, url: string) => {
|
ipcMain.handle('app:proxy', (_, proxy: string) => session.defaultSession.setProxy(proxy ? { proxyRules: proxy } : {}))
|
||||||
shell.openExternal(url)
|
ipcMain.handle('app:reload', () => mainWindow.reload())
|
||||||
|
ipcMain.handle('open:website', (_, url: string) => shell.openExternal(url))
|
||||||
|
|
||||||
|
// theme
|
||||||
|
ipcMain.handle('app:set-theme', (_, theme: 'light' | 'dark') => {
|
||||||
|
configManager.setTheme(theme)
|
||||||
|
mainWindow?.setTitleBarOverlay &&
|
||||||
|
mainWindow.setTitleBarOverlay(theme === 'dark' ? titleBarOverlayDark : titleBarOverlayLight)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('set-proxy', (_, proxy: string) => {
|
// check for update
|
||||||
session.defaultSession.setProxy(proxy ? { proxyRules: proxy } : {})
|
ipcMain.handle('app:check-for-update', async () => {
|
||||||
|
return {
|
||||||
|
currentVersion: autoUpdater.currentVersion,
|
||||||
|
update: await autoUpdater.checkForUpdates()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('reload', () => mainWindow.reload())
|
|
||||||
|
|
||||||
// zip
|
// zip
|
||||||
ipcMain.handle('zip:compress', (_, text: string) => compress(text))
|
ipcMain.handle('zip:compress', (_, text: string) => compress(text))
|
||||||
ipcMain.handle('zip:decompress', (_, text: Buffer) => decompress(text))
|
ipcMain.handle('zip:decompress', (_, text: Buffer) => decompress(text))
|
||||||
@ -73,20 +83,6 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// theme
|
// export
|
||||||
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()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.handle('export:word', exportService.exportToWord)
|
ipcMain.handle('export:word', exportService.exportToWord)
|
||||||
}
|
}
|
||||||
|
|||||||
19
src/main/services/ConfigManager.ts
Normal file
19
src/main/services/ConfigManager.ts
Normal file
@ -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()
|
||||||
@ -6,13 +6,13 @@ import { dialog } from 'electron'
|
|||||||
import Logger from 'electron-log'
|
import Logger from 'electron-log'
|
||||||
import MarkdownIt from 'markdown-it'
|
import MarkdownIt from 'markdown-it'
|
||||||
|
|
||||||
import FileManager from './FileManager'
|
import FileStorage from './FileStorage'
|
||||||
|
|
||||||
export class ExportService {
|
export class ExportService {
|
||||||
private fileManager: FileManager
|
private fileManager: FileStorage
|
||||||
private md: MarkdownIt
|
private md: MarkdownIt
|
||||||
|
|
||||||
constructor(fileManager: FileManager) {
|
constructor(fileManager: FileStorage) {
|
||||||
this.fileManager = fileManager
|
this.fileManager = fileManager
|
||||||
this.md = new MarkdownIt()
|
this.md = new MarkdownIt()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import { chdir } from 'process'
|
|||||||
import sharp from 'sharp'
|
import sharp from 'sharp'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
|
||||||
class FileManager {
|
class FileStorage {
|
||||||
private storageDir = path.join(app.getPath('userData'), 'Data', 'Files')
|
private storageDir = path.join(app.getPath('userData'), 'Data', 'Files')
|
||||||
private tempDir = path.join(app.getPath('temp'), 'CherryStudio')
|
private tempDir = path.join(app.getPath('temp'), 'CherryStudio')
|
||||||
|
|
||||||
@ -135,13 +135,13 @@ class FileManager {
|
|||||||
.jpeg({ quality: 80 })
|
.jpeg({ quality: 80 })
|
||||||
.toFile(destPath)
|
.toFile(destPath)
|
||||||
|
|
||||||
logger.info('[FileManager] Image compressed successfully:', sourcePath)
|
logger.info('[FileStorage] Image compressed successfully:', sourcePath)
|
||||||
} else {
|
} else {
|
||||||
// 小图片直接复制
|
// 小图片直接复制
|
||||||
await fs.promises.copyFile(sourcePath, destPath)
|
await fs.promises.copyFile(sourcePath, destPath)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('[FileManager] Image compression failed:', error)
|
logger.error('[FileStorage] Image compression failed:', error)
|
||||||
// 压缩失败时直接复制原文件
|
// 压缩失败时直接复制原文件
|
||||||
await fs.promises.copyFile(sourcePath, destPath)
|
await fs.promises.copyFile(sourcePath, destPath)
|
||||||
}
|
}
|
||||||
@ -159,7 +159,7 @@ class FileManager {
|
|||||||
const ext = path.extname(origin_name).toLowerCase()
|
const ext = path.extname(origin_name).toLowerCase()
|
||||||
const destPath = path.join(this.storageDir, uuid + ext)
|
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)) {
|
if (imageExts.includes(ext)) {
|
||||||
@ -411,7 +411,7 @@ class FileManager {
|
|||||||
|
|
||||||
return fileMetadata
|
return fileMetadata
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('[FileManager] Download file error:', error)
|
logger.error('[FileStorage] Download file error:', error)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -447,12 +447,12 @@ class FileManager {
|
|||||||
|
|
||||||
// 复制文件
|
// 复制文件
|
||||||
await fs.promises.copyFile(sourcePath, destPath)
|
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) {
|
} catch (error) {
|
||||||
logger.error('[FileManager] Copy file failed:', error)
|
logger.error('[FileStorage] Copy file failed:', error)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default FileManager
|
export default FileStorage
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import fs from 'node:fs'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
|
||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
@ -5,3 +6,11 @@ import { app } from 'electron'
|
|||||||
export function getResourcePath() {
|
export function getResourcePath() {
|
||||||
return path.join(app.getAppPath(), 'resources')
|
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
|
||||||
|
}
|
||||||
|
|||||||
@ -4,7 +4,8 @@ import windowStateKeeper from 'electron-window-state'
|
|||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
|
|
||||||
import icon from '../../build/icon.png?asset'
|
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() {
|
export function createMainWindow() {
|
||||||
// Load the previous state with fallback to defaults
|
// Load the previous state with fallback to defaults
|
||||||
@ -13,7 +14,7 @@ export function createMainWindow() {
|
|||||||
defaultHeight: 670
|
defaultHeight: 670
|
||||||
})
|
})
|
||||||
|
|
||||||
const theme = appConfig.get('theme') || 'light'
|
const theme = configManager.getTheme()
|
||||||
|
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
const isMac = process.platform === 'darwin'
|
const isMac = process.platform === 'darwin'
|
||||||
|
|||||||
2
src/preload/index.d.ts
vendored
2
src/preload/index.d.ts
vendored
@ -20,8 +20,10 @@ declare global {
|
|||||||
setTheme: (theme: 'light' | 'dark') => void
|
setTheme: (theme: 'light' | 'dark') => void
|
||||||
minApp: (options: { url: string; windowOptions?: Electron.BrowserWindowConstructorOptions }) => void
|
minApp: (options: { url: string; windowOptions?: Electron.BrowserWindowConstructorOptions }) => void
|
||||||
reload: () => void
|
reload: () => void
|
||||||
|
zip: {
|
||||||
compress: (text: string) => Promise<Buffer>
|
compress: (text: string) => Promise<Buffer>
|
||||||
decompress: (text: Buffer) => Promise<string>
|
decompress: (text: Buffer) => Promise<string>
|
||||||
|
}
|
||||||
backup: {
|
backup: {
|
||||||
backup: (fileName: string, data: string, destinationPath?: string) => Promise<Readable>
|
backup: (fileName: string, data: string, destinationPath?: string) => Promise<Readable>
|
||||||
restore: (backupPath: string) => Promise<string>
|
restore: (backupPath: string) => Promise<string>
|
||||||
|
|||||||
@ -5,14 +5,16 @@ import { contextBridge, ipcRenderer, OpenDialogOptions } from 'electron'
|
|||||||
// Custom APIs for renderer
|
// Custom APIs for renderer
|
||||||
const api = {
|
const api = {
|
||||||
getAppInfo: () => ipcRenderer.invoke('app:info'),
|
getAppInfo: () => ipcRenderer.invoke('app:info'),
|
||||||
checkForUpdate: () => ipcRenderer.invoke('check-for-update'),
|
reload: () => ipcRenderer.invoke('app:reload'),
|
||||||
openWebsite: (url: string) => ipcRenderer.invoke('open-website', url),
|
setProxy: (proxy: string) => ipcRenderer.invoke('app:proxy', proxy),
|
||||||
setProxy: (proxy: string) => ipcRenderer.invoke('set-proxy', proxy),
|
checkForUpdate: () => ipcRenderer.invoke('app:check-for-update'),
|
||||||
setTheme: (theme: 'light' | 'dark') => ipcRenderer.invoke('set-theme', theme),
|
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),
|
minApp: (url: string) => ipcRenderer.invoke('minapp', url),
|
||||||
reload: () => ipcRenderer.invoke('reload'),
|
zip: {
|
||||||
compress: (text: string) => ipcRenderer.invoke('zip:compress', text),
|
compress: (text: string) => ipcRenderer.invoke('zip:compress', text),
|
||||||
decompress: (text: Buffer) => ipcRenderer.invoke('zip:decompress', text),
|
decompress: (text: Buffer) => ipcRenderer.invoke('zip:decompress', text)
|
||||||
|
},
|
||||||
backup: {
|
backup: {
|
||||||
backup: (fileName: string, data: string, destinationPath?: string) =>
|
backup: (fileName: string, data: string, destinationPath?: string) =>
|
||||||
ipcRenderer.invoke('backup:backup', fileName, data, destinationPath),
|
ipcRenderer.invoke('backup:backup', fileName, data, destinationPath),
|
||||||
|
|||||||
@ -168,7 +168,6 @@ body,
|
|||||||
body[os='mac'] {
|
body[os='mac'] {
|
||||||
#content-container {
|
#content-container {
|
||||||
border-top-left-radius: 10px;
|
border-top-left-radius: 10px;
|
||||||
border-bottom-left-radius: 10px;
|
|
||||||
border-left: 0.5px solid var(--color-border);
|
border-left: 0.5px solid var(--color-border);
|
||||||
box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.05);
|
box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@ export async function restore() {
|
|||||||
const restoreData = await window.api.backup.restore(file.filePath)
|
const restoreData = await window.api.backup.restore(file.filePath)
|
||||||
data = JSON.parse(restoreData)
|
data = JSON.parse(restoreData)
|
||||||
} else {
|
} else {
|
||||||
data = JSON.parse(await window.api.decompress(file.content))
|
data = JSON.parse(await window.api.zip.decompress(file.content))
|
||||||
}
|
}
|
||||||
|
|
||||||
await handleData(data)
|
await handleData(data)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user