Decouple stats daemon and preserve final mine OSD status

- Run `subminer stats -b` as a dedicated daemon process, independent from the overlay app
- Stop Anki progress spinner before showing final `✓`/`x` mine result so it is not overwritten
- Keep grammar/noise subtitle tokens hoverable while stripping annotation metadata
This commit is contained in:
2026-03-18 23:49:27 -07:00
parent 4d96ebf5c0
commit a954f62f55
32 changed files with 1879 additions and 78 deletions

View File

@@ -40,8 +40,10 @@ import { createLogger } from './logger';
import {
createUiFeedbackState,
beginUpdateProgress,
clearUpdateProgress,
endUpdateProgress,
showStatusNotification,
showUpdateResult,
withUpdateProgress,
UiFeedbackState,
} from './anki-integration/ui-feedback';
@@ -310,6 +312,8 @@ export class AnkiIntegration {
),
},
showOsdNotification: (text: string) => this.showOsdNotification(text),
showUpdateResult: (message: string, success: boolean) =>
this.showUpdateResult(message, success),
showStatusNotification: (message: string) => this.showStatusNotification(message),
showNotification: (noteId, label, errorSuffix) =>
this.showNotification(noteId, label, errorSuffix),
@@ -773,6 +777,12 @@ export class AnkiIntegration {
});
}
private clearUpdateProgress(): void {
clearUpdateProgress(this.uiFeedbackState, (timer) => {
clearInterval(timer);
});
}
private async withUpdateProgress<T>(
initialMessage: string,
action: () => Promise<T>,
@@ -903,7 +913,9 @@ export class AnkiIntegration {
const type = this.config.behavior?.notificationType || 'osd';
if (type === 'osd' || type === 'both') {
this.showOsdNotification(message);
this.showUpdateResult(message, true);
} else {
this.clearUpdateProgress();
}
if ((type === 'system' || type === 'both') && this.notificationCallback) {
@@ -938,6 +950,21 @@ export class AnkiIntegration {
}
}
private showUpdateResult(message: string, success: boolean): void {
showUpdateResult(
this.uiFeedbackState,
{
clearProgressTimer: (timer) => {
clearInterval(timer);
},
showOsdNotification: (text) => {
this.showOsdNotification(text);
},
},
{ message, success },
);
}
private mergeFieldValue(existing: string, newValue: string, overwrite: boolean): string {
if (overwrite || !existing.trim()) {
return newValue;