Documentação

This commit is contained in:
Carlos Correia
2026-05-03 23:31:31 +01:00
commit d24cb3242a
167 changed files with 14263 additions and 0 deletions

140
lib/quiz/README_QUIZ.md Normal file
View File

@@ -0,0 +1,140 @@
# Sistema de Quiz Extendido - Check-Teeth Kids
## Novos Arquivos Criados
### 1. `quiz_extended.dart`
Contém 15 novas telas de quiz sequenciais (Quiz 6-20) com temas educativos sobre saúde bucal:
- **Quiz 6**: Tipos de escova para crianças
- **Quiz 7**: Alimentos que causam cáries
- **Quiz 8**: Primeira visita ao dentista
- **Quiz 9**: Uso de chupeta
- **Quiz 10**: Flúor na água
- **Quiz 11**: Escovação noturna
- **Quiz 12**: Bebidas ácidas
- **Quiz 13**: Importância dos dentes de leite
- **Quiz 14**: Técnica de escovação
- **Quiz 15**: Enxaguante bucal infantil
- **Quiz 16**: Lanches escolares saudáveis
- **Quiz 17**: Traumas dentários
- **Quiz 18**: Problemas na mordida
- **Quiz 19**: Gengivas sangrando
- **Quiz 20**: Selantes dentários
### 2. `quiz_random.dart`
Sistema de quiz aleatório com 15 perguntas selecionadas aleatoriamente a cada sessão.
## Como Usar
### Para Quiz Sequencial Extendido (20 perguntas):
```dart
import 'quiz_extended.dart';
// Para iniciar do Quiz 6:
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const Quiz6Screen()),
);
// Para conectar ao final do Quiz 5, modifique quiz5.dart:
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz6Screen(currentScore: nextScore, scopeId: scopeId),
),
```
### Para Quiz Aleatório (15 perguntas):
```dart
import 'quiz_random.dart';
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const QuizRandomScreen()),
);
```
## Sistema de Pontuação
- **Quiz Sequencial**: 20 perguntas × 5 pontos = máximo 100 pontos
- **Quiz Aleatório**: 15 perguntas × 5 pontos = máximo 75 pontos
- **Sistema de pesos**: 2 (melhor) a 5 (pior) pontos
## Estrutura das Perguntas
Cada quiz segue o padrão:
```dart
QuizQuestionScreen(
title: 'Quiz X/20',
question: 'Pergunta educativa...',
answers: [
QuizAnswer(title: 'Resposta A', description: 'Explicação...', weight: 2),
QuizAnswer(title: 'Resposta B', description: 'Explicação...', weight: 5),
QuizAnswer(title: 'Resposta C', description: 'Explicação...', weight: 3),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute(...),
showBackButton: true,
);
```
## Temas Abordados
### 🦷 Higiene Oral
- Tempo e técnica de escovação
- Tipos de escova e pasta de dente
- Uso de fio dental e enxaguante
### 🍎 Nutrição e Saúde
- Alimentos prejudiciais e benéficos
- Bebidas ácidas vs neutras
- Lanches escolares saudáveis
### 👶 Desenvolvimento Infantil
- Dentes de leite e permanentes
- Hábitos como chupeta e sucção
- Primeira visita ao dentista
### 🔬 Prevenção e Tratamento
- Flúor e selantes
- Traumas dentários
- Problemas gengivais
## Integração com Sistema Existente
Os novos quizzes são totalmente compatíveis com:
- ✅ Sistema de pontuação existente
- ✅ Tela de resultados (`QuizResultScreen`)
- ✅ Navegação e animações
- ✅ Design e cores do app
- ✅ Firebase (scopeId)
## Personalização
Para modificar o quiz aleatório:
```dart
// Em quiz_random.dart, altere o número de perguntas:
final List<QuizQuestion> _selectedQuestions = _allQuestions.take(10).toList(); // 10 perguntas
```
Para adicionar novas perguntas:
```dart
// Adicione ao final da lista _allQuestions em quiz_random.dart
QuizQuestion(
id: 16,
title: 'Quiz 16/15',
question: 'Nova pergunta...',
answers: [...],
),
```
## Teste e Validação
Os arquivos foram testados com:
-`flutter analyze` - sem erros
- ✅ Estrutura compatível com código existente
- ✅ Importações corretas
- ✅ Navegação funcional
---
*Criado em 01/05/2026*
*Total de perguntas: 35 (5 originais + 15 sequenciais + 15 aleatórias)*

0
lib/quiz/quiz.dart Normal file
View File

825
lib/quiz/quiz1.dart Normal file
View File

@@ -0,0 +1,825 @@
import 'package:flutter/material.dart';
import 'quiz_question_screen.dart';
import 'quiz_result.dart';
// Quiz 1: Tipos de Escova (antiga Quiz 6)
class Quiz1Screen extends StatelessWidget {
const Quiz1Screen({super.key, this.currentScore = 0, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 1/20',
question: 'Qual tipo de escova é mais recomendada para crianças?',
answers: const [
QuizAnswer(
title: 'Escova macia com cabeça pequena',
description:
'Escovas macias protegem a gengiva sensível das crianças e a cabeça pequena alcança melhor todos os dentes.',
weight: 2,
),
QuizAnswer(
title: 'Escova dura para limpar melhor',
description:
'Escovas duras podem machucar a gengiva e desgastar o esmalte dos dentes das crianças.',
weight: 5,
),
QuizAnswer(
title: 'Escova elétrica sempre é melhor',
description:
'Escova elétrica pode ajudar, mas não é essencial. O mais importante é a técnica e frequência.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz2Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: false,
);
}
}
// Quiz 2: Alimentos que Causam Cáries (antiga Quiz 7)
class Quiz2Screen extends StatelessWidget {
const Quiz2Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 2/20',
question: 'Qual alimento é mais prejudicial para os dentes?',
answers: const [
QuizAnswer(
title: 'Balas e chicletes pegajosos',
description:
'Alimentos pegajosos ficam presos nos dentes por mais tempo, aumentando o risco de cáries.',
weight: 2,
),
QuizAnswer(
title: 'Frutas frescas',
description:
'Frutas são saudáveis, mas algumas são ácidas. O problema maior são os alimentos açucarados e pegajosos.',
weight: 5,
),
QuizAnswer(
title: 'Vegetais crus',
description:
'Vegetais são geralmente seguros para os dentes e muitos ajudam na limpeza natural.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz3Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 3: Primeira Visita ao Dentista (antiga Quiz 8)
class Quiz3Screen extends StatelessWidget {
const Quiz3Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 3/20',
question: 'Qual a idade ideal para a primeira visita ao dentista?',
answers: const [
QuizAnswer(
title: 'A partir dos 1 ano de idade',
description:
'O recomendado é levar ao dentista assim que o primeiro dentição aparecer ou até 1 ano.',
weight: 2,
),
QuizAnswer(
title: 'Só depois dos 6 anos',
description:
'Esperar demais pode permitir que problemas sérios se desenvolvam sem detecção precoce.',
weight: 5,
),
QuizAnswer(
title: 'Apenas quando houver dor',
description:
'Dor geralmente indica que o problema já está avançado. Prevenção é melhor que tratamento.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz4Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 4: Uso de Fio Dental (antiga Quiz 9)
class Quiz4Screen extends StatelessWidget {
const Quiz4Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 4/20',
question: 'Com que frequência crianças devem usar fio dental?',
answers: const [
QuizAnswer(
title: 'Pelo menos uma vez ao dia',
description:
'O uso diário de fio dental é importante para remover placa entre os dentes onde a escova não alcança.',
weight: 2,
),
QuizAnswer(
title: 'Só quando os dentes estiverem muito juntos',
description:
'Fio dental é necessário independentemente do espaçamento dos dentes para remover placa bacteriana.',
weight: 5,
),
QuizAnswer(
title: 'Uma vez por semana é suficiente',
description:
'Uso semanal é insuficiente. Placa bacteriana se forma diariamente e precisa ser removida.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz5Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 5: Flúor (antiga Quiz 10)
class Quiz5Screen extends StatelessWidget {
const Quiz5Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 5/20',
question: 'O flúor é seguro para crianças?',
answers: const [
QuizAnswer(
title: 'Sim, na quantidade correta para cada idade',
description:
'Flúor é seguro e eficaz quando usado nas quantidades recomendadas para cada faixa etária.',
weight: 2,
),
QuizAnswer(
title: 'Não, deve ser evitado completamente',
description:
'Flúor é essencial para prevenir cáries. O problema é o excesso, não o uso adequado.',
weight: 5,
),
QuizAnswer(
title: 'Só necessário depois dos 12 anos',
description:
'Flúor é importante em todas as idades, com ajuste na quantidade conforme a idade da criança.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz6Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 6: Chupetas e Mamadeiras (antiga Quiz 11)
class Quiz6Screen extends StatelessWidget {
const Quiz6Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 6/20',
question: 'Até que idade é aceitável usar chupeta?',
answers: const [
QuizAnswer(
title: 'Até 2-3 anos, com desmame gradual',
description:
'Após 2-3 anos, chupeta pode afetar o desenvolvimento da dentição e fala. O desmame deve ser gradual.',
weight: 2,
),
QuizAnswer(
title: 'Até os 6 anos, não tem problema',
description:
'Uso prolongado pode causar problemas na mordida e fala, além de dificultar o alinhamento dos dentes.',
weight: 5,
),
QuizAnswer(
title: 'Só até 1 ano',
description:
'Um ano pode ser muito cedo para algumas crianças. O importante é começar o desmame após 2 anos.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz7Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 7: Bebidas e Dentição (antiga Quiz 12)
class Quiz7Screen extends StatelessWidget {
const Quiz7Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 7/20',
question: 'Qual bebida é mais prejudicial para os dentes das crianças?',
answers: const [
QuizAnswer(
title: 'Refrigerantes e sucos industrializados',
description:
'Bebidas açucaradas e ácidas são as principais causas de cáries infantis, especialmente se consumidas frequentemente.',
weight: 2,
),
QuizAnswer(
title: 'Leite e água',
description:
'Leite e água são seguros para os dentes. O problema são bebidas açucaradas e ácidas.',
weight: 5,
),
QuizAnswer(
title: 'Sucos naturais sem açúcar',
description:
'Sucos naturais são melhores que industrializados, mas alguns são ácidos. Moderação é importante.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz8Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 8: Hábitos Noturnos (antiga Quiz 13)
class Quiz8Screen extends StatelessWidget {
const Quiz8Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 8/20',
question: 'Crianças devem escovar os dentes antes de dormir?',
answers: const [
QuizAnswer(
title: 'Sim, é fundamental antes de dormir',
description:
'Escovação noturna é crucial porque durante a noite a produção de saliva diminui, aumentando o risco de cáries.',
weight: 2,
),
QuizAnswer(
title: 'Só se comeu doce',
description:
'Placa bacteriana se acumula durante o dia independentemente do que foi comido. Escovação noturna é sempre necessária.',
weight: 5,
),
QuizAnswer(
title: 'Não precisa se escovou durante o dia',
description:
'Mesmo com escovação diurna, a noturna é essencial devido à redução de saliva durante o sono.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz9Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 9: Traumatismos Dentários (antiga Quiz 14)
class Quiz9Screen extends StatelessWidget {
const Quiz9Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 9/20',
question: 'O que fazer se uma criança cair e quebrar um dente?',
answers: const [
QuizAnswer(
title: 'Procurar dentista imediatamente',
description:
'Traumatismo dentário é emergência. Quanto mais rápido o atendimento, melhor o prognóstico.',
weight: 2,
),
QuizAnswer(
title: 'Esperar alguns dias para observar',
description:
'Esperar pode comprometer o tratamento. Dentes fraturados podem infectar ou morrer se não tratados.',
weight: 5,
),
QuizAnswer(
title: 'Dar analgésico e observar',
description:
'Analgésico pode ajudar com dor, mas não resolve o problema dentário que precisa de tratamento profissional.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz10Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 10: Selantes (antiga Quiz 15)
class Quiz10Screen extends StatelessWidget {
const Quiz10Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 10/20',
question: 'Para que servem os selantes dentários?',
answers: const [
QuizAnswer(
title: 'Proteger contra cáries em dentes profundos',
description:
'Selantes criam uma barreira protetora em sulcos e fissuras, locais difíceis de limpar e propensos a cáries.',
weight: 2,
),
QuizAnswer(
title: 'Clarear os dentes',
description:
'Selantes não têm função estética de clareamento, apenas protetora contra cáries.',
weight: 5,
),
QuizAnswer(
title: 'Substituir a escovação',
description:
'Selantes complementam a higiene, não substituem a escovação e o fio dental.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz11Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 11: Aparelhos Ortodônticos (antiga Quiz 16)
class Quiz11Screen extends StatelessWidget {
const Quiz11Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 11/20',
question: 'Qual a melhor idade para avaliar necessidade de aparelho?',
answers: const [
QuizAnswer(
title: 'Entre 7-9 anos para avaliação',
description:
'Avaliação precoce permite identificar problemas e planejar o melhor momento para intervenção.',
weight: 2,
),
QuizAnswer(
title: 'Só depois dos 12 anos',
description:
'Esperar demais pode perder a oportunidade de tratamento interceptativo que simplifica casos complexos.',
weight: 5,
),
QuizAnswer(
title: 'Qualquer idade, não faz diferença',
description:
'Existem momentos ideais para diferentes tipos de tratamento. Avaliação precoce é importante.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz12Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 12: Respiração Bucal (antiga Quiz 17)
class Quiz12Screen extends StatelessWidget {
const Quiz12Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 12/20',
question: 'Respirar pela boca afeta os dentes?',
answers: const [
QuizAnswer(
title: 'Sim, pode causar vários problemas',
description:
'Respiração bucal pode alterar o desenvolvimento facial, causar cáries e problemas ortodônticos.',
weight: 2,
),
QuizAnswer(
title: 'Não, é apenas uma questão de hábito',
description:
'Respiração bucal tem consequências reais na saúde bucal e desenvolvimento facial da criança.',
weight: 5,
),
QuizAnswer(
title: 'Só afeta adultos, não crianças',
description:
'Em crianças, os efeitos são mais sérios pois afetam o desenvolvimento dos ossos faciais.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz13Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 13: Gengivas (antiga Quiz 18)
class Quiz13Screen extends StatelessWidget {
const Quiz13Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 13/20',
question: 'O que causa gengivas inflamadas em crianças?',
answers: const [
QuizAnswer(
title: 'Higiene inadequada e acúmulo de placa',
description:
'Placa bacteriana não removida properly causa inflamação gengival, a forma mais comum de gengivite.',
weight: 2,
),
QuizAnswer(
title: 'É normal na infância, não precisa tratar',
description:
'Gengivite não é normal e precisa tratamento. Se não tratada, pode evoluir para periodontite.',
weight: 5,
),
QuizAnswer(
title: 'Apenas mudanças hormonais',
description:
'Hormônios podem influenciar, mas a causa principal é acúmulo de placa por higiene inadequada.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz14Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 14: Lanche Escolar (antiga Quiz 19)
class Quiz14Screen extends StatelessWidget {
const Quiz14Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 14/20',
question: 'Qual lanche escolar é melhor para os dentes?',
answers: const [
QuizAnswer(
title: 'Frutas, queijo e água',
description:
'Lanches naturais e sem açúcar são ideais. Queijo até ajuda neutralizar ácidos e fortalecer dentes.',
weight: 2,
),
QuizAnswer(
title: 'Bolachas recheadas e suco de caixa',
description:
'Lanches industrializados e açucarados são os principais vilões da saúde bucal escolar.',
weight: 5,
),
QuizAnswer(
title: 'Salgadinhos de pacote',
description:
'Salgadinhos são amiláceos e se transformam em açúcar, além de ficarem presos nos dentes.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz15Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 15: Medo do Dentista (antiga Quiz 20)
class Quiz15Screen extends StatelessWidget {
const Quiz15Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 15/20',
question: 'Como lidar com o medo do dentista em crianças?',
answers: const [
QuizAnswer(
title: 'Conversar positivamente e visitar regularmente',
description:
'Linguagem positiva e visitas frequentes sem necessidade de tratamento ajudam a criar confiança.',
weight: 2,
),
QuizAnswer(
title: 'Evitar falar sobre dentista',
description:
'Não falar sobre o assunto pode aumentar o medo. É importante preparar a criança positivamente.',
weight: 5,
),
QuizAnswer(
title: 'Levar só quando houver problema',
description:
'Visitas só em caso de problema associam dentista a dor. Visitas regulares preventivas são melhores.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz16Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 16: Tempo ideal para escovar (antiga Quiz 1)
class Quiz16Screen extends StatelessWidget {
const Quiz16Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 16/20',
question: 'Qual é o tempo ideal para escovar os dentes?',
answers: const [
QuizAnswer(
title: 'Cerca de 2 minutos',
description:
'O recomendado é escovar por aproximadamente 2 minutos, cobrindo todas as superfícies dos dentes e a linha da gengiva sem pressa.',
weight: 2,
),
QuizAnswer(
title: 'Só 30 segundos, se fizer rápido',
description:
'Muito pouco tempo costuma deixar placa bacteriana para trás, principalmente nos dentes de trás e perto da gengiva.',
weight: 5,
),
QuizAnswer(
title: '5 minutos com força para "limpar bem"',
description:
'Tempo demais e força excessiva podem irritar a gengiva e desgastar o esmalte. Prefira movimentos suaves e tempo adequado.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz17Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 17: Troca da escova (antiga Quiz 2)
class Quiz17Screen extends StatelessWidget {
const Quiz17Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 17/20',
question: 'Quando devo trocar a escova de dentes?',
answers: const [
QuizAnswer(
title: 'A cada 3 meses (ou antes se estragar)',
description:
'O ideal é trocar a cada ~3 meses. Se as cerdas abrirem antes, troque antes. Cerdas abertas limpam pior.',
weight: 2,
),
QuizAnswer(
title: 'Só quando a escova "quebrar"',
description:
'Esperar demais reduz a eficiência da escovação e pode acumular microrganismos na escova.',
weight: 5,
),
QuizAnswer(
title: 'Todo mês, obrigatoriamente',
description:
'Não é regra fixa. Um mês pode ser cedo demais se a escova estiver em bom estado. O principal é o estado das cerdas.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz18Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 18: Quantidade de pasta (antiga Quiz 3)
class Quiz18Screen extends StatelessWidget {
const Quiz18Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 18/20',
question: 'Qual a quantidade ideal de pasta de dente para crianças?',
answers: const [
QuizAnswer(
title: 'Um grão de arroz (pequenos) / ervilha (maiores)',
description:
'Para crianças pequenas, um "grão de arroz" já basta. Conforme cresce, pode ser do tamanho de uma ervilha. Isso ajuda a evitar excesso de flúor ingerido.',
weight: 2,
),
QuizAnswer(
title: 'Cobrir toda a escova com pasta',
description:
'Muito produto não significa melhor limpeza. Em crianças, aumenta o risco de engolir pasta em excesso.',
weight: 5,
),
QuizAnswer(
title: 'Nenhuma pasta, só água',
description:
'A pasta com flúor (na quantidade correta) ajuda a prevenir cáries. Em geral, água sozinha não oferece a mesma proteção.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz19Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 19: Fio dental (antiga Quiz 4)
class Quiz19Screen extends StatelessWidget {
const Quiz19Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 19/20',
question: 'Qual é o melhor horário para usar fio dental?',
answers: const [
QuizAnswer(
title: 'Uma vez ao dia, com calma (geralmente à noite)',
description:
'O importante é a frequência diária. À noite costuma ser mais fácil, pois remove restos e placa antes de dormir.',
weight: 2,
),
QuizAnswer(
title: 'Só quando algo fica preso',
description:
'O fio dental não serve apenas para tirar restos visíveis; ele remove placa bacteriana entre os dentes onde a escova não alcança.',
weight: 5,
),
QuizAnswer(
title: 'Depois de toda refeição (obrigatório)',
description:
'Pode ser útil em alguns casos, mas não é obrigatório para todos. O essencial é fazer bem feito ao menos 1x ao dia.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz20Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 20: Prevenção de cáries (antiga Quiz 5)
class Quiz20Screen extends StatelessWidget {
const Quiz20Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 20/20',
question: 'O que ajuda mais a prevenir cáries no dia a dia?',
answers: const [
QuizAnswer(
title: 'Escovar + flúor + reduzir açúcar frequente',
description:
'A prevenção é um conjunto: boa higiene com flúor e menos "beliscos" açucarados ao longo do dia.',
weight: 2,
),
QuizAnswer(
title: 'Só enxaguante bucal',
description:
'Enxaguante pode ajudar em alguns casos, mas não substitui escovação e fio dental.',
weight: 3,
),
QuizAnswer(
title: 'Evitar completamente dentista',
description:
'Consultas regulares são importantes para prevenção e orientação. O dentista também identifica problemas bem no começo.',
weight: 5,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => QuizResultScreen(finalScore: nextScore, maxScore: 100, scopeId: scopeId),
),
isFinal: true,
showBackButton: true,
);
}
}

46
lib/quiz/quiz2.dart Normal file
View File

@@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
import 'quiz3.dart';
import 'quiz_question_screen.dart';
class Quiz2Screen extends StatelessWidget {
const Quiz2Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 2/5',
question: 'Quando devo trocar a escova de dentes?',
answers: const [
QuizAnswer(
title: 'A cada 3 meses (ou antes se estragar)',
description:
'O ideal é trocar a cada ~3 meses. Se as cerdas abrirem antes, troque antes. Cerdas abertas limpam pior.',
weight: 2,
),
QuizAnswer(
title: 'Só quando a escova “quebrar”',
description:
'Esperar demais reduz a eficiência da escovação e pode acumular microrganismos na escova.',
weight: 5,
),
QuizAnswer(
title: 'Todo mês, obrigatoriamente',
description:
'Não é regra fixa. Um mês pode ser cedo demais se a escova estiver em bom estado. O principal é o estado das cerdas.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz3Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
//

46
lib/quiz/quiz3.dart Normal file
View File

@@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
import 'quiz4.dart';
import 'quiz_question_screen.dart';
class Quiz3Screen extends StatelessWidget {
const Quiz3Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 3/5',
question: 'Qual a quantidade ideal de pasta de dente para crianças?',
answers: const [
QuizAnswer(
title: 'Um grão de arroz (pequenos) / ervilha (maiores)',
description:
'Para crianças pequenas, um “grão de arroz” já basta. Conforme cresce, pode ser do tamanho de uma ervilha. Isso ajuda a evitar excesso de flúor ingerido.',
weight: 2,
),
QuizAnswer(
title: 'Cobrir toda a escova com pasta',
description:
'Muito produto não significa melhor limpeza. Em crianças, aumenta o risco de engolir pasta em excesso.',
weight: 5,
),
QuizAnswer(
title: 'Nenhuma pasta, só água',
description:
'A pasta com flúor (na quantidade correta) ajuda a prevenir cáries. Em geral, água sozinha não oferece a mesma proteção.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz4Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
//

46
lib/quiz/quiz4.dart Normal file
View File

@@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
import 'quiz5.dart';
import 'quiz_question_screen.dart';
class Quiz4Screen extends StatelessWidget {
const Quiz4Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 4/5',
question: 'Qual é o melhor horário para usar fio dental?',
answers: const [
QuizAnswer(
title: 'Uma vez ao dia, com calma (geralmente à noite)',
description:
'O importante é a frequência diária. À noite costuma ser mais fácil, pois remove restos e placa antes de dormir.',
weight: 2,
),
QuizAnswer(
title: 'Só quando algo fica preso',
description:
'O fio dental não serve apenas para tirar restos visíveis; ele remove placa bacteriana entre os dentes onde a escova não alcança.',
weight: 5,
),
QuizAnswer(
title: 'Depois de toda refeição (obrigatório)',
description:
'Pode ser útil em alguns casos, mas não é obrigatório para todos. O essencial é fazer bem feito ao menos 1x ao dia.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz5Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
//

46
lib/quiz/quiz5.dart Normal file
View File

@@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
import 'quiz_result.dart';
import 'quiz_question_screen.dart';
class Quiz5Screen extends StatelessWidget {
const Quiz5Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 5/5',
question: 'O que ajuda mais a prevenir cáries no dia a dia?',
answers: const [
QuizAnswer(
title: 'Escovar + flúor + reduzir açúcar frequente',
description:
'A prevenção é um conjunto: boa higiene com flúor e menos “beliscos” açucarados ao longo do dia.',
weight: 2,
),
QuizAnswer(
title: 'Só enxaguante bucal',
description:
'Enxaguante pode ajudar em alguns casos, mas não substitui escovação e fio dental.',
weight: 3,
),
QuizAnswer(
title: 'Evitar completamente dentista',
description:
'Consultas regulares são importantes para prevenção e orientação. O dentista também identifica problemas bem no começo.',
weight: 5,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => QuizResultScreen(finalScore: nextScore, maxScore: 25, scopeId: scopeId),
),
showBackButton: true,
);
}
}
//

825
lib/quiz/quiz_complete.dart Normal file
View File

@@ -0,0 +1,825 @@
import 'package:flutter/material.dart';
import 'quiz_question_screen.dart';
import 'quiz_result.dart';
// Quiz 1: Tipos de Escova (antiga Quiz 6)
class Quiz1Screen extends StatelessWidget {
const Quiz1Screen({super.key, this.currentScore = 0, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 1/20',
question: 'Qual tipo de escova é mais recomendada para crianças?',
answers: const [
QuizAnswer(
title: 'Escova macia com cabeça pequena',
description:
'Escovas macias protegem a gengiva sensível das crianças e a cabeça pequena alcança melhor todos os dentes.',
weight: 2,
),
QuizAnswer(
title: 'Escova dura para limpar melhor',
description:
'Escovas duras podem machucar a gengiva e desgastar o esmalte dos dentes das crianças.',
weight: 5,
),
QuizAnswer(
title: 'Escova elétrica sempre é melhor',
description:
'Escova elétrica pode ajudar, mas não é essencial. O mais importante é a técnica e frequência.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz2Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: false,
);
}
}
// Quiz 2: Alimentos que Causam Cáries (antiga Quiz 7)
class Quiz2Screen extends StatelessWidget {
const Quiz2Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 2/20',
question: 'Qual alimento é mais prejudicial para os dentes?',
answers: const [
QuizAnswer(
title: 'Balas e chicletes pegajosos',
description:
'Alimentos pegajosos ficam presos nos dentes por mais tempo, aumentando o risco de cáries.',
weight: 2,
),
QuizAnswer(
title: 'Frutas frescas',
description:
'Frutas são saudáveis, mas algumas são ácidas. O problema maior são os alimentos açucarados e pegajosos.',
weight: 5,
),
QuizAnswer(
title: 'Vegetais crus',
description:
'Vegetais são geralmente seguros para os dentes e muitos ajudam na limpeza natural.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz3Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 3: Primeira Visita ao Dentista (antiga Quiz 8)
class Quiz3Screen extends StatelessWidget {
const Quiz3Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 3/20',
question: 'Qual a idade ideal para a primeira visita ao dentista?',
answers: const [
QuizAnswer(
title: 'A partir dos 1 ano de idade',
description:
'O recomendado é levar ao dentista assim que o primeiro dentição aparecer ou até 1 ano.',
weight: 2,
),
QuizAnswer(
title: 'Só depois dos 6 anos',
description:
'Esperar demais pode permitir que problemas sérios se desenvolvam sem detecção precoce.',
weight: 5,
),
QuizAnswer(
title: 'Apenas quando houver dor',
description:
'Dor geralmente indica que o problema já está avançado. Prevenção é melhor que tratamento.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz4Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 4: Uso de Fio Dental (antiga Quiz 9)
class Quiz4Screen extends StatelessWidget {
const Quiz4Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 4/20',
question: 'Com que frequência crianças devem usar fio dental?',
answers: const [
QuizAnswer(
title: 'Pelo menos uma vez ao dia',
description:
'O uso diário de fio dental é importante para remover placa entre os dentes onde a escova não alcança.',
weight: 2,
),
QuizAnswer(
title: 'Só quando os dentes estiverem muito juntos',
description:
'Fio dental é necessário independentemente do espaçamento dos dentes para remover placa bacteriana.',
weight: 5,
),
QuizAnswer(
title: 'Uma vez por semana é suficiente',
description:
'Uso semanal é insuficiente. Placa bacteriana se forma diariamente e precisa ser removida.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz5Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 5: Flúor (antiga Quiz 10)
class Quiz5Screen extends StatelessWidget {
const Quiz5Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 5/20',
question: 'O flúor é seguro para crianças?',
answers: const [
QuizAnswer(
title: 'Sim, na quantidade correta para cada idade',
description:
'Flúor é seguro e eficaz quando usado nas quantidades recomendadas para cada faixa etária.',
weight: 2,
),
QuizAnswer(
title: 'Não, deve ser evitado completamente',
description:
'Flúor é essencial para prevenir cáries. O problema é o excesso, não o uso adequado.',
weight: 5,
),
QuizAnswer(
title: 'Só necessário depois dos 12 anos',
description:
'Flúor é importante em todas as idades, com ajuste na quantidade conforme a idade da criança.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz6Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 6: Chupetas e Mamadeiras (antiga Quiz 11)
class Quiz6Screen extends StatelessWidget {
const Quiz6Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 6/20',
question: 'Até que idade é aceitável usar chupeta?',
answers: const [
QuizAnswer(
title: 'Até 2-3 anos, com desmame gradual',
description:
'Após 2-3 anos, chupeta pode afetar o desenvolvimento da dentição e fala. O desmame deve ser gradual.',
weight: 2,
),
QuizAnswer(
title: 'Até os 6 anos, não tem problema',
description:
'Uso prolongado pode causar problemas na mordida e fala, além de dificultar o alinhamento dos dentes.',
weight: 5,
),
QuizAnswer(
title: 'Só até 1 ano',
description:
'Um ano pode ser muito cedo para algumas crianças. O importante é começar o desmame após 2 anos.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz7Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 7: Bebidas e Dentição (antiga Quiz 12)
class Quiz7Screen extends StatelessWidget {
const Quiz7Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 7/20',
question: 'Qual bebida é mais prejudicial para os dentes das crianças?',
answers: const [
QuizAnswer(
title: 'Refrigerantes e sucos industrializados',
description:
'Bebidas açucaradas e ácidas são as principais causas de cáries infantis, especialmente se consumidas frequentemente.',
weight: 2,
),
QuizAnswer(
title: 'Leite e água',
description:
'Leite e água são seguros para os dentes. O problema são bebidas açucaradas e ácidas.',
weight: 5,
),
QuizAnswer(
title: 'Sucos naturais sem açúcar',
description:
'Sucos naturais são melhores que industrializados, mas alguns são ácidos. Moderação é importante.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz8Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 8: Hábitos Noturnos (antiga Quiz 13)
class Quiz8Screen extends StatelessWidget {
const Quiz8Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 8/20',
question: 'Crianças devem escovar os dentes antes de dormir?',
answers: const [
QuizAnswer(
title: 'Sim, é fundamental antes de dormir',
description:
'Escovação noturna é crucial porque durante a noite a produção de saliva diminui, aumentando o risco de cáries.',
weight: 2,
),
QuizAnswer(
title: 'Só se comeu doce',
description:
'Placa bacteriana se acumula durante o dia independentemente do que foi comido. Escovação noturna é sempre necessária.',
weight: 5,
),
QuizAnswer(
title: 'Não precisa se escovou durante o dia',
description:
'Mesmo com escovação diurna, a noturna é essencial devido à redução de saliva durante o sono.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz9Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 9: Traumatismos Dentários (antiga Quiz 14)
class Quiz9Screen extends StatelessWidget {
const Quiz9Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 9/20',
question: 'O que fazer se uma criança cair e quebrar um dente?',
answers: const [
QuizAnswer(
title: 'Procurar dentista imediatamente',
description:
'Traumatismo dentário é emergência. Quanto mais rápido o atendimento, melhor o prognóstico.',
weight: 2,
),
QuizAnswer(
title: 'Esperar alguns dias para observar',
description:
'Esperar pode comprometer o tratamento. Dentes fraturados podem infectar ou morrer se não tratados.',
weight: 5,
),
QuizAnswer(
title: 'Dar analgésico e observar',
description:
'Analgésico pode ajudar com dor, mas não resolve o problema dentário que precisa de tratamento profissional.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz10Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 10: Selantes (antiga Quiz 15)
class Quiz10Screen extends StatelessWidget {
const Quiz10Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 10/20',
question: 'Para que servem os selantes dentários?',
answers: const [
QuizAnswer(
title: 'Proteger contra cáries em dentes profundos',
description:
'Selantes criam uma barreira protetora em sulcos e fissuras, locais difíceis de limpar e propensos a cáries.',
weight: 2,
),
QuizAnswer(
title: 'Clarear os dentes',
description:
'Selantes não têm função estética de clareamento, apenas protetiva contra cáries.',
weight: 5,
),
QuizAnswer(
title: 'Substituir a escovação',
description:
'Selantes complementam a higiene, não substituem a escovação e o fio dental.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz11Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 11: Aparelhos Ortodônticos (antiga Quiz 16)
class Quiz11Screen extends StatelessWidget {
const Quiz11Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 11/20',
question: 'Qual a melhor idade para avaliar necessidade de aparelho?',
answers: const [
QuizAnswer(
title: 'Entre 7-9 anos para avaliação',
description:
'Avaliação precoce permite identificar problemas e planejar o melhor momento para intervenção.',
weight: 2,
),
QuizAnswer(
title: 'Só depois dos 12 anos',
description:
'Esperar demais pode perder a oportunidade de tratamento interceptativo que simplifica casos complexos.',
weight: 5,
),
QuizAnswer(
title: 'Qualquer idade, não faz diferença',
description:
'Existem momentos ideais para diferentes tipos de tratamento. Avaliação precoce é importante.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz12Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 12: Respiração Bucal (antiga Quiz 17)
class Quiz12Screen extends StatelessWidget {
const Quiz12Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 12/20',
question: 'Respirar pela boca afeta os dentes?',
answers: const [
QuizAnswer(
title: 'Sim, pode causar vários problemas',
description:
'Respiração bucal pode alterar o desenvolvimento facial, causar cáries e problemas ortodônticos.',
weight: 2,
),
QuizAnswer(
title: 'Não, é apenas uma questão de hábito',
description:
'Respiração bucal tem consequências reais na saúde bucal e desenvolvimento facial da criança.',
weight: 5,
),
QuizAnswer(
title: 'Só afeta adultos, não crianças',
description:
'Em crianças, os efeitos são mais sérios pois afetam o desenvolvimento dos ossos faciais.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz13Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 13: Gengivas (antiga Quiz 18)
class Quiz13Screen extends StatelessWidget {
const Quiz13Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 13/20',
question: 'O que causa gengivas inflamadas em crianças?',
answers: const [
QuizAnswer(
title: 'Higiene inadequada e acúmulo de placa',
description:
'Placa bacteriana não removida properly causa inflamação gengival, a forma mais comum de gengivite.',
weight: 2,
),
QuizAnswer(
title: 'É normal na infância, não precisa tratar',
description:
'Gengivite não é normal e precisa tratamento. Se não tratada, pode evoluir para periodontite.',
weight: 5,
),
QuizAnswer(
title: 'Apenas mudanças hormonais',
description:
'Hormônios podem influenciar, mas a causa principal é acúmulo de placa por higiene inadequada.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz14Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 14: Lanche Escolar (antiga Quiz 19)
class Quiz14Screen extends StatelessWidget {
const Quiz14Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 14/20',
question: 'Qual lanche escolar é melhor para os dentes?',
answers: const [
QuizAnswer(
title: 'Frutas, queijo e água',
description:
'Lanches naturais e sem açúcar são ideais. Queijo até ajuda neutralizar ácidos e fortalecer dentes.',
weight: 2,
),
QuizAnswer(
title: 'Bolachas recheadas e suco de caixa',
description:
'Lanches industrializados e açucarados são os principais vilões da saúde bucal escolar.',
weight: 5,
),
QuizAnswer(
title: 'Salgadinhos de pacote',
description:
'Salgadinhos são amiláceos e se transformam em açúcar, além de ficarem presos nos dentes.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz15Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 15: Medo do Dentista (antiga Quiz 20)
class Quiz15Screen extends StatelessWidget {
const Quiz15Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 15/20',
question: 'Como lidar com o medo do dentista em crianças?',
answers: const [
QuizAnswer(
title: 'Conversar positivamente e visitar regularmente',
description:
'Linguagem positiva e visitas frequentes sem necessidade de tratamento ajudam a criar confiança.',
weight: 2,
),
QuizAnswer(
title: 'Evitar falar sobre dentista',
description:
'Não falar sobre o assunto pode aumentar o medo. É importante preparar a criança positivamente.',
weight: 5,
),
QuizAnswer(
title: 'Levar só quando houver problema',
description:
'Visitas só em caso de problema associam dentista a dor. Visitas regulares preventivas são melhores.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz16Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 16: Tempo ideal para escovar (antiga Quiz 1)
class Quiz16Screen extends StatelessWidget {
const Quiz16Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 16/20',
question: 'Qual é o tempo ideal para escovar os dentes?',
answers: const [
QuizAnswer(
title: 'Cerca de 2 minutos',
description:
'O recomendado é escovar por aproximadamente 2 minutos, cobrindo todas as superfícies dos dentes e a linha da gengiva sem pressa.',
weight: 2,
),
QuizAnswer(
title: 'Só 30 segundos, se fizer rápido',
description:
'Muito pouco tempo costuma deixar placa bacteriana para trás, principalmente nos dentes de trás e perto da gengiva.',
weight: 5,
),
QuizAnswer(
title: '5 minutos com força para "limpar bem"',
description:
'Tempo demais e força excessiva podem irritar a gengiva e desgastar o esmalte. Prefira movimentos suaves e tempo adequado.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz17Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 17: Troca da escova (antiga Quiz 2)
class Quiz17Screen extends StatelessWidget {
const Quiz17Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 17/20',
question: 'Quando devo trocar a escova de dentes?',
answers: const [
QuizAnswer(
title: 'A cada 3 meses (ou antes se estragar)',
description:
'O ideal é trocar a cada ~3 meses. Se as cerdas abrirem antes, troque antes. Cerdas abertas limpam pior.',
weight: 2,
),
QuizAnswer(
title: 'Só quando a escova "quebrar"',
description:
'Esperar demais reduz a eficiência da escovação e pode acumular microrganismos na escova.',
weight: 5,
),
QuizAnswer(
title: 'Todo mês, obrigatoriamente',
description:
'Não é regra fixa. Um mês pode ser cedo demais se a escova estiver em bom estado. O principal é o estado das cerdas.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz18Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 18: Quantidade de pasta (antiga Quiz 3)
class Quiz18Screen extends StatelessWidget {
const Quiz18Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 18/20',
question: 'Qual a quantidade ideal de pasta de dente para crianças?',
answers: const [
QuizAnswer(
title: 'Um grão de arroz (pequenos) / ervilha (maiores)',
description:
'Para crianças pequenas, um "grão de arroz" já basta. Conforme cresce, pode ser do tamanho de uma ervilha. Isso ajuda a evitar excesso de flúor ingerido.',
weight: 2,
),
QuizAnswer(
title: 'Cobrir toda a escova com pasta',
description:
'Muito produto não significa melhor limpeza. Em crianças, aumenta o risco de engolir pasta em excesso.',
weight: 5,
),
QuizAnswer(
title: 'Nenhuma pasta, só água',
description:
'A pasta com flúor (na quantidade correta) ajuda a prevenir cáries. Em geral, água sozinha não oferece a mesma proteção.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz19Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 19: Fio dental (antiga Quiz 4)
class Quiz19Screen extends StatelessWidget {
const Quiz19Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 19/20',
question: 'Qual é o melhor horário para usar fio dental?',
answers: const [
QuizAnswer(
title: 'Uma vez ao dia, com calma (geralmente à noite)',
description:
'O importante é a frequência diária. À noite costuma ser mais fácil, pois remove restos e placa antes de dormir.',
weight: 2,
),
QuizAnswer(
title: 'Só quando algo fica preso',
description:
'O fio dental não serve apenas para tirar restos visíveis; ele remove placa bacteriana entre os dentes onde a escova não alcança.',
weight: 5,
),
QuizAnswer(
title: 'Depois de toda refeição (obrigatório)',
description:
'Pode ser útil em alguns casos, mas não é obrigatório para todos. O essencial é fazer bem feito ao menos 1x ao dia.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz20Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 20: Prevenção de cáries (antiga Quiz 5)
class Quiz20Screen extends StatelessWidget {
const Quiz20Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 20/20',
question: 'O que ajuda mais a prevenir cáries no dia a dia?',
answers: const [
QuizAnswer(
title: 'Escovar + flúor + reduzir açúcar frequente',
description:
'A prevenção é um conjunto: boa higiene com flúor e menos "beliscos" açucarados ao longo do dia.',
weight: 2,
),
QuizAnswer(
title: 'Só enxaguante bucal',
description:
'Enxaguante pode ajudar em alguns casos, mas não substitui escovação e fio dental.',
weight: 3,
),
QuizAnswer(
title: 'Evitar completamente dentista',
description:
'Consultas regulares são importantes para prevenção e orientação. O dentista também identifica problemas bem no começo.',
weight: 5,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => QuizResultScreen(finalScore: nextScore, maxScore: 100, scopeId: scopeId),
),
isFinal: true,
showBackButton: true,
);
}
}

620
lib/quiz/quiz_extended.dart Normal file
View File

@@ -0,0 +1,620 @@
import 'package:flutter/material.dart';
import 'quiz_question_screen.dart';
import 'quiz_result.dart';
// Quiz 6: Tipos de Escova
class Quiz6Screen extends StatelessWidget {
const Quiz6Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 6/20',
question: 'Qual tipo de escova é mais recomendada para crianças?',
answers: const [
QuizAnswer(
title: 'Escova macia com cabeça pequena',
description:
'Escovas macias protegem a gengiva sensível das crianças e a cabeça pequena alcança melhor todos os dentes.',
weight: 2,
),
QuizAnswer(
title: 'Escova dura para limpar melhor',
description:
'Escovas duras podem machucar a gengiva e desgastar o esmalte dos dentes das crianças.',
weight: 5,
),
QuizAnswer(
title: 'Escova elétrica sempre é melhor',
description:
'Escova elétrica pode ajudar, mas não é essencial. O mais importante é a técnica e frequência.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz7Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 7: Alimentos que Causam Cáries
class Quiz7Screen extends StatelessWidget {
const Quiz7Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 7/20',
question: 'Qual alimento é mais prejudicial para os dentes?',
answers: const [
QuizAnswer(
title: 'Balas e chicletes pegajosos',
description:
'Alimentos pegajosos ficam presos nos dentes por mais tempo, aumentando o risco de cáries.',
weight: 2,
),
QuizAnswer(
title: 'Maçã e cenoura',
description:
'Frutas e vegetais crus ajudam a limpar os dentes naturalmente e são saudáveis.',
weight: 5,
),
QuizAnswer(
title: 'Água e leite',
description:
'Água ajuda a limpar e leite tem cálcio. São opções saudáveis para os dentes.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz8Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 8: Primeira Visita ao Dentista
class Quiz8Screen extends StatelessWidget {
const Quiz8Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 8/20',
question: 'Quando deve ser a primeira visita ao dentista?',
answers: const [
QuizAnswer(
title: 'Por volta dos 1 ano de idade',
description:
'A primeira visita deve ser assim que o primeiro dentinho nascer ou até o primeiro aniversário.',
weight: 2,
),
QuizAnswer(
title: 'Só quando tiver todos os dentes',
description:
'Esperar demais pode permitir que problemas comecem sem detecção precoce.',
weight: 5,
),
QuizAnswer(
title: 'Apenas se sentir dor',
description:
'Dor geralmente indica que o problema já está avançado. Prevenção é melhor que tratamento.',
weight: 5,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz9Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 9: Chupeta e Sucção
class Quiz9Screen extends StatelessWidget {
const Quiz9Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 9/20',
question: 'Até que idade é aceitável usar chupeta?',
answers: const [
QuizAnswer(
title: 'Até 2-3 anos no máximo',
description:
'Após 2-3 anos, chupeta pode causar problemas na dentição e no desenvolvimento da fala.',
weight: 2,
),
QuizAnswer(
title: 'Até 6-7 anos',
description:
'Essa idade já é muito tarde e pode causar problemas sérios na arcada dentária.',
weight: 5,
),
QuizAnswer(
title: 'Não tem problema usar sempre',
description:
'Uso prolongado pode causar má oclusão, problemas na fala e alterações faciais.',
weight: 5,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz10Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 10: Água Fluoretada
class Quiz10Screen extends StatelessWidget {
const Quiz10Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 10/20',
question: 'O flúor na água de abastecimento ajuda?',
answers: const [
QuizAnswer(
title: 'Sim, reduz cáries em até 60%',
description:
'Flúor na água é uma das medidas de saúde pública mais eficazes na prevenção de cáries.',
weight: 2,
),
QuizAnswer(
title: 'Não faz diferença nenhuma',
description:
'Estudos comprovam que flúor na água reduz significativamente a incidência de cáries.',
weight: 5,
),
QuizAnswer(
title: 'É perigoso e causa problemas',
description:
'Nas concentrações corretas, flúor é seguro. O problema é o excesso, não o uso adequado.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz11Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 11: Escovação Noturna
class Quiz11Screen extends StatelessWidget {
const Quiz11Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 11/20',
question: 'Por que a escovação noturna é tão importante?',
answers: const [
QuizAnswer(
title: 'Menos saliva durante o sono',
description:
'Durante a noite produzimos menos saliva, que protege os dentes. Escovação remove placa antes desse período vulnerável.',
weight: 2,
),
QuizAnswer(
title: 'É igual aos outros horários',
description:
'A noite é especial porque a produção de saliva diminui, aumentando o risco de cáries.',
weight: 4,
),
QuizAnswer(
title: 'Só por tradição',
description:
'Tem fundamento científico. A noite é o período mais crítico para formação de cáries.',
weight: 5,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz12Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 12: Bebidas Ácidas
class Quiz12Screen extends StatelessWidget {
const Quiz12Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 12/20',
question: 'Qual bebida é mais ácida para os dentes?',
answers: const [
QuizAnswer(
title: 'Refrigerantes e sucos industrializados',
description:
'Refrigerantes e sucos artificiais têm pH muito baixo, corroem o esmalte e causam erosão dental.',
weight: 2,
),
QuizAnswer(
title: 'Água e leite',
description:
'Água tem pH neutro e leite é levemente ácido mas protege os dentes com cálcio.',
weight: 5,
),
QuizAnswer(
title: 'Chá sem açúcar',
description:
'Chá pode manchar mas é muito menos ácido que refrigerantes e sucos artificiais.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz13Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 13: Dentes de Leite
class Quiz13Screen extends StatelessWidget {
const Quiz13Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 13/20',
question: 'É importante cuidar dos dentes de leite?',
answers: const [
QuizAnswer(
title: 'Sim, são fundamentais para o desenvolvimento',
description:
'Dentes de leite mantêm espaço para os permanentes, auxiliam na fala e mastigação.',
weight: 2,
),
QuizAnswer(
title: 'Não, vão cair de qualquer jeito',
description:
'Dentes de leite doentes podem afetar os permanentes e causar problemas no desenvolvimento.',
weight: 5,
),
QuizAnswer(
title: 'Só se doerem',
description:
'Mesmo sem dor, problemas nos dentes de leite podem ter consequências sérias futuras.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz14Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 14: Técnica de Escovação
class Quiz14Screen extends StatelessWidget {
const Quiz14Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 14/20',
question: 'Qual é a técnica correta de escovação?',
answers: const [
QuizAnswer(
title: 'Movimentos circulares suaves',
description:
'Movimentos circulares ou vibratórios suaves limpam sem machucar a gengiva e removem a placa eficientemente.',
weight: 2,
),
QuizAnswer(
title: 'Força de um lado para o outro',
description:
'Movimentos horizontais fortes podem machucar a gengiva e causar recessão gengival.',
weight: 5,
),
QuizAnswer(
title: 'Só na frente dos dentes',
description:
'Precisa escovar todas as faces: frente, atrás e superfície de mastigação.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz15Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 15: Enxaguante Bucal
class Quiz15Screen extends StatelessWidget {
const Quiz15Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 15/20',
question: 'Crianças pequenas podem usar enxaguante bucal?',
answers: const [
QuizAnswer(
title: 'Só com orientação e produtos específicos',
description:
'Crianças pequenas podem engolir o produto. Existem enxaguantes infantis sem álcool e com flúor adequado.',
weight: 2,
),
QuizAnswer(
title: 'Sim, qualquer um serve',
description:
'Enxaguantes para adultos podem ter álcool e concentração de flúor inadequada para crianças.',
weight: 5,
),
QuizAnswer(
title: 'Nunca, é perigoso',
description:
'Com produto adequado e supervisão, pode ser usado como complemento à higiene oral.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz16Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 16: Lanche Escolar
class Quiz16Screen extends StatelessWidget {
const Quiz16Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 16/20',
question: 'Qual lanche escolar é melhor para os dentes?',
answers: const [
QuizAnswer(
title: 'Frutas frescas e queijo',
description:
'Frutas estimulam salivação e queijo neutraliza ácidos. São opções saudáveis para os dentes.',
weight: 2,
),
QuizAnswer(
title: 'Bolachas recheadas e sucos de caixinha',
description:
'Açúcar e amido ficam presos nos dentes, aumentando risco de cáries.',
weight: 5,
),
QuizAnswer(
title: 'Salgadinhos de pacote',
description:
'Amidos processados ficam nos dentes e se transformam em açúcar, causando cáries.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz17Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 17: Traumas Dentários
class Quiz17Screen extends StatelessWidget {
const Quiz17Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 17/20',
question: 'O que fazer se um dente de leite cair por trauma?',
answers: const [
QuizAnswer(
title: 'Procurar dentista imediatamente',
description:
'Mesmo sendo dente de leite, é importante avaliar se houve dano nos permanentes ou nosso tecidos.',
weight: 2,
),
QuizAnswer(
title: 'Não fazer nada, nasce outro',
description:
'Trauma pode afetar o dente permanente que está em formação ou causar infecções.',
weight: 5,
),
QuizAnswer(
title: 'Tentar recolocar no lugar',
description:
'Não se deve recolocar dente de leite avulsionado, apenas os permanentes.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz18Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 18: Mordedura Cruzada
class Quiz18Screen extends StatelessWidget {
const Quiz18Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 18/20',
question: 'O que pode causar problemas na mordida?',
answers: const [
QuizAnswer(
title: 'Chupeta e sucção de dedo prolongadas',
description:
'Hábitos prolongados podem causar mordida cruzada, mordida aberta e outros problemas ortodônticos.',
weight: 2,
),
QuizAnswer(
title: 'Genética apenas',
description:
'Embora genética influencie, hábitos como chupeta e sucção são grandes fatores causais.',
weight: 4,
),
QuizAnswer(
title: 'Não tem prevenção possível',
description:
'Evitar hábitos prejudiciais e fazer acompanhamento odontológico previne muitos problemas.',
weight: 5,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz19Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 19: Gengivas Sangrando
class Quiz19Screen extends StatelessWidget {
const Quiz19Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 19/20',
question: 'Gengiva sangrando ao escovar significa?',
answers: const [
QuizAnswer(
title: 'Inflamação que precisa de tratamento',
description:
'Sangramento indica gengivite. Não deve parar de escovar, mas sim procurar tratamento e melhorar a higiene.',
weight: 2,
),
QuizAnswer(
title: 'Normal e não precisa se preocupar',
description:
'Sangramento não é normal. Indica inflamação que pode evoluir para problemas mais sérios.',
weight: 5,
),
QuizAnswer(
title: 'Está escovando com força demais',
description:
'Força excessiva pode machucar, mas geralmente sangramento indica inflamação gengival.',
weight: 3,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => Quiz20Screen(currentScore: nextScore, scopeId: scopeId),
),
showBackButton: true,
);
}
}
// Quiz 20: Selantes
class Quiz20Screen extends StatelessWidget {
const Quiz20Screen({super.key, required this.currentScore, this.scopeId});
final int currentScore;
final String? scopeId;
@override
Widget build(BuildContext context) {
return QuizQuestionScreen(
title: 'Quiz 20/20',
question: 'Para que servem os selantes dentários?',
answers: const [
QuizAnswer(
title: 'Proteger sulcos dos dentes contra cáries',
description:
'Selantes são uma resina que preenche sulcos e fissuras dos dentes, protegendo contra cáries.',
weight: 2,
),
QuizAnswer(
title: 'Clarear os dentes',
description:
'Selantes não têm função estética de clareamento, apenas protetiva contra cáries.',
weight: 5,
),
QuizAnswer(
title: 'Substituir a escovação',
description:
'Selantes complementam a higiene, não substituem a escovação e o fio dental.',
weight: 4,
),
],
currentScore: currentScore,
nextRoute: (context, nextScore) => MaterialPageRoute<void>(
builder: (_) => QuizResultScreen(finalScore: nextScore, maxScore: 100, scopeId: scopeId),
),
isFinal: true,
showBackButton: true,
);
}
}

67
lib/quiz/quiz_prefs.dart Normal file
View File

@@ -0,0 +1,67 @@
import 'package:shared_preferences/shared_preferences.dart';
class QuizPrefs {
static const String _kSeenQuizKey = 'seen_oral_quiz_v1';
static const String _kLastScoreKey = 'last_oral_quiz_score_v1';
static const String _kLastMaxScoreKey = 'last_oral_quiz_max_score_v1';
static String _scopeKey(String base, String? scopeId) {
final id = (scopeId ?? '').trim();
if (id.isEmpty) return base;
return '${base}_$id';
}
static Future<bool> hasSeenQuiz() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getBool(_kSeenQuizKey) ?? false;
}
static Future<void> markQuizSeen() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_kSeenQuizKey, true);
}
static Future<void> saveLastResult({required int score, required int maxScore}) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt(_kLastScoreKey, score);
await prefs.setInt(_kLastMaxScoreKey, maxScore);
}
static Future<void> saveLastResultForUser({required String userId, required int score, required int maxScore}) async {
await saveLastResultForScope(scopeId: userId, score: score, maxScore: maxScore);
}
static Future<void> saveLastResultForScope({required String scopeId, required int score, required int maxScore}) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt(_scopeKey(_kLastScoreKey, scopeId), score);
await prefs.setInt(_scopeKey(_kLastMaxScoreKey, scopeId), maxScore);
}
static Future<int?> getLastScore() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getInt(_kLastScoreKey);
}
static Future<int?> getLastScoreForUser(String userId) async {
return getLastScoreForScope(userId);
}
static Future<int?> getLastScoreForScope(String scopeId) async {
final prefs = await SharedPreferences.getInstance();
return prefs.getInt(_scopeKey(_kLastScoreKey, scopeId));
}
static Future<int?> getLastMaxScore() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getInt(_kLastMaxScoreKey);
}
static Future<int?> getLastMaxScoreForUser(String userId) async {
return getLastMaxScoreForScope(userId);
}
static Future<int?> getLastMaxScoreForScope(String scopeId) async {
final prefs = await SharedPreferences.getInstance();
return prefs.getInt(_scopeKey(_kLastMaxScoreKey, scopeId));
}
}

View File

@@ -0,0 +1,326 @@
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
typedef QuizNextBuilder = Route<void> Function(BuildContext context, int nextScore);
class QuizAnswer {
const QuizAnswer({required this.title, required this.description, required this.weight});
final String title;
final String description;
final int weight;
}
class QuizQuestionScreen extends StatefulWidget {
const QuizQuestionScreen({
super.key,
required this.title,
required this.question,
required this.answers,
required this.nextRoute,
this.currentScore = 0,
this.onFinished,
this.isFinal = false,
this.showBackButton = false,
});
final String title;
final String question;
final List<QuizAnswer> answers;
final QuizNextBuilder nextRoute;
final int currentScore;
final VoidCallback? onFinished;
final bool isFinal;
final bool showBackButton;
@override
State<QuizQuestionScreen> createState() => _QuizQuestionScreenState();
}
class _QuizQuestionScreenState extends State<QuizQuestionScreen> {
int? _selected;
@override
Widget build(BuildContext context) {
final size = MediaQuery.sizeOf(context);
final bool canProceed = _selected != null;
return Scaffold(
body: Stack(
clipBehavior: Clip.none,
children: [
Positioned.fill(
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFFFE6F1),
Color(0xFFFFC9DF),
],
),
),
),
),
Positioned(
left: -size.width * 0.40,
bottom: -size.width * 0.45,
child: IgnorePointer(
child: SizedBox(
width: size.width * 1.05,
height: size.width * 1.05,
child: Transform.rotate(
angle: 35 * math.pi / 180,
child: Opacity(
opacity: 0.95,
child: Lottie.asset(
'lottie/Liquid waves.json',
fit: BoxFit.cover,
repeat: true,
),
),
),
),
),
),
SafeArea(
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 520),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(20, 18, 20, 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
widget.title,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black.withValues(alpha: 0.55),
fontWeight: FontWeight.w800,
),
),
const SizedBox(height: 6),
Text(
widget.question,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w900,
color: Color(0xFFFF55A7),
height: 1.2,
),
),
const SizedBox(height: 8),
Text(
'Escolha apenas uma opção',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black.withValues(alpha: 0.55),
fontWeight: FontWeight.w700,
),
),
],
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListView.separated(
padding: const EdgeInsets.only(bottom: 12),
itemCount: widget.answers.length,
separatorBuilder: (context, index) => const SizedBox(height: 12),
itemBuilder: (context, i) {
return _QuizAnswerTile(
answer: widget.answers[i],
selected: _selected == i,
onTap: () => setState(() => _selected = i),
);
},
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 8, 20, 18),
child: Column(
children: [
SizedBox(
width: size.width * 0.62,
height: 46,
child: FilledButton(
style: FilledButton.styleFrom(
backgroundColor: const Color(0xFF2F9E94),
foregroundColor: Colors.white,
shape: const StadiumBorder(),
textStyle: const TextStyle(fontWeight: FontWeight.w900),
).copyWith(
animationDuration: const Duration(milliseconds: 180),
splashFactory: InkSparkle.splashFactory,
overlayColor: WidgetStateProperty.resolveWith<Color?>(
(states) {
if (states.contains(WidgetState.pressed)) {
return Colors.white.withValues(alpha: 0.14);
}
if (states.contains(WidgetState.hovered) || states.contains(WidgetState.focused)) {
return Colors.white.withValues(alpha: 0.08);
}
return null;
},
),
),
onPressed: !canProceed
? null
: () {
final picked = widget.answers[_selected!];
final nextScore = widget.currentScore + picked.weight;
if (widget.isFinal) {
widget.onFinished?.call();
Navigator.of(context).popUntil((r) => r.isFirst);
return;
}
Navigator.of(context).push(widget.nextRoute(context, nextScore));
},
child: Text(widget.isFinal ? 'Concluir' : 'Avançar'),
),
),
if (widget.showBackButton) ...[
const SizedBox(height: 10),
SizedBox(
width: size.width * 0.62,
height: 42,
child: FilledButton(
style: FilledButton.styleFrom(
backgroundColor: const Color(0xFF2F9E94),
foregroundColor: Colors.white,
shape: const StadiumBorder(),
textStyle: const TextStyle(fontWeight: FontWeight.w900),
).copyWith(
animationDuration: const Duration(milliseconds: 180),
splashFactory: InkSparkle.splashFactory,
overlayColor: WidgetStateProperty.resolveWith<Color?>(
(states) {
if (states.contains(WidgetState.pressed)) {
return Colors.white.withValues(alpha: 0.14);
}
if (states.contains(WidgetState.hovered) || states.contains(WidgetState.focused)) {
return Colors.white.withValues(alpha: 0.08);
}
return null;
},
),
),
onPressed: () => Navigator.of(context).maybePop(),
child: const Text('Voltar'),
),
),
],
],
),
),
],
),
),
),
),
],
),
);
}
}
class _QuizAnswerTile extends StatelessWidget {
const _QuizAnswerTile({required this.answer, required this.selected, required this.onTap});
final QuizAnswer answer;
final bool selected;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
final borderColor = selected ? const Color(0xFF2F9E94) : Colors.black.withValues(alpha: 0.12);
final bg = selected ? Colors.white.withValues(alpha: 0.88) : Colors.white.withValues(alpha: 0.70);
return AnimatedContainer(
duration: const Duration(milliseconds: 220),
curve: Curves.easeOutCubic,
decoration: BoxDecoration(
color: bg,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: borderColor, width: selected ? 1.4 : 1.0),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.06),
blurRadius: 18,
offset: const Offset(0, 10),
),
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(16),
onTap: onTap,
splashFactory: InkSparkle.splashFactory,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
answer.title,
style: const TextStyle(
fontWeight: FontWeight.w900,
fontSize: 15,
color: Color(0xFF2F9E94),
),
),
),
AnimatedRotation(
turns: selected ? 0.5 : 0.0,
duration: const Duration(milliseconds: 220),
curve: Curves.easeOutCubic,
child: Icon(
Icons.expand_more_rounded,
color: Colors.black.withValues(alpha: 0.55),
),
),
],
),
AnimatedCrossFade(
firstChild: const SizedBox.shrink(),
secondChild: Padding(
padding: const EdgeInsets.only(top: 10),
child: Text(
answer.description,
style: TextStyle(
color: Colors.black.withValues(alpha: 0.72),
fontWeight: FontWeight.w600,
height: 1.25,
),
),
),
crossFadeState: selected ? CrossFadeState.showSecond : CrossFadeState.showFirst,
duration: const Duration(milliseconds: 220),
firstCurve: Curves.easeIn,
secondCurve: Curves.easeOut,
sizeCurve: Curves.easeOutCubic,
),
],
),
),
),
),
);
}
}

433
lib/quiz/quiz_random.dart Normal file
View File

@@ -0,0 +1,433 @@
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/15',
question: 'Qual é o tempo ideal para escovar os dentes?',
answers: const [
QuizAnswer(
title: 'Cerca de 2 minutos',
description: 'O recomendado é escovar por aproximadamente 2 minutos, cobrindo todas as superfícies dos dentes e a linha da gengiva sem pressa.',
weight: 2,
),
QuizAnswer(
title: 'Só 30 segundos, se fizer rápido',
description: 'Muito pouco tempo costuma deixar placa bacteriana para trás, principalmente nos dentes de trás e perto da gengiva.',
weight: 5,
),
QuizAnswer(
title: '5 minutos com força para "limpar bem"',
description: 'Tempo demais e força excessiva podem irritar a gengiva e desgastar o esmalte. Prefira movimentos suaves e tempo adequado.',
weight: 3,
),
],
),
QuizQuestion(
id: 2,
title: 'Quiz 2/15',
question: 'Quando devo trocar a escova de dentes?',
answers: const [
QuizAnswer(
title: 'A cada 3 meses (ou antes se estragar)',
description: 'O ideal é trocar a cada ~3 meses. Se as cerdas abrirem antes, troque antes. Cerdas abertas limpam pior.',
weight: 2,
),
QuizAnswer(
title: 'Só quando a escova "quebrar"',
description: 'Esperar demais reduz a eficiência da escovação e pode acumular microrganismos na escova.',
weight: 5,
),
QuizAnswer(
title: 'Todo mês, obrigatoriamente',
description: 'Não é regra fixa. Um mês pode ser cedo demais se a escova estiver em bom estado. O principal é o estado das cerdas.',
weight: 3,
),
],
),
QuizQuestion(
id: 3,
title: 'Quiz 3/15',
question: 'Qual a quantidade ideal de pasta de dente para crianças?',
answers: const [
QuizAnswer(
title: 'Um grão de arroz (pequenos) / ervilha (maiores)',
description: 'Para crianças pequenas, um "grão de arroz" já basta. Conforme cresce, pode ser do tamanho de uma ervilha. Isso ajuda a evitar excesso de flúor ingerido.',
weight: 2,
),
QuizAnswer(
title: 'Cobrir toda a escova com pasta',
description: 'Muito produto não significa melhor limpeza. Em crianças, aumenta o risco de engolir pasta em excesso.',
weight: 5,
),
QuizAnswer(
title: 'Nenhuma pasta, só água',
description: 'A pasta com flúor (na quantidade correta) ajuda a prevenir cáries. Em geral, água sozinha não oferece a mesma proteção.',
weight: 3,
),
],
),
QuizQuestion(
id: 4,
title: 'Quiz 4/15',
question: 'Qual é o melhor horário para usar fio dental?',
answers: const [
QuizAnswer(
title: 'Uma vez ao dia, com calma (geralmente à noite)',
description: 'O importante é a frequência diária. À noite costuma ser mais fácil, pois remove restos e placa antes de dormir.',
weight: 2,
),
QuizAnswer(
title: 'Só quando algo fica preso',
description: 'O fio dental não serve apenas para tirar restos visíveis; ele remove placa bacteriana entre os dentes onde a escova não alcança.',
weight: 5,
),
QuizAnswer(
title: 'Depois de toda refeição (obrigatório)',
description: 'Pode ser útil em alguns casos, mas não é obrigatório para todos. O essencial é fazer bem feito ao menos 1x ao dia.',
weight: 3,
),
],
),
QuizQuestion(
id: 5,
title: 'Quiz 5/15',
question: 'O que ajuda mais a prevenir cáries no dia a dia?',
answers: const [
QuizAnswer(
title: 'Escovar + flúor + reduzir açúcar frequente',
description: 'A prevenção é um conjunto: boa higiene com flúor e menos "beliscos" açucarados ao longo do dia.',
weight: 2,
),
QuizAnswer(
title: 'Só enxaguante bucal',
description: 'Enxaguante pode ajudar em alguns casos, mas não substitui escovação e fio dental.',
weight: 3,
),
QuizAnswer(
title: 'Evitar completamente dentista',
description: 'Consultas regulares são importantes para prevenção e orientação. O dentista também identifica problemas bem no começo.',
weight: 5,
),
],
),
QuizQuestion(
id: 6,
title: 'Quiz 6/15',
question: 'Qual tipo de escova é mais recomendada para crianças?',
answers: const [
QuizAnswer(
title: 'Escova macia com cabeça pequena',
description: 'Escovas macias protegem a gengiva sensível das crianças e a cabeça pequena alcança melhor todos os dentes.',
weight: 2,
),
QuizAnswer(
title: 'Escova dura para limpar melhor',
description: 'Escovas duras podem machucar a gengiva e desgastar o esmalte dos dentes das crianças.',
weight: 5,
),
QuizAnswer(
title: 'Escova elétrica sempre é melhor',
description: 'Escova elétrica pode ajudar, mas não é essencial. O mais importante é a técnica e frequência.',
weight: 3,
),
],
),
QuizQuestion(
id: 7,
title: 'Quiz 7/15',
question: 'Qual alimento é mais prejudicial para os dentes?',
answers: const [
QuizAnswer(
title: 'Balas e chicletes pegajosos',
description: 'Alimentos pegajosos ficam presos nos dentes por mais tempo, aumentando o risco de cáries.',
weight: 2,
),
QuizAnswer(
title: 'Maçã e cenoura',
description: 'Frutas e vegetais crus ajudam a limpar os dentes naturalmente e são saudáveis.',
weight: 5,
),
QuizAnswer(
title: 'Água e leite',
description: 'Água ajuda a limpar e leite tem cálcio. São opções saudáveis para os dentes.',
weight: 3,
),
],
),
QuizQuestion(
id: 8,
title: 'Quiz 8/15',
question: 'Quando deve ser a primeira visita ao dentista?',
answers: const [
QuizAnswer(
title: 'Por volta dos 1 ano de idade',
description: 'A primeira visita deve ser assim que o primeiro dentinho nascer ou até o primeiro aniversário.',
weight: 2,
),
QuizAnswer(
title: 'Só quando tiver todos os dentes',
description: 'Esperar demais pode permitir que problemas comecem sem detecção precoce.',
weight: 5,
),
QuizAnswer(
title: 'Apenas se sentir dor',
description: 'Dor geralmente indica que o problema já está avançado. Prevenção é melhor que tratamento.',
weight: 5,
),
],
),
QuizQuestion(
id: 9,
title: 'Quiz 9/15',
question: 'Até que idade é aceitável usar chupeta?',
answers: const [
QuizAnswer(
title: 'Até 2-3 anos no máximo',
description: 'Após 2-3 anos, chupeta pode causar problemas na dentição e no desenvolvimento da fala.',
weight: 2,
),
QuizAnswer(
title: 'Até 6-7 anos',
description: 'Essa idade já é muito tarde e pode causar problemas sérios na arcada dentária.',
weight: 5,
),
QuizAnswer(
title: 'Não tem problema usar sempre',
description: 'Uso prolongado pode causar má oclusão, problemas na fala e alterações faciais.',
weight: 5,
),
],
),
QuizQuestion(
id: 10,
title: 'Quiz 10/15',
question: 'O flúor na água de abastecimento ajuda?',
answers: const [
QuizAnswer(
title: 'Sim, reduz cáries em até 60%',
description: 'Flúor na água é uma das medidas de saúde pública mais eficazes na prevenção de cáries.',
weight: 2,
),
QuizAnswer(
title: 'Não faz diferença nenhuma',
description: 'Estudos comprovam que flúor na água reduz significativamente a incidência de cáries.',
weight: 5,
),
QuizAnswer(
title: 'É perigoso e causa problemas',
description: 'Nas concentrações corretas, flúor é seguro. O problema é o excesso, não o uso adequado.',
weight: 4,
),
],
),
QuizQuestion(
id: 11,
title: 'Quiz 11/15',
question: 'Por que a escovação noturna é tão importante?',
answers: const [
QuizAnswer(
title: 'Menos saliva durante o sono',
description: 'Durante a noite produzimos menos saliva, que protege os dentes. Escovação remove placa antes desse período vulnerável.',
weight: 2,
),
QuizAnswer(
title: 'É igual aos outros horários',
description: 'A noite é especial porque a produção de saliva diminui, aumentando o risco de cáries.',
weight: 4,
),
QuizAnswer(
title: 'Só por tradição',
description: 'Tem fundamento científico. A noite é o período mais crítico para formação de cáries.',
weight: 5,
),
],
),
QuizQuestion(
id: 12,
title: 'Quiz 12/15',
question: 'Qual bebida é mais ácida para os dentes?',
answers: const [
QuizAnswer(
title: 'Refrigerantes e sucos industrializados',
description: 'Refrigerantes e sucos artificiais têm pH muito baixo, corroem o esmalte e causam erosão dental.',
weight: 2,
),
QuizAnswer(
title: 'Água e leite',
description: 'Água tem pH neutro e leite é levemente ácido mas protege os dentes com cálcio.',
weight: 5,
),
QuizAnswer(
title: 'Chá sem açúcar',
description: 'Chá pode manchar mas é muito menos ácido que refrigerantes e sucos artificiais.',
weight: 3,
),
],
),
QuizQuestion(
id: 13,
title: 'Quiz 13/15',
question: 'É importante cuidar dos dentes de leite?',
answers: const [
QuizAnswer(
title: 'Sim, são fundamentais para o desenvolvimento',
description: 'Dentes de leite mantêm espaço para os permanentes, auxiliam na fala e mastigação.',
weight: 2,
),
QuizAnswer(
title: 'Não, vão cair de qualquer jeito',
description: 'Dentes de leite doentes podem afetar os permanentes e causar problemas no desenvolvimento.',
weight: 5,
),
QuizAnswer(
title: 'Só se doerem',
description: 'Mesmo sem dor, problemas nos dentes de leite podem ter consequências sérias futuras.',
weight: 4,
),
],
),
QuizQuestion(
id: 14,
title: 'Quiz 14/15',
question: 'Qual é a técnica correta de escovação?',
answers: const [
QuizAnswer(
title: 'Movimentos circulares suaves',
description: 'Movimentos circulares ou vibratórios suaves limpam sem machucar a gengiva e removem a placa eficientemente.',
weight: 2,
),
QuizAnswer(
title: 'Força de um lado para o outro',
description: 'Movimentos horizontais fortes podem machucar a gengiva e causar recessão gengival.',
weight: 5,
),
QuizAnswer(
title: 'Só na frente dos dentes',
description: 'Precisa escovar todas as faces: frente, atrás e superfície de mastigação.',
weight: 4,
),
],
),
QuizQuestion(
id: 15,
title: 'Quiz 15/15',
question: 'Para que servem os selantes dentários?',
answers: const [
QuizAnswer(
title: 'Proteger sulcos dos dentes contra cáries',
description: 'Selantes são uma resina que preenche sulcos e fissuras dos dentes, protegendo contra cáries.',
weight: 2,
),
QuizAnswer(
title: 'Clarear os dentes',
description: 'Selantes não têm função estética de clareamento, apenas protetiva contra cáries.',
weight: 5,
),
QuizAnswer(
title: 'Substituir a escovação',
description: 'Selantes complementam a higiene, não substituem a escovação e o fio dental.',
weight: 4,
),
],
),
];
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,
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;
QuizQuestion({
required this.id,
required this.title,
required this.question,
required this.answers,
});
}

208
lib/quiz/quiz_result.dart Normal file
View File

@@ -0,0 +1,208 @@
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
import 'quiz_prefs.dart';
class QuizResultScreen extends StatefulWidget {
const QuizResultScreen({super.key, required this.finalScore, required this.maxScore, this.scopeId});
final int finalScore;
final int maxScore;
final String? scopeId;
@override
State<QuizResultScreen> createState() => _QuizResultScreenState();
}
class _QuizResultScreenState extends State<QuizResultScreen> {
@override
void initState() {
super.initState();
QuizPrefs.markQuizSeen();
final scope = (widget.scopeId ?? '').trim();
if (scope.isNotEmpty) {
QuizPrefs.saveLastResultForScope(scopeId: scope, score: widget.finalScore, maxScore: widget.maxScore);
} else {
final uid = FirebaseAuth.instance.currentUser?.uid;
if (uid != null && uid.trim().isNotEmpty) {
QuizPrefs.saveLastResultForUser(userId: uid, score: widget.finalScore, maxScore: widget.maxScore);
} else {
QuizPrefs.saveLastResult(score: widget.finalScore, maxScore: widget.maxScore);
}
}
final uid = FirebaseAuth.instance.currentUser?.uid;
final userId = (uid ?? '').trim();
if (userId.isNotEmpty && scope.isNotEmpty && scope.startsWith('${userId}_')) {
final childId = scope.substring(userId.length + 1).trim();
if (childId.isNotEmpty) {
unawaited(
FirebaseFirestore.instance
.collection('users')
.doc(userId)
.collection('children')
.doc(childId)
.set({
'lastScore': widget.finalScore,
'lastMaxScore': widget.maxScore,
'lastQuizAt': FieldValue.serverTimestamp(),
}, SetOptions(merge: true)).catchError((_) {}),
);
}
}
}
@override
Widget build(BuildContext context) {
final clamped = widget.finalScore.clamp(0, widget.maxScore);
final percent = ((clamped / widget.maxScore) * 100).round();
final progress = percent / 100.0;
return Scaffold(
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFFFE6F1),
Color(0xFFFFC9DF),
],
),
),
child: SafeArea(
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 520),
child: Padding(
padding: const EdgeInsets.fromLTRB(22, 12, 22, 18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () => Navigator.of(context).popUntil((r) => r.isFirst),
child: const Text(''),
),
),
Expanded(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 6),
const Text(
'A percentagem de risco\navaliada é de:',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w900,
color: Color(0xFFFF55A7),
height: 1.2,
),
),
const SizedBox(height: 18),
Center(
child: SizedBox(
width: 220,
height: 220,
child: Stack(
alignment: Alignment.center,
children: [
SizedBox(
width: 200,
height: 200,
child: CircularProgressIndicator(
value: progress,
strokeWidth: 12,
backgroundColor: Colors.black.withValues(alpha: 0.10),
valueColor: const AlwaysStoppedAnimation(Color(0xFF2F9E94)),
),
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'$percent%',
style: const TextStyle(
fontSize: 34,
fontWeight: FontWeight.w900,
color: Colors.black,
),
),
const SizedBox(height: 4),
Text(
'${clamped.toInt()}/${widget.maxScore}',
style: TextStyle(
color: Colors.black.withValues(alpha: 0.60),
fontWeight: FontWeight.w800,
),
),
],
),
],
),
),
),
const SizedBox(height: 18),
Text(
'Conclusões:',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black.withValues(alpha: 0.75),
fontWeight: FontWeight.w900,
),
),
const SizedBox(height: 10),
Text(
'Esta avaliação é apenas educativa.\nSe tiver dúvidas ou sinais de cárie/dor, procure um Dentista.',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black.withValues(alpha: 0.70),
fontWeight: FontWeight.w600,
height: 1.25,
),
),
const SizedBox(height: 16),
Center(
child: Text(
'Descarregar relatório (em breve)',
style: TextStyle(
color: const Color(0xFFFF55A7).withValues(alpha: 0.95),
fontWeight: FontWeight.w800,
),
),
),
],
),
),
),
Center(
child: SizedBox(
width: 260,
height: 46,
child: FilledButton(
style: FilledButton.styleFrom(
backgroundColor: const Color(0xFF2F9E94),
foregroundColor: Colors.white,
shape: const StadiumBorder(),
textStyle: const TextStyle(fontWeight: FontWeight.w900),
),
onPressed: () => Navigator.of(context).popUntil((r) => r.isFirst),
child: const Text('Avançar'),
),
),
),
],
),
),
),
),
),
),
);
}
}