flagging and exclude

This commit is contained in:
gitea
2026-02-01 19:49:49 +01:00
parent 10a4837ee0
commit fe9c5a9fec
7 changed files with 72 additions and 23 deletions
+18
View File
@@ -24,6 +24,7 @@ class _DeckConfigScreenState extends State<DeckConfigScreen> {
late bool _immediateFeedback;
late bool _includeKnownInAttempts;
late bool _shuffleAnswerOrder;
late bool _excludeFlaggedQuestions;
bool _timeLimitEnabled = false;
String? _lastDeckId;
int _configHashCode = 0;
@@ -74,6 +75,7 @@ class _DeckConfigScreenState extends State<DeckConfigScreen> {
_immediateFeedback = _config!.immediateFeedbackEnabled;
_includeKnownInAttempts = _config!.includeKnownInAttempts;
_shuffleAnswerOrder = _config!.shuffleAnswerOrder;
_excludeFlaggedQuestions = _config!.excludeFlaggedQuestions;
// Initialize time limit controllers
_timeLimitEnabled = _config!.timeLimitSeconds != null;
@@ -196,6 +198,7 @@ class _DeckConfigScreenState extends State<DeckConfigScreen> {
immediateFeedbackEnabled: _immediateFeedback,
includeKnownInAttempts: _includeKnownInAttempts,
shuffleAnswerOrder: _shuffleAnswerOrder,
excludeFlaggedQuestions: _excludeFlaggedQuestions,
timeLimitSeconds: timeLimitSeconds,
);
@@ -416,6 +419,21 @@ class _DeckConfigScreenState extends State<DeckConfigScreen> {
),
const SizedBox(height: 16),
// Exclude Flagged Questions Toggle
SwitchListTile(
title: const Text('Exclude flagged questions'),
subtitle: const Text(
'Flagged questions are not used in attempts and do not count in progress',
),
value: _excludeFlaggedQuestions,
onChanged: (value) {
setState(() {
_excludeFlaggedQuestions = value;
});
},
),
const SizedBox(height: 16),
// Time Limit Section
SwitchListTile(
title: const Text('Enable Time Limit'),
+3
View File
@@ -40,6 +40,7 @@ class _DeckImportScreenState extends State<DeckImportScreen> {
immediateFeedbackEnabled: configJson['immediateFeedbackEnabled'] as bool? ?? true,
includeKnownInAttempts: configJson['includeKnownInAttempts'] as bool? ?? false,
shuffleAnswerOrder: configJson['shuffleAnswerOrder'] as bool? ?? true,
excludeFlaggedQuestions: configJson['excludeFlaggedQuestions'] as bool? ?? false,
);
// Parse questions
@@ -249,6 +250,7 @@ class _DeckImportScreenState extends State<DeckImportScreen> {
'immediateFeedbackEnabled': true,
'includeKnownInAttempts': false,
'shuffleAnswerOrder': true,
'excludeFlaggedQuestions': false,
},
'questions': List.generate(20, (i) {
return {
@@ -545,6 +547,7 @@ class _DeckImportScreenState extends State<DeckImportScreen> {
const Text('• immediateFeedbackEnabled: boolean'),
const Text('• includeKnownInAttempts: boolean'),
const Text('• shuffleAnswerOrder: boolean'),
const Text('• excludeFlaggedQuestions: boolean'),
],
),
),
+13 -9
View File
@@ -59,10 +59,14 @@ class _DeckOverviewScreenState extends State<DeckOverviewScreen> {
}
}
if (deckToCheck == null || deckToCheck.questions.isEmpty) {
if (deckToCheck == null || deckToCheck.activeQuestionCount == 0) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Cannot start attempt: No questions in deck'),
SnackBar(
content: Text(
deckToCheck != null && deckToCheck.questions.isNotEmpty && deckToCheck.config.excludeFlaggedQuestions
? 'Cannot start attempt: All questions are flagged. Unflag some or turn off "Exclude flagged questions" in settings.'
: 'Cannot start attempt: No questions in deck',
),
backgroundColor: Colors.red,
),
);
@@ -158,8 +162,8 @@ class _DeckOverviewScreenState extends State<DeckOverviewScreen> {
}
}
// Check if all questions are known and includeKnownInAttempts is disabled
final allKnown = deckToCheck.knownCount == deckToCheck.numberOfQuestions && deckToCheck.numberOfQuestions > 0;
// Check if all active questions are known and includeKnownInAttempts is disabled
final allKnown = deckToCheck.knownCount == deckToCheck.activeQuestionCount && deckToCheck.activeQuestionCount > 0;
final includeKnownDisabled = !deckToCheck.config.includeKnownInAttempts;
if (allKnown && includeKnownDisabled) {
@@ -285,7 +289,7 @@ class _DeckOverviewScreenState extends State<DeckOverviewScreen> {
Widget _buildProgressStats(BuildContext context) {
if (_deck == null) return const SizedBox.shrink();
final totalQuestions = _deck!.numberOfQuestions;
final totalQuestions = _deck!.activeQuestionCount;
final knownCount = _deck!.knownCount;
final unknownCount = totalQuestions - knownCount;
final unknownPercentage = totalQuestions > 0
@@ -484,7 +488,7 @@ class _DeckOverviewScreenState extends State<DeckOverviewScreen> {
),
const SizedBox(height: 4),
Text(
'${_deck!.knownCount} of ${_deck!.numberOfQuestions} questions known',
'${_deck!.knownCount} of ${_deck!.activeQuestionCount} questions known',
style: Theme.of(context).textTheme.bodySmall,
),
],
@@ -505,7 +509,7 @@ class _DeckOverviewScreenState extends State<DeckOverviewScreen> {
children: [
_StatItem(
label: 'Total',
value: '${_deck!.numberOfQuestions}',
value: '${_deck!.activeQuestionCount}',
icon: Icons.quiz,
),
_StatItem(
@@ -515,7 +519,7 @@ class _DeckOverviewScreenState extends State<DeckOverviewScreen> {
),
_StatItem(
label: 'Practice',
value: '${_deck!.numberOfQuestions - _deck!.knownCount}',
value: '${_deck!.activeQuestionCount - _deck!.knownCount}',
icon: Icons.school,
),
],