fix(vocab): count hard trainer mastery by stored term

This commit is contained in:
Torsten Schulz (local)
2026-08-26 14:38:31 +02:00
parent 71f0e15bb7
commit df3ce328b4

View File

@@ -270,10 +270,15 @@ export default {
return this.pool.filter((item) => this.isItemMarkedHard(item));
},
hardRemainingCount() {
return this.hardPoolItems.filter((item) => {
const key = this.getHardKey(item);
return (Number(this.hardMasteryByKey[key]) || 0) < HARD_REQUIRED_CONSECUTIVE_CORRECT;
}).length;
// A displayed card can be an expanded answer variant of one stored hard
// item (e.g. "A / B"). Count and track the stored hard item once, not
// every generated variant separately.
const hardKeys = new Set(this.hardPoolItems
.map((item) => this.getHardMasteryKey(item))
.filter(Boolean));
return Array.from(hardKeys)
.filter((key) => (Number(this.hardMasteryByKey[key]) || 0) < HARD_REQUIRED_CONSECUTIVE_CORRECT)
.length;
}
},
methods: {
@@ -346,6 +351,11 @@ export default {
isItemMarkedHard(item) {
return Boolean(this.findMatchingHardKey(item));
},
getHardMasteryKey(item) {
// Prefer the key of the persisted SRS hard item. This keeps all
// acceptable variants of the same vocabulary pair on one mastery count.
return this.findMatchingHardKey(item) || this.getHardKey(item);
},
removeHardEntriesForItem(item) {
const itemLearning = this.normalize(item?.learning || '');
const itemReference = this.normalize(item?.reference || '');
@@ -593,6 +603,13 @@ export default {
this.hardVocabMap[key] = { learning: item.learning, reference: item.reference, itemKey: item.itemKey || item.id || null };
});
}
// This dialog is explicitly opened for the hard-vocabulary collection.
// Its correct answers must therefore count towards releasing those items
// from the very first question, rather than only after a full warm-up
// round through the same collection.
if (this.closeOnHardCompletion && this.hardPoolItems.length > 0) {
this.hardPhaseActive = true;
}
if (this.maybeStartDailyHardPractice()) return;
this.reloadPool();
},
@@ -1049,7 +1066,7 @@ export default {
}
if (this.hardPhaseActive) {
const hardItems = this.hardPoolItems.filter((item) => {
const key = this.getHardKey(item);
const key = this.getHardMasteryKey(item);
return (Number(this.hardMasteryByKey[key]) || 0) < HARD_REQUIRED_CONSECUTIVE_CORRECT;
});
if (hardItems.length === 0) {
@@ -1058,7 +1075,7 @@ export default {
}
const rankedHard = hardItems
.map((item) => {
const key = this.getHardKey(item);
const key = this.getHardMasteryKey(item);
const mastery = Number(this.hardMasteryByKey[key]) || 0;
const st = this.perId[item.id] || { c: 0, w: 0, streak: 0, lastAsked: 0 };
return {
@@ -1204,7 +1221,7 @@ export default {
st.streak = st.streak >= 0 ? st.streak + 1 : 1;
}
if (this.hardPhaseActive && this.current) {
const key = this.getHardKey(this.current);
const key = this.getHardMasteryKey(this.current);
this.hardMasteryByKey[key] = Math.max(0, Number(this.hardMasteryByKey[key]) || 0) + 1;
const mapKey = this.findMatchingHardKey(this.current);
if ((Number(this.hardMasteryByKey[key]) || 0) >= HARD_REQUIRED_CONSECUTIVE_CORRECT && mapKey) {
@@ -1222,7 +1239,7 @@ export default {
st.w += 1;
st.streak = st.streak <= 0 ? st.streak - 1 : -1;
if (this.hardPhaseActive && this.current) {
const key = this.getHardKey(this.current);
const key = this.getHardMasteryKey(this.current);
this.hardMasteryByKey[key] = 0;
}
}