Files
farolero/lib/pantallas/pantalla_adivinanza.dart
T
FreeTLab 56f07364c2
Build & Deploy Farolero / Análisis de código (push) Successful in 13s
Build & Deploy Farolero / Build APK + AAB release (push) Successful in 1m22s
feat: confirm before leaving a game, and fix untranslated strings
Exit confirmation
- A dialog in the app's own style now guards every in-game screen. The safe
  action is the prominent one, so a stray tap keeps you in the game.
- Eleven screens covered, against both the system back gesture and the close
  buttons. The message adapts: a single-device game is lost, a host ends it
  for everyone, a client can rejoin.
- The two screens the host also opens from the manager take a flag so that
  back there just closes them instead of offering to quit.

Translations
- 21 keys were still holding the English text in Arabic, Basque, Hindi,
  Japanese, Korean, Dutch, Polish, Russian, Turkish and both Chinese
  variants: 231 strings, covering the whole multi-device flow, permissions
  and the mode picker. Nothing failed, the app just showed English.
- The permissions dialog was hardcoded in Spanish; it is localized now.
- Portuguese used Spanish gerunds where pt-PT takes "a + infinitive".

Checked what looked untranslated but is not: Animals and Notes are correct
Catalan, Configuration and Vibration correct French, Version correct German.
Those are whitelisted in the new test rather than silently rewritten.

l10n_cobertura_test guards all of it: no missing or orphan keys, no empty
values, no English left outside the whitelist, and placeholders preserved.
2026-07-25 23:59:57 +02:00

196 lines
6.3 KiB
Dart

import 'package:flutter/material.dart';
import '../tema/dialogo_confirmacion.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:provider/provider.dart';
import '../estado/estado_juego.dart';
import '../tema/componentes_farolero.dart';
import '../tema/tema_app.dart';
import 'pantalla_debate.dart';
import 'pantalla_fin_partida.dart';
class PantallaAdivinanza extends StatefulWidget {
const PantallaAdivinanza({super.key});
@override
State<PantallaAdivinanza> createState() => _PantallaAdivinanzaState();
}
class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
final _controlador = TextEditingController();
bool? _acierto;
@override
void dispose() {
_controlador.dispose();
super.dispose();
}
void _intentarAdivinar() {
final estado = context.read<EstadoJuego>();
final resultado = estado.intentarAdivinar(_controlador.text);
setState(() => _acierto = resultado);
}
void _continuarTrasNoAdivinar(EstadoJuego estado) {
final fin = estado.comprobarFinPartida();
if (fin) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const PantallaFinPartida()),
);
} else {
estado.siguienteRonda();
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const PantallaDebate()),
);
}
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final estado = context.watch<EstadoJuego>();
final partida = estado.partida;
if (partida == null) return const SizedBox.shrink();
return GuardiaSalidaPartida(
contexto: ContextoSalida.unDispositivo,
child: Scaffold(
appBar: AppBar(
title: Text(l10n.impostorGuessTitle),
automaticallyImplyLeading: false,
),
body: FondoFarolero(
intenso: true,
child: SafeArea(
child: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const ArteGameplayFarolero.fase(height: 132),
const SizedBox(height: 12),
TarjetaFaseFarolero(
icono: Icons.theater_comedy,
assetIconPath: 'assets/ui/generated/actions/action_impostor_mask.webp',
titulo: l10n.impostorCanGuess,
subtitulo: l10n.ifCorrectImpostorsWin,
color: TemaApp.colorAcento,
child: _buildContenido(context, l10n, estado, partida.palabraSecreta),
),
],
),
),
),
),
),
),
);
}
Widget _buildContenido(
BuildContext context,
AppLocalizations l10n,
EstadoJuego estado,
String palabraSecreta,
) {
if (_acierto == null) {
return Column(
children: [
TextField(
controller: _controlador,
decoration: InputDecoration(
hintText: l10n.guessWordHint,
prefixIcon: IconoFarolero(Icons.search),
),
textCapitalization: TextCapitalization.sentences,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20),
onChanged: (value) => setState(() {}),
onSubmitted: (value) => _intentarAdivinar(),
),
const SizedBox(height: 24),
Row(
children: [
Expanded(
child: BotonFarolero.oscuro(
texto: l10n.dontGuess,
icono: Icons.skip_next,
onPressed: () => _continuarTrasNoAdivinar(estado),
),
),
const SizedBox(width: 12),
Expanded(
flex: 2,
child: BotonFarolero(
texto: l10n.guess,
icono: Icons.send,
assetIconPath: 'assets/ui/generated/actions/action_impostor_mask.webp',
onPressed: _controlador.text.trim().isNotEmpty ? _intentarAdivinar : null,
),
),
],
),
],
);
}
final acierto = _acierto == true;
final color = acierto ? TemaApp.colorAcento : TemaApp.colorVerde;
return Column(
children: [
PanelFarolero(
padding: const EdgeInsets.all(24),
borderColor: color,
color: color.withValues(alpha: 0.18),
child: Column(
children: [
IconoFarolero(
acierto ? Icons.celebration : Icons.cancel,
color: color,
size: 52,
),
const SizedBox(height: 12),
Text(
acierto ? l10n.correctGuess : l10n.wrongGuess,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headlineMedium?.copyWith(color: color),
),
const SizedBox(height: 8),
Text(
acierto ? l10n.theWordWas(palabraSecreta) : l10n.gameContinues,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleLarge,
),
if (acierto) ...[
const SizedBox(height: 8),
Text(
l10n.impostorsWin,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyLarge?.copyWith(color: TemaApp.colorNaranja),
),
],
],
),
),
const SizedBox(height: 24),
BotonFarolero(
texto: acierto ? l10n.seeEndResult : l10n.nextRound,
icono: acierto ? Icons.emoji_events : Icons.skip_next,
assetIconPath: acierto ? 'assets/ui/generated/actions/action_result_trophy.webp' : null,
onPressed: acierto
? () {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const PantallaFinPartida()),
);
}
: () => _continuarTrasNoAdivinar(estado),
),
],
);
}
}