refactorización de pantallas
This commit is contained in:
@@ -7,12 +7,14 @@ import '../estado/estado_juego.dart';
|
||||
import '../modelos/gamificacion_usuario.dart';
|
||||
import '../modelos/inicio_partida_multijugador.dart';
|
||||
import '../modelos/jugador.dart';
|
||||
import '../modelos/palabra.dart';
|
||||
import '../modelos/partida.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_revision_palabra.dart';
|
||||
@@ -279,10 +281,13 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
const SizedBox(height: 8),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () => nearby.asumirUsuariosDesconectados(),
|
||||
icon: const Icon(Icons.person_add_alt_1),
|
||||
label: Text(AppLocalizations.of(context)!.assumeOnThisPhone),
|
||||
child: SizedBox(
|
||||
width: 260,
|
||||
child: BotonFarolero.oscuro(
|
||||
texto: AppLocalizations.of(context)!.assumeOnThisPhone,
|
||||
icono: Icons.person_add_alt_1,
|
||||
onPressed: () => nearby.asumirUsuariosDesconectados(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -404,67 +409,35 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
bool todosListos,
|
||||
ServicioNearby nearby,
|
||||
) {
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
l10n.waitingPlayersSeeWord,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
l10n.connectedPlayers,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_buildJugadorTile(nearby.miNombre ?? 'Host', true, _hostListo),
|
||||
...nearby.jugadores.map(
|
||||
(j) => _buildJugadorTile(
|
||||
j.nombre,
|
||||
false,
|
||||
_clientesListos[j.endpointId] ?? false,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
// Botón para que el host vea su palabra
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _mostrarPalabraHost(context),
|
||||
icon: const Icon(Icons.visibility),
|
||||
label: Text(l10n.seeYourWord),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: TemaApp.colorNaranja,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
),
|
||||
return TarjetaFaseFarolero(
|
||||
icono: Icons.visibility,
|
||||
titulo: l10n.waitingPlayersSeeWord,
|
||||
subtitulo: l10n.connectedPlayers,
|
||||
child: Column(
|
||||
children: [
|
||||
_buildJugadorTile(nearby.miNombre ?? 'Host', true, _hostListo),
|
||||
...nearby.jugadores.map(
|
||||
(jugador) => _buildJugadorTile(
|
||||
jugador.nombre,
|
||||
false,
|
||||
_clientesListos[jugador.endpointId] ?? false,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
BotonFarolero(
|
||||
texto: l10n.seeYourWord,
|
||||
icono: Icons.visibility,
|
||||
onPressed: () => _mostrarPalabraHost(context),
|
||||
),
|
||||
if (todosListos) ...[
|
||||
const SizedBox(height: 12),
|
||||
if (todosListos)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: TemaApp.colorVerde.withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.check_circle, color: TemaApp.colorVerde),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.allSeenStartDebate,
|
||||
style: const TextStyle(color: TemaApp.colorVerde),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
EstadoJugadorFarolero(
|
||||
nombre: l10n.allSeenStartDebate,
|
||||
completado: true,
|
||||
icono: Icons.check_circle,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -563,66 +536,32 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
final estado = context.read<EstadoJuego>();
|
||||
final tiempo = estado.partida?.config.tiempoDebateSegundos;
|
||||
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (tiempo != null) ...[
|
||||
Text(l10n.debate, style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: _segundosRestantes == 0
|
||||
? TemaApp.colorAcento.withValues(alpha: 0.3)
|
||||
: TemaApp.colorTarjeta,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
_segundosRestantes == 0
|
||||
? l10n.timeUp
|
||||
: l10n.timeRemaining,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
Text(
|
||||
_formatearTiempo(_segundosRestantes),
|
||||
style: Theme.of(context).textTheme.headlineLarge,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
_buildPrimerTurno(context),
|
||||
return TarjetaFaseFarolero(
|
||||
icono: Icons.forum,
|
||||
titulo: l10n.debate,
|
||||
subtitulo: l10n.debateInstructions,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (tiempo != null) ...[
|
||||
TemporizadorFarolero(
|
||||
etiqueta: _segundosRestantes == 0
|
||||
? l10n.timeUp
|
||||
: l10n.timeRemaining,
|
||||
tiempo: _formatearTiempo(_segundosRestantes),
|
||||
agotado: _segundosRestantes == 0,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
l10n.activePlayers,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: nearby.jugadores.length + 1,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == 0) {
|
||||
return _buildJugadorTile(
|
||||
nearby.miNombre ?? 'Host',
|
||||
true,
|
||||
true,
|
||||
);
|
||||
}
|
||||
final j = nearby.jugadores[index - 1];
|
||||
return _buildJugadorTile(j.nombre, false, true);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
_buildPrimerTurno(context),
|
||||
const SizedBox(height: 16),
|
||||
Text(l10n.activePlayers, style: Theme.of(context).textTheme.titleMedium),
|
||||
const SizedBox(height: 8),
|
||||
_buildJugadorTile(nearby.miNombre ?? 'Host', true, true),
|
||||
...nearby.jugadores.map(
|
||||
(jugador) => _buildJugadorTile(jugador.nombre, false, true),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -644,7 +583,7 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Empieza $nombre diciendo su palabra.',
|
||||
AppLocalizations.of(context)!.firstTurnInstruction(nombre),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
@@ -664,89 +603,42 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
final votosEmitidos = estado.votos.length;
|
||||
final progreso = totalVotos == 0 ? 0.0 : votosEmitidos / totalVotos;
|
||||
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(l10n.voting, style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: TemaApp.colorTarjeta,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(l10n.votesProgress(votosEmitidos, totalVotos)),
|
||||
const SizedBox(height: 8),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: LinearProgressIndicator(
|
||||
value: progreso.clamp(0.0, 1.0).toDouble(),
|
||||
backgroundColor: TemaApp.colorSuperficie,
|
||||
valueColor: const AlwaysStoppedAnimation(
|
||||
TemaApp.colorAcento,
|
||||
),
|
||||
minHeight: 8,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
return TarjetaFaseFarolero(
|
||||
icono: Icons.how_to_vote,
|
||||
titulo: l10n.voting,
|
||||
subtitulo: l10n.votesProgress(votosEmitidos, totalVotos),
|
||||
color: TemaApp.colorAcento,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
child: LinearProgressIndicator(
|
||||
value: progreso.clamp(0.0, 1.0).toDouble(),
|
||||
minHeight: 14,
|
||||
backgroundColor: Colors.black.withValues(alpha: 0.35),
|
||||
valueColor: const AlwaysStoppedAnimation(TemaApp.colorAcento),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: _hostYaVoto(context) ? null : () => _abrirVotacionHost(context),
|
||||
icon: const Icon(Icons.how_to_vote),
|
||||
label: Text(
|
||||
_hostYaVoto(context)
|
||||
? l10n.playersVoted
|
||||
: l10n.confirmVote,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (!_hostYaVoto(context))
|
||||
BotonFarolero.secundario(
|
||||
texto: l10n.votar,
|
||||
icono: Icons.how_to_vote,
|
||||
onPressed: () => _abrirVotacionHost(context),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
l10n.playersVoted,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
if (!_hostYaVoto(context)) const SizedBox(height: 16),
|
||||
...partida.jugadoresActivos.map((jugador) {
|
||||
final haVotado = estado.votos.containsKey(jugador.id);
|
||||
return _buildJugadorTile(jugador.nombre, false, haVotado);
|
||||
}),
|
||||
if (todosVotaron)
|
||||
EstadoJugadorFarolero(
|
||||
nombre: l10n.allVoted,
|
||||
completado: true,
|
||||
icono: Icons.check_circle,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: partida.jugadoresActivos.length,
|
||||
itemBuilder: (context, index) {
|
||||
final jugador = partida.jugadoresActivos[index];
|
||||
final haVotado = estado.votos.containsKey(jugador.id);
|
||||
return _buildJugadorTile(jugador.nombre, false, haVotado);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (todosVotaron)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: TemaApp.colorVerde.withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.check_circle, color: TemaApp.colorVerde),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.allVoted,
|
||||
style: const TextStyle(color: TemaApp.colorVerde),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -760,132 +652,11 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
return Center(child: Text(l10n.noResult));
|
||||
}
|
||||
|
||||
final conteo = <String, int>{};
|
||||
for (final votadoId in 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: [
|
||||
Text(l10n.result, style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: TemaApp.decoracionPanel(
|
||||
color: resultado.eraImpostor
|
||||
? TemaApp.colorVerde.withValues(alpha: 0.18)
|
||||
: TemaApp.colorAcento.withValues(alpha: 0.18),
|
||||
borderColor: resultado.eraImpostor
|
||||
? TemaApp.colorVerde
|
||||
: TemaApp.colorAcento,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
resultado.eliminadoNombre,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
resultado.eraImpostor
|
||||
? l10n.wasImpostor
|
||||
: l10n.wasInnocent,
|
||||
style: TextStyle(
|
||||
color: resultado.eraImpostor
|
||||
? TemaApp.colorVerde
|
||||
: TemaApp.colorAcento,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(l10n.votesThisRound,
|
||||
style: Theme.of(context).textTheme.titleMedium),
|
||||
const SizedBox(height: 12),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
...ranking.map((entry) {
|
||||
final jugador = partida.jugadores.firstWhere(
|
||||
(j) => j.id == entry.key,
|
||||
orElse: () => partida.jugadores.first,
|
||||
);
|
||||
return _buildBarraResultado(
|
||||
context,
|
||||
nombre: jugador.nombre,
|
||||
votos: entry.value,
|
||||
maxVotos: maxVotos,
|
||||
destacado: entry.key == resultado.eliminadoId,
|
||||
);
|
||||
}),
|
||||
const Divider(height: 24),
|
||||
...resultado.votos.entries.map((entry) {
|
||||
final votante = partida.jugadores.firstWhere(
|
||||
(j) => j.id == entry.key,
|
||||
orElse: () => partida.jugadores.first,
|
||||
);
|
||||
final votado = partida.jugadores.firstWhere(
|
||||
(j) => j.id == entry.value,
|
||||
orElse: () => partida.jugadores.first,
|
||||
);
|
||||
return ListTile(
|
||||
dense: true,
|
||||
leading: const Icon(Icons.how_to_vote),
|
||||
title: Text('${votante.nombre} → ${votado.nombre}'),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBarraResultado(
|
||||
BuildContext context, {
|
||||
required String nombre,
|
||||
required int votos,
|
||||
required int maxVotos,
|
||||
required bool destacado,
|
||||
}) {
|
||||
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(nombre)),
|
||||
Text('$votos',
|
||||
style: TextStyle(color: color, fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
child: LinearProgressIndicator(
|
||||
value: (votos / maxVotos).clamp(0.0, 1.0).toDouble(),
|
||||
minHeight: 10,
|
||||
backgroundColor: TemaApp.colorSuperficie,
|
||||
valueColor: AlwaysStoppedAnimation(color),
|
||||
),
|
||||
),
|
||||
],
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: ResultadoRondaFarolero(
|
||||
resultado: resultado,
|
||||
jugadores: partida.jugadores,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -895,102 +666,63 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
final ultimo = partida?.historialVotaciones.isNotEmpty == true
|
||||
? partida!.historialVotaciones.last
|
||||
: null;
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.psychology, size: 56, color: TemaApp.colorNaranja),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
l10n.impostorGuessTitle,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
ultimo == null
|
||||
? l10n.impostorCanGuess
|
||||
: '${ultimo.eliminadoNombre}: ${l10n.impostorCanGuess}',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
return TarjetaFaseFarolero(
|
||||
icono: Icons.psychology,
|
||||
titulo: l10n.impostorGuessTitle,
|
||||
subtitulo: ultimo == null
|
||||
? l10n.impostorCanGuess
|
||||
: '${ultimo.eliminadoNombre}: ${l10n.impostorCanGuess}',
|
||||
color: TemaApp.colorNaranja,
|
||||
child: const ArteGameplayFarolero.resultado(height: 132),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFaseFinOnline(BuildContext context, AppLocalizations l10n) {
|
||||
final partida = context.watch<EstadoJuego>().partida;
|
||||
final ganaronJugadores = partida?.ganador == 'jugadores';
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
ganaronJugadores ? '🎉' : '🎭',
|
||||
style: const TextStyle(fontSize: 64),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
ganaronJugadores ? l10n.playersWin : l10n.impostorsWin,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
partida == null ? '' : l10n.theWordWas(partida.palabraSecreta),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
if (_progresoGamificacion != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
_buildProgresoGamificacion(context, _progresoGamificacion!),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (partida == null) return Center(child: Text(l10n.noResult));
|
||||
|
||||
Widget _buildProgresoGamificacion(
|
||||
BuildContext context,
|
||||
ProgresoGamificacionUsuario progreso,
|
||||
) {
|
||||
final nuevas = progreso.nuevasMedallas;
|
||||
return PanelFarolero(
|
||||
padding: const EdgeInsets.all(14),
|
||||
color: TemaApp.colorSuperficie.withValues(alpha: 0.82),
|
||||
final ganaronJugadores = partida.ganador == 'jugadores';
|
||||
final color = ganaronJugadores ? TemaApp.colorVerde : TemaApp.colorAcento;
|
||||
final impostores = partida.jugadores.where((j) => j.esImpostor).toList();
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Tu progreso', style: Theme.of(context).textTheme.titleMedium),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
children: [
|
||||
const Text('🔥', style: TextStyle(fontSize: 22)),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
child: LinearProgressIndicator(
|
||||
value: progreso.despues.fuego / 100,
|
||||
minHeight: 8,
|
||||
color: TemaApp.colorNaranja,
|
||||
backgroundColor: Colors.black.withValues(alpha: 0.35),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text('${progreso.despues.fuego}%'),
|
||||
],
|
||||
HeroFinalPartidaFarolero(
|
||||
encabezado: l10n.gameOver,
|
||||
titulo: ganaronJugadores ? l10n.playersWin : l10n.impostorsWin,
|
||||
icono: ganaronJugadores ? Icons.emoji_events : Icons.theater_comedy,
|
||||
color: color,
|
||||
),
|
||||
if (nuevas.isNotEmpty) ...[
|
||||
const SizedBox(height: 10),
|
||||
MedallasCompactasFarolero(ids: nuevas, max: nuevas.length),
|
||||
],
|
||||
const SizedBox(height: 12),
|
||||
if (_progresoGamificacion == null)
|
||||
const TarjetaRecompensaCargandoPremium()
|
||||
else
|
||||
TarjetaProgresoGamificacionPremium(
|
||||
progreso: _progresoGamificacion!,
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
TarjetaSecretoPremium(
|
||||
palabra: partida.palabraSecreta,
|
||||
categoria: BancoPalabras.nombreBonitoCategoria(
|
||||
partida.categoriaReal,
|
||||
l10n,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
TarjetaImpostoresPremium(
|
||||
titulo: impostores.length == 1
|
||||
? l10n.theImpostorWas
|
||||
: l10n.theImpostorsWere,
|
||||
impostores: impostores,
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
if (partida.historialVotaciones.isNotEmpty)
|
||||
TarjetaHistorialVotosPremium(
|
||||
historial: partida.historialVotaciones,
|
||||
jugadores: partida.jugadores,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -1046,28 +778,11 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
}
|
||||
|
||||
Widget _buildJugadorTile(String nombre, bool esHost, bool listo) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: listo
|
||||
? TemaApp.colorVerde.withValues(alpha: 0.2)
|
||||
: TemaApp.colorTarjeta,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
esHost ? Icons.phone_android : Icons.devices,
|
||||
color: esHost ? TemaApp.colorDorado : TemaApp.colorNaranja,
|
||||
size: 22,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(child: Text(nombre)),
|
||||
if (listo)
|
||||
const Icon(Icons.check_circle, color: TemaApp.colorVerde, size: 20),
|
||||
],
|
||||
),
|
||||
return EstadoJugadorFarolero(
|
||||
nombre: nombre,
|
||||
destacado: esHost,
|
||||
completado: listo,
|
||||
icono: esHost ? Icons.phone_android : Icons.devices,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1080,60 +795,36 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
) {
|
||||
switch (fase) {
|
||||
case FaseJuego.verPalabra:
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: todosListos
|
||||
? () => _avanzarAFase(FaseJuego.debate)
|
||||
: null,
|
||||
icon: const Icon(Icons.forum),
|
||||
label: Text(
|
||||
todosListos
|
||||
? l10n.allSeenStartDebate
|
||||
: l10n.waitingPlayersSeeWord,
|
||||
),
|
||||
),
|
||||
return BotonFarolero(
|
||||
texto: todosListos ? l10n.allSeenStartDebate : l10n.waitingPlayersSeeWord,
|
||||
icono: Icons.forum,
|
||||
onPressed: todosListos ? () => _avanzarAFase(FaseJuego.debate) : null,
|
||||
);
|
||||
case FaseJuego.debate:
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _avanzarAFase(FaseJuego.votacion),
|
||||
icon: const Icon(Icons.how_to_vote),
|
||||
label: Text(l10n.goToVoting),
|
||||
),
|
||||
return BotonFarolero.secundario(
|
||||
texto: l10n.goToVoting,
|
||||
icono: Icons.how_to_vote,
|
||||
onPressed: () => _avanzarAFase(FaseJuego.votacion),
|
||||
);
|
||||
case FaseJuego.votacion:
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: todosVotaron
|
||||
? () => _avanzarAFase(FaseJuego.resultado)
|
||||
: null,
|
||||
icon: const Icon(Icons.visibility),
|
||||
label: Text(todosVotaron ? l10n.revealResult : l10n.waitingVoting),
|
||||
),
|
||||
return BotonFarolero(
|
||||
texto: todosVotaron ? l10n.revealResult : l10n.waitingVoting,
|
||||
icono: Icons.visibility,
|
||||
onPressed: todosVotaron ? () => _avanzarAFase(FaseJuego.resultado) : null,
|
||||
);
|
||||
case FaseJuego.resultado:
|
||||
return _buildAccionesResultado(context, l10n);
|
||||
case FaseJuego.adivinanza:
|
||||
return _buildAccionesAdivinanza(context, l10n);
|
||||
case FaseJuego.finPartida:
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () async {
|
||||
final nearby = context.read<ServicioNearby>();
|
||||
await nearby.desconectar();
|
||||
widget.onPartidaFin();
|
||||
},
|
||||
icon: const Icon(Icons.home),
|
||||
label: Text(l10n.mainMenu),
|
||||
),
|
||||
return BotonFarolero.oscuro(
|
||||
texto: l10n.mainMenu,
|
||||
icono: Icons.home,
|
||||
onPressed: () async {
|
||||
final nearby = context.read<ServicioNearby>();
|
||||
await nearby.desconectar();
|
||||
widget.onPartidaFin();
|
||||
},
|
||||
);
|
||||
default:
|
||||
return const SizedBox.shrink();
|
||||
@@ -1149,80 +840,58 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
if (partida == null || resultado == null) return const SizedBox.shrink();
|
||||
|
||||
if (_hayFinTrasVotacion(partida)) {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _finalizarPartidaOnline(context),
|
||||
icon: const Icon(Icons.emoji_events),
|
||||
label: Text(l10n.seeEndResult),
|
||||
),
|
||||
return BotonFarolero(
|
||||
texto: l10n.seeEndResult,
|
||||
icono: Icons.emoji_events,
|
||||
onPressed: () => _finalizarPartidaOnline(context),
|
||||
);
|
||||
}
|
||||
|
||||
if (resultado.eraImpostor) {
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () => _iniciarAdivinanzaOnline(context),
|
||||
icon: const Icon(Icons.psychology),
|
||||
label: Text(l10n.impostorGuessWord),
|
||||
),
|
||||
BotonFarolero.oscuro(
|
||||
texto: l10n.impostorGuessWord,
|
||||
icono: Icons.psychology,
|
||||
onPressed: () => _iniciarAdivinanzaOnline(context),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _siguienteRondaOnline(context),
|
||||
icon: const Icon(Icons.skip_next),
|
||||
label: Text(l10n.nextRound),
|
||||
),
|
||||
BotonFarolero(
|
||||
texto: l10n.nextRound,
|
||||
icono: Icons.skip_next,
|
||||
onPressed: () => _siguienteRondaOnline(context),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _siguienteRondaOnline(context),
|
||||
icon: const Icon(Icons.skip_next),
|
||||
label: Text(l10n.nextRound),
|
||||
),
|
||||
return BotonFarolero(
|
||||
texto: l10n.nextRound,
|
||||
icono: Icons.skip_next,
|
||||
onPressed: () => _siguienteRondaOnline(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAccionesAdivinanza(BuildContext context, AppLocalizations l10n) {
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _resolverAdivinanzaOnline(context),
|
||||
icon: const Icon(Icons.check_circle),
|
||||
label: Text(l10n.guess),
|
||||
),
|
||||
BotonFarolero(
|
||||
texto: l10n.guess,
|
||||
icono: Icons.check_circle,
|
||||
onPressed: () => _resolverAdivinanzaOnline(context),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () => _siguienteRondaOnline(context),
|
||||
icon: const Icon(Icons.skip_next),
|
||||
label: Text(l10n.dontGuess),
|
||||
),
|
||||
BotonFarolero.oscuro(
|
||||
texto: l10n.dontGuess,
|
||||
icono: Icons.skip_next,
|
||||
onPressed: () => _siguienteRondaOnline(context),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _finalizarPartidaOnline
|
||||
|
||||
Future<void> _finalizarPartidaOnline(BuildContext context) async {
|
||||
final estado = context.read<EstadoJuego>();
|
||||
final nearby = context.read<ServicioNearby>();
|
||||
@@ -1441,7 +1110,12 @@ class _PantallaRevelarPalabraHostState
|
||||
if (widget.esImpostor && widget.pistaActiva) ...[
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'Categoría: ${widget.categoria}',
|
||||
l10n.clueCategory(
|
||||
BancoPalabras.nombreBonitoCategoria(
|
||||
widget.categoria,
|
||||
l10n,
|
||||
),
|
||||
),
|
||||
style: Theme.of(context).textTheme.bodyLarge
|
||||
?.copyWith(color: TemaApp.colorNaranja),
|
||||
),
|
||||
@@ -1450,7 +1124,11 @@ class _PantallaRevelarPalabraHostState
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
const Text('🔒', style: TextStyle(fontSize: 48)),
|
||||
const Icon(
|
||||
Icons.lock,
|
||||
color: TemaApp.colorDorado,
|
||||
size: 48,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
l10n.holdToSeeWord,
|
||||
@@ -1496,21 +1174,15 @@ class _PantallaRevelarPalabraHostState
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: _haRevelado
|
||||
? () {
|
||||
widget.onVisto();
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
: null,
|
||||
icon: const Icon(Icons.check),
|
||||
label: Text(
|
||||
_haRevelado ? l10n.iveSeenIt : l10n.tapToSee,
|
||||
),
|
||||
),
|
||||
BotonFarolero(
|
||||
texto: _haRevelado ? l10n.iveSeenIt : l10n.tapToSee,
|
||||
icono: Icons.check,
|
||||
onPressed: _haRevelado
|
||||
? () {
|
||||
widget.onVisto();
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user