nuevas pantallas

This commit is contained in:
2026-05-11 18:44:51 +02:00
parent f8545fc783
commit 2503b64d34
18 changed files with 179 additions and 67 deletions
+2
View File
@@ -50,6 +50,8 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const ArteGameplayFarolero.fase(height: 132),
const SizedBox(height: 12),
EncabezadoFarolero(
icono: Icons.theater_comedy,
titulo: l10n.impostorCanGuess,
+2
View File
@@ -82,6 +82,8 @@ class _PantallaDebateState extends State<PantallaDebate> {
padding: const EdgeInsets.all(16),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 110),
const SizedBox(height: 10),
// Temporizador
if (tieneTemporizador) ...[
Container(
+3 -1
View File
@@ -164,6 +164,8 @@ class _PantallaDebateClienteState extends State<PantallaDebateCliente> {
padding: const EdgeInsets.all(24),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 124),
const SizedBox(height: 10),
const Spacer(),
// Timer
@@ -242,7 +244,7 @@ class _PantallaDebateClienteState extends State<PantallaDebateCliente> {
const SizedBox(width: 12),
Expanded(
child: Text(
'Empieza ${widget.primerTurnoNombre} diciendo su palabra.',
widget.primerTurnoNombre!,
style: Theme.of(context).textTheme.titleMedium,
),
),
+32 -24
View File
@@ -209,28 +209,30 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_buildAvisoClientesDesconectados(context, nearby),
_buildFaseIndicator(context, partida.fase, l10n),
const SizedBox(height: 16),
Expanded(
child: _buildContenidoFase(
children: [
_buildAvisoClientesDesconectados(context, nearby),
_buildFaseIndicator(context, partida.fase, l10n),
const SizedBox(height: 8),
const ArteGameplayFarolero.fase(height: 92),
const SizedBox(height: 16),
Expanded(
child: _buildContenidoFase(
context,
partida.fase,
l10n,
todosListos,
todosVotaron,
),
),
const SizedBox(height: 16),
_buildBotonAccion(
context,
partida.fase,
l10n,
todosListos,
todosVotaron,
),
),
const SizedBox(height: 16),
_buildBotonAccion(
context,
partida.fase,
l10n,
todosListos,
todosVotaron,
),
],
],
),
),
),
@@ -703,8 +705,8 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
icon: const Icon(Icons.how_to_vote),
label: Text(
_hostYaVoto(context)
? 'Votos del host registrados'
: 'Votar por los jugadores de este móvil',
? l10n.playersVoted
: l10n.confirmVote,
),
),
),
@@ -1055,9 +1057,10 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
),
child: Row(
children: [
Text(
esHost ? 'Host' : 'Cliente',
style: const TextStyle(fontSize: 18),
Icon(
esHost ? Icons.phone_android : Icons.devices,
color: esHost ? TemaApp.colorDorado : TemaApp.colorNaranja,
size: 22,
),
const SizedBox(width: 8),
Expanded(child: Text(nombre)),
@@ -1410,9 +1413,14 @@ class _PantallaRevelarPalabraHostState
child: _manteniendo
? Column(
children: [
Text(
widget.esImpostor ? 'Impostor' : 'Ciudadano',
style: const TextStyle(fontSize: 48),
Icon(
widget.esImpostor
? Icons.theater_comedy
: Icons.key,
color: widget.esImpostor
? TemaApp.colorAcento
: TemaApp.colorVerde,
size: 48,
),
const SizedBox(height: 16),
Text(
+4
View File
@@ -104,6 +104,8 @@ class _PantallaNotasState extends State<PantallaNotas> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ArteGameplayFarolero.notas(height: 138),
const SizedBox(height: 10),
Text(
l10n.whoAreYou,
style: Theme.of(context).textTheme.headlineMedium,
@@ -159,6 +161,8 @@ class _PantallaNotasState extends State<PantallaNotas> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ArteGameplayFarolero.notas(height: 120),
const SizedBox(height: 8),
Row(
children: [
IconButton(
+4
View File
@@ -130,6 +130,8 @@ class _PantallaNotasOnlineState extends State<PantallaNotasOnline> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ArteGameplayFarolero.notas(height: 138),
const SizedBox(height: 10),
Text(
AppLocalizations.of(context)!.whoAreYou,
style: Theme.of(context).textTheme.headlineSmall,
@@ -165,6 +167,8 @@ class _PantallaNotasOnlineState extends State<PantallaNotasOnline> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ArteGameplayFarolero.notas(height: 120),
const SizedBox(height: 8),
Row(
children: [
if (widget.autoresControlados.length > 1)
+4 -2
View File
@@ -56,6 +56,8 @@ class _PantallaPalabraClienteState extends State<PantallaPalabraCliente> {
padding: const EdgeInsets.all(24),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 124),
const SizedBox(height: 12),
const Spacer(),
// Tarjeta de palabra
GestureDetector(
@@ -136,7 +138,7 @@ class _PantallaPalabraClienteState extends State<PantallaPalabraCliente> {
const SizedBox(width: 8),
Flexible(
child: Text(
'🎭 ${l10n.clueIs(widget.pistaCategoria!)}',
'\u{1F3AD} ${l10n.clueIs(widget.pistaCategoria!)}',
style: const TextStyle(color: TemaApp.colorAcento),
),
),
@@ -151,7 +153,7 @@ class _PantallaPalabraClienteState extends State<PantallaPalabraCliente> {
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
_palabraVisible
? 'Mantén la pantalla oculta. No la enseñes a nadie.'
? l10n.makeSureNoOneLooks
: _haRevelado
? l10n.seeYourWord
: l10n.tapToSee,
+3 -1
View File
@@ -55,8 +55,10 @@ class _PantallaPalabrasClienteState extends State<PantallaPalabrasCliente> {
padding: const EdgeInsets.all(24),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 116),
const SizedBox(height: 8),
Text(
'Jugador ${_indice + 1} de ${widget.jugadores.length}',
'${l10n.defaultPlayerName} ${_indice + 1} / ${widget.jugadores.length}',
style: Theme.of(context).textTheme.titleMedium,
),
const Spacer(),
+2
View File
@@ -24,6 +24,8 @@ class PantallaReglas extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const ArteGameplayFarolero.notas(height: 126),
const SizedBox(height: 10),
EncabezadoFarolero(
icono: Icons.menu_book_rounded,
titulo: l10n.rulesTitle,
+4
View File
@@ -38,6 +38,8 @@ class _PantallaVerPalabraState extends State<PantallaVerPalabra> {
padding: const EdgeInsets.all(16),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 110),
const SizedBox(height: 10),
EncabezadoFarolero(
icono: Icons.visibility,
titulo: l10n.roundNumber(partida.rondaActual),
@@ -174,6 +176,8 @@ class _PantallaRevelarPalabraState extends State<_PantallaRevelarPalabra> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const ArteGameplayFarolero.fase(height: 128),
const SizedBox(height: 12),
Text(
widget.nombre,
style: Theme.of(context).textTheme.headlineMedium,
+36 -34
View File
@@ -65,6 +65,8 @@ class _PantallaVotacionState extends State<PantallaVotacion> {
padding: const EdgeInsets.all(16),
child: Column(
children: [
const ArteGameplayFarolero.fase(height: 108),
const SizedBox(height: 10),
// Progreso de votos
Container(
width: double.infinity,
@@ -192,41 +194,41 @@ class _PantallaVotacionState extends State<PantallaVotacion> {
child: Padding(
padding: const EdgeInsets.all(32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('🗳️', style: TextStyle(fontSize: 64)),
const SizedBox(height: 24),
Text(
l10n.allVoted,
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 16),
Text(
l10n.tapToReveal,
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 32),
SizedBox(
width: double.infinity,
height: 56,
child: ElevatedButton.icon(
onPressed: () {
final resultado = estado.procesarVotacion();
if (resultado != null) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) =>
PantallaResultado(resultado: resultado),
),
);
}
},
icon: const Icon(Icons.visibility),
label: Text(l10n.revealResult),
mainAxisAlignment: MainAxisAlignment.center,
children: [
const ArteGameplayFarolero.fase(height: 132),
const SizedBox(height: 24),
Text(
l10n.allVoted,
style: Theme.of(context).textTheme.headlineMedium,
),
),
],
const SizedBox(height: 16),
Text(
l10n.tapToReveal,
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 32),
SizedBox(
width: double.infinity,
height: 56,
child: ElevatedButton.icon(
onPressed: () {
final resultado = estado.procesarVotacion();
if (resultado != null) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) =>
PantallaResultado(resultado: resultado),
),
);
}
},
icon: const Icon(Icons.visibility),
label: Text(l10n.revealResult),
),
),
],
),
),
),
+6 -4
View File
@@ -134,12 +134,12 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ArteGameplayFarolero.fase(height: 108),
const SizedBox(height: 10),
EncabezadoFarolero(
icono: Icons.how_to_vote,
titulo: l10n.whoDoYouThinkIsTheImpostor,
subtitulo: _modoMultiVotante
? 'Emití un voto por cada jugador que manejás.'
: l10n.selectOnePlayer,
subtitulo: l10n.selectOnePlayer,
color: TemaApp.colorAcento,
trailing: Image.asset(
'assets/ui/premium/vote_danger_glow.png',
@@ -254,6 +254,8 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ArteGameplayFarolero.fase(height: 118),
const SizedBox(height: 10),
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
@@ -275,7 +277,7 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
),
const SizedBox(height: 8),
Text(
eraImpostor ? 'Era impostor' : 'Era inocente',
eraImpostor ? l10n.wasImpostor : l10n.wasInnocent,
style: TextStyle(
color: eraImpostor
? TemaApp.colorVerde
+73
View File
@@ -22,6 +22,19 @@ class FondoFarolero extends StatelessWidget {
decoration: const BoxDecoration(gradient: TemaApp.gradienteFondo),
child: Stack(
children: [
if (intenso)
Positioned.fill(
child: IgnorePointer(
child: Image.asset(
'assets/ui/generated/gameplay/gameplay_atmosphere_bg.png',
fit: BoxFit.cover,
opacity: const AlwaysStoppedAnimation(0.30),
filterQuality: FilterQuality.high,
errorBuilder: (context, error, stackTrace) =>
const SizedBox.shrink(),
),
),
),
Positioned.fill(
child: CustomPaint(painter: _FondoFaroleroPainter(intenso: intenso)),
),
@@ -383,6 +396,56 @@ class BotonFarolero extends StatelessWidget {
}
}
class ArteGameplayFarolero extends StatelessWidget {
final String assetPath;
final double height;
final double opacity;
final EdgeInsetsGeometry padding;
const ArteGameplayFarolero({
super.key,
required this.assetPath,
this.height = 128,
this.opacity = 0.92,
this.padding = EdgeInsets.zero,
});
const ArteGameplayFarolero.fase({
super.key,
this.height = 128,
this.opacity = 0.92,
this.padding = EdgeInsets.zero,
}) : assetPath = 'assets/ui/generated/gameplay/gameplay_phase_emblem.png';
const ArteGameplayFarolero.notas({
super.key,
this.height = 150,
this.opacity = 0.94,
this.padding = EdgeInsets.zero,
}) : assetPath = 'assets/ui/generated/gameplay/notes_strategy_art.png';
@override
Widget build(BuildContext context) {
return ExcludeSemantics(
child: Padding(
padding: padding,
child: SizedBox(
height: height,
width: double.infinity,
child: Image.asset(
assetPath,
fit: BoxFit.contain,
opacity: AlwaysStoppedAnimation(opacity),
filterQuality: FilterQuality.high,
errorBuilder: (context, error, stackTrace) =>
const SizedBox.shrink(),
),
),
),
);
}
}
class AccesoFarolero extends StatelessWidget {
final String etiqueta;
final IconData icono;
@@ -452,6 +515,16 @@ class TarjetaPalabraFarolero extends StatelessWidget {
child: Stack(
alignment: Alignment.center,
children: [
Positioned.fill(
child: Image.asset(
'assets/ui/generated/gameplay/gameplay_phase_emblem.png',
fit: BoxFit.contain,
opacity: const AlwaysStoppedAnimation(0.14),
filterQuality: FilterQuality.high,
errorBuilder: (context, error, stackTrace) =>
const SizedBox.shrink(),
),
),
Positioned.fill(
child: Image.asset(
'assets/ui/premium/word_reveal_glow.png',