You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
4.7 KiB

import '../models/deck.dart';
import '../models/question.dart';
import '../models/deck_config.dart';
import '../algorithms/priority_manager.dart';
/// Service for managing deck operations.
class DeckService {
/// Marks a question as known (manual override).
///
/// Sets streak to threshold and isKnown to true.
static Deck markQuestionAsKnown({
required Deck deck,
required String questionId,
}) {
final updatedQuestions = deck.questions.map((q) {
if (q.id == questionId) {
return q.copyWith(
consecutiveCorrect: deck.config.requiredConsecutiveCorrect,
isKnown: true,
);
}
return q;
}).toList();
return deck.copyWith(questions: updatedQuestions);
}
/// Marks a question as needs practice (manual override).
///
/// Sets isKnown to false and streak to 0, but keeps priority unchanged.
static Deck markQuestionAsNeedsPractice({
required Deck deck,
required String questionId,
}) {
final updatedQuestions = deck.questions.map((q) {
if (q.id == questionId) {
return q.copyWith(
isKnown: false,
consecutiveCorrect: 0,
// priorityPoints remains unchanged
);
}
return q;
}).toList();
return deck.copyWith(questions: updatedQuestions);
}
/// Resets the entire deck.
///
/// Resets all questions: streak = 0, isKnown = false, priority = 0.
/// Optionally resets totalAttempts if [resetAttemptCounts] is true.
/// Optionally clears attempt history if [clearAttemptHistory] is true.
static Deck resetDeck({
required Deck deck,
bool resetAttemptCounts = false,
bool clearAttemptHistory = false,
}) {
final updatedQuestions = deck.questions.map((q) {
return q.copyWith(
consecutiveCorrect: 0,
isKnown: false,
priorityPoints: 0,
lastAttemptIndex: -1,
totalCorrectAttempts: resetAttemptCounts ? 0 : q.totalCorrectAttempts,
totalAttempts: resetAttemptCounts ? 0 : q.totalAttempts,
);
}).toList();
return deck.copyWith(
questions: updatedQuestions,
currentAttemptIndex: 0,
attemptHistory: clearAttemptHistory ? [] : deck.attemptHistory,
);
}
/// Updates a question's state after an answer.
///
/// Applies correctness rules and updates streak, priority, and isKnown.
static Question updateQuestionAfterAnswer({
required Question question,
required bool isCorrect,
required DeckConfig config,
required int currentAttemptIndex,
}) {
Question updated = question;
if (isCorrect) {
// Increment streak
final newStreak = question.consecutiveCorrect + 1;
updated = updated.copyWith(consecutiveCorrect: newStreak);
// Update isKnown if streak reaches threshold
if (newStreak >= config.requiredConsecutiveCorrect) {
updated = updated.copyWith(isKnown: true);
}
// Decrease priority
updated = PriorityManager.applyAnswerResult(
question: updated,
isCorrect: true,
config: config,
);
// Update totals
updated = updated.copyWith(
totalCorrectAttempts: question.totalCorrectAttempts + 1,
totalAttempts: question.totalAttempts + 1,
);
} else {
// Reset streak
updated = updated.copyWith(
consecutiveCorrect: 0,
isKnown: false,
);
// Increase priority
updated = PriorityManager.applyAnswerResult(
question: updated,
isCorrect: false,
config: config,
);
// Update totals
updated = updated.copyWith(
totalAttempts: question.totalAttempts + 1,
);
}
// Update lastAttemptIndex
updated = updated.copyWith(lastAttemptIndex: currentAttemptIndex);
return updated;
}
/// Updates a question with manual override after an answer.
///
/// If user marks as "Needs Practice" even after correct answer,
/// ignore correctness and don't increment streak or decrease priority.
static Question updateQuestionWithManualOverride({
required Question question,
required bool isCorrect,
required bool userMarkedNeedsPractice,
required DeckConfig config,
required int currentAttemptIndex,
}) {
if (userMarkedNeedsPractice) {
// User marked as needs practice - ignore correctness
// Don't increment streak, don't decrease priority
// Just update attempt counts and lastAttemptIndex
return question.copyWith(
totalAttempts: question.totalAttempts + 1,
lastAttemptIndex: currentAttemptIndex,
);
} else {
// Normal flow
return updateQuestionAfterAnswer(
question: question,
isCorrect: isCorrect,
config: config,
currentAttemptIndex: currentAttemptIndex,
);
}
}
}

Powered by TurnKey Linux.