Files
SubMiner/src/main/runtime/character-dictionary-auto-sync-notifications.ts
T

85 lines
3.2 KiB
TypeScript

import type { CharacterDictionaryAutoSyncStatusEvent } from './character-dictionary-auto-sync';
import type { StartupOsdSequencerCharacterDictionaryEvent } from './startup-osd-sequencer';
import type { NotificationType, OverlayNotificationPayload } from '../../types/notification';
import { shouldShowDesktop, shouldShowOverlay, shouldShowOsd } from './notification-routing';
export type CharacterDictionaryAutoSyncNotificationEvent = CharacterDictionaryAutoSyncStatusEvent;
export interface CharacterDictionaryAutoSyncNotificationDeps {
getNotificationType: () => NotificationType | undefined;
showOsd: (message: string) => boolean | void;
showOverlayNotification?: (payload: OverlayNotificationPayload) => void;
showDesktopNotification: (title: string, options: { body?: string; replaceId?: string }) => void;
startupOsdSequencer?: {
notifyCharacterDictionaryStatus: (
event: StartupOsdSequencerCharacterDictionaryEvent,
) => boolean;
};
}
// One live desktop notification for the whole sync: progress updates replace each other and the
// terminal ready/failed message replaces the last progress one, matching the overlay toast.
const CHARACTER_DICTIONARY_DESKTOP_NOTIFICATION_ID = 'character-dictionary-auto-sync';
function isTerminalPhase(phase: CharacterDictionaryAutoSyncNotificationEvent['phase']): boolean {
return phase === 'ready' || phase === 'failed';
}
function overlayVariantForPhase(
phase: CharacterDictionaryAutoSyncNotificationEvent['phase'],
): OverlayNotificationPayload['variant'] {
if (phase === 'ready') return 'success';
if (phase === 'failed') return 'error';
return 'progress';
}
function historyIdForEvent(event: CharacterDictionaryAutoSyncNotificationEvent): string {
const mediaId = typeof event.mediaId === 'number' ? String(event.mediaId) : 'current';
return `character-dictionary-auto-sync-${mediaId}-${event.phase}`;
}
export function notifyCharacterDictionaryAutoSyncStatus(
event: CharacterDictionaryAutoSyncNotificationEvent,
deps: CharacterDictionaryAutoSyncNotificationDeps,
): void {
const type = deps.getNotificationType() ?? 'overlay';
if (type === 'none') return;
let startupSequencerShown = false;
if (shouldShowOverlay(type)) {
if (deps.showOverlayNotification) {
deps.showOverlayNotification({
id: 'character-dictionary-auto-sync',
historyId: historyIdForEvent(event),
title: 'Character dictionary',
body: event.message,
variant: overlayVariantForPhase(event.phase),
persistent: !isTerminalPhase(event.phase),
});
} else if (!shouldShowDesktop(type)) {
deps.showDesktopNotification('SubMiner', {
body: event.message,
replaceId: CHARACTER_DICTIONARY_DESKTOP_NOTIFICATION_ID,
});
}
}
if (shouldShowOsd(type)) {
if (deps.startupOsdSequencer) {
startupSequencerShown = deps.startupOsdSequencer.notifyCharacterDictionaryStatus({
phase: event.phase,
message: event.message,
});
} else {
deps.showOsd(event.message);
}
}
if (shouldShowDesktop(type) && !startupSequencerShown) {
deps.showDesktopNotification('SubMiner', {
body: event.message,
replaceId: CHARACTER_DICTIONARY_DESKTOP_NOTIFICATION_ID,
});
}
}