mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-10-26 23:35:17 -07:00
fix(plugins): ignore stale plugin panel close notices
The overlay's modal-closed notice now carries the panel id, and the runtime only finishes the active panel when the ids match. A late notice for a replaced panel no longer aborts the newer one.
This commit is contained in:
9 files changed
+46
-21
No files matched your search
@@ -575,8 +575,8 @@ test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => {
|
||||
const openedModals: unknown[] = [];
|
||||
registerIpcHandlers(
|
||||
{
|
||||
onOverlayModalClosed: (modal) => {
|
||||
closedModals.push(modal);
|
||||
onOverlayModalClosed: (modal, _senderWindow, instanceId) => {
|
||||
closedModals.push(instanceId === undefined ? modal : [modal, instanceId]);
|
||||
},
|
||||
onOverlayModalOpened: (modal) => {
|
||||
openedModals.push(modal);
|
||||
@@ -637,7 +637,9 @@ test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => {
|
||||
handlers.on.get(IPC_CHANNELS.command.overlayModalClosed)!({}, 'not-a-modal');
|
||||
handlers.on.get(IPC_CHANNELS.command.overlayModalClosed)!({}, 'subsync');
|
||||
handlers.on.get(IPC_CHANNELS.command.overlayModalClosed)!({}, 'kiku');
|
||||
assert.deepEqual(closedModals, ['subsync', 'kiku']);
|
||||
handlers.on.get(IPC_CHANNELS.command.overlayModalClosed)!({}, 'plugin-panel', 4);
|
||||
handlers.on.get(IPC_CHANNELS.command.overlayModalClosed)!({}, 'plugin-panel', 'bad');
|
||||
assert.deepEqual(closedModals, ['subsync', 'kiku', ['plugin-panel', 4], 'plugin-panel']);
|
||||
|
||||
handlers.on.get(IPC_CHANNELS.command.overlayModalOpened)!({}, 'bad');
|
||||
handlers.on.get(IPC_CHANNELS.command.overlayModalOpened)!({}, 'subsync');
|
||||
|
||||
@@ -50,6 +50,7 @@ export interface IpcServiceDeps {
|
||||
onOverlayModalClosed: (
|
||||
modal: OverlayHostedModal,
|
||||
senderWindow: ElectronBrowserWindow | null,
|
||||
instanceId?: number,
|
||||
) => void;
|
||||
onOverlayModalOpened?: (
|
||||
modal: OverlayHostedModal,
|
||||
@@ -317,6 +318,7 @@ export interface IpcDepsRuntimeOptions {
|
||||
onOverlayModalClosed: (
|
||||
modal: OverlayHostedModal,
|
||||
senderWindow: ElectronBrowserWindow | null,
|
||||
instanceId?: number,
|
||||
) => void;
|
||||
onOverlayModalOpened?: (
|
||||
modal: OverlayHostedModal,
|
||||
@@ -527,13 +529,20 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar
|
||||
},
|
||||
);
|
||||
|
||||
ipc.on(IPC_CHANNELS.command.overlayModalClosed, (event: unknown, modal: unknown) => {
|
||||
const parsedModal = parseOverlayHostedModal(modal);
|
||||
if (!parsedModal) return;
|
||||
const senderWindow =
|
||||
electron.BrowserWindow?.fromWebContents((event as IpcMainEvent).sender) ?? null;
|
||||
deps.onOverlayModalClosed(parsedModal, senderWindow);
|
||||
});
|
||||
ipc.on(
|
||||
IPC_CHANNELS.command.overlayModalClosed,
|
||||
(event: unknown, modal: unknown, instanceId: unknown) => {
|
||||
const parsedModal = parseOverlayHostedModal(modal);
|
||||
if (!parsedModal) return;
|
||||
const senderWindow =
|
||||
electron.BrowserWindow?.fromWebContents((event as IpcMainEvent).sender) ?? null;
|
||||
deps.onOverlayModalClosed(
|
||||
parsedModal,
|
||||
senderWindow,
|
||||
Number.isInteger(instanceId) ? (instanceId as number) : undefined,
|
||||
);
|
||||
},
|
||||
);
|
||||
ipc.on(IPC_CHANNELS.command.overlayModalOpened, (event: unknown, modal: unknown) => {
|
||||
const parsedModal = parseOverlayHostedModal(modal);
|
||||
if (!parsedModal) return;
|
||||
|
||||
+3
-3
@@ -6024,12 +6024,12 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onOverlayModalClosed: (modal, senderWindow) => {
|
||||
onOverlayModalClosed: (modal, senderWindow, instanceId) => {
|
||||
if (modal === 'media-timing-review') {
|
||||
void mediaTimingReviewRuntime.dispose();
|
||||
}
|
||||
if (modal === 'plugin-panel') {
|
||||
pluginPanelRuntime.handleModalClosed();
|
||||
if (modal === 'plugin-panel' && instanceId !== undefined) {
|
||||
pluginPanelRuntime.handleModalClosed(instanceId);
|
||||
}
|
||||
if (modal === 'subtitle-sidebar' && senderWindow === overlayManager.getMainWindow()) {
|
||||
subtitleSidebarRequestedOpen = false;
|
||||
|
||||
@@ -303,7 +303,7 @@ test('subtitle sidebar open state is restored for replacement visible overlay wi
|
||||
/onOverlayModalOpened:\s*\(modal,\s*senderWindow\)\s*=>\s*\{(?<body>[\s\S]*?)\n \},/,
|
||||
)?.groups?.body;
|
||||
const closedBlock = source.match(
|
||||
/onOverlayModalClosed:\s*\(modal,\s*senderWindow\)\s*=>\s*\{(?<body>[\s\S]*?)\n \},/,
|
||||
/onOverlayModalClosed:\s*\(modal,\s*senderWindow(?:,\s*instanceId)?\)\s*=>\s*\{(?<body>[\s\S]*?)\n \},/,
|
||||
)?.groups?.body;
|
||||
const depsBlock = source.match(/getSubtitleSidebarOpen:\s*\(\)\s*=>\s*(?<body>[^\n,]+)/)?.groups
|
||||
?.body;
|
||||
|
||||
@@ -44,7 +44,7 @@ test('closing from the overlay aborts the handle and ignores later updates', asy
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
const sentBefore = h.sent.length;
|
||||
|
||||
h.runtime.handleModalClosed();
|
||||
h.runtime.handleModalClosed(1);
|
||||
panel.update({ markdown: 'too late' });
|
||||
|
||||
assert.equal(panel.signal.aborted, true);
|
||||
@@ -52,6 +52,17 @@ test('closing from the overlay aborts the handle and ignores later updates', asy
|
||||
assert.equal(h.sent.length, sentBefore);
|
||||
});
|
||||
|
||||
test('a late close acknowledgement for a replaced panel leaves the new panel open', () => {
|
||||
const h = createHarness(Promise.resolve(true));
|
||||
const first = h.runtime.open({ title: 'One', markdown: '' });
|
||||
first.close();
|
||||
const second = h.runtime.open({ title: 'Two', markdown: '' });
|
||||
|
||||
h.runtime.handleModalClosed(1);
|
||||
|
||||
assert.equal(second.signal.aborted, false);
|
||||
});
|
||||
|
||||
test('opening a new panel aborts the previous one', () => {
|
||||
const h = createHarness(Promise.resolve(true));
|
||||
const first = h.runtime.open({ title: 'One', markdown: '' });
|
||||
|
||||
@@ -103,9 +103,9 @@ export function createPluginPanelRuntime(deps: {
|
||||
};
|
||||
},
|
||||
|
||||
/** The user closed the panel in the overlay. */
|
||||
handleModalClosed(): void {
|
||||
if (active) finish(active);
|
||||
/** The overlay closed `panelId`; a late notice for an already replaced panel is ignored. */
|
||||
handleModalClosed(panelId: number): void {
|
||||
if (active?.panelId === panelId) finish(active);
|
||||
},
|
||||
};
|
||||
}
|
||||
+2
-2
@@ -532,8 +532,8 @@ const electronAPI: ElectronAPI = {
|
||||
mediaId,
|
||||
direction,
|
||||
),
|
||||
notifyOverlayModalClosed: (modal) => {
|
||||
ipcRenderer.send(IPC_CHANNELS.command.overlayModalClosed, modal);
|
||||
notifyOverlayModalClosed: (modal, instanceId) => {
|
||||
ipcRenderer.send(IPC_CHANNELS.command.overlayModalClosed, modal, instanceId);
|
||||
},
|
||||
notifyOverlayModalOpened: (modal) => {
|
||||
ipcRenderer.send(IPC_CHANNELS.command.overlayModalOpened, modal);
|
||||
|
||||
@@ -60,12 +60,13 @@ export function createPluginPanelModal(
|
||||
function closePluginPanelModal(): void {
|
||||
if (!ctx.state.pluginPanelModalOpen) return;
|
||||
|
||||
const closedPanelId = panelId ?? undefined;
|
||||
ctx.state.pluginPanelModalOpen = false;
|
||||
panelId = null;
|
||||
options.syncSettingsModalSubtitleSuppression();
|
||||
ctx.dom.pluginPanelModal.classList.add('hidden');
|
||||
ctx.dom.pluginPanelModal.setAttribute('aria-hidden', 'true');
|
||||
window.electronAPI.notifyOverlayModalClosed('plugin-panel');
|
||||
window.electronAPI.notifyOverlayModalClosed('plugin-panel', closedPanelId);
|
||||
if (!ctx.state.isOverSubtitle && !options.modalStateReader.isAnyModalOpen()) {
|
||||
ctx.dom.overlay.classList.remove('interactive');
|
||||
}
|
||||
|
||||
@@ -625,6 +625,8 @@ export interface ElectronAPI {
|
||||
| 'character-dictionary'
|
||||
| 'changelog'
|
||||
| 'plugin-panel',
|
||||
/** Which instance closed, for modals that swap content in place (the plugin panel's id). */
|
||||
instanceId?: number,
|
||||
) => void;
|
||||
notifyOverlayModalOpened: (
|
||||
modal:
|
||||
|
||||
Reference in new issue
Block a user