Enhanced handling of hard relearning
This commit is contained in:
@@ -161,7 +161,6 @@ import { normalizeComparableWithNumberWords } from '@/utils/numberAnswerVariants
|
|||||||
const PRACTICE_MIN_EXPOSURES = 3;
|
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 SRS_AGAIN_REINSERT_OFFSET = 3;
|
|
||||||
const MAX_DAILY_DUE = 50;
|
const MAX_DAILY_DUE = 50;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -175,6 +174,7 @@ export default {
|
|||||||
allVocabs: false,
|
allVocabs: false,
|
||||||
srsMode: false,
|
srsMode: false,
|
||||||
initialPool: null,
|
initialPool: null,
|
||||||
|
closeOnHardCompletion: false,
|
||||||
simpleMode: false,
|
simpleMode: false,
|
||||||
pool: [],
|
pool: [],
|
||||||
|
|
||||||
@@ -450,10 +450,8 @@ export default {
|
|||||||
const matchingKey = this.findMatchingHardKey(this.current);
|
const matchingKey = this.findMatchingHardKey(this.current);
|
||||||
if (!matchingKey) return;
|
if (!matchingKey) return;
|
||||||
this.removeHardEntriesForItem(this.current);
|
this.removeHardEntriesForItem(this.current);
|
||||||
if (this.hardPhaseActive && this.hardRemainingCount <= 0) {
|
|
||||||
this.hardPhaseActive = false;
|
|
||||||
}
|
|
||||||
this.saveHardVocabMap();
|
this.saveHardVocabMap();
|
||||||
|
this.maybeFinishHardPhase();
|
||||||
},
|
},
|
||||||
addCurrentToCycle() {
|
addCurrentToCycle() {
|
||||||
if (!this.current?.id) return;
|
if (!this.current?.id) return;
|
||||||
@@ -467,10 +465,16 @@ export default {
|
|||||||
this.hardPhaseActive = true;
|
this.hardPhaseActive = true;
|
||||||
},
|
},
|
||||||
maybeFinishHardPhase() {
|
maybeFinishHardPhase() {
|
||||||
if (!this.hardPhaseActive) return;
|
if (!this.hardPhaseActive && !this.closeOnHardCompletion) return false;
|
||||||
if (this.hardRemainingCount > 0) return;
|
if (this.hardRemainingCount > 0) return false;
|
||||||
|
if (this.hardCount <= 0 && this.closeOnHardCompletion) {
|
||||||
|
this.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!this.hardPhaseActive) return false;
|
||||||
this.hardPhaseActive = false;
|
this.hardPhaseActive = false;
|
||||||
this.cycleAskedIds = [];
|
this.cycleAskedIds = [];
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
getLocalDateKey() {
|
getLocalDateKey() {
|
||||||
const d = new Date();
|
const d = new Date();
|
||||||
@@ -575,7 +579,7 @@ export default {
|
|||||||
}
|
}
|
||||||
this.saveSrsSession();
|
this.saveSrsSession();
|
||||||
},
|
},
|
||||||
open({ languageId, chapterId, lessonId, courseId, initialPool = null, srsMode = false, onClose = null }) {
|
open({ languageId, chapterId, lessonId, courseId, initialPool = null, srsMode = false, closeOnHardCompletion = false, onClose = null }) {
|
||||||
if (this.autoAdvanceTimer) {
|
if (this.autoAdvanceTimer) {
|
||||||
clearTimeout(this.autoAdvanceTimer);
|
clearTimeout(this.autoAdvanceTimer);
|
||||||
this.autoAdvanceTimer = null;
|
this.autoAdvanceTimer = null;
|
||||||
@@ -588,6 +592,7 @@ export default {
|
|||||||
this.onClose = typeof onClose === 'function' ? onClose : null;
|
this.onClose = typeof onClose === 'function' ? onClose : 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.allVocabs = false;
|
this.allVocabs = false;
|
||||||
this.simpleMode = false;
|
this.simpleMode = false;
|
||||||
this.srsSession = null;
|
this.srsSession = null;
|
||||||
@@ -1231,6 +1236,9 @@ export default {
|
|||||||
delete next[mapKey];
|
delete next[mapKey];
|
||||||
this.hardVocabMap = next;
|
this.hardVocabMap = next;
|
||||||
this.saveHardVocabMap();
|
this.saveHardVocabMap();
|
||||||
|
if (this.maybeFinishHardPhase()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1256,21 +1264,18 @@ export default {
|
|||||||
|
|
||||||
const id = this.current?.id;
|
const id = this.current?.id;
|
||||||
const treatAsAgain = rating === 'again' || !this.lastCorrect;
|
const treatAsAgain = rating === 'again' || !this.lastCorrect;
|
||||||
|
const moveToHardPractice = treatAsAgain && this.isItemMarkedHard(this.current);
|
||||||
|
|
||||||
if (id && this.srsSession) {
|
if (id && this.srsSession) {
|
||||||
if (treatAsAgain) {
|
if (treatAsAgain && !moveToHardPractice) {
|
||||||
// Wrong answers are not done yet: requeue near the end so the user
|
// Keep the card at the front of the queue. After the solution has
|
||||||
// sees them again before the session finishes.
|
// been shown, the user must type it correctly before moving on.
|
||||||
if (Array.isArray(this.srsQueueIds)) {
|
|
||||||
const remaining = this.srsQueueIds.filter((x) => x !== id);
|
|
||||||
const insertAt = Math.min(remaining.length, SRS_AGAIN_REINSERT_OFFSET);
|
|
||||||
remaining.splice(insertAt, 0, id);
|
|
||||||
this.srsQueueIds = remaining;
|
|
||||||
}
|
|
||||||
if (Array.isArray(this.srsSession.doneIds)) {
|
if (Array.isArray(this.srsSession.doneIds)) {
|
||||||
this.srsSession.doneIds = this.srsSession.doneIds.filter((x) => x !== id);
|
this.srsSession.doneIds = this.srsSession.doneIds.filter((x) => x !== id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Hard cards leave the daily review after a wrong answer. They are
|
||||||
|
// practiced separately through the hard-vocab drill.
|
||||||
const done = Array.isArray(this.srsSession.doneIds) ? this.srsSession.doneIds : [];
|
const done = Array.isArray(this.srsSession.doneIds) ? this.srsSession.doneIds : [];
|
||||||
if (!done.includes(id)) {
|
if (!done.includes(id)) {
|
||||||
done.push(id);
|
done.push(id);
|
||||||
@@ -1285,6 +1290,21 @@ export default {
|
|||||||
this.saveSrsSession();
|
this.saveSrsSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (treatAsAgain && !moveToHardPractice) {
|
||||||
|
const retryItem = this.pool.find((item) => item.id === id) || this.current;
|
||||||
|
const retryDirection = this.direction;
|
||||||
|
this.resetQuestion();
|
||||||
|
this.current = retryItem;
|
||||||
|
this.direction = retryDirection;
|
||||||
|
const prompt = this.currentAnswerPrompt;
|
||||||
|
this.acceptableAnswers = this.getAnswersForPrompt(prompt, this.direction);
|
||||||
|
if (this.simpleMode) this.buildChoices();
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (!this.simpleMode) this.$refs.answerInput?.focus?.();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.next();
|
this.next();
|
||||||
},
|
},
|
||||||
submitChoice(opt) {
|
submitChoice(opt) {
|
||||||
@@ -1338,7 +1358,7 @@ export default {
|
|||||||
this.addCurrentToCycle();
|
this.addCurrentToCycle();
|
||||||
}
|
}
|
||||||
this.maybeStartHardPhase();
|
this.maybeStartHardPhase();
|
||||||
this.maybeFinishHardPhase();
|
if (this.maybeFinishHardPhase()) return;
|
||||||
const retryDirection = this.pendingRetry?.direction || null;
|
const retryDirection = this.pendingRetry?.direction || null;
|
||||||
this.resetQuestion();
|
this.resetQuestion();
|
||||||
if (retryDirection) {
|
if (retryDirection) {
|
||||||
@@ -1346,7 +1366,7 @@ export default {
|
|||||||
}
|
}
|
||||||
this.current = this.pickNextItem();
|
this.current = this.pickNextItem();
|
||||||
if (!this.current) {
|
if (!this.current) {
|
||||||
this.maybeFinishHardPhase();
|
if (this.maybeFinishHardPhase()) return;
|
||||||
if (!this.hardPhaseActive) {
|
if (!this.hardPhaseActive) {
|
||||||
this.current = this.pickNextItem();
|
this.current = this.pickNextItem();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -966,6 +966,7 @@ export default {
|
|||||||
this.$refs.practiceDialog?.open?.({
|
this.$refs.practiceDialog?.open?.({
|
||||||
courseId: this.courseId,
|
courseId: this.courseId,
|
||||||
initialPool: this.hardVocabList,
|
initialPool: this.hardVocabList,
|
||||||
|
closeOnHardCompletion: true,
|
||||||
onClose: () => this.refreshHardVocabList()
|
onClose: () => this.refreshHardVocabList()
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user