Files
SubMiner/src/anki-integration-ui-feedback.ts

108 lines
2.8 KiB
TypeScript

import { NotificationOptions } from "./types";
export interface UiFeedbackState {
progressDepth: number;
progressTimer: ReturnType<typeof setInterval> | null;
progressMessage: string;
progressFrame: number;
}
export interface UiFeedbackNotificationContext {
getNotificationType: () => string | undefined;
showOsd: (text: string) => void;
showSystemNotification: (
title: string,
options: NotificationOptions,
) => void;
}
export interface UiFeedbackOptions {
setUpdateInProgress: (value: boolean) => void;
showOsdNotification: (text: string) => void;
}
export function createUiFeedbackState(): UiFeedbackState {
return {
progressDepth: 0,
progressTimer: null,
progressMessage: "",
progressFrame: 0,
};
}
export function showStatusNotification(
message: string,
context: UiFeedbackNotificationContext,
): void {
const type = context.getNotificationType() || "osd";
if (type === "osd" || type === "both") {
context.showOsd(message);
}
if (type === "system" || type === "both") {
context.showSystemNotification("SubMiner", { body: message });
}
}
export function beginUpdateProgress(
state: UiFeedbackState,
initialMessage: string,
showProgressTick: (text: string) => void,
): void {
state.progressDepth += 1;
if (state.progressDepth > 1) return;
state.progressMessage = initialMessage;
state.progressFrame = 0;
showProgressTick(`${state.progressMessage}`);
state.progressTimer = setInterval(() => {
showProgressTick(`${state.progressMessage} ${["|", "/", "-", "\\"][state.progressFrame % 4]}`);
state.progressFrame += 1;
}, 180);
}
export function endUpdateProgress(
state: UiFeedbackState,
clearProgressTimer: (timer: ReturnType<typeof setInterval>) => void,
): void {
state.progressDepth = Math.max(0, state.progressDepth - 1);
if (state.progressDepth > 0) return;
if (state.progressTimer) {
clearProgressTimer(state.progressTimer);
state.progressTimer = null;
}
state.progressMessage = "";
state.progressFrame = 0;
}
export function showProgressTick(
state: UiFeedbackState,
showOsdNotification: (text: string) => void,
): void {
if (!state.progressMessage) return;
const frames = ["|", "/", "-", "\\"];
const frame = frames[state.progressFrame % frames.length];
state.progressFrame += 1;
showOsdNotification(`${state.progressMessage} ${frame}`);
}
export async function withUpdateProgress<T>(
state: UiFeedbackState,
options: UiFeedbackOptions,
initialMessage: string,
action: () => Promise<T>,
): Promise<T> {
beginUpdateProgress(state, initialMessage, (message) =>
showProgressTick(state, options.showOsdNotification),
);
options.setUpdateInProgress(true);
try {
return await action();
} finally {
options.setUpdateInProgress(false);
endUpdateProgress(state, clearInterval);
}
}