import 'package:flutter/material.dart'; import 'quiz_checklist_screen.dart'; import 'quiz_question_screen.dart'; import 'quiz_result.dart'; import 'quiz_video_guide.dart'; /// Recorta/zoom numa zona específica de uma foto de rosto (ex.: só a zona /// dos olhos), também sem precisar de um novo ficheiro de imagem. Widget _zoomCrop( String path, { Alignment alignment = Alignment.center, double scale = 2.0, // Alinhamento do próprio Image.asset ao aplicar o BoxFit.cover — separado // do alignment do Transform.scale acima, porque o cover já decide (antes // do zoom) que fatia vertical/horizontal da foto original mostrar; se essa // fatia inicial não incluir a zona pretendida (ex.: queixo cortado fora), // nenhum scale/alignment do Transform consegue "recuperar" esses pixels. Alignment imageAlignment = Alignment.center, }) { return ClipRect( child: Transform.scale( scale: scale, alignment: alignment, child: Image.asset(path, fit: BoxFit.cover, alignment: imageAlignment), ), ); } /// Transição entre perguntas do quiz — fade + leve deslize para cima, no /// mesmo estilo do [FadeSlideIn] já usado dentro de cada ecrã, em vez do /// slide-from-right abrupto padrão do Material ao navegar entre perguntas. Route quizPageRoute({required WidgetBuilder builder}) { return PageRouteBuilder( transitionDuration: const Duration(milliseconds: 320), reverseTransitionDuration: const Duration(milliseconds: 220), pageBuilder: (context, animation, secondaryAnimation) => builder(context), transitionsBuilder: (context, animation, secondaryAnimation, child) { final fade = CurvedAnimation(parent: animation, curve: Curves.easeOut); final slide = Tween( begin: const Offset(0, 0.04), end: Offset.zero, ).animate(CurvedAnimation(parent: animation, curve: Curves.easeOutCubic)); return FadeTransition( opacity: fade, child: SlideTransition(position: slide, child: child), ); }, ); } /// Rota inicial do quiz: mostra primeiro o ecrã de checklist explicativo, /// só depois a pergunta 1 — usada em todos os pontos de entrada do quiz /// em vez de navegar diretamente para [Quiz1Screen]. Route quizStartRoute({String? scopeId}) { return quizPageRoute( builder: (_) => QuizChecklistScreen( heading: 'Vamos ajudá-lo/a a compreender:', items: const [ 'Sinais de alerta podem passar despercebidos', 'Prevenir é melhor do que tratar', 'Quando deve procurar um dentista (urgência vs vigilância)', ], onAdvance: (context) => Navigator.of(context).pushReplacement( quizPageRoute(builder: (_) => Quiz1Screen(scopeId: scopeId)), ), ), ); } // Quiz 1: Problemas respiratórios (Yes/No) class Quiz1Screen extends StatelessWidget { const Quiz1Screen({ super.key, this.currentScore = const QuizScore(), this.scopeId, }); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 1/28', category: 'Saúde respiratória', categoryIcon: Icons.medical_information_rounded, fallbackIcon: Icons.medical_information_rounded, fallbackColor: const Color(0xFFFF55A7), question: 'O seu filho/a tem problemas respiratórios diagnosticados?', answers: const [ QuizAnswer( title: 'Sim', description: 'Problemas respiratórios diagnosticados', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Sem problemas respiratórios diagnosticados', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 6, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz2Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: false, ); } } // Quiz 2: Respira pela boca (Yes/No) class Quiz2Screen extends StatelessWidget { const Quiz2Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 2/28', category: 'Respiração', categoryIcon: Icons.air_rounded, fallbackIcon: Icons.air_rounded, fallbackColor: const Color(0xFF2F9E94), question: 'O seu filho/a respira habitualmente pela boca?', answers: const [ QuizAnswer( title: 'Sim', description: 'Respira habitualmente pela boca', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não respira habitualmente pela boca', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 10, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz3Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 3: Ressonar (Yes/No) class Quiz3Screen extends StatelessWidget { const Quiz3Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 3/28', category: 'Sono', categoryIcon: Icons.bedtime_rounded, fallbackIcon: Icons.bedtime_rounded, fallbackColor: const Color(0xFF8E7CC3), question: 'O seu filho/a ressona habitualmente durante a noite?', answers: const [ QuizAnswer( title: 'Sim', description: 'Ressonar habitualmente durante a noite', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não ressona habitualmente', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 8, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz4Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 4: Nariz tapado (Yes/No) class Quiz4Screen extends StatelessWidget { const Quiz4Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 4/28', category: 'Respiração', categoryIcon: Icons.sick_rounded, fallbackIcon: Icons.sick_rounded, fallbackColor: const Color(0xFFFF55A7), question: 'O seu filho/a sente habitualmente o nariz "tapado"?', answers: const [ QuizAnswer( title: 'Sim', description: 'Sente habitualmente o nariz tapado', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não sente habitualmente o nariz tapado', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 1, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz5Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 5: Interrupções respiração (Yes/No) class Quiz5Screen extends StatelessWidget { const Quiz5Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 5/28', category: 'Sono', categoryIcon: Icons.nights_stay_rounded, fallbackIcon: Icons.nights_stay_rounded, fallbackColor: const Color(0xFF8E7CC3), question: 'Durante o sono, o seu filho/a tem habitualmente interrupções da respiração?', answers: const [ QuizAnswer( title: 'Sim', description: 'Tem habitualmente interrupções da respiração durante o sono', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não tem interrupções da respiração durante o sono', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 7, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz6Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 6: Range os dentes (Yes/No) class Quiz6Screen extends StatelessWidget { const Quiz6Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 6/28', category: 'Hábitos noturnos', categoryIcon: Icons.nights_stay_rounded, fallbackIcon: Icons.nights_stay_rounded, fallbackColor: const Color(0xFF2F9E94), question: 'O seu filho/a range os dentes com frequência?', answers: const [ QuizAnswer( title: 'Sim', description: 'Range os dentes com frequência', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não range os dentes com frequência', weight: 1, value: 'nao', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz7Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 7: Alergias sazonais (Yes/No) class Quiz7Screen extends StatelessWidget { const Quiz7Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 7/28', category: 'Saúde geral', categoryIcon: Icons.local_florist_rounded, fallbackIcon: Icons.local_florist_rounded, fallbackColor: const Color(0xFFFF55A7), question: 'O seu filho/a habitualmente tem alergias sazonais?', answers: const [ QuizAnswer( title: 'Sim', description: 'Habitualmente tem alergias sazonais', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não tem alergias sazonais', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 2, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz8Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 8: Saliva seca (Yes/No) class Quiz8Screen extends StatelessWidget { const Quiz8Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 8/28', category: 'Sono', categoryIcon: Icons.water_drop_rounded, fallbackIcon: Icons.water_drop_rounded, fallbackColor: const Color(0xFF8E7CC3), question: 'O seu filho/a acorda com saliva seca na cara ou na almofada?', answers: const [ QuizAnswer( title: 'Sim', description: 'Acorda com saliva seca na cara ou na almofada', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não acorda com saliva seca', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 9, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz9Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 9: Otites (Yes/No) class Quiz9Screen extends StatelessWidget { const Quiz9Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 9/28', category: 'Saúde geral', categoryIcon: Icons.hearing_rounded, fallbackIcon: Icons.hearing_rounded, fallbackColor: const Color(0xFF2F9E94), question: 'O seu filho/a teve ou costuma ter com frequência otites?', answers: const [ QuizAnswer( title: 'Sim', description: 'Teve ou costuma ter com frequência otites', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não teve ou não costuma ter otites', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 3, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz10Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 10: Amigdalites (Yes/No) class Quiz10Screen extends StatelessWidget { const Quiz10Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 10/28', category: 'Saúde geral', categoryIcon: Icons.healing_rounded, fallbackIcon: Icons.healing_rounded, fallbackColor: const Color(0xFFFF55A7), question: 'O seu filho/a teve ou costuma ter com frequência amigdalites?', answers: const [ QuizAnswer( title: 'Sim', description: 'Teve ou costuma ter com frequência amigdalites', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não teve ou não costuma ter amigdalites', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 4, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz11Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 11: Bronquiolites (Yes/No) class Quiz11Screen extends StatelessWidget { const Quiz11Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 11/28', category: 'Saúde respiratória', categoryIcon: Icons.air_rounded, fallbackIcon: Icons.air_rounded, fallbackColor: const Color(0xFF2F9E94), question: 'O seu filho/a teve ou costuma ter com frequência bronquiolites?', answers: const [ QuizAnswer( title: 'Sim', description: 'Teve ou costuma ter com frequência bronquiolites', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não teve ou não costuma ter bronquiolites', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 5, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz12Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 12: Dificuldades a mastigar (Yes/No) class Quiz12Screen extends StatelessWidget { const Quiz12Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 12/28', category: 'Hábitos alimentares', categoryIcon: Icons.restaurant_rounded, fallbackIcon: Icons.restaurant_rounded, fallbackColor: const Color(0xFFFF55A7), question: 'O seu filho/a apresenta dificuldades a mastigar?', answers: const [ QuizAnswer( title: 'Sim', description: 'Apresenta dificuldades a mastigar', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não apresenta dificuldades a mastigar', weight: 1, value: 'nao', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz13Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 13: Lento a comer (Yes/No) class Quiz13Screen extends StatelessWidget { const Quiz13Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 13/28', category: 'Hábitos alimentares', categoryIcon: Icons.schedule_rounded, fallbackIcon: Icons.schedule_rounded, fallbackColor: const Color(0xFF2F9E94), question: 'O seu filho/a habitualmente é lento a comer?', answers: const [ QuizAnswer( title: 'Sim', description: 'Habitualmente é lento a comer', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não é lento a comer', weight: 1, value: 'nao', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz14Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 14: Prefere alimentos moles (Yes/No) class Quiz14Screen extends StatelessWidget { const Quiz14Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 14/28', category: 'Hábitos alimentares', categoryIcon: Icons.restaurant_menu_rounded, fallbackIcon: Icons.restaurant_menu_rounded, fallbackColor: const Color(0xFF8E7CC3), question: 'O seu filho/a habitualmente prefere comer alimentos moles?', answers: const [ QuizAnswer( title: 'Sim', description: 'Habitualmente prefere comer alimentos moles', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não prefere alimentos moles', weight: 1, value: 'nao', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz15Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 15: Alimentado por biberão (Yes/No) class Quiz15Screen extends StatelessWidget { const Quiz15Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 15/28', category: 'Hábitos alimentares', categoryIcon: Icons.local_drink_rounded, fallbackIcon: Icons.local_drink_rounded, fallbackColor: const Color(0xFFFF55A7), question: 'Em bebé apenas foi alimentado por biberão?', answers: const [ QuizAnswer( title: 'Sim', description: 'Em bebé apenas foi alimentado por biberão', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não foi apenas alimentado por biberão', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 11, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz16Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 16: Chupeta (Yes/No) class Quiz16Screen extends StatelessWidget { const Quiz16Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 16/28', category: 'Hábitos orais', categoryIcon: Icons.child_care_rounded, fallbackIcon: Icons.child_care_rounded, fallbackColor: const Color(0xFF2F9E94), question: 'O seu filho/a usa ou usou chupeta com frequência?', answers: const [ QuizAnswer( title: 'Sim', description: 'Usa ou usou chupeta com frequência', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não usa ou não usou chupeta com frequência', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 12, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz17Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 17: Chucha o dedo (Yes/No) class Quiz17Screen extends StatelessWidget { const Quiz17Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 17/28', category: 'Hábitos orais', categoryIcon: Icons.back_hand_rounded, fallbackIcon: Icons.back_hand_rounded, fallbackColor: const Color(0xFF8E7CC3), question: 'O seu filho/a chucha ou já chuchou o dedo com frequência?', answers: const [ QuizAnswer( title: 'Sim', description: 'Chucha ou já chuchou o dedo com frequência', weight: 2, value: 'sim', ), QuizAnswer( title: 'Não', description: 'Não chucha ou não chuchou o dedo com frequência', weight: 1, value: 'nao', ), QuizAnswer( title: 'Não sei', description: 'Não tenho a certeza', weight: 1, value: 'nao_sei', helpVideoId: 13, ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => QuizVideoGuideScreen( youtubeId: 'W2BcK9nSyt0', onAdvance: (ctx) => Navigator.of(ctx).pushReplacement( quizPageRoute( builder: (_) => Quiz18Screen(currentScore: nextScore, scopeId: scopeId), ), ), ), ), answerType: QuizAnswerType.yesNo, showBackButton: true, ); } } // Quiz 18: Postura (Image-choice) class Quiz18Screen extends StatelessWidget { const Quiz18Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 18/28', category: 'Avaliação postural', categoryIcon: Icons.accessibility_new_rounded, fallbackIcon: Icons.accessibility_new_rounded, fallbackColor: const Color(0xFF8E7CC3), answerImageAspectRatio: 1.5, question: 'Qual das seguintes imagens é mais parecida com a postura do seu filho/a?', answers: const [ QuizAnswer( title: 'Postura inadequada', description: 'Postura curvada, ombros e pescoço projetados', weight: 2, hideTitle: true, value: 'postura_inadequada', imagePath: 'assets/mockup_images/0.1.png', ), QuizAnswer( title: 'Postura correta', description: 'Postura ereta, coluna alinhada', weight: 1, hideTitle: true, value: 'postura_correta', imagePath: 'assets/mockup_images/0.png', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz19Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.image, showBackButton: true, ); } } // Quiz 19: Perfil (Image-choice) class Quiz19Screen extends StatelessWidget { const Quiz19Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 19/28', category: 'Avaliação facial', categoryIcon: Icons.face_rounded, fallbackIcon: Icons.face_rounded, fallbackColor: const Color(0xFFFF55A7), question: 'Qual das seguintes imagens é mais parecida com o perfil do seu filho/a?', answers: [ QuizAnswer( title: 'Perfil convexo', description: 'Perfil facial convexo', weight: 2, hideTitle: true, value: 'perfil_convexo', imageBuilder: (context) => _zoomCrop( 'assets/mockup_images/1.jpeg', alignment: const Alignment(0.1, 0.7), scale: 1.05, ), ), QuizAnswer( title: 'Perfil reto', description: 'Perfil facial reto', weight: 1, hideTitle: true, value: 'perfil_reto', imageBuilder: (context) => _zoomCrop( 'assets/mockup_images/2.jpeg', alignment: const Alignment(0.1, 0.7), scale: 1.05, ), ), QuizAnswer( title: 'Perfil côncavo', description: 'Perfil facial côncavo', weight: 2, hideTitle: true, value: 'perfil_concavo', imageBuilder: (context) => _zoomCrop( 'assets/mockup_images/3.jpeg', alignment: const Alignment(0.1, 0.7), scale: 1.05, ), ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz20Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.image, showBackButton: true, ); } } // Quiz 20: Boca habitual (Image-choice) class Quiz20Screen extends StatelessWidget { const Quiz20Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 20/28', category: 'Avaliação facial', categoryIcon: Icons.sentiment_neutral_rounded, fallbackIcon: Icons.sentiment_neutral_rounded, fallbackColor: const Color(0xFF2F9E94), question: 'Qual é a posição da boca do seu filho/a habitualmente?', answers: [ const QuizAnswer( title: 'Boca fechada', description: 'Boca fechada habitualmente', weight: 1, hideTitle: true, value: 'boca_fechada', imagePath: 'assets/mockup_images/7.png', ), QuizAnswer( title: 'Boca entreaberta', description: 'Boca entreaberta habitualmente', weight: 2, hideTitle: true, value: 'boca_entreaberta', imageBuilder: (context) => _zoomCrop( 'assets/mockup_images/4.jpeg', alignment: const Alignment(0, 0.45), scale: 1.8, ), ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => QuizVideoGuideScreen( youtubeId: 'msKYr7nPxcw', onAdvance: (ctx) => Navigator.of(ctx).pushReplacement( quizPageRoute( builder: (_) => Quiz21Screen(currentScore: nextScore, scopeId: scopeId), ), ), ), ), answerType: QuizAnswerType.image, showBackButton: true, ); } } // Quiz 21: Zona abaixo dos olhos (Image-choice) class Quiz21Screen extends StatelessWidget { const Quiz21Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 21/28', category: 'Avaliação facial', categoryIcon: Icons.visibility_rounded, fallbackIcon: Icons.visibility_rounded, fallbackColor: const Color(0xFFFF55A7), question: 'Qual das imagens, na zona abaixo dos olhos, se assemelha mais ao seu filho/a?', answers: [ QuizAnswer( title: 'Sem sinais', description: 'Sem olheiras visíveis abaixo dos olhos', weight: 1, hideTitle: true, value: 'sem_olheiras', imageBuilder: (context) => _zoomCrop( 'assets/mockup_images/9.png', alignment: const Alignment(0, -0.55), scale: 2.3, ), ), QuizAnswer( title: 'Sinal de risco', description: 'Olheiras visíveis abaixo dos olhos', weight: 2, hideTitle: true, value: 'com_olheiras', imageBuilder: (context) => _zoomCrop( 'assets/mockup_images/8.jpeg', alignment: const Alignment(0, -0.55), scale: 2.3, ), ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz22Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.image, showBackButton: true, ); } } // Quiz 22: Queixo com a boca fechada (Image-choice) class Quiz22Screen extends StatelessWidget { const Quiz22Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 22/28', category: 'Avaliação facial', categoryIcon: Icons.face_rounded, fallbackIcon: Icons.face_rounded, fallbackColor: const Color(0xFF8E7CC3), isSignQuestion: true, question: 'Qual das imagens é mais parecida com o queixo do seu filho/a com a boca fechada?', answers: [ QuizAnswer( title: 'Queixo relaxado', description: 'Queixo liso e relaxado com a boca fechada', weight: 1, hideTitle: true, value: 'queixo_correto', imageBuilder: (context) => _zoomCrop( 'assets/mockup_images/5.png', imageAlignment: const Alignment(0, 1), alignment: const Alignment(0, 1), scale: 1.8, ), ), const QuizAnswer( title: 'Queixo tenso', description: 'Queixo tenso/franzido com a boca fechada', weight: 2, hideTitle: true, value: 'queixo_tenso', imagePath: 'assets/mockup_images/6.jpeg', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz23Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.image, showBackButton: true, ); } } // Quiz 23: Boca / dentição (Image-choice) class Quiz23Screen extends StatelessWidget { const Quiz23Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 23/28', category: 'Avaliação facial', categoryIcon: Icons.sentiment_neutral_rounded, fallbackIcon: Icons.sentiment_neutral_rounded, fallbackColor: const Color(0xFF2F9E94), isSignQuestion: true, question: 'Qual das seguintes imagens se assemelha à boca do seu filho/a?', answers: const [ QuizAnswer( title: 'Dentição alinhada', description: 'Dentição bem alinhada, sem apinhamento', weight: 1, hideTitle: true, value: 'dentes_alinhados', imagePath: 'assets/mockup_images/11.png', ), QuizAnswer( title: 'Dentição desalinhada', description: 'Dentição desalinhada/apinhada', weight: 2, hideTitle: true, value: 'dentes_desalinhados', imagePath: 'assets/mockup_images/13.png', ), QuizAnswer( title: 'Dentição sobreposta', description: 'Dentes sobrepostos/tortos', weight: 2, hideTitle: true, value: 'dentes_sobrepostos', imagePath: 'assets/mockup_images/10.png', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz24Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.image, showBackButton: true, ); } } // Quiz 24: Apinhamento visto de perto (Image-choice) class Quiz24Screen extends StatelessWidget { const Quiz24Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 24/28', category: 'Avaliação facial', categoryIcon: Icons.zoom_in_rounded, fallbackIcon: Icons.zoom_in_rounded, fallbackColor: const Color(0xFF2F9E94), isSignQuestion: true, question: 'Qual das seguintes imagens se assemelha à boca do seu filho/a?', answers: const [ QuizAnswer( title: 'Apinhamento moderado', description: 'Dentes rodados/desalinhados de forma mais visível', weight: 2, hideTitle: true, value: 'apinhamento_moderado', imagePath: 'assets/mockup_images/16.png', ), QuizAnswer( title: 'Ligeiro desalinhamento', description: 'Pequeno desalinhamento ou espaço entre alguns dentes', weight: 1, hideTitle: true, value: 'apinhamento_leve', imagePath: 'assets/mockup_images/15.png', ), QuizAnswer( title: 'Apinhamento acentuado', description: 'Dentes muito sobrepostos entre si', weight: 2, hideTitle: true, value: 'apinhamento_acentuado', imagePath: 'assets/mockup_images/14.jpeg', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz25Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.image, showBackButton: true, ); } } // Quiz 25: Freio labial (Image-choice) class Quiz25Screen extends StatelessWidget { const Quiz25Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 25/28', category: 'Avaliação facial', categoryIcon: Icons.record_voice_over_rounded, fallbackIcon: Icons.record_voice_over_rounded, fallbackColor: const Color(0xFFFF55A7), question: 'Qual das seguintes imagens se assemelha ao freio labial do seu filho/a?', answers: const [ QuizAnswer( title: 'Freio labial correto', description: 'Inserção do freio labial mais alta', weight: 1, hideTitle: true, value: 'freio_labial_correto', imagePath: 'assets/mockup_images/20.png', ), QuizAnswer( title: 'Freio labial inadequado', description: 'Inserção do freio labial baixa, entre os dentes', weight: 2, hideTitle: true, value: 'freio_labial_inadequado', imagePath: 'assets/mockup_images/19.jpeg', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz26Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.image, showBackButton: true, ); } } // Quiz 26: Freio lingual (Image-choice) class Quiz26Screen extends StatelessWidget { const Quiz26Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 26/28', category: 'Avaliação facial', categoryIcon: Icons.record_voice_over_rounded, fallbackIcon: Icons.record_voice_over_rounded, fallbackColor: const Color(0xFF8E7CC3), question: 'Qual das seguintes imagens se assemelha ao freio lingual do seu filho/a?', answers: const [ QuizAnswer( title: 'Freio lingual inadequado', description: 'Freio lingual curto/apertado (língua em coração)', weight: 2, hideTitle: true, value: 'freio_lingual_inadequado', imagePath: 'assets/mockup_images/17.png', ), QuizAnswer( title: 'Freio lingual correto', description: 'Língua move-se livremente, sem restrição visível', weight: 1, hideTitle: true, value: 'freio_lingual_correto', imagePath: 'assets/mockup_images/18.jpeg', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz27Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.image, showBackButton: true, ); } } // Quiz 27: Boca / dentição (Image-choice) class Quiz27Screen extends StatelessWidget { const Quiz27Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 27/28', category: 'Avaliação facial', categoryIcon: Icons.sentiment_neutral_rounded, fallbackIcon: Icons.sentiment_neutral_rounded, fallbackColor: const Color(0xFF2F9E94), isSignQuestion: true, question: 'Qual das seguintes imagens se assemelha à boca do seu filho/a?', answers: const [ QuizAnswer( title: 'Dentição alinhada', description: 'Dentição bem alinhada, sem apinhamento', weight: 1, hideTitle: true, value: 'dentes_alinhados_2', imagePath: 'assets/mockup_images/29.jpeg', ), QuizAnswer( title: 'Dentição desalinhada', description: 'Dentes sobrepostos/apinhados', weight: 2, hideTitle: true, value: 'dentes_desalinhados_2', imagePath: 'assets/mockup_images/28.jpeg', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => Quiz28Screen(currentScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.image, showBackButton: true, ); } } // Quiz 28: Céu da boca (Image-choice, final) class Quiz28Screen extends StatelessWidget { const Quiz28Screen({super.key, required this.currentScore, this.scopeId}); final QuizScore currentScore; final String? scopeId; @override Widget build(BuildContext context) { return QuizQuestionScreen( title: 'Quiz 28/28', category: 'Avaliação facial', categoryIcon: Icons.architecture_rounded, fallbackIcon: Icons.architecture_rounded, fallbackColor: const Color(0xFFFF55A7), isSignQuestion: true, question: 'Qual das seguintes imagens se assemelha ao céu da boca do seu filho/a?', answers: const [ QuizAnswer( title: 'Posição profunda incorreta', description: 'Palato estreito/profundo, em forma de V', weight: 2, hideTitle: true, value: 'palato_v', imagePath: 'assets/mockup_images/26.png', ), QuizAnswer( title: 'Posição em U saudável', description: 'Palato largo, em forma de U', weight: 1, hideTitle: true, value: 'palato_u', imagePath: 'assets/mockup_images/27.png', ), ], currentScore: currentScore, nextRoute: (context, nextScore) => quizPageRoute( builder: (_) => QuizResultScreen(finalScore: nextScore, scopeId: scopeId), ), answerType: QuizAnswerType.image, isFinal: true, showBackButton: true, ); } }