Files
farolero/lib/pantallas/pantalla_palabras_cliente.dart
freetlab 6e5e423ab4 Implementado:
No se puede marcar “vista” sin revelar la palabra antes.
Se puede volver a ver la palabra durante debate/votación/resultado.
Notas online privadas por partida y jugador.
Tests añadidos para notas scoped.
Ajusté roomId en el payload de inicio para que las notas no se mezclen entre partidas.
2026-05-05 21:49:40 +02:00

152 lines
5.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:farolero/modelos/inicio_partida_multijugador.dart';
import 'package:farolero/tema/componentes_farolero.dart';
import 'package:farolero/tema/tema_app.dart';
/// Reveal secuencial para clientes que manejan uno o varios jugadores.
class PantallaPalabrasCliente extends StatefulWidget {
final List<JugadorInicioPartida> jugadores;
final String? pistaCategoria;
final VoidCallback onTodosVistos;
const PantallaPalabrasCliente({
super.key,
required this.jugadores,
this.pistaCategoria,
required this.onTodosVistos,
});
@override
State<PantallaPalabrasCliente> createState() => _PantallaPalabrasClienteState();
}
class _PantallaPalabrasClienteState extends State<PantallaPalabrasCliente> {
int _indice = 0;
bool _visible = false;
final Set<String> _jugadoresRevelados = {};
JugadorInicioPartida get _actual => widget.jugadores[_indice];
bool get _esUltimo => _indice == widget.jugadores.length - 1;
bool get _actualRevelado => _jugadoresRevelados.contains(_actual.jugadorId);
void _continuar() {
if (!_actualRevelado) return;
if (_esUltimo) {
widget.onTodosVistos();
return;
}
setState(() {
_indice++;
_visible = false;
});
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final actual = _actual;
return Scaffold(
body: FondoFarolero(
intenso: true,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
children: [
Text(
'Jugador ${_indice + 1} de ${widget.jugadores.length}',
style: Theme.of(context).textTheme.titleMedium,
),
const Spacer(),
Text(
actual.nombre,
style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
GestureDetector(
onTap: () => setState(() {
_visible = !_visible;
if (_visible) _jugadoresRevelados.add(actual.jugadorId);
}),
child: AnimatedContainer(
duration: const Duration(milliseconds: 250),
width: double.infinity,
padding: const EdgeInsets.symmetric(
vertical: 48,
horizontal: 24,
),
decoration: BoxDecoration(
color: _visible ? TemaApp.colorSuperficie : TemaApp.colorTarjeta,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: _visible ? TemaApp.colorNaranja : TemaApp.colorBorde,
),
),
child: Column(
children: [
Icon(
_visible ? Icons.visibility : Icons.visibility_off,
color: _visible ? Colors.white : TemaApp.colorTextoSecundario,
size: 32,
),
const SizedBox(height: 16),
if (_visible && !actual.esImpostor)
TarjetaPalabraFarolero(palabra: actual.palabra ?? '')
else
Text(
_visible ? l10n.youAreImpostor : '???',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: _visible
? TemaApp.colorDorado
: TemaApp.colorTextoSecundario,
),
),
],
),
),
),
if (_visible && actual.esImpostor && widget.pistaCategoria != null) ...[
const SizedBox(height: 12),
Text(
l10n.clueIs(widget.pistaCategoria!),
style: const TextStyle(color: TemaApp.colorNaranja),
textAlign: TextAlign.center,
),
],
const SizedBox(height: 12),
Text(
_actualRevelado
? l10n.seeYourWord
: l10n.tapToSee,
textAlign: TextAlign.center,
style: TextStyle(color: TemaApp.colorTextoSecundario),
),
const Spacer(),
SizedBox(
width: double.infinity,
height: 56,
child: ElevatedButton.icon(
onPressed: _actualRevelado ? _continuar : null,
icon: Icon(_esUltimo ? Icons.check : Icons.arrow_forward),
label: Text(
_actualRevelado
? (_esUltimo ? l10n.iveSeenIt : l10n.next)
: l10n.tapToSee,
),
),
),
],
),
),
),
),
);
}
}