mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
refactor: extract overlay bridge runtime helpers
This commit is contained in:
@@ -16,7 +16,7 @@
|
|||||||
"docs:build": "vitepress build docs",
|
"docs:build": "vitepress build docs",
|
||||||
"docs:preview": "vitepress preview docs --host 0.0.0.0 --port 4173 --strictPort",
|
"docs:preview": "vitepress preview docs --host 0.0.0.0 --port 4173 --strictPort",
|
||||||
"test:config": "pnpm run build && node --test dist/config/config.test.js",
|
"test:config": "pnpm run build && node --test dist/config/config.test.js",
|
||||||
"test:core": "pnpm run build && node --test dist/cli/args.test.js dist/cli/help.test.js dist/core/services/cli-command-service.test.js dist/core/services/numeric-shortcut-session-service.test.js dist/core/services/secondary-subtitle-service.test.js dist/core/services/mpv-render-metrics-service.test.js dist/core/services/mpv-runtime-service.test.js dist/core/services/runtime-options-runtime-service.test.js dist/core/services/overlay-modal-restore-service.test.js dist/core/services/runtime-config-service.test.js",
|
"test:core": "pnpm run build && node --test dist/cli/args.test.js dist/cli/help.test.js dist/core/services/cli-command-service.test.js dist/core/services/numeric-shortcut-session-service.test.js dist/core/services/secondary-subtitle-service.test.js dist/core/services/mpv-render-metrics-service.test.js dist/core/services/mpv-runtime-service.test.js dist/core/services/runtime-options-runtime-service.test.js dist/core/services/overlay-modal-restore-service.test.js dist/core/services/runtime-config-service.test.js dist/core/services/overlay-bridge-runtime-service.test.js",
|
||||||
"test:subtitle": "pnpm run build && node --test dist/subtitle/stages.test.js dist/subtitle/pipeline.test.js",
|
"test:subtitle": "pnpm run build && node --test dist/subtitle/stages.test.js dist/subtitle/pipeline.test.js",
|
||||||
"generate:config-example": "pnpm run build && node dist/generate-config-example.js",
|
"generate:config-example": "pnpm run build && node dist/generate-config-example.js",
|
||||||
"start": "pnpm run build && electron . --start",
|
"start": "pnpm run build && electron . --start",
|
||||||
|
|||||||
76
src/core/services/overlay-bridge-runtime-service.test.ts
Normal file
76
src/core/services/overlay-bridge-runtime-service.test.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import test from "node:test";
|
||||||
|
import assert from "node:assert/strict";
|
||||||
|
import { KikuFieldGroupingChoice } from "../../types";
|
||||||
|
import {
|
||||||
|
createFieldGroupingCallbackRuntimeService,
|
||||||
|
sendToVisibleOverlayRuntimeService,
|
||||||
|
} from "./overlay-bridge-runtime-service";
|
||||||
|
|
||||||
|
test("sendToVisibleOverlayRuntimeService restores visibility flag when opening hidden overlay modal", () => {
|
||||||
|
const sent: unknown[][] = [];
|
||||||
|
const restoreSet = new Set<"runtime-options" | "subsync">();
|
||||||
|
let visibleOverlayVisible = false;
|
||||||
|
|
||||||
|
const ok = sendToVisibleOverlayRuntimeService({
|
||||||
|
mainWindow: {
|
||||||
|
isDestroyed: () => false,
|
||||||
|
webContents: {
|
||||||
|
send: (...args: unknown[]) => {
|
||||||
|
sent.push(args);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as unknown as Electron.BrowserWindow,
|
||||||
|
visibleOverlayVisible,
|
||||||
|
setVisibleOverlayVisible: (visible) => {
|
||||||
|
visibleOverlayVisible = visible;
|
||||||
|
},
|
||||||
|
channel: "runtime-options:open",
|
||||||
|
restoreOnModalClose: "runtime-options",
|
||||||
|
restoreVisibleOverlayOnModalClose: restoreSet,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(ok, true);
|
||||||
|
assert.equal(visibleOverlayVisible, true);
|
||||||
|
assert.equal(restoreSet.has("runtime-options"), true);
|
||||||
|
assert.deepEqual(sent, [["runtime-options:open"]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("createFieldGroupingCallbackRuntimeService cancels when overlay request cannot be sent", async () => {
|
||||||
|
let resolver: ((choice: KikuFieldGroupingChoice) => void) | null = null;
|
||||||
|
const callback = createFieldGroupingCallbackRuntimeService<
|
||||||
|
"runtime-options" | "subsync"
|
||||||
|
>({
|
||||||
|
getVisibleOverlayVisible: () => false,
|
||||||
|
getInvisibleOverlayVisible: () => false,
|
||||||
|
setVisibleOverlayVisible: () => {},
|
||||||
|
setInvisibleOverlayVisible: () => {},
|
||||||
|
getResolver: () => resolver,
|
||||||
|
setResolver: (next) => {
|
||||||
|
resolver = next;
|
||||||
|
},
|
||||||
|
sendToVisibleOverlay: () => false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await callback({
|
||||||
|
original: {
|
||||||
|
noteId: 1,
|
||||||
|
expression: "a",
|
||||||
|
sentencePreview: "a",
|
||||||
|
hasAudio: false,
|
||||||
|
hasImage: false,
|
||||||
|
isOriginal: true,
|
||||||
|
},
|
||||||
|
duplicate: {
|
||||||
|
noteId: 2,
|
||||||
|
expression: "b",
|
||||||
|
sentencePreview: "b",
|
||||||
|
hasAudio: false,
|
||||||
|
hasImage: false,
|
||||||
|
isOriginal: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(result.cancelled, true);
|
||||||
|
assert.equal(result.keepNoteId, 0);
|
||||||
|
assert.equal(result.deleteNoteId, 0);
|
||||||
|
});
|
||||||
61
src/core/services/overlay-bridge-runtime-service.ts
Normal file
61
src/core/services/overlay-bridge-runtime-service.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import {
|
||||||
|
KikuFieldGroupingChoice,
|
||||||
|
KikuFieldGroupingRequestData,
|
||||||
|
} from "../../types";
|
||||||
|
import { addOverlayModalRestoreFlagService } from "./overlay-modal-restore-service";
|
||||||
|
import { sendToVisibleOverlayService } from "./overlay-send-service";
|
||||||
|
import { createFieldGroupingCallbackService } from "./field-grouping-service";
|
||||||
|
import { BrowserWindow } from "electron";
|
||||||
|
|
||||||
|
export function sendToVisibleOverlayRuntimeService<T extends string>(options: {
|
||||||
|
mainWindow: BrowserWindow | null;
|
||||||
|
visibleOverlayVisible: boolean;
|
||||||
|
setVisibleOverlayVisible: (visible: boolean) => void;
|
||||||
|
channel: string;
|
||||||
|
payload?: unknown;
|
||||||
|
restoreOnModalClose?: T;
|
||||||
|
restoreVisibleOverlayOnModalClose: Set<T>;
|
||||||
|
}): boolean {
|
||||||
|
return sendToVisibleOverlayService({
|
||||||
|
mainWindow: options.mainWindow,
|
||||||
|
visibleOverlayVisible: options.visibleOverlayVisible,
|
||||||
|
setVisibleOverlayVisible: options.setVisibleOverlayVisible,
|
||||||
|
channel: options.channel,
|
||||||
|
payload: options.payload,
|
||||||
|
restoreOnModalClose: options.restoreOnModalClose,
|
||||||
|
addRestoreFlag: (modal) =>
|
||||||
|
addOverlayModalRestoreFlagService(
|
||||||
|
options.restoreVisibleOverlayOnModalClose,
|
||||||
|
modal as T,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createFieldGroupingCallbackRuntimeService<T extends string>(
|
||||||
|
options: {
|
||||||
|
getVisibleOverlayVisible: () => boolean;
|
||||||
|
getInvisibleOverlayVisible: () => boolean;
|
||||||
|
setVisibleOverlayVisible: (visible: boolean) => void;
|
||||||
|
setInvisibleOverlayVisible: (visible: boolean) => void;
|
||||||
|
getResolver: () => ((choice: KikuFieldGroupingChoice) => void) | null;
|
||||||
|
setResolver: (
|
||||||
|
resolver: ((choice: KikuFieldGroupingChoice) => void) | null,
|
||||||
|
) => void;
|
||||||
|
sendToVisibleOverlay: (
|
||||||
|
channel: string,
|
||||||
|
payload?: unknown,
|
||||||
|
runtimeOptions?: { restoreOnModalClose?: T },
|
||||||
|
) => boolean;
|
||||||
|
},
|
||||||
|
): (data: KikuFieldGroupingRequestData) => Promise<KikuFieldGroupingChoice> {
|
||||||
|
return createFieldGroupingCallbackService({
|
||||||
|
getVisibleOverlayVisible: options.getVisibleOverlayVisible,
|
||||||
|
getInvisibleOverlayVisible: options.getInvisibleOverlayVisible,
|
||||||
|
setVisibleOverlayVisible: options.setVisibleOverlayVisible,
|
||||||
|
setInvisibleOverlayVisible: options.setInvisibleOverlayVisible,
|
||||||
|
getResolver: options.getResolver,
|
||||||
|
setResolver: options.setResolver,
|
||||||
|
sendRequestToVisibleOverlay: (data) =>
|
||||||
|
options.sendToVisibleOverlay("kiku:field-grouping-request", data),
|
||||||
|
});
|
||||||
|
}
|
||||||
38
src/main.ts
38
src/main.ts
@@ -170,7 +170,6 @@ import {
|
|||||||
ensureOverlayWindowLevelService,
|
ensureOverlayWindowLevelService,
|
||||||
updateOverlayBoundsService,
|
updateOverlayBoundsService,
|
||||||
} from "./core/services/overlay-window-service";
|
} from "./core/services/overlay-window-service";
|
||||||
import { createFieldGroupingCallbackService } from "./core/services/field-grouping-service";
|
|
||||||
import { initializeOverlayRuntimeService } from "./core/services/overlay-runtime-init-service";
|
import { initializeOverlayRuntimeService } from "./core/services/overlay-runtime-init-service";
|
||||||
import {
|
import {
|
||||||
setInvisibleOverlayVisibleService,
|
setInvisibleOverlayVisibleService,
|
||||||
@@ -185,11 +184,13 @@ import { applyMpvSubtitleRenderMetricsPatchService } from "./core/services/mpv-r
|
|||||||
import {
|
import {
|
||||||
handleMpvCommandFromIpcService,
|
handleMpvCommandFromIpcService,
|
||||||
} from "./core/services/ipc-command-service";
|
} from "./core/services/ipc-command-service";
|
||||||
import { sendToVisibleOverlayService } from "./core/services/overlay-send-service";
|
|
||||||
import {
|
import {
|
||||||
addOverlayModalRestoreFlagService,
|
|
||||||
handleOverlayModalClosedService,
|
handleOverlayModalClosedService,
|
||||||
} from "./core/services/overlay-modal-restore-service";
|
} from "./core/services/overlay-modal-restore-service";
|
||||||
|
import {
|
||||||
|
createFieldGroupingCallbackRuntimeService,
|
||||||
|
sendToVisibleOverlayRuntimeService,
|
||||||
|
} from "./core/services/overlay-bridge-runtime-service";
|
||||||
import {
|
import {
|
||||||
runSubsyncManualFromIpcRuntimeService,
|
runSubsyncManualFromIpcRuntimeService,
|
||||||
triggerSubsyncFromConfigRuntimeService,
|
triggerSubsyncFromConfigRuntimeService,
|
||||||
@@ -1235,9 +1236,36 @@ registerIpcHandlersService({
|
|||||||
* Create and show a desktop notification with robust icon handling.
|
* Create and show a desktop notification with robust icon handling.
|
||||||
* Supports both file paths (preferred on Linux/Wayland) and data URLs (fallback).
|
* Supports both file paths (preferred on Linux/Wayland) and data URLs (fallback).
|
||||||
*/
|
*/
|
||||||
function createFieldGroupingCallback() { return createFieldGroupingCallbackService({ getVisibleOverlayVisible: () => visibleOverlayVisible, getInvisibleOverlayVisible: () => invisibleOverlayVisible, setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible), setInvisibleOverlayVisible: (visible) => setInvisibleOverlayVisible(visible), getResolver: () => fieldGroupingResolver, setResolver: (resolver) => { fieldGroupingResolver = resolver; }, sendRequestToVisibleOverlay: (data) => sendToVisibleOverlay("kiku:field-grouping-request", data) }); }
|
function createFieldGroupingCallback() {
|
||||||
|
return createFieldGroupingCallbackRuntimeService({
|
||||||
|
getVisibleOverlayVisible: () => visibleOverlayVisible,
|
||||||
|
getInvisibleOverlayVisible: () => invisibleOverlayVisible,
|
||||||
|
setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible),
|
||||||
|
setInvisibleOverlayVisible: (visible) => setInvisibleOverlayVisible(visible),
|
||||||
|
getResolver: () => fieldGroupingResolver,
|
||||||
|
setResolver: (resolver) => {
|
||||||
|
fieldGroupingResolver = resolver;
|
||||||
|
},
|
||||||
|
sendToVisibleOverlay: (
|
||||||
|
channel,
|
||||||
|
payload,
|
||||||
|
runtimeOptions?: { restoreOnModalClose?: OverlayHostedModal },
|
||||||
|
) =>
|
||||||
|
sendToVisibleOverlay(channel, payload, runtimeOptions),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function sendToVisibleOverlay(channel: string, payload?: unknown, options?: { restoreOnModalClose?: OverlayHostedModal }): boolean { return sendToVisibleOverlayService({ mainWindow, visibleOverlayVisible, setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible), channel, payload, restoreOnModalClose: options?.restoreOnModalClose, addRestoreFlag: (modal) => addOverlayModalRestoreFlagService(restoreVisibleOverlayOnModalClose, modal as OverlayHostedModal) }); }
|
function sendToVisibleOverlay(channel: string, payload?: unknown, options?: { restoreOnModalClose?: OverlayHostedModal }): boolean {
|
||||||
|
return sendToVisibleOverlayRuntimeService({
|
||||||
|
mainWindow,
|
||||||
|
visibleOverlayVisible,
|
||||||
|
setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible),
|
||||||
|
channel,
|
||||||
|
payload,
|
||||||
|
restoreOnModalClose: options?.restoreOnModalClose,
|
||||||
|
restoreVisibleOverlayOnModalClose,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
registerAnkiJimakuIpcRuntimeService({
|
registerAnkiJimakuIpcRuntimeService({
|
||||||
patchAnkiConnectEnabled: (enabled) => { configService.patchRawConfig({ ankiConnect: { enabled } }); },
|
patchAnkiConnectEnabled: (enabled) => { configService.patchRawConfig({ ankiConnect: { enabled } }); },
|
||||||
|
|||||||
Reference in New Issue
Block a user