Posible mejora en el multidispositivo
This commit is contained in:
@@ -7,6 +7,7 @@ import '../estado/estado_juego.dart';
|
||||
import '../modelos/inicio_partida_multijugador.dart';
|
||||
import '../modelos/jugador.dart';
|
||||
import '../modelos/partida.dart';
|
||||
import '../modelos/snapshot_partida_online.dart';
|
||||
import '../servicios/servicio_nearby.dart';
|
||||
import '../tema/componentes_farolero.dart';
|
||||
import '../tema/tema_app.dart';
|
||||
@@ -94,6 +95,7 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
estado.iniciarDebate();
|
||||
final primero = _elegirPrimerTurno();
|
||||
nearby.enviarCambioFase('debate', {
|
||||
..._snapshot(fase: 'debate').toJson(),
|
||||
if (primero != null) ...{
|
||||
'primerTurnoId': primero.id,
|
||||
'primerTurnoNombre': primero.nombre,
|
||||
@@ -105,18 +107,19 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
break;
|
||||
case FaseJuego.votacion:
|
||||
estado.iniciarVotacion();
|
||||
nearby.enviarCambioFase('votacion');
|
||||
nearby.enviarCambioFase('votacion', _snapshot(fase: 'votacion').toJson());
|
||||
_votosRecibidos.clear();
|
||||
break;
|
||||
case FaseJuego.resultado:
|
||||
final resultado = estado.procesarVotacion();
|
||||
if (resultado != null) {
|
||||
nearby.enviarResultadoVotacion({
|
||||
'eliminadoId': resultado.eliminadoId,
|
||||
'eliminadoNombre': resultado.eliminadoNombre,
|
||||
'eraImpostor': resultado.eraImpostor,
|
||||
'votos': resultado.votos,
|
||||
});
|
||||
nearby.enviarResultadoVotacion(
|
||||
_snapshot(
|
||||
fase: 'resultado',
|
||||
resultadoActual: resultado,
|
||||
mensaje: _mensajeSiguienteAccion(estado, resultado),
|
||||
).toJson(),
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -233,6 +236,8 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
(FaseJuego.debate, l10n.debate),
|
||||
(FaseJuego.votacion, l10n.voting),
|
||||
(FaseJuego.resultado, l10n.result),
|
||||
(FaseJuego.adivinanza, l10n.guess),
|
||||
(FaseJuego.finPartida, l10n.gameOver),
|
||||
];
|
||||
|
||||
return SingleChildScrollView(
|
||||
@@ -278,11 +283,55 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
return _buildFaseVotacion(context, l10n, todosVotaron, nearby);
|
||||
case FaseJuego.resultado:
|
||||
return _buildFaseResultado(context, l10n);
|
||||
case FaseJuego.adivinanza:
|
||||
return _buildFaseAdivinanza(context, l10n);
|
||||
case FaseJuego.finPartida:
|
||||
return _buildFaseFinOnline(context, l10n);
|
||||
default:
|
||||
return const Center(child: Text('Fin de la partida'));
|
||||
}
|
||||
}
|
||||
|
||||
SnapshotPartidaOnline _snapshot({
|
||||
required String fase,
|
||||
ResultadoVotacion? resultadoActual,
|
||||
String? mensaje,
|
||||
bool revelarFinal = false,
|
||||
}) {
|
||||
final estado = context.read<EstadoJuego>();
|
||||
final nearby = context.read<ServicioNearby>();
|
||||
final partida = estado.partida!;
|
||||
return SnapshotPartidaOnline.desdePartida(
|
||||
partida,
|
||||
roomId: nearby.roomId,
|
||||
fase: fase,
|
||||
resultadoActual: resultadoActual,
|
||||
mensaje: mensaje,
|
||||
revelarPalabra: revelarFinal,
|
||||
revelarImpostores: revelarFinal,
|
||||
);
|
||||
}
|
||||
|
||||
String _mensajeSiguienteAccion(
|
||||
EstadoJuego estado,
|
||||
ResultadoVotacion resultado,
|
||||
) {
|
||||
final partida = estado.partida;
|
||||
if (partida != null && _hayFinTrasVotacion(partida)) {
|
||||
return 'La partida ha terminado.';
|
||||
}
|
||||
if (resultado.eraImpostor) {
|
||||
return 'El impostor eliminado puede intentar adivinar la palabra.';
|
||||
}
|
||||
return 'La partida continúa en la siguiente ronda.';
|
||||
}
|
||||
|
||||
bool _hayFinTrasVotacion(Partida partida) {
|
||||
final impostoresVivos = partida.impostoresActivos.length;
|
||||
final jugadoresVivos = partida.jugadoresNormalesActivos.length;
|
||||
return impostoresVivos == 0 || impostoresVivos >= jugadoresVivos;
|
||||
}
|
||||
|
||||
Widget _buildFaseVerPalabra(
|
||||
BuildContext context,
|
||||
AppLocalizations l10n,
|
||||
@@ -775,6 +824,67 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFaseAdivinanza(BuildContext context, AppLocalizations l10n) {
|
||||
final partida = context.watch<EstadoJuego>().partida;
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool _hostYaVoto(BuildContext context) {
|
||||
final estado = context.read<EstadoJuego>();
|
||||
final sala = context.read<ServicioNearby>().estadoSala;
|
||||
@@ -895,10 +1005,200 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
||||
label: Text(todosVotaron ? l10n.revealResult : l10n.waitingVoting),
|
||||
),
|
||||
);
|
||||
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),
|
||||
),
|
||||
);
|
||||
default:
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildAccionesResultado(BuildContext context, AppLocalizations l10n) {
|
||||
final estado = context.read<EstadoJuego>();
|
||||
final partida = estado.partida;
|
||||
final resultado = partida?.historialVotaciones.isNotEmpty == true
|
||||
? partida!.historialVotaciones.last
|
||||
: null;
|
||||
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),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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),
|
||||
),
|
||||
),
|
||||
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),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
height: 56,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _siguienteRondaOnline(context),
|
||||
icon: const Icon(Icons.skip_next),
|
||||
label: Text(l10n.nextRound),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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),
|
||||
),
|
||||
),
|
||||
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),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _finalizarPartidaOnline(BuildContext context) async {
|
||||
final estado = context.read<EstadoJuego>();
|
||||
final nearby = context.read<ServicioNearby>();
|
||||
estado.comprobarFinPartida();
|
||||
await nearby.enviarFinPartida(
|
||||
_snapshot(fase: 'finPartida', revelarFinal: true).toJson(),
|
||||
);
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _iniciarAdivinanzaOnline(BuildContext context) async {
|
||||
final estado = context.read<EstadoJuego>();
|
||||
final nearby = context.read<ServicioNearby>();
|
||||
estado.iniciarAdivinanza();
|
||||
await nearby.enviarCambioFase(
|
||||
'adivinanza',
|
||||
_snapshot(
|
||||
fase: 'adivinanza',
|
||||
mensaje: AppLocalizations.of(context)!.impostorCanGuess,
|
||||
).toJson(),
|
||||
);
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _resolverAdivinanzaOnline(BuildContext context) async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final controller = TextEditingController();
|
||||
final intento = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: Text(l10n.impostorGuessTitle),
|
||||
content: TextField(
|
||||
controller: controller,
|
||||
autofocus: true,
|
||||
decoration: InputDecoration(hintText: l10n.guessWordHint),
|
||||
onSubmitted: (value) => Navigator.pop(ctx, value),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
child: Text(l10n.cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, controller.text),
|
||||
child: Text(l10n.accept),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
controller.dispose();
|
||||
if (!context.mounted) return;
|
||||
if (intento == null || intento.trim().isEmpty) {
|
||||
await _siguienteRondaOnline(context);
|
||||
return;
|
||||
}
|
||||
final estado = context.read<EstadoJuego>();
|
||||
final acierto = estado.intentarAdivinar(intento);
|
||||
if (acierto) {
|
||||
final nearby = context.read<ServicioNearby>();
|
||||
await nearby.enviarFinPartida(
|
||||
_snapshot(fase: 'finPartida', revelarFinal: true).toJson(),
|
||||
);
|
||||
if (mounted) setState(() {});
|
||||
return;
|
||||
}
|
||||
await _siguienteRondaOnline(context);
|
||||
}
|
||||
|
||||
Future<void> _siguienteRondaOnline(BuildContext context) async {
|
||||
final estado = context.read<EstadoJuego>();
|
||||
final nearby = context.read<ServicioNearby>();
|
||||
estado.siguienteRonda();
|
||||
_primerTurnoId = null;
|
||||
_primerTurnoNombre = null;
|
||||
final primero = _elegirPrimerTurno();
|
||||
await nearby.enviarCambioFase('debate', {
|
||||
..._snapshot(fase: 'debate').toJson(),
|
||||
if (primero != null) ...{
|
||||
'primerTurnoId': primero.id,
|
||||
'primerTurnoNombre': primero.nombre,
|
||||
},
|
||||
if (estado.partida?.config.tiempoDebateSegundos != null)
|
||||
'tiempoDebateSegundos': estado.partida!.config.tiempoDebateSegundos,
|
||||
});
|
||||
_timer?.cancel();
|
||||
_iniciarTemporizador();
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
class _PantallaRevelarPalabraHost extends StatefulWidget {
|
||||
|
||||
Reference in New Issue
Block a user