diff --git a/packages/app-common/src/apis/app/apis.ts b/packages/app-common/src/apis/app/apis.ts index d3e7a262..cdfb86a5 100644 --- a/packages/app-common/src/apis/app/apis.ts +++ b/packages/app-common/src/apis/app/apis.ts @@ -7,7 +7,7 @@ export enum AppAPIChannel { GET_APP_DETAILS = 'App_GetAppDetails', } -type CreateWindowAPI = IpcRendererInvokerAPI<(windowType: WindowType) => void>; +type CreateWindowAPI = IpcRendererInvokerAPI<(type: WindowType) => void>; type GetAppDetails = IpcRendererInvokerAPI<() => AppDetails>; export interface AppMainAPI { diff --git a/packages/app-main/src/main/apis/app/index.ts b/packages/app-main/src/main/apis/app/index.ts index 16c578fa..393bf414 100644 --- a/packages/app-main/src/main/apis/app/index.ts +++ b/packages/app-main/src/main/apis/app/index.ts @@ -3,10 +3,10 @@ import { AppAPIChannel } from '@ter/app-common/apis/app'; import { ipcMain } from 'electron'; import { getAppDetails } from 'src/main/app'; -import { windowManager } from 'src/main/window'; +import { WindowManager } from 'src/main/window'; function registerCreateWindowHandler() { - const handler: AppMainAPI['handleCreateWindow'] = (_, windowType) => windowManager.createWindow({ windowType }); + const handler: AppMainAPI['handleCreateWindow'] = (_, type) => WindowManager.INSTANCE.createWindow({ type }); ipcMain.handle(AppAPIChannel.CREATE_WINDOW, handler); } diff --git a/packages/app-main/src/main/index.ts b/packages/app-main/src/main/index.ts index cc527f43..b6b0ae10 100644 --- a/packages/app-main/src/main/index.ts +++ b/packages/app-main/src/main/index.ts @@ -2,7 +2,7 @@ import { WindowType } from '@ter/app-common/apis/app'; import { app, BrowserWindow } from 'electron'; import { registerAppGlobalHandlers } from './apis/app'; -import { windowManager } from './window'; +import { WindowManager } from './window'; async function installExtensions(): Promise { const { @@ -29,7 +29,7 @@ async function handleReady() { registerAppGlobalHandlers(); - windowManager.createWindow({ windowType: WindowType.MAIN }); + WindowManager.INSTANCE.createWindow({ type: WindowType.MAIN }); } // This method will be called when Electron has finished initialization and is ready to create browser windows. @@ -48,6 +48,6 @@ app.on('activate', () => { // On macOS, usually applications will re-create new windows if single click the dock icon when no other windows // opened. if (BrowserWindow.getAllWindows().length === 0) { - windowManager.createWindow({ windowType: WindowType.MAIN }); + WindowManager.INSTANCE.createWindow({ type: WindowType.MAIN }); } }); diff --git a/packages/app-main/src/main/window/abstractWindow.ts b/packages/app-main/src/main/window/abstractWindow.ts index cfb13261..9fab2383 100644 --- a/packages/app-main/src/main/window/abstractWindow.ts +++ b/packages/app-main/src/main/window/abstractWindow.ts @@ -11,15 +11,13 @@ import type { AbstractWindowOption, CloseWindowOption } from './types'; export abstract class AbstractWindow { protected declare readonly _window: BrowserWindow; protected declare readonly _windowType: WindowType; - protected declare readonly _windowId: string; private declare readonly _onClose: (option: CloseWindowOption) => void | Promise; constructor(option: AbstractWindowOption) { - this._windowId = option.windowId; - this._windowType = option.windowType; + this._windowType = option.type; - const windowStateKeeper = new WindowStateKeeper(option.windowType); + const windowStateKeeper = new WindowStateKeeper(this._windowType); this._window = new BrowserWindow({ x: windowStateKeeper.x, @@ -42,6 +40,10 @@ export abstract class AbstractWindow { this._addAPIHandlers(); } + get id() { + return this._window.id; + } + async show(): Promise { if (process.env.NODE_ENV === 'production') { await this._window.loadFile(path.resolve(appPaths.src, 'index.html')); @@ -66,7 +68,7 @@ export abstract class AbstractWindow { private _close = () => { this._removeAPIHandlers(); - void this._onClose({ windowId: this._windowId }); + void this._onClose({ id: this.id }); }; // ---------------------------------------------------------------------------------------------------- Ipc Handlers diff --git a/packages/app-main/src/main/window/mainWindow.ts b/packages/app-main/src/main/window/mainWindow.ts index 727dcc01..ceb59cac 100644 --- a/packages/app-main/src/main/window/mainWindow.ts +++ b/packages/app-main/src/main/window/mainWindow.ts @@ -5,6 +5,6 @@ import type { WindowOption } from './types'; export class MainWindow extends AbstractWindow { constructor(option: WindowOption) { - super({ windowType: WindowType.MAIN, ...option }); + super({ type: WindowType.MAIN, ...option }); } } diff --git a/packages/app-main/src/main/window/types.ts b/packages/app-main/src/main/window/types.ts index 579e3034..dea64a56 100644 --- a/packages/app-main/src/main/window/types.ts +++ b/packages/app-main/src/main/window/types.ts @@ -1,18 +1,17 @@ import type { WindowType } from '@ter/app-common/apis/app'; export interface CreateWindowOption { - windowType: WindowType; + type: WindowType; } export interface CloseWindowOption { - windowId: string; + id: number; } export interface WindowOption { - windowId: string; onClose: (option: CloseWindowOption) => void | Promise; } export interface AbstractWindowOption extends WindowOption { - windowType: WindowType; + type: WindowType; } diff --git a/packages/app-main/src/main/window/windowManager.ts b/packages/app-main/src/main/window/windowManager.ts index 3cc2c1d0..093c9ca8 100644 --- a/packages/app-main/src/main/window/windowManager.ts +++ b/packages/app-main/src/main/window/windowManager.ts @@ -7,47 +7,44 @@ import type { AbstractWindow } from './abstractWindow'; import { MainWindow } from './mainWindow'; import type { CloseWindowOption, CreateWindowOption } from './types'; -interface WindowStore { - [id: string]: Nullable; -} +type WindowStore = Record>; export class WindowManager { - private declare _count: number; - private declare _store: WindowStore; + private declare static _instance?: WindowManager; - constructor() { - this._count = 0; - this._store = {}; + static get INSTANCE() { + if (!WindowManager._instance) { + WindowManager._instance = new WindowManager(); + } + return WindowManager._instance; } - createWindow = (option: CreateWindowOption): void => { - this._count++; + private declare _store: WindowStore; - const { windowType } = option; - const windowId = `${windowType}-${this._count}`; + private constructor() { + this._store = {}; + } - switch (windowType) { + private _newWindow(type: WindowType): AbstractWindow { + switch (type) { case WindowType.MAIN: - this._store[windowId] = new MainWindow({ - windowId, + return new MainWindow({ onClose: this._closeWindow, }); - break; /* istanbul ignore next */ default: - assertIsNever(windowType); + assertIsNever(type); } + } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - void this._store[windowId]!.show(); - }; + createWindow(option: CreateWindowOption): void { + const window = this._newWindow(option.type); + this._store[window.id] = window; + void window.show(); + } private _closeWindow = (option: CloseWindowOption): void => { - const { windowId } = option; - - this._store[windowId] = null; + this._store[option.id] = null; }; } - -export const windowManager = new WindowManager();