literales y unificación de resultados en los dos modos de juego

This commit is contained in:
2026-05-11 21:57:46 +02:00
parent 8ecd1ead32
commit 3c5d98d6dd
42 changed files with 1815 additions and 786 deletions
+26 -169
View File
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:farolero/modelos/inicio_partida_multijugador.dart';
import 'package:farolero/modelos/jugador.dart';
import 'package:farolero/modelos/partida.dart';
import 'package:farolero/modelos/snapshot_partida_online.dart';
import 'package:farolero/pantallas/pantalla_notas_online.dart';
import 'package:farolero/pantallas/pantalla_revision_palabra.dart';
@@ -36,7 +37,6 @@ class PantallaVotacionCliente extends StatefulWidget {
class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
final Map<String, String> _votosPorVotante = {};
Map<String, dynamic>? _resultado;
OnMensajeCallback? _listener;
ServicioNearby? _nearby;
@@ -63,7 +63,31 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
),
);
} else {
setState(() => _resultado = mensaje.datos);
final votosRaw = mensaje.datos['votos'] as Map<dynamic, dynamic>? ?? {};
final snapshot = SnapshotPartidaOnline(
roomId: widget.partidaId,
fase: 'resultado',
ronda: 1,
categoria: '',
jugadores: widget.jugadores,
resultadoActual: ResultadoVotacion(
eliminadoId: mensaje.datos['eliminadoId'] as String? ?? '',
eliminadoNombre: mensaje.datos['eliminadoNombre'] as String? ?? '?',
eraImpostor: mensaje.datos['eraImpostor'] as bool? ?? false,
votos: votosRaw.map(
(key, value) => MapEntry(key.toString(), value.toString()),
),
),
);
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (_) => PantallaResultadoOnline(
snapshot: snapshot,
jugadoresControlados: widget.jugadoresControlados,
pistaCategoria: widget.pistaCategoria,
),
),
);
}
};
WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -87,7 +111,6 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
if (_resultado != null) return _buildResultado(context, _resultado!);
return Scaffold(
backgroundColor: TemaApp.colorFondo,
@@ -189,172 +212,6 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
widget.jugadoresControlados.isNotEmpty;
}
Widget _buildResultado(BuildContext context, Map<String, dynamic> resultado) {
final l10n = AppLocalizations.of(context)!;
final eliminadoId = resultado['eliminadoId'] as String?;
final eliminadoNombre = resultado['eliminadoNombre'] as String? ?? '?';
final eraImpostor = resultado['eraImpostor'] as bool? ?? false;
final votosRaw = resultado['votos'] as Map<dynamic, dynamic>? ?? {};
final votos = votosRaw.map(
(key, value) => MapEntry(key.toString(), value.toString()),
);
final jugadores = {for (final jugador in widget.jugadores) jugador.id: jugador};
final conteo = <String, int>{};
for (final votadoId in 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 Scaffold(
backgroundColor: TemaApp.colorFondo,
appBar: AppBar(
title: Text(l10n.result),
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
elevation: 0,
actions: [
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: _puedeAbrirNotas
? () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => PantallaNotasOnline(
partidaId: widget.partidaId!,
jugadores: widget.jugadores,
autoresControlados: widget.jugadoresControlados,
),
),
)
: null,
),
],
),
body: FondoFarolero(
intenso: true,
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ArteGameplayFarolero.fase(height: 118),
const SizedBox(height: 10),
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: eraImpostor
? TemaApp.colorVerde.withValues(alpha: 0.18)
: TemaApp.colorAcento.withValues(alpha: 0.18),
borderRadius: BorderRadius.circular(18),
border: Border.all(
color: eraImpostor ? TemaApp.colorVerde : TemaApp.colorAcento,
),
),
child: Column(
children: [
Text(
eliminadoNombre,
style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Text(
eraImpostor ? l10n.wasImpostor : l10n.wasInnocent,
style: TextStyle(
color: eraImpostor
? TemaApp.colorVerde
: TemaApp.colorAcento,
fontWeight: FontWeight.bold,
),
),
],
),
),
const SizedBox(height: 20),
Text(
'Detalle de votos',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 12),
Expanded(
child: ListView(
children: [
...ranking.map((entry) {
final jugador = jugadores[entry.key];
final destacado = entry.key == eliminadoId;
final color = destacado
? TemaApp.colorAcento
: TemaApp.colorNaranja;
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(child: Text(jugador?.nombre ?? '?')),
Text(
'${entry.value}',
style: TextStyle(
color: color,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 6),
ClipRRect(
borderRadius: BorderRadius.circular(999),
child: LinearProgressIndicator(
value: (entry.value / maxVotos)
.clamp(0.0, 1.0)
.toDouble(),
minHeight: 10,
backgroundColor: TemaApp.colorSuperficie,
valueColor: AlwaysStoppedAnimation(color),
),
),
],
),
);
}),
const Divider(height: 24),
...votos.entries.map((entry) {
final votante = jugadores[entry.key]?.nombre ?? '?';
final votado = jugadores[entry.value]?.nombre ?? '?';
return ListTile(
dense: true,
leading: const Icon(Icons.how_to_vote),
title: Text('$votante$votado'),
);
}),
],
),
),
],
),
),
),
);
}
Widget _buildSelectorLegacy() {
return ListView.builder(
itemCount: widget.jugadores.length,