mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-27 00:15:26 -07:00
fix(anki): keep overlay progress visible through card updates (#218)
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
type: fixed
|
||||||
|
area: overlay
|
||||||
|
|
||||||
|
- Kept the Anki card update spinner visible until audio and image updates finish.
|
||||||
@@ -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
@@ -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',
|
||||||
|
|||||||
@@ -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 } : {}),
|
||||||
|
|||||||
@@ -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) =>
|
||||||
|
|||||||
@@ -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 } : {}),
|
||||||
|
|||||||
Reference in New Issue
Block a user