|
@@ -283,6 +283,8 @@ export class LearningPageComponent implements OnInit, OnDestroy {
|
|
|
private examTimer: ReturnType<typeof setInterval> | null = null;
|
|
private examTimer: ReturnType<typeof setInterval> | null = null;
|
|
|
private antiStartedAt = Date.now();
|
|
private antiStartedAt = Date.now();
|
|
|
private calendarRequest?: Subscription;
|
|
private calendarRequest?: Subscription;
|
|
|
|
|
+ private choiceOptionsRequest?: Subscription;
|
|
|
|
|
+ private choiceOptionsVersion = 0;
|
|
|
private stopLiveRefresh?: () => void;
|
|
private stopLiveRefresh?: () => void;
|
|
|
|
|
|
|
|
ngOnInit(): void {
|
|
ngOnInit(): void {
|
|
@@ -307,6 +309,8 @@ export class LearningPageComponent implements OnInit, OnDestroy {
|
|
|
|
|
|
|
|
ngOnDestroy(): void {
|
|
ngOnDestroy(): void {
|
|
|
this.calendarRequestId++;this.calendarRequest?.unsubscribe();this.selectionRequest?.unsubscribe();
|
|
this.calendarRequestId++;this.calendarRequest?.unsubscribe();this.selectionRequest?.unsubscribe();
|
|
|
|
|
+ this.choiceOptionsVersion++;
|
|
|
|
|
+ this.choiceOptionsRequest?.unsubscribe();
|
|
|
this.stopLiveRefresh?.();
|
|
this.stopLiveRefresh?.();
|
|
|
this.stopExamTimer();
|
|
this.stopExamTimer();
|
|
|
this.platform.stopAudio();
|
|
this.platform.stopAudio();
|
|
@@ -1397,18 +1401,28 @@ export class LearningPageComponent implements OnInit, OnDestroy {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private prepareChoiceOptions(): void {
|
|
private prepareChoiceOptions(): void {
|
|
|
|
|
+ this.choiceOptionsRequest?.unsubscribe();
|
|
|
|
|
+ const version = ++this.choiceOptionsVersion;
|
|
|
const current = this.current();
|
|
const current = this.current();
|
|
|
if (!current) {
|
|
if (!current) {
|
|
|
this.choiceOptions.set([]);
|
|
this.choiceOptions.set([]);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- const distractors = this.shuffle(this.words().filter((word) => word.id !== current.id)).slice(0, 3);
|
|
|
|
|
|
|
+ const distractors = this.shuffle(this.words().filter((word) => word.id !== current.id && word.meaning !== current.meaning)).slice(0, 3);
|
|
|
this.choiceOptions.set(this.shuffle([current, ...distractors]));
|
|
this.choiceOptions.set(this.shuffle([current, ...distractors]));
|
|
|
if (distractors.length < 3) {
|
|
if (distractors.length < 3) {
|
|
|
- this.api.get<unknown>('content_list', { modelId: 52, orders: 'NEWID()', cpage: 1, psize: 8 }).subscribe({
|
|
|
|
|
|
|
+ this.choiceOptionsRequest = this.api.get<unknown>('content_list', { modelId: 52, orders: 'NEWID()', cpage: 1, psize: 8 }).subscribe({
|
|
|
next: ({ result }) => {
|
|
next: ({ result }) => {
|
|
|
- const extras = this.findList(result).map((item) => this.toWord(item)).filter((word) => word.id !== current.id && !distractors.some((item) => item.id === word.id));
|
|
|
|
|
- this.choiceOptions.set(this.shuffle([current, ...distractors, ...extras]).slice(0, 4));
|
|
|
|
|
|
|
+ if (version !== this.choiceOptionsVersion || this.current() !== current || this.completed()) return;
|
|
|
|
|
+ const usedIds = new Set([current.id, ...distractors.map((word) => word.id)]);
|
|
|
|
|
+ const usedMeanings = new Set([current.meaning, ...distractors.map((word) => word.meaning)]);
|
|
|
|
|
+ const extras = this.shuffle(this.findList(result).map((item) => this.toWord(item))).filter((word) => {
|
|
|
|
|
+ if (!word.id || !word.meaning || usedIds.has(word.id) || usedMeanings.has(word.meaning)) return false;
|
|
|
|
|
+ usedIds.add(word.id);
|
|
|
|
|
+ usedMeanings.add(word.meaning);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }).slice(0, 3 - distractors.length);
|
|
|
|
|
+ this.choiceOptions.set(this.shuffle([current, ...distractors, ...extras]));
|
|
|
},
|
|
},
|
|
|
error: () => undefined,
|
|
error: () => undefined,
|
|
|
});
|
|
});
|
|
@@ -2026,6 +2040,8 @@ export class LearningPageComponent implements OnInit, OnDestroy {
|
|
|
private clearLearningStorage(): void { this.draft().clear(); }
|
|
private clearLearningStorage(): void { this.draft().clear(); }
|
|
|
|
|
|
|
|
private resetPageState(): void {
|
|
private resetPageState(): void {
|
|
|
|
|
+ this.choiceOptionsVersion++;
|
|
|
|
|
+ this.choiceOptionsRequest?.unsubscribe();
|
|
|
this.stopExamTimer();
|
|
this.stopExamTimer();
|
|
|
this.nodes.set([]);
|
|
this.nodes.set([]);
|
|
|
this.selectedNodes.set(new Set());
|
|
this.selectedNodes.set(new Set());
|