Files
CheckTheethKids/lib/quiz/quiz_random.dart
2026-05-26 16:21:11 +01:00

714 lines
19 KiB
Dart

import 'dart:math';
import 'package:flutter/material.dart';
import 'quiz_question_screen.dart';
import 'quiz_result.dart';
class QuizRandomScreen extends StatefulWidget {
const QuizRandomScreen({super.key, this.currentScore = 0, this.scopeId});
final int currentScore;
final String? scopeId;
@override
State<QuizRandomScreen> createState() => _QuizRandomScreenState();
}
class _QuizRandomScreenState extends State<QuizRandomScreen> {
final List<QuizQuestion> _allQuestions = [
QuizQuestion(
id: 1,
title: 'Quiz 1/26',
question:
'Qual das seguintes imagens se assemelha à face do seu filho/a?',
answerType: QuizAnswerType.image,
answers: const [
QuizAnswer(
//1.jpeg
title: 'Opção A',
description:
'Selecione se a imagem se assemelha à face do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/1.jpeg',
),
QuizAnswer(
//2.jpeg
title: 'Opção B',
description:
'Selecione se a imagem se assemelha à face do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/2.jpeg',
),
QuizAnswer(
//3.jpeg
title: 'Opção C',
description:
'Selecione se a imagem se assemelha à face do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/3.jpeg',
),
],
),
QuizQuestion(
id: 2,
title: 'Quiz 2/26',
question:
'Qual das seguintes imagens se assemelha à posição boca do seu filho/a habitualmente?',
answerType: QuizAnswerType.image,
answers: const [
QuizAnswer(
//4.jpeg
title: 'Opção A',
description:
'Selecione se a imagem se assemelha à boca do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/4.jpeg',
),
QuizAnswer(
//5.png
title: 'Opção B',
description:
'Selecione se a imagem se assemelha à boca do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/5.png',
),
],
),
QuizQuestion(
id: 3,
title: 'Quiz 3/26',
question:
'Qual das seguintes imagens se assemelha às olheiras do seu filho/a?',
answerType: QuizAnswerType.image,
answers: const [
QuizAnswer(
//8.jpeg
title: 'Opção A',
description:
'Selecione se a imagem se assemelha às olheiras do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/8.jpeg',
),
QuizAnswer(
//9.png
title: 'Opção B',
description:
'Selecione se a imagem se assemelha às olheiras do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/9.png',
),
],
),
QuizQuestion(
id: 4,
title: 'Quiz 4/26',
question:
'Qual das seguintes imagens se assemelha ao queixo do seu filho/a com a boca fechada?',
answerType: QuizAnswerType.image,
answers: const [
QuizAnswer(
//6.jpeg
title: 'Opção A',
description:
'Selecione se a imagem se assemelha ao queixo do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/6.jpeg',
),
QuizAnswer(
//7.png
title: 'Opção B',
description:
'Selecione se a imagem se assemelha ao queixo do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/7.png',
),
],
),
QuizQuestion(
id: 6,
title: 'Quiz 6/26',
question:
'Qual das seguintes imagens se assemelha à boca do seu filho/a?',
answerType: QuizAnswerType.image,
answers: const [
QuizAnswer(
//14.jpeg
title: 'Opção A',
description:
'Selecione se a imagem se assemelha à boca do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/14.jpeg',
),
QuizAnswer(
//15.png
title: 'Opção B',
description:
'Selecione se a imagem se assemelha à boca do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/15.png',
),
QuizAnswer(
//16.png
title: 'Opção C',
description:
'Selecione se a imagem se assemelha à boca do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/16.png',
),
],
),
QuizQuestion(
id: 7,
title: 'Quiz 7/26',
question:
'Qual das seguintes imagens se assemelha à boca do seu filho/a?',
answerType: QuizAnswerType.image,
answers: const [
QuizAnswer(
//10.png
title: 'Opção A',
description:
'Selecione se a imagem se assemelha à boca do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/10.png',
),
QuizAnswer(
//11.png
title: 'Opção B',
description:
'Selecione se a imagem se assemelha à boca do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/11.png',
),
QuizAnswer(
//13.png
title: 'Opção C',
description:
'Selecione se a imagem se assemelha à boca do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/13.png',
),
],
),
QuizQuestion(
id: 8,
title: 'Quiz 8/26',
question:
'Qual das seguintes imagens se assemelha ao freio do seu filho/a?',
answerType: QuizAnswerType.image,
answers: const [
QuizAnswer(
//17.png
title: 'Opção A',
description:
'Selecione se a imagem se assemelha ao freio do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/17.png',
),
QuizAnswer(
//18.jpeg
title: 'Opção B',
description:
'Selecione se a imagem se assemelha ao freio do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/18.jpeg',
),
],
),
QuizQuestion(
id: 8,
title: 'Quiz 8/26',
question:
'Qual das seguintes imagens se assemelha ao freio do seu filho/a?',
answerType: QuizAnswerType.image,
answers: const [
QuizAnswer(
//19.jpeg
title: 'Opção A',
description:
'Selecione se a imagem se assemelha ao freio do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/19.jpeg',
),
QuizAnswer(
//20.png
title: 'Opção B',
description:
'Selecione se a imagem se assemelha ao freio do seu filho/a',
weight: 2,
imagePath: 'assets/mockup_images/20.png',
),
],
),
QuizQuestion(
id: 9,
title: 'Quiz 9/26',
question: 'O seu filho/a tem problemas respiratórios diagnosticados?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Problemas respiratórios diagnosticados',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Sem problemas respiratórios diagnosticados',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 10,
title: 'Quiz 10/26',
question: 'O seu filho/a respira habitualmente pela boca?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Respira habitualmente pela boca',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não respira habitualmente pela boca',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 11,
title: 'Quiz 11/26',
question: 'O seu filho/a ressona habitualmente durante a noite?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Ressonar habitualmente durante a noite',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não ressona habitualmente',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 12,
title: 'Quiz 12/26',
question: 'O seu filho/a sente habitualmente o nariz "tapado"?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Sente habitualmente o nariz tapado',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não sente habitualmente o nariz tapado',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 13,
title: 'Quiz 13/26',
question:
'Durante o sono, o seu filho/a tem habitualmente interrupções da respiração?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description:
'Tem habitualmente interrupções da respiração durante o sono',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não tem interrupções da respiração durante o sono',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 14,
title: 'Quiz 14/26',
question: 'O seu filho/a range os dentes com frequência?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Range os dentes com frequência',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não range os dentes com frequência',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 15,
title: 'Quiz 15/26',
question: 'O seu filho/a habitualmente tem alergias sazonais?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Habitualmente tem alergias sazonais',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não tem alergias sazonais',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 16,
title: 'Quiz 16/26',
question: 'O seu filho/a acorda com saliva seca na cara ou na almofada?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Acorda com saliva seca na cara ou na almofada',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não acorda com saliva seca',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 17,
title: 'Quiz 17/26',
question: 'O seu filho/a teve ou costuma ter com frequência otites?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Teve ou costuma ter com frequência otites',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não teve ou não costuma ter otites',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 18,
title: 'Quiz 18/26',
question: 'O seu filho/a teve ou costuma ter com frequência amigdalites?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Teve ou costuma ter com frequência amigdalites',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não teve ou não costuma ter amigdalites',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 19,
title: 'Quiz 19/26',
question:
'O seu filho/a teve ou costuma ter com frequência bronquiolites?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Teve ou costuma ter com frequência bronquiolites',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não teve ou não costuma ter bronquiolites',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 20,
title: 'Quiz 20/26',
question: 'O seu filho/a apresenta dificuldades a mastigar?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Apresenta dificuldades a mastigar',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não apresenta dificuldades a mastigar',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 21,
title: 'Quiz 21/26',
question: 'O seu filho/a habitualmente é lento a comer?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Habitualmente é lento a comer',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não é lento a comer',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 22,
title: 'Quiz 22/26',
question: 'O seu filho/a habitualmente prefere comer alimentos moles?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Habitualmente prefere comer alimentos moles',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não prefere alimentos moles',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 23,
title: 'Quiz 23/26',
question: 'Em bebé apenas foi alimentado por biberão?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Em bebé apenas foi alimentado por biberão',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não foi apenas alimentado por biberão',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 24,
title: 'Quiz 24/26',
question: 'O seu filho/a usa ou usou chupeta com frequência?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Usa ou usou chupeta com frequência',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não usa ou não usou chupeta com frequência',
weight: 1,
value: 'nao',
),
],
),
QuizQuestion(
id: 25,
title: 'Quiz 25/26',
question: 'O seu filho/a chucha ou já chuchou o dedo com frequência?',
answerType: QuizAnswerType.yesNo,
answers: const [
QuizAnswer(
title: 'Sim',
description: 'Chucha ou já chuchou o dedo com frequência',
weight: 2,
value: 'sim',
),
QuizAnswer(
title: 'Não',
description: 'Não chucha ou não chuchou o dedo com frequência',
weight: 1,
value: 'nao',
),
],
),
];
late List<QuizQuestion> _shuffledQuestions;
int _currentQuestionIndex = 0;
int _currentScore = 0;
final Random _random = Random();
@override
void initState() {
super.initState();
_currentScore = widget.currentScore;
_shuffledQuestions = List.from(_allQuestions)..shuffle(_random);
}
void _nextQuestion(int scoreToAdd) {
setState(() {
_currentScore += scoreToAdd;
_currentQuestionIndex++;
});
if (_currentQuestionIndex >= _shuffledQuestions.length) {
// Quiz finished
Navigator.of(context).pushReplacement(
MaterialPageRoute<void>(
builder: (_) => QuizResultScreen(
finalScore: _currentScore,
maxScore: 75, // 15 questions * 5 max points
scopeId: widget.scopeId,
),
),
);
}
}
@override
Widget build(BuildContext context) {
if (_currentQuestionIndex >= _shuffledQuestions.length) {
return const Scaffold(body: Center(child: CircularProgressIndicator()));
}
final currentQuestion = _shuffledQuestions[_currentQuestionIndex];
final isLastQuestion =
_currentQuestionIndex == _shuffledQuestions.length - 1;
return QuizQuestionScreen(
title: currentQuestion.title,
question: currentQuestion.question,
answers: currentQuestion.answers,
currentScore: _currentScore,
nextRoute: (context, nextScore) {
_nextQuestion(nextScore - _currentScore);
return MaterialPageRoute<void>(builder: (_) => const SizedBox.shrink());
},
isFinal: isLastQuestion,
showBackButton: _currentQuestionIndex > 0,
answerType: currentQuestion.answerType,
questionImagePaths: currentQuestion.questionImagePaths,
onFinished: isLastQuestion
? () {
Navigator.of(context).pushReplacement(
MaterialPageRoute<void>(
builder: (_) => QuizResultScreen(
finalScore: _currentScore,
maxScore: 75,
scopeId: widget.scopeId,
),
),
);
}
: null,
);
}
}
class QuizQuestion {
final int id;
final String title;
final String question;
final List<QuizAnswer> answers;
final QuizAnswerType answerType;
// Reference images shown ABOVE the question text (visualization only).
final List<String> questionImagePaths;
QuizQuestion({
required this.id,
required this.title,
required this.question,
required this.answers,
this.answerType = QuizAnswerType.text,
this.questionImagePaths = const [],
});
}
// Helper: returns the asset path for a numbered mockup image (0..27).
// Use in QuizAnswer.imagePath or QuizQuestion.questionImagePaths.
String mockup(int n) => 'assets/mockup_images/$n${_mockupExt[n] ?? '.png'}';
const Map<int, String> _mockupExt = {
0: '.png',
1: '.jpeg',
2: '.jpeg',
3: '.jpeg',
4: '.jpeg',
5: '.png',
6: '.jpeg',
7: '.png',
8: '.jpeg',
9: '.png',
10: '.png',
11: '.png',
12: '.png',
13: '.png',
14: '.jpeg',
15: '.png',
16: '.png',
17: '.png',
18: '.jpeg',
19: '.jpeg',
20: '.png',
21: '.jpeg',
22: '.png',
23: '.jpeg',
24: '.png',
25: '.jpg',
26: '.png',
27: '.png',
};