From 187d74db8db9274476350da841855c0df9724243 Mon Sep 17 00:00:00 2001 From: gitea Date: Sun, 1 Feb 2026 21:37:19 +0100 Subject: [PATCH] flag and end of attempt --- lib/screens/attempt_result_screen.dart | 105 ++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 13 deletions(-) diff --git a/lib/screens/attempt_result_screen.dart b/lib/screens/attempt_result_screen.dart index 5bdadc5..433457e 100644 --- a/lib/screens/attempt_result_screen.dart +++ b/lib/screens/attempt_result_screen.dart @@ -3,6 +3,7 @@ import 'package:practice_engine/practice_engine.dart'; import '../routes.dart'; import '../widgets/status_chip.dart'; import '../services/deck_storage.dart'; +import '../utils/top_snackbar.dart'; class AttemptResultScreen extends StatefulWidget { const AttemptResultScreen({super.key}); @@ -82,6 +83,42 @@ class _AttemptResultScreenState extends State { ); } + Question? _currentQuestionInDeck(String questionId) { + if (_deck == null) return null; + try { + return _deck!.questions.firstWhere((q) => q.id == questionId); + } catch (_) { + return null; + } + } + + void _toggleFlag(String questionId) { + if (_deck == null) return; + setState(() { + _deck = DeckService.toggleQuestionFlag(deck: _deck!, questionId: questionId); + }); + _deckStorage.saveDeckSync(_deck!); + final q = _currentQuestionInDeck(questionId); + showTopSnackBar( + context, + q?.isFlagged == true ? 'Question flagged for review' : 'Question unflagged', + backgroundColor: q?.isFlagged == true ? Colors.orange : null, + ); + } + + void _markNeedsPractice(String questionId) { + if (_deck == null) return; + setState(() { + _deck = DeckService.markQuestionAsNeedsPractice(deck: _deck!, questionId: questionId); + }); + _deckStorage.saveDeckSync(_deck!); + showTopSnackBar( + context, + 'Marked as needs practice', + backgroundColor: Colors.blue, + ); + } + @override Widget build(BuildContext context) { if (_deck == null || _result == null) { @@ -217,6 +254,8 @@ class _AttemptResultScreenState extends State { ), const SizedBox(height: 12), ..._result!.incorrectQuestions.map((answerResult) { + final currentQ = _currentQuestionInDeck(answerResult.question.id); + final isFlagged = currentQ?.isFlagged ?? false; return Card( margin: const EdgeInsets.only(bottom: 8), child: Padding( @@ -233,23 +272,42 @@ class _AttemptResultScreenState extends State { children: [ StatusChip(statusChange: answerResult.statusChange), const Spacer(), + Text( + 'Your answer${answerResult.userAnswerIndices.length > 1 ? 's' : ''}: ${answerResult.userAnswerIndices.map((idx) => answerResult.question.answers[idx]).join(', ')}', + style: TextStyle( + color: Colors.red, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 8), Text( - 'Your answer${answerResult.userAnswerIndices.length > 1 ? 's' : ''}: ${answerResult.userAnswerIndices.map((idx) => answerResult.question.answers[idx]).join(', ')}', + 'Correct answer${answerResult.question.correctIndices.length > 1 ? 's' : ''}: ${answerResult.question.correctIndices.map((idx) => answerResult.question.answers[idx]).join(', ')}', style: TextStyle( - color: Colors.red, + color: Colors.green, fontWeight: FontWeight.bold, ), ), - ], - ), - const SizedBox(height: 8), - Text( - 'Correct answer${answerResult.question.correctIndices.length > 1 ? 's' : ''}: ${answerResult.question.correctIndices.map((idx) => answerResult.question.answers[idx]).join(', ')}', - style: TextStyle( - color: Colors.green, - fontWeight: FontWeight.bold, - ), - ), + const SizedBox(height: 12), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton.icon( + onPressed: () => _markNeedsPractice(answerResult.question.id), + icon: const Icon(Icons.replay, size: 20), + label: const Text('Needs practice'), + ), + IconButton( + onPressed: () => _toggleFlag(answerResult.question.id), + icon: Icon( + isFlagged ? Icons.flag : Icons.outlined_flag, + color: isFlagged ? Colors.red : null, + ), + tooltip: isFlagged ? 'Unflag' : 'Flag for review', + ), + ], + ), ], ), ), @@ -265,6 +323,8 @@ class _AttemptResultScreenState extends State { ), const SizedBox(height: 12), ..._result!.allResults.map((answerResult) { + final currentQ = _currentQuestionInDeck(answerResult.question.id); + final isFlagged = currentQ?.isFlagged ?? false; return Card( margin: const EdgeInsets.only(bottom: 8), child: ListTile( @@ -274,7 +334,26 @@ class _AttemptResultScreenState extends State { ? 'Correct' : 'Incorrect - Selected: ${answerResult.userAnswerIndices.map((idx) => answerResult.question.answers[idx]).join(', ')}', ), - trailing: StatusChip(statusChange: answerResult.statusChange), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + StatusChip(statusChange: answerResult.statusChange), + IconButton( + onPressed: () => _markNeedsPractice(answerResult.question.id), + icon: const Icon(Icons.replay, size: 22), + tooltip: 'Mark as needs practice', + ), + IconButton( + onPressed: () => _toggleFlag(answerResult.question.id), + icon: Icon( + isFlagged ? Icons.flag : Icons.outlined_flag, + color: isFlagged ? Colors.red : null, + size: 22, + ), + tooltip: isFlagged ? 'Unflag' : 'Flag for review', + ), + ], + ), ), ); }),