fix(anki): keep overlay progress visible through card updates (#218)

This commit is contained in:
2026-08-25 20:27:58 -07:00
committed by GitHub
parent 556de61756
commit c2c25c0da6
12 changed files with 127 additions and 2 deletions
+4
View File
@@ -0,0 +1,4 @@
type: fixed
area: overlay
- Kept the Anki card update spinner visible until audio and image updates finish.
+78
View File
@@ -11,10 +11,12 @@ import type { MediaInput } from './media-input';
import { AnkiConnectConfig } from './types'; import { AnkiConnectConfig } from './types';
type TestOverlayNotificationPayload = { type TestOverlayNotificationPayload = {
id?: string;
title: string; title: string;
body?: string; body?: string;
image?: string; image?: string;
variant?: string; variant?: string;
persistent?: boolean;
actions?: Array<{ id: string; label: string; noteId?: number }>; actions?: Array<{ id: string; label: string; noteId?: number }>;
}; };
@@ -1182,6 +1184,82 @@ test('AnkiIntegration embeds generated notification image on overlay mined-card
assert.deepEqual(cleanupPaths, [notificationIconPath]); assert.deepEqual(cleanupPaths, [notificationIconPath]);
}); });
test('AnkiIntegration keeps overlay card-update progress visible until the terminal notification', async () => {
const overlayNotifications: TestOverlayNotificationPayload[] = [];
const integration = new AnkiIntegration(
{
behavior: {
notificationType: 'overlay',
},
},
{} as never,
{} as never,
undefined,
undefined,
undefined,
undefined,
{},
undefined,
(payload) => {
overlayNotifications.push(payload);
},
);
const updateNotifications = integration as unknown as {
beginUpdateProgress: (message: string) => void;
showNotification: (noteId: number, label: string | number) => Promise<void>;
};
updateNotifications.beginUpdateProgress('Updating card');
await updateNotifications.showNotification(42, '食べる');
assert.deepEqual(
overlayNotifications.map(({ id, variant, persistent }) => ({ id, variant, persistent })),
[
{ id: 'anki-update-progress', variant: 'progress', persistent: true },
{ id: 'anki-update-progress', variant: 'success', persistent: false },
],
);
});
test('AnkiIntegration dismisses persistent overlay update progress when no terminal notification replaces it', () => {
const overlayNotifications: TestOverlayNotificationPayload[] = [];
const dismissedIds: string[] = [];
const integration = new AnkiIntegration(
{
behavior: {
notificationType: 'overlay',
},
},
{} as never,
{} as never,
undefined,
undefined,
undefined,
undefined,
{},
undefined,
(payload) => {
overlayNotifications.push(payload);
},
undefined,
undefined,
undefined,
(id) => {
dismissedIds.push(id);
},
);
const updateNotifications = integration as unknown as {
beginUpdateProgress: (message: string) => void;
endUpdateProgress: () => void;
};
updateNotifications.beginUpdateProgress('Updating card');
updateNotifications.endUpdateProgress();
assert.equal(overlayNotifications[0]?.persistent, true);
assert.deepEqual(dismissedIds, ['anki-update-progress']);
});
test('AnkiIntegration keeps overlay notification image when temp icon write fails', async () => { test('AnkiIntegration keeps overlay notification image when temp icon write fails', async () => {
const desktopNotifications: Array<{ title: string; body?: string; icon?: string }> = []; const desktopNotifications: Array<{ title: string; body?: string; icon?: string }> = [];
const overlayNotifications: TestOverlayNotificationPayload[] = []; const overlayNotifications: TestOverlayNotificationPayload[] = [];
+14 -2
View File
@@ -218,6 +218,8 @@ export class AnkiIntegration {
null; null;
private overlayNotificationCallback: ((payload: OverlayNotificationPayload) => void) | null = private overlayNotificationCallback: ((payload: OverlayNotificationPayload) => void) | null =
null; null;
private overlayNotificationDismissCallback: ((id: string) => void) | null = null;
private overlayUpdateProgressActive = false;
private updateInProgress = false; private updateInProgress = false;
private uiFeedbackState: UiFeedbackState = createUiFeedbackState(); private uiFeedbackState: UiFeedbackState = createUiFeedbackState();
private parseWarningKeys = new Set<string>(); private parseWarningKeys = new Set<string>();
@@ -265,6 +267,7 @@ export class AnkiIntegration {
getCachedMediaPath?: MediaGenerationInputResolverOptions['getCachedMediaPath'], getCachedMediaPath?: MediaGenerationInputResolverOptions['getCachedMediaPath'],
shouldRequireRemoteMediaCache?: () => boolean, shouldRequireRemoteMediaCache?: () => boolean,
getYoutubeMediaSourceUrl?: () => Promise<string | null | undefined> | string | null | undefined, getYoutubeMediaSourceUrl?: () => Promise<string | null | undefined> | string | null | undefined,
overlayNotificationDismissCallback?: (id: string) => void,
) { ) {
this.config = normalizeAnkiIntegrationConfig(config); this.config = normalizeAnkiIntegrationConfig(config);
this.aiConfig = { ...aiConfig }; this.aiConfig = { ...aiConfig };
@@ -280,6 +283,7 @@ export class AnkiIntegration {
this.getCachedMediaPath = getCachedMediaPath ?? null; this.getCachedMediaPath = getCachedMediaPath ?? null;
this.shouldRequireRemoteMediaCache = shouldRequireRemoteMediaCache ?? null; this.shouldRequireRemoteMediaCache = shouldRequireRemoteMediaCache ?? null;
this.getYoutubeMediaSourceUrl = getYoutubeMediaSourceUrl ?? null; this.getYoutubeMediaSourceUrl = getYoutubeMediaSourceUrl ?? null;
this.overlayNotificationDismissCallback = overlayNotificationDismissCallback ?? null;
this.pendingYoutubeMediaQueue = this.createPendingYoutubeMediaQueue(); this.pendingYoutubeMediaQueue = this.createPendingYoutubeMediaQueue();
this.knownWordCache = this.createKnownWordCache(knownWordCacheStatePath); this.knownWordCache = this.createKnownWordCache(knownWordCacheStatePath);
this.pollingRunner = this.createPollingRunner(); this.pollingRunner = this.createPollingRunner();
@@ -1203,12 +1207,13 @@ export class AnkiIntegration {
private beginUpdateProgress(initialMessage: string): void { private beginUpdateProgress(initialMessage: string): void {
if (!this.shouldUseOsdNotifications()) { if (!this.shouldUseOsdNotifications()) {
if (this.shouldUseOverlayNotifications()) { if (this.shouldUseOverlayNotifications()) {
this.overlayUpdateProgressActive = true;
this.overlayNotificationCallback?.({ this.overlayNotificationCallback?.({
id: 'anki-update-progress', id: 'anki-update-progress',
title: 'Anki update', title: 'Anki update',
body: initialMessage, body: initialMessage,
variant: 'progress', variant: 'progress',
persistent: false, persistent: true,
}); });
} }
return; return;
@@ -1220,6 +1225,10 @@ export class AnkiIntegration {
private endUpdateProgress(): void { private endUpdateProgress(): void {
if (!this.shouldUseOsdNotifications()) { if (!this.shouldUseOsdNotifications()) {
if (this.overlayUpdateProgressActive) {
this.overlayUpdateProgressActive = false;
this.overlayNotificationDismissCallback?.('anki-update-progress');
}
return; return;
} }
endUpdateProgress(this.uiFeedbackState, (timer) => { endUpdateProgress(this.uiFeedbackState, (timer) => {
@@ -1243,18 +1252,20 @@ export class AnkiIntegration {
if (!this.shouldUseOsdNotifications()) { if (!this.shouldUseOsdNotifications()) {
this.updateInProgress = true; this.updateInProgress = true;
if (this.shouldUseOverlayNotifications()) { if (this.shouldUseOverlayNotifications()) {
this.overlayUpdateProgressActive = true;
this.overlayNotificationCallback?.({ this.overlayNotificationCallback?.({
id: 'anki-update-progress', id: 'anki-update-progress',
title: 'Anki update', title: 'Anki update',
body: initialMessage, body: initialMessage,
variant: 'progress', variant: 'progress',
persistent: false, persistent: true,
}); });
} }
try { try {
return await action(); return await action();
} finally { } finally {
this.updateInProgress = false; this.updateInProgress = false;
this.endUpdateProgress();
} }
} }
return withUpdateProgress( return withUpdateProgress(
@@ -1353,6 +1364,7 @@ export class AnkiIntegration {
: undefined; : undefined;
if (shouldShowOverlayNotification && this.overlayNotificationCallback) { if (shouldShowOverlayNotification && this.overlayNotificationCallback) {
this.overlayUpdateProgressActive = false;
this.overlayNotificationCallback({ this.overlayNotificationCallback({
id: 'anki-update-progress', id: 'anki-update-progress',
title: 'Anki Card Updated', title: 'Anki Card Updated',
+2
View File
@@ -65,6 +65,7 @@ export interface AnkiJimakuIpcRuntimeOptions {
getYoutubeMediaSourceUrl?: () => Promise<string | null | undefined> | string | null | undefined; getYoutubeMediaSourceUrl?: () => Promise<string | null | undefined> | string | null | undefined;
showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void; showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void;
showOverlayNotification?: (payload: OverlayNotificationPayload) => void; showOverlayNotification?: (payload: OverlayNotificationPayload) => void;
dismissOverlayNotification?: (id: string) => void;
createFieldGroupingCallback: () => ( createFieldGroupingCallback: () => (
data: KikuFieldGroupingRequestData, data: KikuFieldGroupingRequestData,
) => Promise<KikuFieldGroupingChoice>; ) => Promise<KikuFieldGroupingChoice>;
@@ -166,6 +167,7 @@ export function registerAnkiJimakuIpcRuntime(
options.getCachedMediaPath, options.getCachedMediaPath,
options.shouldRequireRemoteMediaCache, options.shouldRequireRemoteMediaCache,
options.getYoutubeMediaSourceUrl, options.getYoutubeMediaSourceUrl,
options.dismissOverlayNotification,
); );
integration.start(); integration.start();
options.setAnkiIntegration(integration); options.setAnkiIntegration(integration);
@@ -21,6 +21,7 @@ type CreateAnkiIntegrationArgs = {
mpvClient: { send?: (payload: { command: string[] }) => void }; mpvClient: { send?: (payload: { command: string[] }) => void };
showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void; showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void;
showOverlayNotification?: (payload: OverlayNotificationPayload) => void; showOverlayNotification?: (payload: OverlayNotificationPayload) => void;
dismissOverlayNotification?: (id: string) => void;
createFieldGroupingCallback: () => ( createFieldGroupingCallback: () => (
data: KikuFieldGroupingRequestData, data: KikuFieldGroupingRequestData,
) => Promise<KikuFieldGroupingChoice>; ) => Promise<KikuFieldGroupingChoice>;
@@ -74,6 +75,7 @@ function createDefaultAnkiIntegration(args: CreateAnkiIntegrationArgs): AnkiInte
args.getCachedMediaPath, args.getCachedMediaPath,
args.shouldRequireRemoteMediaCache, args.shouldRequireRemoteMediaCache,
args.getYoutubeMediaSourceUrl, args.getYoutubeMediaSourceUrl,
args.dismissOverlayNotification,
); );
} }
@@ -137,6 +139,7 @@ export function initializeOverlayRuntime(
setAnkiIntegration: (integration: unknown | null) => void; setAnkiIntegration: (integration: unknown | null) => void;
showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void; showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void;
showOverlayNotification?: (payload: OverlayNotificationPayload) => void; showOverlayNotification?: (payload: OverlayNotificationPayload) => void;
dismissOverlayNotification?: (id: string) => void;
createFieldGroupingCallback: () => ( createFieldGroupingCallback: () => (
data: KikuFieldGroupingRequestData, data: KikuFieldGroupingRequestData,
) => Promise<KikuFieldGroupingChoice>; ) => Promise<KikuFieldGroupingChoice>;
@@ -177,6 +180,7 @@ export function initializeOverlayAnkiIntegration(options: {
setAnkiIntegration: (integration: unknown | null) => void; setAnkiIntegration: (integration: unknown | null) => void;
showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void; showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void;
showOverlayNotification?: (payload: OverlayNotificationPayload) => void; showOverlayNotification?: (payload: OverlayNotificationPayload) => void;
dismissOverlayNotification?: (id: string) => void;
createFieldGroupingCallback: () => ( createFieldGroupingCallback: () => (
data: KikuFieldGroupingRequestData, data: KikuFieldGroupingRequestData,
) => Promise<KikuFieldGroupingChoice>; ) => Promise<KikuFieldGroupingChoice>;
@@ -219,6 +223,7 @@ export function initializeOverlayAnkiIntegration(options: {
mpvClient, mpvClient,
showDesktopNotification: options.showDesktopNotification, showDesktopNotification: options.showDesktopNotification,
showOverlayNotification: options.showOverlayNotification, showOverlayNotification: options.showOverlayNotification,
dismissOverlayNotification: options.dismissOverlayNotification,
createFieldGroupingCallback: options.createFieldGroupingCallback, createFieldGroupingCallback: options.createFieldGroupingCallback,
knownWordCacheStatePath: options.getKnownWordCacheStatePath(), knownWordCacheStatePath: options.getKnownWordCacheStatePath(),
...(options.getCachedMediaPath ? { getCachedMediaPath: options.getCachedMediaPath } : {}), ...(options.getCachedMediaPath ? { getCachedMediaPath: options.getCachedMediaPath } : {}),
+4
View File
@@ -5925,6 +5925,8 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({
showDesktopNotification, showDesktopNotification,
showOverlayNotification: (payload) => showOverlayNotification: (payload) =>
overlayNotificationsRuntime.showOverlayNotification(payload), overlayNotificationsRuntime.showOverlayNotification(payload),
dismissOverlayNotification: (id) =>
overlayNotificationsRuntime.dismissOverlayNotification(id),
createFieldGroupingCallback: () => createFieldGroupingCallback(), createFieldGroupingCallback: () => createFieldGroupingCallback(),
broadcastRuntimeOptionsChanged: () => broadcastRuntimeOptionsChanged: () =>
overlayVisibilityComposer.broadcastRuntimeOptionsChanged(), overlayVisibilityComposer.broadcastRuntimeOptionsChanged(),
@@ -6415,6 +6417,8 @@ const { initializeOverlayRuntime: initializeOverlayRuntimeHandler } =
showDesktopNotification, showDesktopNotification,
showOverlayNotification: (payload) => showOverlayNotification: (payload) =>
overlayNotificationsRuntime.showOverlayNotification(payload), overlayNotificationsRuntime.showOverlayNotification(payload),
dismissOverlayNotification: (id) =>
overlayNotificationsRuntime.dismissOverlayNotification(id),
createFieldGroupingCallback: () => createFieldGroupingCallback(), createFieldGroupingCallback: () => createFieldGroupingCallback(),
getKnownWordCacheStatePath: () => path.join(USER_DATA_PATH, 'known-words-cache.json'), getKnownWordCacheStatePath: () => path.join(USER_DATA_PATH, 'known-words-cache.json'),
getCachedMediaPath: (currentVideoPath, kind) => getCachedMediaPath: (currentVideoPath, kind) =>
+2
View File
@@ -132,6 +132,7 @@ export interface AnkiJimakuIpcRuntimeServiceDepsParams {
getYoutubeMediaSourceUrl?: AnkiJimakuIpcRuntimeOptions['getYoutubeMediaSourceUrl']; getYoutubeMediaSourceUrl?: AnkiJimakuIpcRuntimeOptions['getYoutubeMediaSourceUrl'];
showDesktopNotification: AnkiJimakuIpcRuntimeOptions['showDesktopNotification']; showDesktopNotification: AnkiJimakuIpcRuntimeOptions['showDesktopNotification'];
showOverlayNotification?: (payload: OverlayNotificationPayload) => void; showOverlayNotification?: (payload: OverlayNotificationPayload) => void;
dismissOverlayNotification?: (id: string) => void;
createFieldGroupingCallback: AnkiJimakuIpcRuntimeOptions['createFieldGroupingCallback']; createFieldGroupingCallback: AnkiJimakuIpcRuntimeOptions['createFieldGroupingCallback'];
broadcastRuntimeOptionsChanged: AnkiJimakuIpcRuntimeOptions['broadcastRuntimeOptionsChanged']; broadcastRuntimeOptionsChanged: AnkiJimakuIpcRuntimeOptions['broadcastRuntimeOptionsChanged'];
getFieldGroupingResolver: AnkiJimakuIpcRuntimeOptions['getFieldGroupingResolver']; getFieldGroupingResolver: AnkiJimakuIpcRuntimeOptions['getFieldGroupingResolver'];
@@ -334,6 +335,7 @@ export function createAnkiJimakuIpcRuntimeServiceDeps(
: {}), : {}),
showDesktopNotification: params.showDesktopNotification, showDesktopNotification: params.showDesktopNotification,
showOverlayNotification: params.showOverlayNotification, showOverlayNotification: params.showOverlayNotification,
dismissOverlayNotification: params.dismissOverlayNotification,
createFieldGroupingCallback: params.createFieldGroupingCallback, createFieldGroupingCallback: params.createFieldGroupingCallback,
broadcastRuntimeOptionsChanged: params.broadcastRuntimeOptionsChanged, broadcastRuntimeOptionsChanged: params.broadcastRuntimeOptionsChanged,
getFieldGroupingResolver: params.getFieldGroupingResolver, getFieldGroupingResolver: params.getFieldGroupingResolver,
@@ -26,6 +26,7 @@ type InitializeOverlayRuntimeCore = (options: {
} | null; } | null;
setAnkiIntegration: (integration: unknown | null) => void; setAnkiIntegration: (integration: unknown | null) => void;
showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void; showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void;
dismissOverlayNotification?: (id: string) => void;
createFieldGroupingCallback: () => ( createFieldGroupingCallback: () => (
data: KikuFieldGroupingRequestData, data: KikuFieldGroupingRequestData,
) => Promise<KikuFieldGroupingChoice>; ) => Promise<KikuFieldGroupingChoice>;
@@ -33,6 +33,8 @@ test('overlay runtime main deps builder maps runtime state and callbacks', () =>
getOverlayWindows: () => [], getOverlayWindows: () => [],
getResolvedConfig: () => ({}), getResolvedConfig: () => ({}),
showDesktopNotification: () => calls.push('notify'), showDesktopNotification: () => calls.push('notify'),
showOverlayNotification: () => calls.push('show-overlay'),
dismissOverlayNotification: () => calls.push('dismiss-overlay'),
createFieldGroupingCallback: () => async () => ({ createFieldGroupingCallback: () => async () => ({
keepNoteId: 1, keepNoteId: 1,
deleteNoteId: 2, deleteNoteId: 2,
@@ -57,6 +59,8 @@ test('overlay runtime main deps builder maps runtime state and callbacks', () =>
deps.refreshCurrentSubtitle?.(); deps.refreshCurrentSubtitle?.();
deps.syncOverlayShortcuts(); deps.syncOverlayShortcuts();
deps.showDesktopNotification('title', {}); deps.showDesktopNotification('title', {});
deps.showOverlayNotification?.({ title: 'title' });
deps.dismissOverlayNotification?.('notification-id');
const tracker = { const tracker = {
close: () => {}, close: () => {},
@@ -73,6 +77,8 @@ test('overlay runtime main deps builder maps runtime state and callbacks', () =>
'refresh-subtitle', 'refresh-subtitle',
'sync-shortcuts', 'sync-shortcuts',
'notify', 'notify',
'show-overlay',
'dismiss-overlay',
]); ]);
assert.equal(appState.windowTracker, tracker); assert.equal(appState.windowTracker, tracker);
assert.deepEqual(appState.ankiIntegration, { id: 'anki' }); assert.deepEqual(appState.ankiIntegration, { id: 'anki' });
@@ -39,6 +39,7 @@ export function createBuildInitializeOverlayRuntimeMainDepsHandler(deps: {
getResolvedConfig: () => { ankiConnect?: AnkiConnectConfig }; getResolvedConfig: () => { ankiConnect?: AnkiConnectConfig };
showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void; showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void;
showOverlayNotification?: (payload: OverlayNotificationPayload) => void; showOverlayNotification?: (payload: OverlayNotificationPayload) => void;
dismissOverlayNotification?: (id: string) => void;
createFieldGroupingCallback: OverlayRuntimeOptionsMainDeps['createFieldGroupingCallback']; createFieldGroupingCallback: OverlayRuntimeOptionsMainDeps['createFieldGroupingCallback'];
getKnownWordCacheStatePath: () => string; getKnownWordCacheStatePath: () => string;
getCachedMediaPath?: OverlayRuntimeOptionsMainDeps['getCachedMediaPath']; getCachedMediaPath?: OverlayRuntimeOptionsMainDeps['getCachedMediaPath'];
@@ -78,6 +79,7 @@ export function createBuildInitializeOverlayRuntimeMainDepsHandler(deps: {
}, },
showDesktopNotification: deps.showDesktopNotification, showDesktopNotification: deps.showDesktopNotification,
showOverlayNotification: deps.showOverlayNotification, showOverlayNotification: deps.showOverlayNotification,
dismissOverlayNotification: deps.dismissOverlayNotification,
createFieldGroupingCallback: () => deps.createFieldGroupingCallback(), createFieldGroupingCallback: () => deps.createFieldGroupingCallback(),
getKnownWordCacheStatePath: () => deps.getKnownWordCacheStatePath(), getKnownWordCacheStatePath: () => deps.getKnownWordCacheStatePath(),
...(deps.getCachedMediaPath ? { getCachedMediaPath: deps.getCachedMediaPath } : {}), ...(deps.getCachedMediaPath ? { getCachedMediaPath: deps.getCachedMediaPath } : {}),
@@ -22,6 +22,8 @@ test('build initialize overlay runtime options maps dependencies', () => {
getRuntimeOptionsManager: () => null, getRuntimeOptionsManager: () => null,
setAnkiIntegration: () => calls.push('set-anki'), setAnkiIntegration: () => calls.push('set-anki'),
showDesktopNotification: () => calls.push('notify'), showDesktopNotification: () => calls.push('notify'),
showOverlayNotification: () => calls.push('show-overlay'),
dismissOverlayNotification: () => calls.push('dismiss-overlay'),
createFieldGroupingCallback: () => async () => ({ createFieldGroupingCallback: () => async () => ({
keepNoteId: 1, keepNoteId: 1,
deleteNoteId: 2, deleteNoteId: 2,
@@ -47,6 +49,8 @@ test('build initialize overlay runtime options maps dependencies', () => {
options.setWindowTracker(null); options.setWindowTracker(null);
options.setAnkiIntegration(null); options.setAnkiIntegration(null);
options.showDesktopNotification('title', {}); options.showDesktopNotification('title', {});
options.showOverlayNotification?.({ title: 'title' });
options.dismissOverlayNotification?.('notification-id');
assert.deepEqual(calls, [ assert.deepEqual(calls, [
'create-main', 'create-main',
@@ -58,5 +62,7 @@ test('build initialize overlay runtime options maps dependencies', () => {
'set-tracker', 'set-tracker',
'set-anki', 'set-anki',
'notify', 'notify',
'show-overlay',
'dismiss-overlay',
]); ]);
}); });
@@ -33,6 +33,7 @@ type OverlayRuntimeOptions = {
setAnkiIntegration: (integration: unknown | null) => void; setAnkiIntegration: (integration: unknown | null) => void;
showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void; showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void;
showOverlayNotification?: (payload: OverlayNotificationPayload) => void; showOverlayNotification?: (payload: OverlayNotificationPayload) => void;
dismissOverlayNotification?: (id: string) => void;
createFieldGroupingCallback: () => ( createFieldGroupingCallback: () => (
data: KikuFieldGroupingRequestData, data: KikuFieldGroupingRequestData,
) => Promise<KikuFieldGroupingChoice>; ) => Promise<KikuFieldGroupingChoice>;
@@ -73,6 +74,7 @@ export function createBuildInitializeOverlayRuntimeOptionsHandler(deps: {
setAnkiIntegration: (integration: unknown | null) => void; setAnkiIntegration: (integration: unknown | null) => void;
showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void; showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void;
showOverlayNotification?: (payload: OverlayNotificationPayload) => void; showOverlayNotification?: (payload: OverlayNotificationPayload) => void;
dismissOverlayNotification?: (id: string) => void;
createFieldGroupingCallback: () => ( createFieldGroupingCallback: () => (
data: KikuFieldGroupingRequestData, data: KikuFieldGroupingRequestData,
) => Promise<KikuFieldGroupingChoice>; ) => Promise<KikuFieldGroupingChoice>;
@@ -107,6 +109,7 @@ export function createBuildInitializeOverlayRuntimeOptionsHandler(deps: {
setAnkiIntegration: deps.setAnkiIntegration, setAnkiIntegration: deps.setAnkiIntegration,
showDesktopNotification: deps.showDesktopNotification, showDesktopNotification: deps.showDesktopNotification,
showOverlayNotification: deps.showOverlayNotification, showOverlayNotification: deps.showOverlayNotification,
dismissOverlayNotification: deps.dismissOverlayNotification,
createFieldGroupingCallback: deps.createFieldGroupingCallback, createFieldGroupingCallback: deps.createFieldGroupingCallback,
getKnownWordCacheStatePath: deps.getKnownWordCacheStatePath, getKnownWordCacheStatePath: deps.getKnownWordCacheStatePath,
...(deps.getCachedMediaPath ? { getCachedMediaPath: deps.getCachedMediaPath } : {}), ...(deps.getCachedMediaPath ? { getCachedMediaPath: deps.getCachedMediaPath } : {}),