refactor: use singleton pattern for screenshot service

- Export screenshotService singleton instance instead of class
- Remove redundant instantiation in IPC handlers
- Align with project patterns (mcpService, searchService, etc.)
- Simplify IPC handler code

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
suyao 2025-12-15 03:29:21 +08:00
parent 0534585fa9
commit 76ecc7376f
No known key found for this signature in database
2 changed files with 12 additions and 20 deletions

View File

@ -54,7 +54,7 @@ import powerMonitorService from './services/PowerMonitorService'
import { proxyManager } from './services/ProxyManager' import { proxyManager } from './services/ProxyManager'
import { pythonService } from './services/PythonService' import { pythonService } from './services/PythonService'
import { FileServiceManager } from './services/remotefile/FileServiceManager' import { FileServiceManager } from './services/remotefile/FileServiceManager'
import { Screenshot } from './services/ScreenshotService' import { screenshotService } from './services/ScreenshotService'
import { searchService } from './services/SearchService' import { searchService } from './services/SearchService'
import { SelectionService } from './services/SelectionService' import { SelectionService } from './services/SelectionService'
import { registerShortcuts, unregisterAllShortcuts } from './services/ShortcutService' import { registerShortcuts, unregisterAllShortcuts } from './services/ShortcutService'
@ -612,34 +612,24 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
} }
}) })
// Screenshot service singleton for selection flow // Screenshot
let screenshotService: Screenshot | null = null
ipcMain.handle(IpcChannel.Screenshot_Capture, async (_event, fileName: string) => { ipcMain.handle(IpcChannel.Screenshot_Capture, async (_event, fileName: string) => {
const service = new Screenshot() return await screenshotService.capture(fileName)
return await service.capture(fileName)
}) })
ipcMain.handle(IpcChannel.Screenshot_CaptureWithSelection, async (_event, fileName: string) => { ipcMain.handle(IpcChannel.Screenshot_CaptureWithSelection, async (_event, fileName: string) => {
if (!screenshotService) {
screenshotService = new Screenshot()
}
return await screenshotService.captureWithSelection(fileName) return await screenshotService.captureWithSelection(fileName)
}) })
ipcMain.handle( ipcMain.handle(
IpcChannel.Screenshot_SelectionConfirm, IpcChannel.Screenshot_SelectionConfirm,
async (_event, selection: { x: number; y: number; width: number; height: number }) => { async (_event, selection: { x: number; y: number; width: number; height: number }) => {
if (screenshotService) { screenshotService.confirmSelection(selection)
screenshotService.confirmSelection(selection)
}
} }
) )
ipcMain.handle(IpcChannel.Screenshot_SelectionCancel, async () => { ipcMain.handle(IpcChannel.Screenshot_SelectionCancel, async () => {
if (screenshotService) { screenshotService.cancelSelection()
screenshotService.cancelSelection()
}
}) })
ipcMain.handle(IpcChannel.File_BinaryImage, fileManager.binaryImage.bind(fileManager)) ipcMain.handle(IpcChannel.File_BinaryImage, fileManager.binaryImage.bind(fileManager))

View File

@ -29,7 +29,7 @@ interface Rectangle {
height: number height: number
} }
export class ScreenshotService { class ScreenshotService {
private selectionWindow: BrowserWindow | null = null private selectionWindow: BrowserWindow | null = null
private screenshotBuffer: Buffer | null = null private screenshotBuffer: Buffer | null = null
private screenshotData: string | null = null private screenshotData: string | null = null
@ -176,7 +176,7 @@ export class ScreenshotService {
} }
} }
public confirmSelection(selection: Rectangle): void { public async confirmSelection(selection: Rectangle): Promise<void> {
if (!this.selectionPromise) { if (!this.selectionPromise) {
logger.warn('No active selection to confirm') logger.warn('No active selection to confirm')
return return
@ -189,7 +189,7 @@ export class ScreenshotService {
status: 'error', status: 'error',
message: 'Selection too small (minimum 10×10 pixels)' message: 'Selection too small (minimum 10×10 pixels)'
}) })
void this.cleanupSelection() await this.cleanupSelection()
return return
} }
@ -197,7 +197,7 @@ export class ScreenshotService {
this.processSelection(selection) this.processSelection(selection)
} }
public cancelSelection(): void { public async cancelSelection(): Promise<void> {
if (!this.selectionPromise) { if (!this.selectionPromise) {
logger.warn('No active selection to cancel') logger.warn('No active selection to cancel')
return return
@ -208,7 +208,7 @@ export class ScreenshotService {
status: 'cancelled', status: 'cancelled',
message: 'User cancelled selection' message: 'User cancelled selection'
}) })
void this.cleanupSelection() await this.cleanupSelection()
} }
private async processSelection(selection: Rectangle): Promise<void> { private async processSelection(selection: Rectangle): Promise<void> {
@ -349,3 +349,5 @@ export class ScreenshotService {
} }
} }
} }
export const screenshotService = new ScreenshotService()