/// Configuration for a practice deck. class DeckConfig { /// Number of consecutive correct answers required to mark a question as known. final int requiredConsecutiveCorrect; /// Default number of questions to include in an attempt. final int defaultAttemptSize; /// Priority points to add when a question is answered incorrectly. final int priorityIncreaseOnIncorrect; /// Priority points to subtract when a question is answered correctly. final int priorityDecreaseOnCorrect; /// Whether to provide immediate feedback after each answer. final bool immediateFeedbackEnabled; /// Whether to include known questions in attempts. /// If false, known questions will be excluded from attempts. final bool includeKnownInAttempts; /// Whether to shuffle answer order for each question in an attempt. /// When true, answer options appear in random order each attempt. final bool shuffleAnswerOrder; /// Optional time limit for attempts in seconds. /// If null, no time limit is enforced. final int? timeLimitSeconds; const DeckConfig({ this.requiredConsecutiveCorrect = 3, this.defaultAttemptSize = 10, this.priorityIncreaseOnIncorrect = 5, this.priorityDecreaseOnCorrect = 2, this.immediateFeedbackEnabled = true, this.includeKnownInAttempts = false, this.shuffleAnswerOrder = true, this.timeLimitSeconds, }); /// Creates a copy of this config with the given fields replaced. DeckConfig copyWith({ int? requiredConsecutiveCorrect, int? defaultAttemptSize, int? priorityIncreaseOnIncorrect, int? priorityDecreaseOnCorrect, bool? immediateFeedbackEnabled, bool? includeKnownInAttempts, bool? shuffleAnswerOrder, int? timeLimitSeconds, }) { return DeckConfig( requiredConsecutiveCorrect: requiredConsecutiveCorrect ?? this.requiredConsecutiveCorrect, defaultAttemptSize: defaultAttemptSize ?? this.defaultAttemptSize, priorityIncreaseOnIncorrect: priorityIncreaseOnIncorrect ?? this.priorityIncreaseOnIncorrect, priorityDecreaseOnCorrect: priorityDecreaseOnCorrect ?? this.priorityDecreaseOnCorrect, immediateFeedbackEnabled: immediateFeedbackEnabled ?? this.immediateFeedbackEnabled, includeKnownInAttempts: includeKnownInAttempts ?? this.includeKnownInAttempts, shuffleAnswerOrder: shuffleAnswerOrder ?? this.shuffleAnswerOrder, timeLimitSeconds: timeLimitSeconds ?? this.timeLimitSeconds, ); } @override bool operator ==(Object other) => identical(this, other) || other is DeckConfig && runtimeType == other.runtimeType && requiredConsecutiveCorrect == other.requiredConsecutiveCorrect && defaultAttemptSize == other.defaultAttemptSize && priorityIncreaseOnIncorrect == other.priorityIncreaseOnIncorrect && priorityDecreaseOnCorrect == other.priorityDecreaseOnCorrect && immediateFeedbackEnabled == other.immediateFeedbackEnabled && includeKnownInAttempts == other.includeKnownInAttempts && shuffleAnswerOrder == other.shuffleAnswerOrder && timeLimitSeconds == other.timeLimitSeconds; @override int get hashCode => requiredConsecutiveCorrect.hashCode ^ defaultAttemptSize.hashCode ^ priorityIncreaseOnIncorrect.hashCode ^ priorityDecreaseOnCorrect.hashCode ^ immediateFeedbackEnabled.hashCode ^ includeKnownInAttempts.hashCode ^ shuffleAnswerOrder.hashCode ^ (timeLimitSeconds?.hashCode ?? 0); }