import 'package:flutter/material.dart'; import 'dart:async'; import '../main.dart' show supabase; import '../widgets/entrance.dart'; import '../widgets/tap_bounce.dart'; 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 createState() => _QuizResultScreenState(); } class _QuizResultScreenState extends State { late final Future _saveResultFuture; @override void initState() { super.initState(); _saveResultFuture = _saveResult(); } Future _saveResult() async { QuizPrefs.markQuizSeen(); final scope = (widget.scopeId ?? '').trim(); if (scope.isNotEmpty) { await QuizPrefs.saveLastResultForScope( scopeId: scope, score: widget.finalScore, maxScore: widget.maxScore, ); } else { final uid = supabase.auth.currentUser?.id; if (uid != null && uid.trim().isNotEmpty) { await QuizPrefs.saveLastResultForUser( userId: uid, score: widget.finalScore, maxScore: widget.maxScore, ); } else { await QuizPrefs.saveLastResult( score: widget.finalScore, maxScore: widget.maxScore, ); } } final uid = supabase.auth.currentUser?.id; final userId = (uid ?? '').trim(); if (userId.isNotEmpty && scope.isNotEmpty && scope.startsWith('${userId}_')) { final childId = scope.substring(userId.length + 1).trim(); if (childId.isNotEmpty) { // Fire-and-forget: avoid blocking UI on erros de rede. unawaited( supabase .from('children') .update({ 'last_score': widget.finalScore, 'last_max_score': widget.maxScore, 'last_quiz_at': DateTime.now().toIso8601String(), }) .eq('id', childId) .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), FadeSlideIn( child: 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: TweenAnimationBuilder( duration: const Duration(milliseconds: 1100), curve: Curves.easeOutCubic, tween: Tween(begin: 0, end: progress), builder: (context, animatedProgress, _) { final animatedPercent = (animatedProgress * 100).round(); return SizedBox( width: 220, height: 220, child: Stack( alignment: Alignment.center, children: [ SizedBox( width: 200, height: 200, child: CircularProgressIndicator( value: animatedProgress, strokeWidth: 12, backgroundColor: Colors.black .withValues(alpha: 0.10), valueColor: const AlwaysStoppedAnimation( Color(0xFF2F9E94), ), ), ), Column( mainAxisSize: MainAxisSize.min, children: [ Text( '$animatedPercent%', 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), FadeSlideIn( delay: const Duration(milliseconds: 120), child: Text( 'Conclusões:', textAlign: TextAlign.center, style: TextStyle( color: Colors.black.withValues(alpha: 0.75), fontWeight: FontWeight.w900, ), ), ), const SizedBox(height: 10), FadeSlideIn( delay: const Duration(milliseconds: 160), child: 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: TapBounce( 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: () async { await _saveResultFuture; if (!context.mounted) return; Navigator.of(context).popUntil((r) => r.isFirst); }, child: const Text('Avançar'), ), ), ), ), ], ), ), ), ), ), ), ); } }