mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-07-29 01:01:34 -07:00
af826837ab
- Add "Delete Entry" to the anime detail view: removes every episode, session, subtitle line, rollup and cover art for a title plus the vocab counts derived from them, then drops it from the Library grid; refused while that title is currently playing. - Show delete progress (session, session group, episode, entry) app-wide via a top progress bar + status toast that persist across tab switches, detail views, and the stats overlay window instead of going blank off-tab. - Fix delete and Vocabulary-tab performance: store seen_ms on word/kanji occurrences so deletes subtract only removed rows via a covering index instead of rescanning each word's full history, and paginate vocab rows before aggregating anime counts. - Migrate existing databases in place on first launch after upgrade.
84 lines
2.7 KiB
TypeScript
84 lines
2.7 KiB
TypeScript
type NativeDialogBridge = {
|
|
electronAPI?: {
|
|
stats?: {
|
|
confirmNativeDialog?: (message: string) => boolean;
|
|
beginNativeDialog?: () => void;
|
|
endNativeDialog?: () => void;
|
|
};
|
|
};
|
|
};
|
|
|
|
type DeleteConfirmPresenter = (message: string) => boolean | Promise<boolean>;
|
|
|
|
let deleteConfirmPresenter: DeleteConfirmPresenter | null = null;
|
|
|
|
export function setDeleteConfirmPresenter(presenter: DeleteConfirmPresenter): () => void {
|
|
deleteConfirmPresenter = presenter;
|
|
return () => {
|
|
if (deleteConfirmPresenter === presenter) {
|
|
deleteConfirmPresenter = null;
|
|
}
|
|
};
|
|
}
|
|
|
|
async function confirmWithStatsNativeDialogLayer(message: string): Promise<boolean> {
|
|
if (deleteConfirmPresenter) {
|
|
return deleteConfirmPresenter(message);
|
|
}
|
|
|
|
const statsApi = (globalThis as typeof globalThis & NativeDialogBridge).electronAPI?.stats;
|
|
if (statsApi?.confirmNativeDialog) {
|
|
return statsApi.confirmNativeDialog(message);
|
|
}
|
|
|
|
statsApi?.beginNativeDialog?.();
|
|
try {
|
|
return globalThis.confirm(message);
|
|
} finally {
|
|
statsApi?.endNativeDialog?.();
|
|
}
|
|
}
|
|
|
|
export function confirmSessionDelete(): Promise<boolean> {
|
|
return confirmWithStatsNativeDialogLayer('Delete this session and all associated data?');
|
|
}
|
|
|
|
export function confirmDayGroupDelete(dayLabel: string, count: number): Promise<boolean> {
|
|
if (count === 1) {
|
|
return confirmWithStatsNativeDialogLayer(
|
|
`Delete this session from ${dayLabel} and all associated data?`,
|
|
);
|
|
}
|
|
return confirmWithStatsNativeDialogLayer(
|
|
`Delete all ${count} sessions from ${dayLabel} and all associated data?`,
|
|
);
|
|
}
|
|
|
|
export function confirmAnimeGroupDelete(title: string, count: number): Promise<boolean> {
|
|
return confirmWithStatsNativeDialogLayer(
|
|
`Delete all ${count} session${count === 1 ? '' : 's'} for "${title}" and all associated data?`,
|
|
);
|
|
}
|
|
|
|
export function confirmAnimeDelete(title: string, episodeCount: number): Promise<boolean> {
|
|
const episodes = `${episodeCount} episode${episodeCount === 1 ? '' : 's'}`;
|
|
return confirmWithStatsNativeDialogLayer(
|
|
`Delete "${title}" from your library? This removes ${episodes} plus every session and stat recorded for them.`,
|
|
);
|
|
}
|
|
|
|
export function confirmEpisodeDelete(title: string): Promise<boolean> {
|
|
return confirmWithStatsNativeDialogLayer(`Delete "${title}" and all its sessions?`);
|
|
}
|
|
|
|
export function confirmBucketDelete(title: string, count: number): Promise<boolean> {
|
|
if (count === 1) {
|
|
return confirmWithStatsNativeDialogLayer(
|
|
`Delete this session of "${title}" from this day and all associated data?`,
|
|
);
|
|
}
|
|
return confirmWithStatsNativeDialogLayer(
|
|
`Delete all ${count} sessions of "${title}" from this day and all associated data?`,
|
|
);
|
|
}
|