flagging and exclude
This commit is contained in:
@@ -27,11 +27,14 @@ class AttemptService {
|
||||
final size = attemptSize ?? deck.config.defaultAttemptSize;
|
||||
|
||||
// Filter candidates based on includeKnownInAttempts setting
|
||||
// Use override parameter if provided, otherwise use config
|
||||
final shouldIncludeKnown = includeKnown ?? deck.config.includeKnownInAttempts;
|
||||
final candidates = shouldIncludeKnown
|
||||
? deck.questions
|
||||
var candidates = shouldIncludeKnown
|
||||
? List<Question>.from(deck.questions)
|
||||
: deck.questions.where((q) => !q.isKnown).toList();
|
||||
// Exclude flagged questions when config says so
|
||||
if (deck.config.excludeFlaggedQuestions) {
|
||||
candidates = candidates.where((q) => !q.isFlagged).toList();
|
||||
}
|
||||
|
||||
final selected = _selector.selectQuestions(
|
||||
candidates: candidates,
|
||||
|
||||
@@ -67,8 +67,17 @@ class Deck {
|
||||
/// Total number of questions in the deck.
|
||||
int get numberOfQuestions => questions.length;
|
||||
|
||||
/// Number of questions marked as known.
|
||||
int get knownCount => questions.where((q) => q.isKnown).length;
|
||||
/// Questions that count for attempts and statistics (excludes flagged when config says so).
|
||||
List<Question> get _activeQuestions =>
|
||||
config.excludeFlaggedQuestions
|
||||
? questions.where((q) => !q.isFlagged).toList()
|
||||
: questions;
|
||||
|
||||
/// Number of active questions (excludes flagged when [DeckConfig.excludeFlaggedQuestions] is true).
|
||||
int get activeQuestionCount => _activeQuestions.length;
|
||||
|
||||
/// Number of questions marked as known (among active questions only).
|
||||
int get knownCount => _activeQuestions.where((q) => q.isKnown).length;
|
||||
|
||||
/// Number of questions the user has flagged.
|
||||
int get flaggedCount => questions.where((q) => q.isFlagged).length;
|
||||
@@ -76,24 +85,24 @@ class Deck {
|
||||
/// Questions that the user has flagged.
|
||||
List<Question> get flaggedQuestions => questions.where((q) => q.isFlagged).toList();
|
||||
|
||||
/// Practice percentage: (known / total) * 100
|
||||
/// Practice percentage: (known among active / active count) * 100
|
||||
double get practicePercentage {
|
||||
if (questions.isEmpty) return 0.0;
|
||||
return (knownCount / questions.length) * 100.0;
|
||||
final active = _activeQuestions;
|
||||
if (active.isEmpty) return 0.0;
|
||||
return (knownCount / active.length) * 100.0;
|
||||
}
|
||||
|
||||
/// Progress percentage including partial credit: each question contributes
|
||||
/// 1.0 if known, otherwise (consecutiveCorrect / requiredConsecutiveCorrect)
|
||||
/// capped at 1.0. Averaged over all questions * 100.
|
||||
/// Progress percentage including partial credit over active questions only.
|
||||
double get progressPercentage {
|
||||
if (questions.isEmpty) return 0.0;
|
||||
final active = _activeQuestions;
|
||||
if (active.isEmpty) return 0.0;
|
||||
final required = config.requiredConsecutiveCorrect;
|
||||
final sum = questions.fold<double>(0.0, (sum, q) {
|
||||
final sum = active.fold<double>(0.0, (sum, q) {
|
||||
if (q.isKnown) return sum + 1.0;
|
||||
final partial = (q.consecutiveCorrect / required).clamp(0.0, 1.0);
|
||||
return sum + partial;
|
||||
});
|
||||
return (sum / questions.length) * 100.0;
|
||||
return (sum / active.length) * 100.0;
|
||||
}
|
||||
|
||||
/// Number of completed attempts.
|
||||
|
||||
@@ -23,6 +23,10 @@ class DeckConfig {
|
||||
/// When true, answer options appear in random order each attempt.
|
||||
final bool shuffleAnswerOrder;
|
||||
|
||||
/// Whether to exclude flagged questions from attempts and statistics.
|
||||
/// When true, flagged questions are not selected for attempts and do not count in progress/known.
|
||||
final bool excludeFlaggedQuestions;
|
||||
|
||||
/// Optional time limit for attempts in seconds.
|
||||
/// If null, no time limit is enforced.
|
||||
final int? timeLimitSeconds;
|
||||
@@ -35,6 +39,7 @@ class DeckConfig {
|
||||
this.immediateFeedbackEnabled = true,
|
||||
this.includeKnownInAttempts = false,
|
||||
this.shuffleAnswerOrder = true,
|
||||
this.excludeFlaggedQuestions = false,
|
||||
this.timeLimitSeconds,
|
||||
});
|
||||
|
||||
@@ -47,6 +52,7 @@ class DeckConfig {
|
||||
bool? immediateFeedbackEnabled,
|
||||
bool? includeKnownInAttempts,
|
||||
bool? shuffleAnswerOrder,
|
||||
bool? excludeFlaggedQuestions,
|
||||
int? timeLimitSeconds,
|
||||
}) {
|
||||
return DeckConfig(
|
||||
@@ -62,6 +68,8 @@ class DeckConfig {
|
||||
includeKnownInAttempts:
|
||||
includeKnownInAttempts ?? this.includeKnownInAttempts,
|
||||
shuffleAnswerOrder: shuffleAnswerOrder ?? this.shuffleAnswerOrder,
|
||||
excludeFlaggedQuestions:
|
||||
excludeFlaggedQuestions ?? this.excludeFlaggedQuestions,
|
||||
timeLimitSeconds: timeLimitSeconds ?? this.timeLimitSeconds,
|
||||
);
|
||||
}
|
||||
@@ -78,6 +86,7 @@ class DeckConfig {
|
||||
immediateFeedbackEnabled == other.immediateFeedbackEnabled &&
|
||||
includeKnownInAttempts == other.includeKnownInAttempts &&
|
||||
shuffleAnswerOrder == other.shuffleAnswerOrder &&
|
||||
excludeFlaggedQuestions == other.excludeFlaggedQuestions &&
|
||||
timeLimitSeconds == other.timeLimitSeconds;
|
||||
|
||||
@override
|
||||
@@ -89,6 +98,7 @@ class DeckConfig {
|
||||
immediateFeedbackEnabled.hashCode ^
|
||||
includeKnownInAttempts.hashCode ^
|
||||
shuffleAnswerOrder.hashCode ^
|
||||
excludeFlaggedQuestions.hashCode ^
|
||||
(timeLimitSeconds?.hashCode ?? 0);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user