Play rejected version code 54 for still targeting 34. From API 35 Android forces edge-to-edge: content is drawn behind the system bars and it is up to each screen to keep clear of them. Seven screens had no SafeArea and their bottom action button would have ended up under the gesture bar, so FondoFarolero gains a respetarBarras flag that insets the content while the background still paints full bleed. The seventeen screens that already handle it are untouched. The navigation bar colour is ignored under edge-to-edge, so its icons are now forced light to stay visible over the dark background. Verified on the merged manifest: targetSdkVersion 35, and the release bundle builds. The visual result has not been checked on a device.
166 lines
4.7 KiB
Dart
166 lines
4.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:farolero/l10n/generated/app_localizations.dart';
|
|
import 'package:provider/provider.dart';
|
|
import '../estado/estado_juego.dart';
|
|
import '../modelos/partida.dart';
|
|
import '../tema/componentes_farolero.dart';
|
|
import '../tema/componentes_resultado_farolero.dart';
|
|
import '../tema/tema_app.dart';
|
|
import 'pantalla_adivinanza.dart';
|
|
import 'pantalla_debate.dart';
|
|
import 'pantalla_fin_partida.dart';
|
|
|
|
class PantallaResultado extends StatefulWidget {
|
|
final ResultadoVotacion resultado;
|
|
|
|
const PantallaResultado({super.key, required this.resultado});
|
|
|
|
@override
|
|
State<PantallaResultado> createState() => _PantallaResultadoState();
|
|
}
|
|
|
|
class _PantallaResultadoState extends State<PantallaResultado>
|
|
with SingleTickerProviderStateMixin {
|
|
bool _revelado = false;
|
|
late AnimationController _animController;
|
|
late Animation<double> _animOpacidad;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_animController = AnimationController(
|
|
duration: const Duration(milliseconds: 2500),
|
|
vsync: this,
|
|
);
|
|
_animOpacidad = Tween<double>(begin: 0.0, end: 1.0).animate(
|
|
CurvedAnimation(
|
|
parent: _animController,
|
|
curve: const Interval(0.6, 1.0, curve: Curves.easeIn),
|
|
),
|
|
);
|
|
|
|
// Iniciar animación de suspense
|
|
Future.delayed(const Duration(milliseconds: 500), () {
|
|
_animController.forward().then((_) {
|
|
setState(() => _revelado = true);
|
|
});
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_animController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = AppLocalizations.of(context)!;
|
|
final estado = context.read<EstadoJuego>();
|
|
final partida = estado.partida;
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text(l10n.result),
|
|
automaticallyImplyLeading: false,
|
|
),
|
|
body: FondoFarolero(
|
|
intenso: true,
|
|
respetarBarras: true,
|
|
child: Center(
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.all(32),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
// Animación de suspense
|
|
if (!_revelado) ...[
|
|
const ArteGameplayFarolero.resultado(height: 152),
|
|
const SizedBox(height: 16),
|
|
Text(
|
|
l10n.revealing,
|
|
style: Theme.of(context).textTheme.headlineMedium,
|
|
),
|
|
const SizedBox(height: 24),
|
|
const CircularProgressIndicator(color: TemaApp.colorAcento),
|
|
],
|
|
|
|
if (_revelado) ...[
|
|
FadeTransition(
|
|
opacity: _animOpacidad,
|
|
child: ResultadoRondaFarolero(
|
|
resultado: widget.resultado,
|
|
jugadores: partida?.jugadores ?? const [],
|
|
acciones: _construirBotones(context, estado),
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _construirBotones(BuildContext context, EstadoJuego estado) {
|
|
final l10n = AppLocalizations.of(context)!;
|
|
final partida = estado.partida;
|
|
if (partida == null) return const SizedBox.shrink();
|
|
|
|
final finPartida = estado.comprobarFinPartida();
|
|
|
|
if (finPartida) {
|
|
return BotonFarolero(
|
|
texto: l10n.seeEndResult,
|
|
icono: Icons.emoji_events,
|
|
onPressed: () {
|
|
Navigator.pushReplacement(
|
|
context,
|
|
MaterialPageRoute(builder: (_) => const PantallaFinPartida()),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
if (widget.resultado.eraImpostor) {
|
|
return Column(
|
|
children: [
|
|
BotonFarolero.oscuro(
|
|
texto: l10n.impostorGuessWord,
|
|
icono: Icons.gps_fixed,
|
|
onPressed: () {
|
|
Navigator.pushReplacement(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (_) => const PantallaAdivinanza(),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
const SizedBox(height: 12),
|
|
BotonFarolero(
|
|
texto: l10n.nextRound,
|
|
icono: Icons.skip_next,
|
|
onPressed: () => _siguienteRonda(context, estado),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
return BotonFarolero(
|
|
texto: l10n.nextRound,
|
|
icono: Icons.skip_next,
|
|
onPressed: () => _siguienteRonda(context, estado),
|
|
);
|
|
}
|
|
|
|
void _siguienteRonda(BuildContext context, EstadoJuego estado) {
|
|
estado.siguienteRonda();
|
|
Navigator.pushReplacement(
|
|
context,
|
|
MaterialPageRoute(builder: (_) => const PantallaDebate()),
|
|
);
|
|
}
|
|
}
|