import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:lottie/lottie.dart'; typedef QuizNextBuilder = Route 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 answers; final QuizNextBuilder nextRoute; final int currentScore; final VoidCallback? onFinished; final bool isFinal; final bool showBackButton; @override State createState() => _QuizQuestionScreenState(); } class _QuizQuestionScreenState extends State { 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( (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( (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, ), ], ), ), ), ), ); } }