explanation
This commit is contained in:
@@ -17,18 +17,21 @@ class DefaultDeck {
|
|||||||
prompt: 'What is the capital city of Australia?',
|
prompt: 'What is the capital city of Australia?',
|
||||||
answers: ['Sydney', 'Melbourne', 'Canberra', 'Perth'],
|
answers: ['Sydney', 'Melbourne', 'Canberra', 'Perth'],
|
||||||
correctAnswerIndices: [2],
|
correctAnswerIndices: [2],
|
||||||
|
explanation: 'Canberra was chosen as the capital in 1908 as a compromise between Sydney and Melbourne.',
|
||||||
),
|
),
|
||||||
Question(
|
Question(
|
||||||
id: 'gk_2',
|
id: 'gk_2',
|
||||||
prompt: 'Which planet is known as the Red Planet?',
|
prompt: 'Which planet is known as the Red Planet?',
|
||||||
answers: ['Venus', 'Mars', 'Jupiter', 'Saturn'],
|
answers: ['Venus', 'Mars', 'Jupiter', 'Saturn'],
|
||||||
correctAnswerIndices: [1],
|
correctAnswerIndices: [1],
|
||||||
|
explanation: 'Mars appears red due to iron oxide (rust) on its surface.',
|
||||||
),
|
),
|
||||||
Question(
|
Question(
|
||||||
id: 'gk_3',
|
id: 'gk_3',
|
||||||
prompt: 'What is the largest ocean on Earth?',
|
prompt: 'What is the largest ocean on Earth?',
|
||||||
answers: ['Atlantic Ocean', 'Indian Ocean', 'Arctic Ocean', 'Pacific Ocean'],
|
answers: ['Atlantic Ocean', 'Indian Ocean', 'Arctic Ocean', 'Pacific Ocean'],
|
||||||
correctAnswerIndices: [3],
|
correctAnswerIndices: [3],
|
||||||
|
explanation: 'The Pacific Ocean covers about 63 million square miles and is larger than all of Earth\'s land area combined.',
|
||||||
),
|
),
|
||||||
Question(
|
Question(
|
||||||
id: 'gk_4',
|
id: 'gk_4',
|
||||||
@@ -203,6 +206,7 @@ class DefaultDeck {
|
|||||||
prompt: 'What is the capital city of Australia?',
|
prompt: 'What is the capital city of Australia?',
|
||||||
answers: ['Sydney', 'Melbourne', 'Canberra', 'Perth'],
|
answers: ['Sydney', 'Melbourne', 'Canberra', 'Perth'],
|
||||||
correctAnswerIndices: [2],
|
correctAnswerIndices: [2],
|
||||||
|
explanation: 'Canberra was chosen as the capital in 1908 as a compromise between Sydney and Melbourne.',
|
||||||
consecutiveCorrect: 3,
|
consecutiveCorrect: 3,
|
||||||
isKnown: true,
|
isKnown: true,
|
||||||
priorityPoints: 0,
|
priorityPoints: 0,
|
||||||
@@ -216,6 +220,7 @@ class DefaultDeck {
|
|||||||
prompt: 'Which planet is known as the Red Planet?',
|
prompt: 'Which planet is known as the Red Planet?',
|
||||||
answers: ['Venus', 'Mars', 'Jupiter', 'Saturn'],
|
answers: ['Venus', 'Mars', 'Jupiter', 'Saturn'],
|
||||||
correctAnswerIndices: [1],
|
correctAnswerIndices: [1],
|
||||||
|
explanation: 'Mars appears red due to iron oxide (rust) on its surface.',
|
||||||
consecutiveCorrect: 3,
|
consecutiveCorrect: 3,
|
||||||
isKnown: true,
|
isKnown: true,
|
||||||
priorityPoints: 0,
|
priorityPoints: 0,
|
||||||
@@ -227,6 +232,7 @@ class DefaultDeck {
|
|||||||
Question(
|
Question(
|
||||||
id: 'gk_3',
|
id: 'gk_3',
|
||||||
prompt: 'What is the largest ocean on Earth?',
|
prompt: 'What is the largest ocean on Earth?',
|
||||||
|
explanation: 'The Pacific Ocean covers about 63 million square miles and is larger than all of Earth\'s land area combined.',
|
||||||
answers: ['Atlantic Ocean', 'Indian Ocean', 'Arctic Ocean', 'Pacific Ocean'],
|
answers: ['Atlantic Ocean', 'Indian Ocean', 'Arctic Ocean', 'Pacific Ocean'],
|
||||||
correctAnswerIndices: [3],
|
correctAnswerIndices: [3],
|
||||||
consecutiveCorrect: 3,
|
consecutiveCorrect: 3,
|
||||||
|
|||||||
@@ -209,6 +209,22 @@ class _AttemptResultScreenState extends State<AttemptResultScreen> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
if (q.explanation != null && q.explanation!.trim().isNotEmpty) ...[
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
const Divider(),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
'Explanation',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
q.explanation!,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ class _DeckEditScreenState extends State<DeckEditScreen> {
|
|||||||
final list = questions.map((q) => {
|
final list = questions.map((q) => {
|
||||||
'id': q.id,
|
'id': q.id,
|
||||||
'prompt': q.prompt,
|
'prompt': q.prompt,
|
||||||
|
if (q.explanation != null && q.explanation!.isNotEmpty) 'explanation': q.explanation,
|
||||||
'answers': q.answers,
|
'answers': q.answers,
|
||||||
'correctAnswerIndices': q.correctAnswerIndices,
|
'correctAnswerIndices': q.correctAnswerIndices,
|
||||||
}).toList();
|
}).toList();
|
||||||
@@ -378,6 +379,16 @@ class _QuestionEditorCardState extends State<QuestionEditorCard> {
|
|||||||
),
|
),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
TextField(
|
||||||
|
controller: widget.editor.explanationController,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Explanation (optional)',
|
||||||
|
helperText: 'Shown when viewing question details after an attempt',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
maxLines: 3,
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Answers
|
// Answers
|
||||||
@@ -474,12 +485,14 @@ class _QuestionEditorCardState extends State<QuestionEditorCard> {
|
|||||||
|
|
||||||
class QuestionEditor {
|
class QuestionEditor {
|
||||||
final TextEditingController promptController;
|
final TextEditingController promptController;
|
||||||
|
final TextEditingController explanationController;
|
||||||
final List<TextEditingController> answerControllers;
|
final List<TextEditingController> answerControllers;
|
||||||
Set<int> correctAnswerIndices;
|
Set<int> correctAnswerIndices;
|
||||||
final String? originalId;
|
final String? originalId;
|
||||||
|
|
||||||
QuestionEditor({
|
QuestionEditor({
|
||||||
required this.promptController,
|
required this.promptController,
|
||||||
|
required this.explanationController,
|
||||||
required this.answerControllers,
|
required this.answerControllers,
|
||||||
Set<int>? correctAnswerIndices,
|
Set<int>? correctAnswerIndices,
|
||||||
this.originalId,
|
this.originalId,
|
||||||
@@ -488,6 +501,7 @@ class QuestionEditor {
|
|||||||
factory QuestionEditor.fromQuestion(Question question) {
|
factory QuestionEditor.fromQuestion(Question question) {
|
||||||
return QuestionEditor(
|
return QuestionEditor(
|
||||||
promptController: TextEditingController(text: question.prompt),
|
promptController: TextEditingController(text: question.prompt),
|
||||||
|
explanationController: TextEditingController(text: question.explanation ?? ''),
|
||||||
answerControllers: question.answers
|
answerControllers: question.answers
|
||||||
.map((answer) => TextEditingController(text: answer))
|
.map((answer) => TextEditingController(text: answer))
|
||||||
.toList(),
|
.toList(),
|
||||||
@@ -499,6 +513,7 @@ class QuestionEditor {
|
|||||||
factory QuestionEditor.empty() {
|
factory QuestionEditor.empty() {
|
||||||
return QuestionEditor(
|
return QuestionEditor(
|
||||||
promptController: TextEditingController(),
|
promptController: TextEditingController(),
|
||||||
|
explanationController: TextEditingController(),
|
||||||
answerControllers: [
|
answerControllers: [
|
||||||
TextEditingController(),
|
TextEditingController(),
|
||||||
TextEditingController(),
|
TextEditingController(),
|
||||||
@@ -521,9 +536,11 @@ class QuestionEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Question toQuestion() {
|
Question toQuestion() {
|
||||||
|
final explanationText = explanationController.text.trim();
|
||||||
return Question(
|
return Question(
|
||||||
id: originalId ?? DateTime.now().millisecondsSinceEpoch.toString(),
|
id: originalId ?? DateTime.now().millisecondsSinceEpoch.toString(),
|
||||||
prompt: promptController.text.trim(),
|
prompt: promptController.text.trim(),
|
||||||
|
explanation: explanationText.isEmpty ? null : explanationText,
|
||||||
answers: answerControllers.map((c) => c.text.trim()).toList(),
|
answers: answerControllers.map((c) => c.text.trim()).toList(),
|
||||||
correctAnswerIndices: correctAnswerIndices.toList()..sort(),
|
correctAnswerIndices: correctAnswerIndices.toList()..sort(),
|
||||||
);
|
);
|
||||||
@@ -531,6 +548,7 @@ class QuestionEditor {
|
|||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
promptController.dispose();
|
promptController.dispose();
|
||||||
|
explanationController.dispose();
|
||||||
for (final controller in answerControllers) {
|
for (final controller in answerControllers) {
|
||||||
controller.dispose();
|
controller.dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ class _DeckImportScreenState extends State<DeckImportScreen> {
|
|||||||
return Question(
|
return Question(
|
||||||
id: questionMap['id'] as String? ?? '',
|
id: questionMap['id'] as String? ?? '',
|
||||||
prompt: questionMap['prompt'] as String? ?? '',
|
prompt: questionMap['prompt'] as String? ?? '',
|
||||||
|
explanation: questionMap['explanation'] as String?,
|
||||||
answers: (questionMap['answers'] as List<dynamic>?)
|
answers: (questionMap['answers'] as List<dynamic>?)
|
||||||
?.map((e) => e.toString())
|
?.map((e) => e.toString())
|
||||||
.toList() ??
|
.toList() ??
|
||||||
@@ -643,6 +644,7 @@ class _DeckImportScreenState extends State<DeckImportScreen> {
|
|||||||
const Text('• answers: array of strings (required)'),
|
const Text('• answers: array of strings (required)'),
|
||||||
const Text('• correctAnswerIndex: number (deprecated, use correctAnswerIndices)'),
|
const Text('• correctAnswerIndex: number (deprecated, use correctAnswerIndices)'),
|
||||||
const Text('• correctAnswerIndices: array of numbers (for multiple correct answers)'),
|
const Text('• correctAnswerIndices: array of numbers (for multiple correct answers)'),
|
||||||
|
const Text('• explanation: string (optional, shown when viewing question details)'),
|
||||||
const Text('• isKnown: boolean (optional)'),
|
const Text('• isKnown: boolean (optional)'),
|
||||||
const Text('• consecutiveCorrect: number (optional)'),
|
const Text('• consecutiveCorrect: number (optional)'),
|
||||||
const Text('• priorityPoints: number (optional)'),
|
const Text('• priorityPoints: number (optional)'),
|
||||||
|
|||||||
@@ -156,8 +156,10 @@ class _FlaggedQuestionsScreenState extends State<FlaggedQuestionsScreen> {
|
|||||||
if (id == null) continue;
|
if (id == null) continue;
|
||||||
final existing = questionMap[id];
|
final existing = questionMap[id];
|
||||||
if (existing == null) continue;
|
if (existing == null) continue;
|
||||||
|
final explanationText = editor.explanationController.text.trim();
|
||||||
final updated = existing.copyWith(
|
final updated = existing.copyWith(
|
||||||
prompt: editor.promptController.text.trim(),
|
prompt: editor.promptController.text.trim(),
|
||||||
|
explanation: explanationText.isEmpty ? null : explanationText,
|
||||||
answers: editor.answerControllers.map((c) => c.text.trim()).toList(),
|
answers: editor.answerControllers.map((c) => c.text.trim()).toList(),
|
||||||
correctAnswerIndices: editor.correctAnswerIndices.toList()..sort(),
|
correctAnswerIndices: editor.correctAnswerIndices.toList()..sort(),
|
||||||
);
|
);
|
||||||
@@ -203,6 +205,7 @@ class _FlaggedQuestionsScreenState extends State<FlaggedQuestionsScreen> {
|
|||||||
final list = questions.map((q) => {
|
final list = questions.map((q) => {
|
||||||
'id': q.id,
|
'id': q.id,
|
||||||
'prompt': q.prompt,
|
'prompt': q.prompt,
|
||||||
|
if (q.explanation != null && q.explanation!.isNotEmpty) 'explanation': q.explanation,
|
||||||
'answers': q.answers,
|
'answers': q.answers,
|
||||||
'correctAnswerIndices': q.correctAnswerIndices,
|
'correctAnswerIndices': q.correctAnswerIndices,
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class DeckStorage {
|
|||||||
'questions': deck.questions.map((q) => {
|
'questions': deck.questions.map((q) => {
|
||||||
'id': q.id,
|
'id': q.id,
|
||||||
'prompt': q.prompt,
|
'prompt': q.prompt,
|
||||||
|
if (q.explanation != null && q.explanation!.isNotEmpty) 'explanation': q.explanation,
|
||||||
'answers': q.answers,
|
'answers': q.answers,
|
||||||
'correctAnswerIndices': q.correctAnswerIndices,
|
'correctAnswerIndices': q.correctAnswerIndices,
|
||||||
'consecutiveCorrect': q.consecutiveCorrect,
|
'consecutiveCorrect': q.consecutiveCorrect,
|
||||||
@@ -133,6 +134,7 @@ class DeckStorage {
|
|||||||
return Question(
|
return Question(
|
||||||
id: questionMap['id'] as String? ?? '',
|
id: questionMap['id'] as String? ?? '',
|
||||||
prompt: questionMap['prompt'] as String? ?? '',
|
prompt: questionMap['prompt'] as String? ?? '',
|
||||||
|
explanation: questionMap['explanation'] as String?,
|
||||||
answers: (questionMap['answers'] as List<dynamic>?)
|
answers: (questionMap['answers'] as List<dynamic>?)
|
||||||
?.map((e) => e.toString())
|
?.map((e) => e.toString())
|
||||||
.toList() ??
|
.toList() ??
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ class Question {
|
|||||||
/// The question prompt.
|
/// The question prompt.
|
||||||
final String prompt;
|
final String prompt;
|
||||||
|
|
||||||
|
/// Optional explanation shown when viewing question details (e.g. after an attempt).
|
||||||
|
final String? explanation;
|
||||||
|
|
||||||
/// List of possible answers.
|
/// List of possible answers.
|
||||||
final List<String> answers;
|
final List<String> answers;
|
||||||
|
|
||||||
@@ -42,6 +45,7 @@ class Question {
|
|||||||
Question({
|
Question({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.prompt,
|
required this.prompt,
|
||||||
|
this.explanation,
|
||||||
required this.answers,
|
required this.answers,
|
||||||
List<int>? correctAnswerIndices,
|
List<int>? correctAnswerIndices,
|
||||||
@Deprecated('Use correctAnswerIndices instead') int? correctAnswerIndex,
|
@Deprecated('Use correctAnswerIndices instead') int? correctAnswerIndex,
|
||||||
@@ -60,6 +64,7 @@ class Question {
|
|||||||
Question copyWith({
|
Question copyWith({
|
||||||
String? id,
|
String? id,
|
||||||
String? prompt,
|
String? prompt,
|
||||||
|
String? explanation,
|
||||||
List<String>? answers,
|
List<String>? answers,
|
||||||
List<int>? correctAnswerIndices,
|
List<int>? correctAnswerIndices,
|
||||||
@Deprecated('Use correctAnswerIndices instead') int? correctAnswerIndex,
|
@Deprecated('Use correctAnswerIndices instead') int? correctAnswerIndex,
|
||||||
@@ -74,6 +79,7 @@ class Question {
|
|||||||
return Question(
|
return Question(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
prompt: prompt ?? this.prompt,
|
prompt: prompt ?? this.prompt,
|
||||||
|
explanation: explanation ?? this.explanation,
|
||||||
answers: answers ?? this.answers,
|
answers: answers ?? this.answers,
|
||||||
correctAnswerIndices: correctAnswerIndices ?? this.correctAnswerIndices,
|
correctAnswerIndices: correctAnswerIndices ?? this.correctAnswerIndices,
|
||||||
correctAnswerIndex: correctAnswerIndex ?? this.correctAnswerIndex,
|
correctAnswerIndex: correctAnswerIndex ?? this.correctAnswerIndex,
|
||||||
@@ -119,6 +125,7 @@ class Question {
|
|||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
id == other.id &&
|
id == other.id &&
|
||||||
prompt == other.prompt &&
|
prompt == other.prompt &&
|
||||||
|
explanation == other.explanation &&
|
||||||
answers.toString() == other.answers.toString() &&
|
answers.toString() == other.answers.toString() &&
|
||||||
correctAnswerIndices.toString() == other.correctAnswerIndices.toString() &&
|
correctAnswerIndices.toString() == other.correctAnswerIndices.toString() &&
|
||||||
consecutiveCorrect == other.consecutiveCorrect &&
|
consecutiveCorrect == other.consecutiveCorrect &&
|
||||||
@@ -133,6 +140,7 @@ class Question {
|
|||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
id.hashCode ^
|
id.hashCode ^
|
||||||
prompt.hashCode ^
|
prompt.hashCode ^
|
||||||
|
(explanation?.hashCode ?? 0) ^
|
||||||
answers.hashCode ^
|
answers.hashCode ^
|
||||||
correctAnswerIndices.hashCode ^
|
correctAnswerIndices.hashCode ^
|
||||||
consecutiveCorrect.hashCode ^
|
consecutiveCorrect.hashCode ^
|
||||||
|
|||||||
Reference in New Issue
Block a user