Auto switch to hard vocabulary

This commit is contained in:
Torsten Schulz (local)
2026-08-17 10:28:13 +02:00
parent f8a2d471d2
commit 3cd2ce747b
2 changed files with 26 additions and 1 deletions

View File

@@ -162,6 +162,7 @@ const PRACTICE_MIN_EXPOSURES = 3;
const SRS_SESSION_STORAGE_VERSION = 2; const SRS_SESSION_STORAGE_VERSION = 2;
const HARD_REQUIRED_CONSECUTIVE_CORRECT = 5; const HARD_REQUIRED_CONSECUTIVE_CORRECT = 5;
const MAX_DAILY_DUE = 50; const MAX_DAILY_DUE = 50;
const MAX_DAILY_HARD_VOCABS = 7;
export default { export default {
name: 'VocabPracticeDialog', name: 'VocabPracticeDialog',
@@ -170,6 +171,7 @@ export default {
return { return {
openParams: null, // { languageId, chapterId, lessonId, courseId } openParams: null, // { languageId, chapterId, lessonId, courseId }
onClose: null, onClose: null,
onDailyHardLimitReached: null,
loading: false, loading: false,
allVocabs: false, allVocabs: false,
srsMode: false, srsMode: false,
@@ -207,6 +209,7 @@ export default {
hardPhaseActive: false, hardPhaseActive: false,
hardMasteryByKey: {}, // { [hardKey]: consecutiveCorrect } hardMasteryByKey: {}, // { [hardKey]: consecutiveCorrect }
cycleAskedIds: [], cycleAskedIds: [],
dailyHardMarkedCount: 0,
}; };
}, },
computed: { computed: {
@@ -444,6 +447,22 @@ export default {
this.hardMasteryByKey[key] = 0; this.hardMasteryByKey[key] = 0;
} }
this.saveHardVocabMap(); this.saveHardVocabMap();
if (this.srsMode) {
this.dailyHardMarkedCount += 1;
this.maybeStartDailyHardPractice();
}
},
maybeStartDailyHardPractice() {
if (this.dailyHardMarkedCount < MAX_DAILY_HARD_VOCABS) return;
const callback = this.onDailyHardLimitReached;
this.close();
this.$nextTick(() => {
try {
callback?.();
} catch (_) {
// A missing parent callback must not interrupt the dialog close.
}
});
}, },
unmarkCurrentAsHard() { unmarkCurrentAsHard() {
if (!this.current) return; if (!this.current) return;
@@ -587,7 +606,7 @@ export default {
} }
this.saveSrsSession(); this.saveSrsSession();
}, },
open({ languageId, chapterId, lessonId, courseId, initialPool = null, srsMode = false, closeOnHardCompletion = false, onClose = null }) { open({ languageId, chapterId, lessonId, courseId, initialPool = null, srsMode = false, closeOnHardCompletion = false, onDailyHardLimitReached = null, onClose = null }) {
if (this.autoAdvanceTimer) { if (this.autoAdvanceTimer) {
clearTimeout(this.autoAdvanceTimer); clearTimeout(this.autoAdvanceTimer);
this.autoAdvanceTimer = null; this.autoAdvanceTimer = null;
@@ -598,6 +617,7 @@ export default {
console.debug('[VocabPracticeDialog] open called with', { languageId, chapterId, lessonId, courseId, srsMode, hasInitialPool: Array.isArray(initialPool) }); console.debug('[VocabPracticeDialog] open called with', { languageId, chapterId, lessonId, courseId, srsMode, hasInitialPool: Array.isArray(initialPool) });
} catch (_) {} } catch (_) {}
this.onClose = typeof onClose === 'function' ? onClose : null; this.onClose = typeof onClose === 'function' ? onClose : null;
this.onDailyHardLimitReached = typeof onDailyHardLimitReached === 'function' ? onDailyHardLimitReached : null;
this.srsMode = Boolean(srsMode); this.srsMode = Boolean(srsMode);
this.initialPool = Array.isArray(initialPool) ? initialPool : null; this.initialPool = Array.isArray(initialPool) ? initialPool : null;
this.closeOnHardCompletion = Boolean(closeOnHardCompletion); this.closeOnHardCompletion = Boolean(closeOnHardCompletion);
@@ -616,6 +636,7 @@ export default {
this.hardPhaseActive = false; this.hardPhaseActive = false;
this.hardMasteryByKey = {}; this.hardMasteryByKey = {};
this.cycleAskedIds = []; this.cycleAskedIds = [];
this.dailyHardMarkedCount = 0;
this.locked = false; this.locked = false;
this.resetQuestion(); this.resetQuestion();
this.$refs.dialog.open(); this.$refs.dialog.open();

View File

@@ -978,6 +978,10 @@ export default {
courseId: this.courseId, courseId: this.courseId,
initialPool: this.srsDueItems, initialPool: this.srsDueItems,
srsMode: true, srsMode: true,
onDailyHardLimitReached: () => {
this.refreshHardVocabList();
this.$nextTick(() => this.openHardPractice());
},
onClose: () => this.loadSrsDueItems() onClose: () => this.loadSrsDueItems()
}); });
}, },