mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
refactor(main): finish TASK-94 composition-root extraction
Move IPC, shortcuts, startup lifecycle, and app-ready assembly behind dedicated runtime composers so main.ts stays focused on boot wiring while preserving behavior and test coverage.
This commit is contained in:
1682
src/main.ts
1682
src/main.ts
File diff suppressed because it is too large
Load Diff
75
src/main/runtime/composers/app-ready-composer.test.ts
Normal file
75
src/main/runtime/composers/app-ready-composer.test.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { composeAppReadyRuntime } from './app-ready-composer';
|
||||
|
||||
test('composeAppReadyRuntime returns reload/critical/app-ready handlers', () => {
|
||||
const composed = composeAppReadyRuntime({
|
||||
reloadConfigMainDeps: {
|
||||
reloadConfigStrict: () => ({ config: {} as never, warnings: [] }),
|
||||
logInfo: () => {},
|
||||
logWarning: () => {},
|
||||
showDesktopNotification: () => {},
|
||||
startConfigHotReload: () => {},
|
||||
refreshAnilistClientSecretState: async () => {},
|
||||
failHandlers: {
|
||||
logError: () => {},
|
||||
showErrorBox: () => {},
|
||||
quit: () => {},
|
||||
},
|
||||
},
|
||||
criticalConfigErrorMainDeps: {
|
||||
getConfigPath: () => '/tmp/config.jsonc',
|
||||
failHandlers: {
|
||||
logError: () => {},
|
||||
showErrorBox: () => {},
|
||||
quit: () => {},
|
||||
},
|
||||
},
|
||||
appReadyRuntimeMainDeps: {
|
||||
loadSubtitlePosition: () => {},
|
||||
resolveKeybindings: () => {},
|
||||
createMpvClient: () => {},
|
||||
getResolvedConfig: () => ({}) as never,
|
||||
getConfigWarnings: () => [],
|
||||
logConfigWarning: () => {},
|
||||
setLogLevel: () => {},
|
||||
initRuntimeOptionsManager: () => {},
|
||||
setSecondarySubMode: () => {},
|
||||
defaultSecondarySubMode: 'hover',
|
||||
defaultWebsocketPort: 5174,
|
||||
hasMpvWebsocketPlugin: () => false,
|
||||
startSubtitleWebsocket: () => {},
|
||||
log: () => {},
|
||||
createMecabTokenizerAndCheck: async () => {},
|
||||
createSubtitleTimingTracker: () => {},
|
||||
loadYomitanExtension: async () => {},
|
||||
startJellyfinRemoteSession: async () => {},
|
||||
prewarmSubtitleDictionaries: async () => {},
|
||||
startBackgroundWarmups: () => {},
|
||||
texthookerOnlyMode: false,
|
||||
shouldAutoInitializeOverlayRuntimeFromConfig: () => false,
|
||||
initializeOverlayRuntime: () => {},
|
||||
handleInitialArgs: () => {},
|
||||
logDebug: () => {},
|
||||
now: () => Date.now(),
|
||||
},
|
||||
immersionTrackerStartupMainDeps: {
|
||||
getResolvedConfig: () => ({}) as never,
|
||||
getConfiguredDbPath: () => '/tmp/immersion.sqlite',
|
||||
createTrackerService: () =>
|
||||
({
|
||||
startSession: () => {},
|
||||
}) as never,
|
||||
setTracker: () => {},
|
||||
getMpvClient: () => null,
|
||||
seedTrackerFromCurrentMedia: () => {},
|
||||
logInfo: () => {},
|
||||
logDebug: () => {},
|
||||
logWarn: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(typeof composed.reloadConfig, 'function');
|
||||
assert.equal(typeof composed.criticalConfigError, 'function');
|
||||
assert.equal(typeof composed.appReadyRuntimeRunner, 'function');
|
||||
});
|
||||
58
src/main/runtime/composers/app-ready-composer.ts
Normal file
58
src/main/runtime/composers/app-ready-composer.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { createAppReadyRuntimeRunner } from '../../app-lifecycle';
|
||||
import { createBuildAppReadyRuntimeMainDepsHandler } from '../app-ready-main-deps';
|
||||
import {
|
||||
createBuildCriticalConfigErrorMainDepsHandler,
|
||||
createBuildReloadConfigMainDepsHandler,
|
||||
} from '../startup-config-main-deps';
|
||||
import { createCriticalConfigErrorHandler, createReloadConfigHandler } from '../startup-config';
|
||||
import { createBuildImmersionTrackerStartupMainDepsHandler } from '../immersion-startup-main-deps';
|
||||
import { createImmersionTrackerStartupHandler } from '../immersion-startup';
|
||||
|
||||
type ReloadConfigMainDeps = Parameters<typeof createBuildReloadConfigMainDepsHandler>[0];
|
||||
type CriticalConfigErrorMainDeps = Parameters<
|
||||
typeof createBuildCriticalConfigErrorMainDepsHandler
|
||||
>[0];
|
||||
type AppReadyRuntimeMainDeps = Parameters<typeof createBuildAppReadyRuntimeMainDepsHandler>[0];
|
||||
|
||||
export type AppReadyComposerOptions = {
|
||||
reloadConfigMainDeps: ReloadConfigMainDeps;
|
||||
criticalConfigErrorMainDeps: CriticalConfigErrorMainDeps;
|
||||
appReadyRuntimeMainDeps: Omit<AppReadyRuntimeMainDeps, 'reloadConfig' | 'onCriticalConfigErrors'>;
|
||||
immersionTrackerStartupMainDeps: Parameters<
|
||||
typeof createBuildImmersionTrackerStartupMainDepsHandler
|
||||
>[0];
|
||||
};
|
||||
|
||||
export type AppReadyComposerResult = {
|
||||
reloadConfig: ReturnType<typeof createReloadConfigHandler>;
|
||||
criticalConfigError: ReturnType<typeof createCriticalConfigErrorHandler>;
|
||||
appReadyRuntimeRunner: ReturnType<typeof createAppReadyRuntimeRunner>;
|
||||
};
|
||||
|
||||
export function composeAppReadyRuntime(options: AppReadyComposerOptions): AppReadyComposerResult {
|
||||
const reloadConfig = createReloadConfigHandler(
|
||||
createBuildReloadConfigMainDepsHandler(options.reloadConfigMainDeps)(),
|
||||
);
|
||||
const criticalConfigError = createCriticalConfigErrorHandler(
|
||||
createBuildCriticalConfigErrorMainDepsHandler(options.criticalConfigErrorMainDeps)(),
|
||||
);
|
||||
|
||||
const appReadyRuntimeRunner = createAppReadyRuntimeRunner(
|
||||
createBuildAppReadyRuntimeMainDepsHandler({
|
||||
...options.appReadyRuntimeMainDeps,
|
||||
reloadConfig,
|
||||
createImmersionTracker: createImmersionTrackerStartupHandler(
|
||||
createBuildImmersionTrackerStartupMainDepsHandler(
|
||||
options.immersionTrackerStartupMainDeps,
|
||||
)(),
|
||||
),
|
||||
onCriticalConfigErrors: criticalConfigError,
|
||||
})(),
|
||||
);
|
||||
|
||||
return {
|
||||
reloadConfig,
|
||||
criticalConfigError,
|
||||
appReadyRuntimeRunner,
|
||||
};
|
||||
}
|
||||
97
src/main/runtime/composers/ipc-runtime-composer.test.ts
Normal file
97
src/main/runtime/composers/ipc-runtime-composer.test.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { composeIpcRuntimeHandlers } from './ipc-runtime-composer';
|
||||
|
||||
test('composeIpcRuntimeHandlers returns callable IPC handlers and registration bridge', async () => {
|
||||
let registered = false;
|
||||
|
||||
const composed = composeIpcRuntimeHandlers<{ value: number }, { ok: boolean; received: number }>({
|
||||
mpvCommandMainDeps: {
|
||||
triggerSubsyncFromConfig: async () => {},
|
||||
openRuntimeOptionsPalette: () => {},
|
||||
cycleRuntimeOption: () => ({ ok: true }),
|
||||
showMpvOsd: () => {},
|
||||
replayCurrentSubtitle: () => {},
|
||||
playNextSubtitle: () => {},
|
||||
sendMpvCommand: () => {},
|
||||
isMpvConnected: () => false,
|
||||
hasRuntimeOptionsManager: () => true,
|
||||
},
|
||||
handleMpvCommandFromIpcRuntime: () => {},
|
||||
runSubsyncManualFromIpc: async (request) => ({ ok: true, received: request.value }),
|
||||
registration: {
|
||||
runtimeOptions: {
|
||||
getRuntimeOptionsManager: () => null,
|
||||
showMpvOsd: () => {},
|
||||
},
|
||||
mainDeps: {
|
||||
getInvisibleWindow: () => null,
|
||||
getMainWindow: () => null,
|
||||
getVisibleOverlayVisibility: () => false,
|
||||
getInvisibleOverlayVisibility: () => false,
|
||||
focusMainWindow: () => {},
|
||||
onOverlayModalClosed: () => {},
|
||||
openYomitanSettings: () => {},
|
||||
quitApp: () => {},
|
||||
toggleVisibleOverlay: () => {},
|
||||
tokenizeCurrentSubtitle: async () => null,
|
||||
getCurrentSubtitleRaw: () => '',
|
||||
getCurrentSubtitleAss: () => '',
|
||||
getMpvSubtitleRenderMetrics: () => ({}) as never,
|
||||
getSubtitlePosition: () => ({}) as never,
|
||||
getSubtitleStyle: () => ({}) as never,
|
||||
saveSubtitlePosition: () => {},
|
||||
getMecabTokenizer: () => null,
|
||||
getKeybindings: () => [],
|
||||
getConfiguredShortcuts: () => ({}) as never,
|
||||
getSecondarySubMode: () => 'hover' as never,
|
||||
getMpvClient: () => null,
|
||||
getAnkiConnectStatus: () => false,
|
||||
getRuntimeOptions: () => [],
|
||||
reportOverlayContentBounds: () => {},
|
||||
getAnilistStatus: () => ({}) as never,
|
||||
clearAnilistToken: () => {},
|
||||
openAnilistSetup: () => {},
|
||||
getAnilistQueueStatus: () => ({}) as never,
|
||||
retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }),
|
||||
appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }),
|
||||
},
|
||||
ankiJimakuDeps: {
|
||||
patchAnkiConnectEnabled: () => {},
|
||||
getResolvedConfig: () => ({}) as never,
|
||||
getRuntimeOptionsManager: () => null,
|
||||
getSubtitleTimingTracker: () => null,
|
||||
getMpvClient: () => null,
|
||||
getAnkiIntegration: () => null,
|
||||
setAnkiIntegration: () => {},
|
||||
getKnownWordCacheStatePath: () => '',
|
||||
showDesktopNotification: () => {},
|
||||
createFieldGroupingCallback: () => (() => {}) as never,
|
||||
broadcastRuntimeOptionsChanged: () => {},
|
||||
getFieldGroupingResolver: () => null,
|
||||
setFieldGroupingResolver: () => {},
|
||||
parseMediaInfo: () => ({}) as never,
|
||||
getCurrentMediaPath: () => null,
|
||||
jimakuFetchJson: async () => ({ data: null }) as never,
|
||||
getJimakuMaxEntryResults: () => 0,
|
||||
getJimakuLanguagePreference: () => 'ja' as never,
|
||||
resolveJimakuApiKey: async () => null,
|
||||
isRemoteMediaPath: () => false,
|
||||
downloadToFile: async () => ({ ok: true, path: '/tmp/file' }),
|
||||
},
|
||||
registerIpcRuntimeServices: () => {
|
||||
registered = true;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(typeof composed.handleMpvCommandFromIpc, 'function');
|
||||
assert.equal(typeof composed.runSubsyncManualFromIpc, 'function');
|
||||
assert.equal(typeof composed.registerIpcRuntimeHandlers, 'function');
|
||||
|
||||
const result = await composed.runSubsyncManualFromIpc({ value: 7 });
|
||||
assert.deepEqual(result, { ok: true, received: 7 });
|
||||
|
||||
composed.registerIpcRuntimeHandlers();
|
||||
assert.equal(registered, true);
|
||||
});
|
||||
75
src/main/runtime/composers/ipc-runtime-composer.ts
Normal file
75
src/main/runtime/composers/ipc-runtime-composer.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import type { RegisterIpcRuntimeServicesParams } from '../../ipc-runtime';
|
||||
import {
|
||||
createBuildMpvCommandFromIpcRuntimeMainDepsHandler,
|
||||
createIpcRuntimeHandlers,
|
||||
} from '../domains/ipc';
|
||||
|
||||
type MpvCommand = (string | number)[];
|
||||
|
||||
type IpcMainDepsWithoutHandlers = Omit<
|
||||
RegisterIpcRuntimeServicesParams['mainDeps'],
|
||||
'handleMpvCommand' | 'runSubsyncManual'
|
||||
>;
|
||||
|
||||
type IpcRuntimeDeps<TRequest, TResult> = Parameters<
|
||||
typeof createIpcRuntimeHandlers<TRequest, TResult>
|
||||
>[0];
|
||||
|
||||
export type IpcRuntimeComposerOptions<TRequest, TResult> = {
|
||||
mpvCommandMainDeps: Parameters<typeof createBuildMpvCommandFromIpcRuntimeMainDepsHandler>[0];
|
||||
handleMpvCommandFromIpcRuntime: IpcRuntimeDeps<
|
||||
TRequest,
|
||||
TResult
|
||||
>['handleMpvCommandFromIpcDeps']['handleMpvCommandFromIpcRuntime'];
|
||||
runSubsyncManualFromIpc: (request: TRequest) => Promise<TResult>;
|
||||
registration: {
|
||||
runtimeOptions: RegisterIpcRuntimeServicesParams['runtimeOptions'];
|
||||
mainDeps: IpcMainDepsWithoutHandlers;
|
||||
ankiJimakuDeps: RegisterIpcRuntimeServicesParams['ankiJimakuDeps'];
|
||||
registerIpcRuntimeServices: (params: RegisterIpcRuntimeServicesParams) => void;
|
||||
};
|
||||
};
|
||||
|
||||
export type IpcRuntimeComposerResult<TRequest, TResult> = {
|
||||
handleMpvCommandFromIpc: (command: MpvCommand) => void;
|
||||
runSubsyncManualFromIpc: (request: TRequest) => Promise<TResult>;
|
||||
registerIpcRuntimeHandlers: () => void;
|
||||
};
|
||||
|
||||
export function composeIpcRuntimeHandlers<TRequest, TResult>(
|
||||
options: IpcRuntimeComposerOptions<TRequest, TResult>,
|
||||
): IpcRuntimeComposerResult<TRequest, TResult> {
|
||||
const mpvCommandFromIpcRuntimeMainDeps = createBuildMpvCommandFromIpcRuntimeMainDepsHandler(
|
||||
options.mpvCommandMainDeps,
|
||||
)();
|
||||
const { handleMpvCommandFromIpc, runSubsyncManualFromIpc } = createIpcRuntimeHandlers<
|
||||
TRequest,
|
||||
TResult
|
||||
>({
|
||||
handleMpvCommandFromIpcDeps: {
|
||||
handleMpvCommandFromIpcRuntime: options.handleMpvCommandFromIpcRuntime,
|
||||
buildMpvCommandDeps: () => mpvCommandFromIpcRuntimeMainDeps,
|
||||
},
|
||||
runSubsyncManualFromIpcDeps: {
|
||||
runManualFromIpc: (request) => options.runSubsyncManualFromIpc(request),
|
||||
},
|
||||
});
|
||||
|
||||
const registerIpcRuntimeHandlers = (): void => {
|
||||
options.registration.registerIpcRuntimeServices({
|
||||
runtimeOptions: options.registration.runtimeOptions,
|
||||
mainDeps: {
|
||||
...options.registration.mainDeps,
|
||||
handleMpvCommand: (command) => handleMpvCommandFromIpc(command),
|
||||
runSubsyncManual: (request) => runSubsyncManualFromIpc(request as TRequest),
|
||||
},
|
||||
ankiJimakuDeps: options.registration.ankiJimakuDeps,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
handleMpvCommandFromIpc: (command) => handleMpvCommandFromIpc(command),
|
||||
runSubsyncManualFromIpc: (request) => runSubsyncManualFromIpc(request),
|
||||
registerIpcRuntimeHandlers,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { composeShortcutRuntimes } from './shortcuts-runtime-composer';
|
||||
|
||||
test('composeShortcutRuntimes returns callable shortcut runtime handlers', () => {
|
||||
const composed = composeShortcutRuntimes({
|
||||
globalShortcuts: {
|
||||
getConfiguredShortcutsMainDeps: {
|
||||
getResolvedConfig: () => ({}) as never,
|
||||
defaultConfig: {} as never,
|
||||
resolveConfiguredShortcuts: () => ({}) as never,
|
||||
},
|
||||
buildRegisterGlobalShortcutsMainDeps: () => ({
|
||||
getConfiguredShortcuts: () => ({}) as never,
|
||||
registerGlobalShortcutsCore: () => {},
|
||||
toggleVisibleOverlay: () => {},
|
||||
toggleInvisibleOverlay: () => {},
|
||||
openYomitanSettings: () => {},
|
||||
isDev: false,
|
||||
getMainWindow: () => null,
|
||||
}),
|
||||
buildRefreshGlobalAndOverlayShortcutsMainDeps: () => ({
|
||||
unregisterAllGlobalShortcuts: () => {},
|
||||
registerGlobalShortcuts: () => {},
|
||||
syncOverlayShortcuts: () => {},
|
||||
}),
|
||||
},
|
||||
numericShortcutRuntimeMainDeps: {
|
||||
globalShortcut: {
|
||||
register: () => true,
|
||||
unregister: () => {},
|
||||
},
|
||||
showMpvOsd: () => {},
|
||||
setTimer: (handler, timeoutMs) => setTimeout(handler, timeoutMs),
|
||||
clearTimer: (timer) => clearTimeout(timer),
|
||||
},
|
||||
numericSessions: {
|
||||
onMultiCopyDigit: () => {},
|
||||
onMineSentenceDigit: () => {},
|
||||
},
|
||||
overlayShortcutsRuntimeMainDeps: {
|
||||
overlayShortcutsRuntime: {
|
||||
registerOverlayShortcuts: () => {},
|
||||
unregisterOverlayShortcuts: () => {},
|
||||
syncOverlayShortcuts: () => {},
|
||||
refreshOverlayShortcuts: () => {},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(typeof composed.getConfiguredShortcuts, 'function');
|
||||
assert.equal(typeof composed.registerGlobalShortcuts, 'function');
|
||||
assert.equal(typeof composed.refreshGlobalAndOverlayShortcuts, 'function');
|
||||
assert.equal(typeof composed.cancelPendingMultiCopy, 'function');
|
||||
assert.equal(typeof composed.startPendingMultiCopy, 'function');
|
||||
assert.equal(typeof composed.cancelPendingMineSentenceMultiple, 'function');
|
||||
assert.equal(typeof composed.startPendingMineSentenceMultiple, 'function');
|
||||
assert.equal(typeof composed.registerOverlayShortcuts, 'function');
|
||||
assert.equal(typeof composed.unregisterOverlayShortcuts, 'function');
|
||||
assert.equal(typeof composed.syncOverlayShortcuts, 'function');
|
||||
assert.equal(typeof composed.refreshOverlayShortcuts, 'function');
|
||||
});
|
||||
59
src/main/runtime/composers/shortcuts-runtime-composer.ts
Normal file
59
src/main/runtime/composers/shortcuts-runtime-composer.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { createNumericShortcutRuntime } from '../../../core/services/numeric-shortcut';
|
||||
import {
|
||||
createBuildNumericShortcutRuntimeMainDepsHandler,
|
||||
createGlobalShortcutsRuntimeHandlers,
|
||||
createNumericShortcutSessionRuntimeHandlers,
|
||||
createOverlayShortcutsRuntimeHandlers,
|
||||
} from '../domains/shortcuts';
|
||||
|
||||
type GlobalShortcutsOptions = Parameters<typeof createGlobalShortcutsRuntimeHandlers>[0];
|
||||
type NumericShortcutRuntimeMainDeps = Parameters<
|
||||
typeof createBuildNumericShortcutRuntimeMainDepsHandler
|
||||
>[0];
|
||||
type NumericSessionOptions = Omit<
|
||||
Parameters<typeof createNumericShortcutSessionRuntimeHandlers>[0],
|
||||
'multiCopySession' | 'mineSentenceSession'
|
||||
>;
|
||||
type OverlayShortcutsMainDeps = Parameters<
|
||||
typeof createOverlayShortcutsRuntimeHandlers
|
||||
>[0]['overlayShortcutsRuntimeMainDeps'];
|
||||
|
||||
export type ShortcutsRuntimeComposerOptions = {
|
||||
globalShortcuts: GlobalShortcutsOptions;
|
||||
numericShortcutRuntimeMainDeps: NumericShortcutRuntimeMainDeps;
|
||||
numericSessions: NumericSessionOptions;
|
||||
overlayShortcutsRuntimeMainDeps: OverlayShortcutsMainDeps;
|
||||
};
|
||||
|
||||
export type ShortcutsRuntimeComposerResult = ReturnType<
|
||||
typeof createGlobalShortcutsRuntimeHandlers
|
||||
> &
|
||||
ReturnType<typeof createNumericShortcutSessionRuntimeHandlers> &
|
||||
ReturnType<typeof createOverlayShortcutsRuntimeHandlers>;
|
||||
|
||||
export function composeShortcutRuntimes(
|
||||
options: ShortcutsRuntimeComposerOptions,
|
||||
): ShortcutsRuntimeComposerResult {
|
||||
const globalShortcuts = createGlobalShortcutsRuntimeHandlers(options.globalShortcuts);
|
||||
|
||||
const numericShortcutRuntimeMainDeps = createBuildNumericShortcutRuntimeMainDepsHandler(
|
||||
options.numericShortcutRuntimeMainDeps,
|
||||
)();
|
||||
const numericShortcutRuntime = createNumericShortcutRuntime(numericShortcutRuntimeMainDeps);
|
||||
const numericSessions = createNumericShortcutSessionRuntimeHandlers({
|
||||
multiCopySession: numericShortcutRuntime.createSession(),
|
||||
mineSentenceSession: numericShortcutRuntime.createSession(),
|
||||
onMultiCopyDigit: options.numericSessions.onMultiCopyDigit,
|
||||
onMineSentenceDigit: options.numericSessions.onMineSentenceDigit,
|
||||
});
|
||||
|
||||
const overlayShortcuts = createOverlayShortcutsRuntimeHandlers({
|
||||
overlayShortcutsRuntimeMainDeps: options.overlayShortcutsRuntimeMainDeps,
|
||||
});
|
||||
|
||||
return {
|
||||
...globalShortcuts,
|
||||
...numericSessions,
|
||||
...overlayShortcuts,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { composeStartupLifecycleHandlers } from './startup-lifecycle-composer';
|
||||
|
||||
test('composeStartupLifecycleHandlers returns callable startup lifecycle handlers', () => {
|
||||
const composed = composeStartupLifecycleHandlers({
|
||||
registerProtocolUrlHandlersMainDeps: {
|
||||
registerOpenUrl: () => {},
|
||||
registerSecondInstance: () => {},
|
||||
handleAnilistSetupProtocolUrl: () => false,
|
||||
findAnilistSetupDeepLinkArgvUrl: () => null,
|
||||
logUnhandledOpenUrl: () => {},
|
||||
logUnhandledSecondInstanceUrl: () => {},
|
||||
},
|
||||
onWillQuitCleanupMainDeps: {
|
||||
destroyTray: () => {},
|
||||
stopConfigHotReload: () => {},
|
||||
restorePreviousSecondarySubVisibility: () => {},
|
||||
unregisterAllGlobalShortcuts: () => {},
|
||||
stopSubtitleWebsocket: () => {},
|
||||
stopTexthookerService: () => {},
|
||||
getYomitanParserWindow: () => null,
|
||||
clearYomitanParserState: () => {},
|
||||
getWindowTracker: () => null,
|
||||
getMpvSocket: () => null,
|
||||
getReconnectTimer: () => null,
|
||||
clearReconnectTimerRef: () => {},
|
||||
getSubtitleTimingTracker: () => null,
|
||||
getImmersionTracker: () => null,
|
||||
clearImmersionTracker: () => {},
|
||||
getAnkiIntegration: () => null,
|
||||
getAnilistSetupWindow: () => null,
|
||||
clearAnilistSetupWindow: () => {},
|
||||
getJellyfinSetupWindow: () => null,
|
||||
clearJellyfinSetupWindow: () => {},
|
||||
stopJellyfinRemoteSession: async () => {},
|
||||
},
|
||||
shouldRestoreWindowsOnActivateMainDeps: {
|
||||
isOverlayRuntimeInitialized: () => false,
|
||||
getAllWindowCount: () => 0,
|
||||
},
|
||||
restoreWindowsOnActivateMainDeps: {
|
||||
createMainWindow: () => {},
|
||||
createInvisibleWindow: () => {},
|
||||
updateVisibleOverlayVisibility: () => {},
|
||||
updateInvisibleOverlayVisibility: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(typeof composed.registerProtocolUrlHandlers, 'function');
|
||||
assert.equal(typeof composed.onWillQuitCleanup, 'function');
|
||||
assert.equal(typeof composed.shouldRestoreWindowsOnActivate, 'function');
|
||||
assert.equal(typeof composed.restoreWindowsOnActivate, 'function');
|
||||
});
|
||||
65
src/main/runtime/composers/startup-lifecycle-composer.ts
Normal file
65
src/main/runtime/composers/startup-lifecycle-composer.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
createOnWillQuitCleanupHandler,
|
||||
createRestoreWindowsOnActivateHandler,
|
||||
createShouldRestoreWindowsOnActivateHandler,
|
||||
} from '../app-lifecycle-actions';
|
||||
import { createBuildOnWillQuitCleanupDepsHandler } from '../app-lifecycle-main-cleanup';
|
||||
import {
|
||||
createBuildRestoreWindowsOnActivateMainDepsHandler,
|
||||
createBuildShouldRestoreWindowsOnActivateMainDepsHandler,
|
||||
} from '../app-lifecycle-main-activate';
|
||||
import { createBuildRegisterProtocolUrlHandlersMainDepsHandler } from '../protocol-url-handlers-main-deps';
|
||||
import { registerProtocolUrlHandlers } from '../protocol-url-handlers';
|
||||
|
||||
type RegisterProtocolUrlHandlersMainDeps = Parameters<
|
||||
typeof createBuildRegisterProtocolUrlHandlersMainDepsHandler
|
||||
>[0];
|
||||
type OnWillQuitCleanupDeps = Parameters<typeof createBuildOnWillQuitCleanupDepsHandler>[0];
|
||||
type ShouldRestoreWindowsOnActivateMainDeps = Parameters<
|
||||
typeof createBuildShouldRestoreWindowsOnActivateMainDepsHandler
|
||||
>[0];
|
||||
type RestoreWindowsOnActivateMainDeps = Parameters<
|
||||
typeof createBuildRestoreWindowsOnActivateMainDepsHandler
|
||||
>[0];
|
||||
|
||||
export type StartupLifecycleComposerOptions = {
|
||||
registerProtocolUrlHandlersMainDeps: RegisterProtocolUrlHandlersMainDeps;
|
||||
onWillQuitCleanupMainDeps: OnWillQuitCleanupDeps;
|
||||
shouldRestoreWindowsOnActivateMainDeps: ShouldRestoreWindowsOnActivateMainDeps;
|
||||
restoreWindowsOnActivateMainDeps: RestoreWindowsOnActivateMainDeps;
|
||||
};
|
||||
|
||||
export type StartupLifecycleComposerResult = {
|
||||
registerProtocolUrlHandlers: () => void;
|
||||
onWillQuitCleanup: () => void;
|
||||
shouldRestoreWindowsOnActivate: () => boolean;
|
||||
restoreWindowsOnActivate: () => void;
|
||||
};
|
||||
|
||||
export function composeStartupLifecycleHandlers(
|
||||
options: StartupLifecycleComposerOptions,
|
||||
): StartupLifecycleComposerResult {
|
||||
const registerProtocolUrlHandlersMainDeps = createBuildRegisterProtocolUrlHandlersMainDepsHandler(
|
||||
options.registerProtocolUrlHandlersMainDeps,
|
||||
)();
|
||||
|
||||
const onWillQuitCleanupHandler = createOnWillQuitCleanupHandler(
|
||||
createBuildOnWillQuitCleanupDepsHandler(options.onWillQuitCleanupMainDeps)(),
|
||||
);
|
||||
const shouldRestoreWindowsOnActivateHandler = createShouldRestoreWindowsOnActivateHandler(
|
||||
createBuildShouldRestoreWindowsOnActivateMainDepsHandler(
|
||||
options.shouldRestoreWindowsOnActivateMainDeps,
|
||||
)(),
|
||||
);
|
||||
const restoreWindowsOnActivateHandler = createRestoreWindowsOnActivateHandler(
|
||||
createBuildRestoreWindowsOnActivateMainDepsHandler(options.restoreWindowsOnActivateMainDeps)(),
|
||||
);
|
||||
|
||||
return {
|
||||
registerProtocolUrlHandlers: () =>
|
||||
registerProtocolUrlHandlers(registerProtocolUrlHandlersMainDeps),
|
||||
onWillQuitCleanup: () => onWillQuitCleanupHandler(),
|
||||
shouldRestoreWindowsOnActivate: () => shouldRestoreWindowsOnActivateHandler(),
|
||||
restoreWindowsOnActivate: () => restoreWindowsOnActivateHandler(),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user