import 'package:flutter/material.dart'; import 'package:farolero/l10n/generated/app_localizations.dart'; import 'package:provider/provider.dart'; import '../estado/estado_juego.dart'; import '../modelos/partida.dart'; import '../tema/componentes_farolero.dart'; import '../tema/tema_app.dart'; import 'pantalla_adivinanza.dart'; import 'pantalla_debate.dart'; import 'pantalla_fin_partida.dart'; class PantallaResultado extends StatefulWidget { final ResultadoVotacion resultado; const PantallaResultado({super.key, required this.resultado}); @override State createState() => _PantallaResultadoState(); } class _PantallaResultadoState extends State with SingleTickerProviderStateMixin { bool _revelado = false; late AnimationController _animController; late Animation _animOpacidad; @override void initState() { super.initState(); _animController = AnimationController( duration: const Duration(milliseconds: 2500), vsync: this, ); _animOpacidad = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _animController, curve: const Interval(0.6, 1.0, curve: Curves.easeIn), ), ); // Iniciar animación de suspense Future.delayed(const Duration(milliseconds: 500), () { _animController.forward().then((_) { setState(() => _revelado = true); }); }); } @override void dispose() { _animController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final estado = context.read(); final partida = estado.partida; return Scaffold( appBar: AppBar( title: Text(l10n.result), automaticallyImplyLeading: false, ), body: FondoFarolero( intenso: true, child: Center( child: SingleChildScrollView( padding: const EdgeInsets.all(32), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Animación de suspense if (!_revelado) ...[ const Text('🥁', style: TextStyle(fontSize: 64)), const SizedBox(height: 16), Text( l10n.revealing, style: Theme.of(context).textTheme.headlineMedium, ), const SizedBox(height: 24), const CircularProgressIndicator(color: TemaApp.colorAcento), ], if (_revelado) ...[ // Resultado revelado FadeTransition( opacity: _animOpacidad, child: Column( children: [ Text( widget.resultado.eraImpostor ? '🎭' : '😇', style: const TextStyle(fontSize: 72), ), const SizedBox(height: 16), Text( widget.resultado.eliminadoNombre, style: Theme.of(context) .textTheme .headlineLarge ?.copyWith(fontSize: 32), ), const SizedBox(height: 12), Container( padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 12), decoration: BoxDecoration( color: widget.resultado.eraImpostor ? TemaApp.colorVerde.withValues(alpha: 0.3) : TemaApp.colorAcento.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(30), border: Border.all( color: widget.resultado.eraImpostor ? TemaApp.colorVerde : TemaApp.colorAcento, ), ), child: Text( widget.resultado.eraImpostor ? l10n.wasImpostor : l10n.wasInnocent, style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: widget.resultado.eraImpostor ? TemaApp.colorVerde : TemaApp.colorAcento, ), ), ), const SizedBox(height: 24), _buildDetalleVotos(context, partida, l10n), const SizedBox(height: 24), // Acciones _construirBotones(context, estado), ], ), ), ], ], ), ), ), ), ); } Widget _buildDetalleVotos( BuildContext context, Partida? partida, AppLocalizations l10n, ) { final jugadores = { for (final jugador in partida?.jugadores ?? []) jugador.id: jugador, }; final conteo = {}; for (final votadoId in widget.resultado.votos.values) { conteo[votadoId] = (conteo[votadoId] ?? 0) + 1; } final maxVotos = conteo.values.isEmpty ? 1 : conteo.values.reduce((a, b) => a > b ? a : b); final ranking = conteo.entries.toList() ..sort((a, b) => b.value.compareTo(a.value)); return Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.bar_chart, color: TemaApp.colorNaranja), const SizedBox(width: 8), Text( l10n.votesThisRound, style: Theme.of(context).textTheme.titleMedium, ), ], ), const SizedBox(height: 12), ...ranking.map((entry) { final jugador = jugadores[entry.key]; final eliminado = entry.key == widget.resultado.eliminadoId; return _buildBarraVotos( context, nombre: jugador?.nombre ?? '?', votos: entry.value, total: maxVotos, destacado: eliminado, ); }), const Divider(height: 24), ...widget.resultado.votos.entries.map((entry) { final votante = jugadores[entry.key]?.nombre ?? '?'; final votado = jugadores[entry.value]?.nombre ?? '?'; final fueAlEliminado = entry.value == widget.resultado.eliminadoId; return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( children: [ Icon( fueAlEliminado ? Icons.how_to_vote : Icons.arrow_forward, size: 18, color: fueAlEliminado ? TemaApp.colorAcento : TemaApp.colorTextoSecundario, ), const SizedBox(width: 8), Expanded( child: Text( '$votante → $votado', style: TextStyle( color: fueAlEliminado ? TemaApp.colorTexto : TemaApp.colorTextoSecundario, fontWeight: fueAlEliminado ? FontWeight.bold : FontWeight.normal, ), ), ), ], ), ); }), ], ), ), ); } Widget _buildBarraVotos( BuildContext context, { required String nombre, required int votos, required int total, required bool destacado, }) { final color = destacado ? TemaApp.colorAcento : TemaApp.colorNaranja; final proporcion = total == 0 ? 0.0 : votos / total; return Padding( padding: const EdgeInsets.only(bottom: 10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( nombre, style: TextStyle( fontWeight: destacado ? FontWeight.bold : FontWeight.w600, ), ), ), Text( '$votos', style: TextStyle(color: color, fontWeight: FontWeight.bold), ), ], ), const SizedBox(height: 6), ClipRRect( borderRadius: BorderRadius.circular(999), child: LinearProgressIndicator( value: proporcion.clamp(0.0, 1.0).toDouble(), minHeight: 10, backgroundColor: TemaApp.colorSuperficie, valueColor: AlwaysStoppedAnimation(color), ), ), ], ), ); } Widget _construirBotones(BuildContext context, EstadoJuego estado) { final l10n = AppLocalizations.of(context)!; final partida = estado.partida; if (partida == null) return const SizedBox.shrink(); // Comprobar si la partida terminó final finPartida = estado.comprobarFinPartida(); if (finPartida) { return SizedBox( width: double.infinity, height: 56, child: ElevatedButton.icon( onPressed: () { Navigator.pushReplacement( context, MaterialPageRoute(builder: (_) => const PantallaFinPartida()), ); }, icon: const Icon(Icons.emoji_events), label: Text(l10n.seeEndResult), ), ); } // Si era impostor, puede intentar adivinar if (widget.resultado.eraImpostor) { return Column( children: [ SizedBox( width: double.infinity, height: 56, child: OutlinedButton.icon( onPressed: () { Navigator.pushReplacement( context, MaterialPageRoute( builder: (_) => const PantallaAdivinanza(), ), ); }, icon: const Text('🎯', style: TextStyle(fontSize: 18)), label: Text(l10n.impostorGuessWord), ), ), const SizedBox(height: 12), SizedBox( width: double.infinity, height: 56, child: ElevatedButton.icon( onPressed: () => _siguienteRonda(context, estado), icon: const Icon(Icons.skip_next), label: Text(l10n.nextRound), ), ), ], ); } return SizedBox( width: double.infinity, height: 56, child: ElevatedButton.icon( onPressed: () => _siguienteRonda(context, estado), icon: const Icon(Icons.skip_next), label: Text(l10n.nextRound), ), ); } void _siguienteRonda(BuildContext context, EstadoJuego estado) { estado.siguienteRonda(); Navigator.pushReplacement( context, MaterialPageRoute(builder: (_) => const PantallaDebate()), ); } }