import 'package:confetti/confetti.dart'; import 'package:farolero/l10n/generated/app_localizations.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../modelos/gamificacion_usuario.dart'; import '../modelos/inicio_partida_multijugador.dart'; import '../modelos/jugador.dart'; import '../modelos/palabra.dart'; import '../modelos/snapshot_partida_online.dart'; import '../servicios/servicio_historial_partidas.dart'; import '../servicios/servicio_nearby.dart'; import '../servicios/servicio_perfil_usuario.dart'; import '../tema/componentes_farolero.dart'; import '../tema/componentes_resultado_farolero.dart'; import '../tema/tema_app.dart'; import 'pantalla_notas_online.dart'; import 'pantalla_principal.dart'; import 'pantalla_revision_palabra.dart'; class PantallaFinPartidaOnline extends StatefulWidget { final SnapshotPartidaOnline snapshot; final List jugadoresControlados; final String? pistaCategoria; const PantallaFinPartidaOnline({ super.key, required this.snapshot, required this.jugadoresControlados, this.pistaCategoria, }); @override State createState() => _PantallaFinPartidaOnlineState(); } class _PantallaFinPartidaOnlineState extends State { bool _guardada = false; ProgresoGamificacionUsuario? _progreso; late final ConfettiController _confetti; @override void initState() { super.initState(); _confetti = ConfettiController(duration: const Duration(seconds: 5)); Future.delayed(const Duration(milliseconds: 450), () { if (mounted) _confetti.play(); }); } @override void dispose() { _confetti.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final snapshot = widget.snapshot; final ganaronJugadores = snapshot.ganador == 'jugadores'; final color = ganaronJugadores ? TemaApp.colorVerde : TemaApp.colorAcento; _registrarResultadoSiHaceFalta(context, snapshot); return Scaffold( extendBodyBehindAppBar: true, backgroundColor: const Color(0xFF05070D), appBar: AppBar( title: Text(l10n.gameOver), automaticallyImplyLeading: false, backgroundColor: Colors.transparent, elevation: 0, actions: _acciones(context, l10n, snapshot), ), body: FondoFarolero( intenso: true, child: Stack( children: [ Positioned.fill( child: IgnorePointer( child: CustomPaint( painter: EscenarioFinPartidaFaroleroPainter(color: color), ), ), ), Align( alignment: Alignment.topCenter, child: ConfettiWidget( confettiController: _confetti, blastDirectionality: BlastDirectionality.explosive, emissionFrequency: 0.09, numberOfParticles: 28, gravity: 0.18, colors: const [ TemaApp.colorDorado, TemaApp.colorNaranja, TemaApp.colorAcento, Color(0xFFFFECBE), ], ), ), Positioned.fill( child: IgnorePointer( child: DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( colors: [ Colors.transparent, Colors.black.withValues(alpha: 0.10), Colors.black.withValues(alpha: 0.52), ], stops: const [0.0, 0.54, 1.0], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), ), ), ), SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB(20, 72, 20, 28), child: Column( children: [ HeroFinalPartidaFarolero( encabezado: l10n.gameOver, titulo: ganaronJugadores ? l10n.playersWin : l10n.impostorsWin, icono: ganaronJugadores ? Icons.emoji_events : Icons.theater_comedy, color: color, ), const SizedBox(height: 12), if (_progreso == null) const TarjetaRecompensaCargandoPremium() else TarjetaProgresoGamificacionPremium(progreso: _progreso!), const SizedBox(height: 18), if (snapshot.palabraSecreta != null) TarjetaSecretoPremium( palabra: snapshot.palabraSecreta!, categoria: BancoPalabras.nombreBonitoCategoria( snapshot.categoria, l10n, ), ), const SizedBox(height: 18), TarjetaImpostoresPremium( titulo: snapshot.impostores.length == 1 ? l10n.theImpostorWas : l10n.theImpostorsWere, impostores: _impostores(snapshot), ), const SizedBox(height: 18), if (snapshot.historialVotaciones.isNotEmpty) TarjetaHistorialVotosPremium( historial: snapshot.historialVotaciones, jugadores: snapshot.jugadores, ), const SizedBox(height: 24), BotonFarolero.oscuro( texto: l10n.mainMenu, icono: Icons.home, assetIconPath: 'assets/ui/generated/actions/action_result_trophy.webp', onPressed: () async { await context.read().desconectar(); if (!context.mounted) return; Navigator.pushAndRemoveUntil( context, MaterialPageRoute( builder: (_) => const PantallaPrincipal(), ), (route) => false, ); }, ), const SizedBox(height: 16), ], ), ), ), ], ), ), ); } List _acciones( BuildContext context, AppLocalizations l10n, SnapshotPartidaOnline snapshot, ) { return [ IconButton( tooltip: l10n.seeYourWord, icon: const Icon(Icons.visibility), onPressed: widget.jugadoresControlados.isEmpty ? null : () => mostrarRevisionPalabraOnline( context: context, jugadoresControlados: widget.jugadoresControlados, pistaCategoria: widget.pistaCategoria, ), ), IconButton( tooltip: l10n.notesTitle, icon: const Icon(Icons.edit_note), onPressed: snapshot.roomId == null || widget.jugadoresControlados.isEmpty ? null : () => Navigator.push( context, MaterialPageRoute( builder: (_) => PantallaNotasOnline( partidaId: snapshot.roomId!, jugadores: snapshot.jugadores, autoresControlados: widget.jugadoresControlados, ), ), ), ), ]; } void _registrarResultadoSiHaceFalta( BuildContext context, SnapshotPartidaOnline snapshot, ) { if (_guardada || snapshot.ganador == null) return; _guardada = true; WidgetsBinding.instance.addPostFrameCallback((_) async { if (!mounted) return; final historial = context.read(); final perfil = context.read(); await historial.guardarSnapshotOnline(snapshot); final progreso = await perfil.registrarPartidaCompletada( victoria: _perfilLocalGano(snapshot, widget.jugadoresControlados), comoImpostor: widget.jugadoresControlados.any((j) => j.esImpostor), victoriaComoImpostor: snapshot.ganador == 'impostores' && widget.jugadoresControlados.any((j) => j.esImpostor), ); if (!mounted) return; setState(() => _progreso = progreso); if (progreso.nuevasMedallas.isNotEmpty || progreso.incrementoFuego > 0) { _confetti.play(); } }); } bool _perfilLocalGano( SnapshotPartidaOnline snapshot, List jugadoresControlados, ) { if (jugadoresControlados.isEmpty) return snapshot.ganador == 'jugadores'; final ganaronImpostores = snapshot.ganador == 'impostores'; return jugadoresControlados.any( (jugador) => jugador.esImpostor ? ganaronImpostores : !ganaronImpostores, ); } List _impostores(SnapshotPartidaOnline snapshot) { final porNombre = {for (final jugador in snapshot.jugadores) jugador.nombre: jugador}; return snapshot.impostores .map( (nombre) => porNombre[nombre] ?? Jugador(id: nombre, nombre: nombre, esImpostor: true), ) .toList(); } }