Cambios visuales completos
BIN
assets/ui/premium/card_sheen_overlay.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/ui/premium/corner_orange_glow.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
assets/ui/premium/lantern_radial_glow.png
Normal file
|
After Width: | Height: | Size: 285 KiB |
BIN
assets/ui/premium/qr_frame_overlay.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
assets/ui/premium/sparks_overlay.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/ui/premium/timer_ring_glow.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
assets/ui/premium/vote_danger_glow.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
assets/ui/premium/word_reveal_glow.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
58
docs/premium_screen_mockups.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Maquetas premium por pantalla
|
||||||
|
|
||||||
|
Estas maquetas son la guía de implementación. No son screenshots finales: definen composición, jerarquía y assets por pantalla para mantener coherencia sin romper Flutter/localización/estado.
|
||||||
|
|
||||||
|
## Sistema común
|
||||||
|
|
||||||
|
- Fondo: noche azul-negro + glow de farol + chispas.
|
||||||
|
- Paneles: cristal oscuro, borde dorado fino, sheen transparente.
|
||||||
|
- CTAs: primario dorado/naranja, secundarios cristal oscuro.
|
||||||
|
- Iconografía: farol/fuego/máscara/voto/QR según fase.
|
||||||
|
- Assets base: `assets/ui/premium/lantern_radial_glow.png`, `card_sheen_overlay.png`, `sparks_overlay.png`, `corner_orange_glow.png`.
|
||||||
|
- Assets específicos ya creados: `word_reveal_glow.png`, `vote_danger_glow.png`, `qr_frame_overlay.png`, `timer_ring_glow.png`.
|
||||||
|
|
||||||
|
## Entrada y lobby
|
||||||
|
|
||||||
|
| Pantalla | Maqueta objetivo | Assets |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Principal | Perfil glass arriba, hero FAROLERO, CTA JUGAR dominante, secundarios debajo. | base |
|
||||||
|
| Selección modo | Hero “¿Cómo querés jugar?”, dos cards grandes con iconos y glow diferenciado. | base |
|
||||||
|
| Crear partida | Cabecera de configuración, cards por sección: modo, categoría, jugadores, reglas. CTA fijo visual al final. | base |
|
||||||
|
| Unirse | Paso guiado: nombre → búsqueda → sala → espera. Estados con cards amplias y feedback luminoso. | base + futuro scan frame |
|
||||||
|
| Lobby host | QR como pieza hero en marco dorado, stats compactos, lista de usuarios en panel alto, CTA iniciar fuerte. | base + futuro qr frame |
|
||||||
|
|
||||||
|
## Palabra y debate
|
||||||
|
|
||||||
|
| Pantalla | Maqueta objetivo | Assets |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Ver palabra | Card secreta teatral, gesto de “tap/reveal”, aviso de privacidad. | base + word glow |
|
||||||
|
| Palabra cliente | Igual que ver palabra, adaptado a remoto. | base + word glow |
|
||||||
|
| Palabras cliente | Carrusel/lista de jugadores controlados con estado “visto/no visto”. | base |
|
||||||
|
| Debate host/cliente | Timer o estado central como módulo hero, lista de jugadores activa, accesos a notas/palabra. | base + timer ring futuro |
|
||||||
|
| Revisión palabra | Bottom sheet oscuro, cards de roles/palabra con glow discreto. | base |
|
||||||
|
| Notas host/online | Selector de jugador arriba, editor en panel cristal, guardado visible. | base |
|
||||||
|
|
||||||
|
## Votación y resultados
|
||||||
|
|
||||||
|
| Pantalla | Maqueta objetivo | Assets |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Votación host/cliente | Header “Votación”, candidatos como cards con avatar, peligro rojo y CTA votar. | base + vote glow |
|
||||||
|
| Resultado host/online | Eliminado como hero card, barras/votos en paneles, decisión clara de siguiente fase. | base |
|
||||||
|
| Adivinanza | Máscara impostor grande, input protagonista, dos CTAs con tensión visual. | base + danger glow |
|
||||||
|
| Fin partida host/online | Cinemática de resultado, recompensas, palabra, impostor y votos como cards premium. | rewards + base |
|
||||||
|
|
||||||
|
## Soporte
|
||||||
|
|
||||||
|
| Pantalla | Maqueta objetivo | Assets |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Gestor host | Dashboard de fase: estado arriba, jugadores, acciones de host, controles claros. | base |
|
||||||
|
| Historial | Timeline/cards de partidas con resultado y medallas/fuego. | base |
|
||||||
|
| Reglas | Secciones tipo manual premium con iconos y numeración. | base |
|
||||||
|
| Ajustes | Perfil, idioma, avatar y opciones en secciones glass. | base |
|
||||||
|
|
||||||
|
## Assets específicos
|
||||||
|
|
||||||
|
- `assets/ui/premium/word_reveal_glow.png` — usado por `TarjetaPalabraFarolero`.
|
||||||
|
- `assets/ui/premium/vote_danger_glow.png` — usado en votación cliente.
|
||||||
|
- `assets/ui/premium/qr_frame_overlay.png` — usado en lobby host.
|
||||||
|
- `assets/ui/premium/timer_ring_glow.png` — usado en debate cliente.
|
||||||
78
docs/premium_screen_redesign_plan.md
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# Rediseño premium global de pantallas
|
||||||
|
|
||||||
|
Objetivo: que todas las pantallas de Farolero compartan una misma dirección visual premium: noche, farol, cristal oscuro, dorado/naranja, impostores, fuego, partículas y jerarquía clara.
|
||||||
|
|
||||||
|
## Regla de implementación
|
||||||
|
|
||||||
|
- Las pantallas siguen siendo Flutter real: textos, botones, listas, progreso, formularios y navegación.
|
||||||
|
- Los assets generados se usan como capas transparentes: glows, chispas, sheens, rayos y overlays.
|
||||||
|
- Los fondos full-screen pueden ser opacos, pero los overlays deben tener alpha real.
|
||||||
|
- Primero se aplica un sistema visual común; después se retoca cada pantalla por grupos.
|
||||||
|
|
||||||
|
## Asset kit base
|
||||||
|
|
||||||
|
| Asset | Uso | Transparencia |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `assets/ui/premium/lantern_radial_glow.png` | Glow hero/farol global | Alpha real, esquinas transparentes |
|
||||||
|
| `assets/ui/premium/card_sheen_overlay.png` | Brillo sutil para panels/botones | Alpha real, esquinas transparentes |
|
||||||
|
| `assets/ui/premium/sparks_overlay.png` | Partículas/chispas atmosféricas | Alpha real |
|
||||||
|
| `assets/ui/premium/corner_orange_glow.png` | Glow decorativo de esquina | Alpha real, visible en una esquina por diseño |
|
||||||
|
| `assets/ui/premium/word_reveal_glow.png` | Glow para revelar palabra | Alpha real, esquinas transparentes |
|
||||||
|
| `assets/ui/premium/vote_danger_glow.png` | Glow rojo de votación/peligro | Alpha real, esquinas transparentes |
|
||||||
|
| `assets/ui/premium/qr_frame_overlay.png` | Marco transparente para QR | Alpha real, esquinas transparentes |
|
||||||
|
| `assets/ui/premium/timer_ring_glow.png` | Aro de temporizador | Alpha real, esquinas transparentes |
|
||||||
|
|
||||||
|
## Pantallas por lote
|
||||||
|
|
||||||
|
### Lote 1 — Core shell y entrada
|
||||||
|
|
||||||
|
- `pantalla_principal.dart`
|
||||||
|
- `pantalla_seleccion_modo_juego.dart`
|
||||||
|
- `pantalla_crear_partida.dart`
|
||||||
|
- `pantalla_unirse.dart`
|
||||||
|
- `pantalla_lobby_host.dart`
|
||||||
|
|
||||||
|
### Lote 2 — Flujo de palabra y partida
|
||||||
|
|
||||||
|
- `pantalla_ver_palabra.dart`
|
||||||
|
- `pantalla_palabra_cliente.dart`
|
||||||
|
- `pantalla_palabras_cliente.dart`
|
||||||
|
- `pantalla_debate.dart`
|
||||||
|
- `pantalla_debate_cliente.dart`
|
||||||
|
- `pantalla_revision_palabra.dart`
|
||||||
|
|
||||||
|
### Lote 3 — Votación y resultado
|
||||||
|
|
||||||
|
- `pantalla_votacion.dart`
|
||||||
|
- `pantalla_votacion_cliente.dart`
|
||||||
|
- `pantalla_resultado.dart`
|
||||||
|
- `pantalla_resultado_online.dart`
|
||||||
|
- `pantalla_adivinanza.dart`
|
||||||
|
- `pantalla_fin_partida.dart`
|
||||||
|
- `pantalla_fin_partida_online.dart`
|
||||||
|
|
||||||
|
### Lote 4 — Soporte y configuración
|
||||||
|
|
||||||
|
- `pantalla_gestor_host.dart`
|
||||||
|
- `pantalla_notas.dart`
|
||||||
|
- `pantalla_notas_online.dart`
|
||||||
|
- `pantalla_historial.dart`
|
||||||
|
- `pantalla_reglas.dart`
|
||||||
|
- `pantalla_ajustes.dart`
|
||||||
|
|
||||||
|
## Aplicación global ya iniciada
|
||||||
|
|
||||||
|
- `FondoFarolero` ahora usa assets transparentes de glow y sparks para elevar todas las pantallas que ya lo usan.
|
||||||
|
- `PanelFarolero` ahora incorpora sheen transparente para una base glassmorphism común.
|
||||||
|
- `BotonFarolero` se hizo más redondeado, con brillo y sombra premium.
|
||||||
|
- Todas las pantallas con `Scaffold` principal quedan bajo `FondoFarolero` para unificar atmósfera.
|
||||||
|
- `EncabezadoFarolero` y `EstadoVacioFarolero` centralizan headers/estados premium reutilizables.
|
||||||
|
|
||||||
|
## Siguiente paso recomendado
|
||||||
|
|
||||||
|
Implementar por lotes, no todo a ciegas en un único mega-cambio. Cada lote debe:
|
||||||
|
|
||||||
|
1. Tener maqueta/objetivo visual.
|
||||||
|
2. Reutilizar el asset kit base.
|
||||||
|
3. Crear assets nuevos solo si el lote lo necesita.
|
||||||
|
4. Verificarse visualmente antes de seguir al siguiente.
|
||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:farolero/l10n/generated/app_localizations.dart';
|
import 'package:farolero/l10n/generated/app_localizations.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../estado/estado_juego.dart';
|
import '../estado/estado_juego.dart';
|
||||||
|
import '../tema/componentes_farolero.dart';
|
||||||
import '../tema/tema_app.dart';
|
import '../tema/tema_app.dart';
|
||||||
import 'pantalla_debate.dart';
|
import 'pantalla_debate.dart';
|
||||||
import 'pantalla_fin_partida.dart';
|
import 'pantalla_fin_partida.dart';
|
||||||
@@ -41,24 +42,24 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
|
|||||||
title: Text(l10n.impostorGuessTitle),
|
title: Text(l10n.impostorGuessTitle),
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
),
|
),
|
||||||
body: Center(
|
body: FondoFarolero(
|
||||||
child: SingleChildScrollView(
|
intenso: true,
|
||||||
|
child: Center(
|
||||||
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(32),
|
padding: const EdgeInsets.all(32),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Text('🎭', style: TextStyle(fontSize: 64)),
|
EncabezadoFarolero(
|
||||||
const SizedBox(height: 16),
|
icono: Icons.theater_comedy,
|
||||||
Text(
|
titulo: l10n.impostorCanGuess,
|
||||||
l10n.impostorCanGuess,
|
subtitulo: l10n.ifCorrectImpostorsWin,
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
color: TemaApp.colorAcento,
|
||||||
textAlign: TextAlign.center,
|
trailing: Image.asset(
|
||||||
),
|
'assets/ui/premium/vote_danger_glow.png',
|
||||||
const SizedBox(height: 8),
|
width: 42,
|
||||||
Text(
|
height: 42,
|
||||||
l10n.ifCorrectImpostorsWin,
|
opacity: const AlwaysStoppedAnimation(0.64),
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
||||||
color: TemaApp.colorNaranja,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
@@ -231,6 +232,7 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class _PantallaAjustesState extends State<PantallaAjustes> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(l10n.settingsTitle)),
|
appBar: AppBar(title: Text(l10n.settingsTitle)),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@@ -317,42 +317,23 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(l10n.createGame)),
|
appBar: AppBar(title: Text(l10n.createGame)),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.fromLTRB(18, 18, 18, 28),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
PanelFarolero(
|
EncabezadoFarolero(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 18),
|
icono: Icons.groups,
|
||||||
child: Row(
|
titulo: '¿Cómo quieres jugar?',
|
||||||
children: [
|
subtitulo: l10n.playersRange,
|
||||||
const Icon(Icons.groups, color: TemaApp.colorNaranja, size: 42),
|
|
||||||
const SizedBox(width: 14),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'¿Cómo quieres jugar?',
|
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 3),
|
|
||||||
Text(
|
|
||||||
l10n.playersRange,
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
if (!widget.bloquearModo) ...[
|
if (!widget.bloquearModo) ...[
|
||||||
// Modo de juego
|
// Modo de juego
|
||||||
Card(
|
Card(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.fromLTRB(18, 18, 18, 28),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -416,7 +397,7 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
|||||||
// Categoría
|
// Categoría
|
||||||
Card(
|
Card(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.fromLTRB(18, 18, 18, 28),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -453,7 +434,7 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
|||||||
// Jugadores
|
// Jugadores
|
||||||
Card(
|
Card(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.fromLTRB(18, 18, 18, 28),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -542,7 +523,7 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
|||||||
// Configuración de partida
|
// Configuración de partida
|
||||||
Card(
|
Card(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.fromLTRB(18, 18, 18, 28),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -614,22 +595,12 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
|||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
// Botón iniciar
|
// Botón iniciar
|
||||||
SizedBox(
|
BotonFarolero(
|
||||||
width: double.infinity,
|
texto: l10n.startGame,
|
||||||
height: 56,
|
icono: Icons.play_arrow,
|
||||||
child: ElevatedButton.icon(
|
onPressed: (_modoMultimovil || _jugadores.length >= 3)
|
||||||
onPressed: (_modoMultimovil || _jugadores.length >= 3)
|
? _iniciarPartida
|
||||||
? _iniciarPartida
|
: null,
|
||||||
: null,
|
|
||||||
icon: const Icon(Icons.play_arrow),
|
|
||||||
label: Text(l10n.startGame),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
textStyle: const TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ class _PantallaDebateState extends State<PantallaDebate> {
|
|||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
),
|
),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -95,40 +96,56 @@ class _PantallaDebateState extends State<PantallaDebate> {
|
|||||||
? Border.all(color: TemaApp.colorAcento, width: 2)
|
? Border.all(color: TemaApp.colorAcento, width: 2)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Positioned.fill(
|
||||||
_tiempoAgotado ? l10n.timeUp : l10n.timeRemaining,
|
child: Image.asset(
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
'assets/ui/premium/timer_ring_glow.png',
|
||||||
color: _tiempoAgotado
|
fit: BoxFit.contain,
|
||||||
? TemaApp.colorAcento
|
opacity: const AlwaysStoppedAnimation(0.36),
|
||||||
: TemaApp.colorTextoSecundario,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
Column(
|
||||||
Text(
|
mainAxisSize: MainAxisSize.min,
|
||||||
_formatearTiempo(_segundosRestantes),
|
children: [
|
||||||
style: Theme.of(context).textTheme.headlineLarge?.copyWith(
|
Text(
|
||||||
fontSize: 48,
|
_tiempoAgotado ? l10n.timeUp : l10n.timeRemaining,
|
||||||
fontWeight: FontWeight.bold,
|
style:
|
||||||
color: _segundosRestantes < 10 && !_tiempoAgotado
|
Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
? TemaApp.colorAcento
|
color: _tiempoAgotado
|
||||||
: TemaApp.colorTexto,
|
? TemaApp.colorAcento
|
||||||
),
|
: TemaApp.colorTextoSecundario,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
child: LinearProgressIndicator(
|
|
||||||
value: progreso,
|
|
||||||
backgroundColor: TemaApp.colorSuperficie,
|
|
||||||
valueColor: AlwaysStoppedAnimation(
|
|
||||||
_segundosRestantes < 10
|
|
||||||
? TemaApp.colorAcento
|
|
||||||
: TemaApp.colorVerde,
|
|
||||||
),
|
),
|
||||||
minHeight: 6,
|
const SizedBox(height: 8),
|
||||||
),
|
Text(
|
||||||
|
_formatearTiempo(_segundosRestantes),
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.headlineLarge?.copyWith(
|
||||||
|
fontSize: 48,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: _segundosRestantes < 10 &&
|
||||||
|
!_tiempoAgotado
|
||||||
|
? TemaApp.colorAcento
|
||||||
|
: TemaApp.colorTexto,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
child: LinearProgressIndicator(
|
||||||
|
value: progreso,
|
||||||
|
backgroundColor: TemaApp.colorSuperficie,
|
||||||
|
valueColor: AlwaysStoppedAnimation(
|
||||||
|
_segundosRestantes < 10
|
||||||
|
? TemaApp.colorAcento
|
||||||
|
: TemaApp.colorVerde,
|
||||||
|
),
|
||||||
|
minHeight: 6,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:farolero/pantallas/pantalla_notas_online.dart';
|
|||||||
import 'package:farolero/pantallas/pantalla_revision_palabra.dart';
|
import 'package:farolero/pantallas/pantalla_revision_palabra.dart';
|
||||||
import 'package:farolero/pantallas/pantalla_votacion_cliente.dart';
|
import 'package:farolero/pantallas/pantalla_votacion_cliente.dart';
|
||||||
import 'package:farolero/servicios/servicio_nearby.dart';
|
import 'package:farolero/servicios/servicio_nearby.dart';
|
||||||
|
import 'package:farolero/tema/componentes_farolero.dart';
|
||||||
import 'package:farolero/tema/tema_app.dart';
|
import 'package:farolero/tema/tema_app.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@@ -157,9 +158,11 @@ class _PantallaDebateClienteState extends State<PantallaDebateCliente> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: FondoFarolero(
|
||||||
padding: const EdgeInsets.all(24),
|
intenso: true,
|
||||||
child: Column(
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
|
||||||
@@ -173,23 +176,37 @@ class _PantallaDebateClienteState extends State<PantallaDebateCliente> {
|
|||||||
: TemaApp.colorTarjeta,
|
: TemaApp.colorTarjeta,
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Positioned.fill(
|
||||||
_segundosRestantes == 0
|
child: Image.asset(
|
||||||
? l10n.timeUp
|
'assets/ui/premium/timer_ring_glow.png',
|
||||||
: l10n.timeRemaining,
|
fit: BoxFit.contain,
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
opacity: const AlwaysStoppedAnimation(0.42),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
Column(
|
||||||
Text(
|
mainAxisSize: MainAxisSize.min,
|
||||||
_formatearTiempo(_segundosRestantes),
|
children: [
|
||||||
style: Theme.of(context).textTheme.displayMedium?.copyWith(
|
Text(
|
||||||
fontWeight: FontWeight.bold,
|
_segundosRestantes == 0
|
||||||
color: _segundosRestantes == 0
|
? l10n.timeUp
|
||||||
? TemaApp.colorAcento
|
: l10n.timeRemaining,
|
||||||
: TemaApp.colorTexto,
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
_formatearTiempo(_segundosRestantes),
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.displayMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: _segundosRestantes == 0
|
||||||
|
? TemaApp.colorAcento
|
||||||
|
: TemaApp.colorTexto,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -273,6 +290,7 @@ class _PantallaDebateClienteState extends State<PantallaDebateCliente> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -96,9 +96,11 @@ class _PantallaFinPartidaOnlineState extends State<PantallaFinPartidaOnline> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: SingleChildScrollView(
|
body: FondoFarolero(
|
||||||
padding: const EdgeInsets.all(24),
|
intenso: true,
|
||||||
child: Column(
|
child: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
@@ -266,6 +268,7 @@ class _PantallaFinPartidaOnlineState extends State<PantallaFinPartidaOnline> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ class _PantallaGestorHostState extends State<PantallaGestorHost> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class PantallaHistorial extends StatelessWidget {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Historial')),
|
appBar: AppBar(title: const Text('Historial')),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: partidas.isEmpty
|
child: partidas.isEmpty
|
||||||
? const Center(child: Text('Todavía no hay partidas guardadas.'))
|
? const Center(child: Text('Todavía no hay partidas guardadas.'))
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
|
|||||||
@@ -48,25 +48,66 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
EncabezadoFarolero(
|
||||||
|
icono: Icons.wifi_tethering,
|
||||||
|
titulo: widget.nombreSala,
|
||||||
|
subtitulo: l10n.scanToJoin,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 14),
|
||||||
|
PanelFarolero(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
child: Column(
|
||||||
color: Colors.white,
|
children: [
|
||||||
borderRadius: BorderRadius.circular(16),
|
SizedBox(
|
||||||
),
|
width: 196,
|
||||||
child: QrImageView(
|
height: 196,
|
||||||
data: nearby.generarDatosQR(widget.nombreSala),
|
child: Stack(
|
||||||
version: QrVersions.auto,
|
alignment: Alignment.center,
|
||||||
size: 160,
|
children: [
|
||||||
backgroundColor: Colors.white,
|
Container(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(18),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: TemaApp.colorNaranja.withValues(alpha: 0.18),
|
||||||
|
blurRadius: 24,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: QrImageView(
|
||||||
|
data: nearby.generarDatosQR(widget.nombreSala),
|
||||||
|
version: QrVersions.auto,
|
||||||
|
size: 156,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned.fill(
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/ui/premium/qr_frame_overlay.png',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
'Escanea este código desde otro móvil',
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
|
||||||
Text(l10n.scanToJoin),
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildResumenSala(context, seleccionados, nearby.jugadores.length),
|
_buildResumenSala(context, seleccionados, nearby.jugadores.length),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
@@ -119,15 +160,15 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
|||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: ElevatedButton.icon(
|
child: BotonFarolero(
|
||||||
|
texto: _iniciando ? l10n.starting : l10n.startGame,
|
||||||
|
icono: Icons.play_arrow,
|
||||||
onPressed: puedeIniciar && !_iniciando
|
onPressed: puedeIniciar && !_iniciando
|
||||||
? () {
|
? () {
|
||||||
setState(() => _iniciando = true);
|
setState(() => _iniciando = true);
|
||||||
widget.onIniciar();
|
widget.onIniciar();
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
icon: const Icon(Icons.play_arrow),
|
|
||||||
label: Text(_iniciando ? l10n.starting : l10n.startGame),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:farolero/l10n/generated/app_localizations.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../estado/estado_juego.dart';
|
import '../estado/estado_juego.dart';
|
||||||
import '../servicios/servicio_notas.dart';
|
import '../servicios/servicio_notas.dart';
|
||||||
|
import '../tema/componentes_farolero.dart';
|
||||||
import '../tema/tema_app.dart';
|
import '../tema/tema_app.dart';
|
||||||
|
|
||||||
class PantallaNotas extends StatefulWidget {
|
class PantallaNotas extends StatefulWidget {
|
||||||
@@ -86,9 +87,12 @@ class _PantallaNotasState extends State<PantallaNotas> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: _jugadorSeleccionadoId == null
|
body: FondoFarolero(
|
||||||
? _construirSelectorJugador(partida)
|
intenso: true,
|
||||||
: _construirNotas(partida),
|
child: _jugadorSeleccionadoId == null
|
||||||
|
? _construirSelectorJugador(partida)
|
||||||
|
: _construirNotas(partida),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:farolero/l10n/generated/app_localizations.dart';
|
|||||||
import 'package:farolero/modelos/inicio_partida_multijugador.dart';
|
import 'package:farolero/modelos/inicio_partida_multijugador.dart';
|
||||||
import 'package:farolero/modelos/jugador.dart';
|
import 'package:farolero/modelos/jugador.dart';
|
||||||
import 'package:farolero/servicios/servicio_notas.dart';
|
import 'package:farolero/servicios/servicio_notas.dart';
|
||||||
|
import 'package:farolero/tema/componentes_farolero.dart';
|
||||||
import 'package:farolero/tema/tema_app.dart';
|
import 'package:farolero/tema/tema_app.dart';
|
||||||
|
|
||||||
class PantallaNotasOnline extends StatefulWidget {
|
class PantallaNotasOnline extends StatefulWidget {
|
||||||
@@ -115,7 +116,10 @@ class _PantallaNotasOnlineState extends State<PantallaNotasOnline> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: _autor == null ? _buildSelector(context) : _buildNotas(context),
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
|
child: _autor == null ? _buildSelector(context) : _buildNotas(context),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class PantallaPrincipal extends StatelessWidget {
|
|||||||
final gamificacion = servicioPerfil.resumenGamificacion;
|
final gamificacion = servicioPerfil.resumenGamificacion;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
extendBodyBehindAppBar: true,
|
||||||
backgroundColor: const Color(0xFF05070D),
|
backgroundColor: const Color(0xFF05070D),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
intenso: true,
|
intenso: true,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class PantallaReglas extends StatelessWidget {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(l10n.rulesTitle)),
|
appBar: AppBar(title: Text(l10n.rulesTitle)),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ class _PantallaResultadoState extends State<PantallaResultado>
|
|||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
),
|
),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(32),
|
padding: const EdgeInsets.all(32),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import '../modelos/inicio_partida_multijugador.dart';
|
|||||||
import '../modelos/partida.dart';
|
import '../modelos/partida.dart';
|
||||||
import '../modelos/snapshot_partida_online.dart';
|
import '../modelos/snapshot_partida_online.dart';
|
||||||
import '../servicios/servicio_nearby.dart';
|
import '../servicios/servicio_nearby.dart';
|
||||||
|
import '../tema/componentes_farolero.dart';
|
||||||
import '../tema/tema_app.dart';
|
import '../tema/tema_app.dart';
|
||||||
import 'pantalla_debate_cliente.dart';
|
import 'pantalla_debate_cliente.dart';
|
||||||
import 'pantalla_fin_partida_online.dart';
|
import 'pantalla_fin_partida_online.dart';
|
||||||
@@ -168,11 +169,14 @@ class _PantallaResultadoOnlineState extends State<PantallaResultadoOnline> {
|
|||||||
elevation: 0,
|
elevation: 0,
|
||||||
actions: _acciones(context, l10n),
|
actions: _acciones(context, l10n),
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: FondoFarolero(
|
||||||
padding: const EdgeInsets.all(24),
|
intenso: true,
|
||||||
child: resultado == null
|
child: Padding(
|
||||||
? _buildEsperaAdivinanza(context, l10n)
|
padding: const EdgeInsets.all(24),
|
||||||
: _buildResultado(context, l10n, resultado),
|
child: resultado == null
|
||||||
|
? _buildEsperaAdivinanza(context, l10n)
|
||||||
|
: _buildResultado(context, l10n, resultado),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
|
||||||
import '../tema/componentes_farolero.dart';
|
import '../tema/componentes_farolero.dart';
|
||||||
import '../tema/tema_app.dart';
|
import '../tema/tema_app.dart';
|
||||||
@@ -10,40 +11,27 @@ class PantallaSeleccionModoJuego extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Elegir modo de juego')),
|
extendBodyBehindAppBar: true,
|
||||||
|
appBar: AppBar(title: const Text('Elegir modo')),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.fromLTRB(20, 24, 20, 28),
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: const BoxConstraints(maxWidth: 460),
|
constraints: const BoxConstraints(maxWidth: 470),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
const Icon(
|
const SizedBox(height: 12),
|
||||||
Icons.sports_esports,
|
const _ModoHero().animate().fadeIn(duration: 320.ms).slideY(begin: -0.12),
|
||||||
size: 64,
|
const SizedBox(height: 34),
|
||||||
color: TemaApp.colorNaranja,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Text(
|
|
||||||
'¿Cómo querés jugar?',
|
|
||||||
style: Theme.of(context).textTheme.headlineMedium,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
'Elegí primero el tipo de partida para configurar solo lo necesario.',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 28),
|
|
||||||
_ModoCard(
|
_ModoCard(
|
||||||
icono: Icons.phone_android,
|
icono: Icons.phone_android_rounded,
|
||||||
titulo: 'Partida en este dispositivo',
|
titulo: 'Un móvil',
|
||||||
descripcion:
|
subtitulo: 'Partida en este dispositivo',
|
||||||
'Todos los jugadores usan este móvil. Acá se agregan los nombres manualmente.',
|
descripcion: 'Ideal para jugar todos juntos pasando el móvil. Configuración rápida y directa.',
|
||||||
onTap: () => Navigator.push(
|
onTap: () => Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
@@ -53,13 +41,13 @@ class PantallaSeleccionModoJuego extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
).animate().fadeIn(delay: 120.ms).slideX(begin: -0.08),
|
||||||
const SizedBox(height: 14),
|
const SizedBox(height: 16),
|
||||||
_ModoCard(
|
_ModoCard(
|
||||||
icono: Icons.devices,
|
icono: Icons.devices_rounded,
|
||||||
titulo: 'Partida multidispositivo',
|
titulo: 'Multidispositivo',
|
||||||
descripcion:
|
subtitulo: 'Cada jugador en su móvil',
|
||||||
'Este móvil crea el servidor. Los usuarios se gestionan después en el lobby.',
|
descripcion: 'Crea una sala premium, comparte QR y gestiona usuarios desde el lobby.',
|
||||||
destacado: true,
|
destacado: true,
|
||||||
onTap: () => Navigator.push(
|
onTap: () => Navigator.push(
|
||||||
context,
|
context,
|
||||||
@@ -70,7 +58,7 @@ class PantallaSeleccionModoJuego extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
).animate().fadeIn(delay: 200.ms).slideX(begin: 0.08),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -82,9 +70,82 @@ class PantallaSeleccionModoJuego extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _ModoHero extends StatelessWidget {
|
||||||
|
const _ModoHero();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
height: 230,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/ui/premium/lantern_radial_glow.png',
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
opacity: const AlwaysStoppedAnimation(0.58),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 90,
|
||||||
|
height: 90,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
gradient: RadialGradient(
|
||||||
|
colors: [
|
||||||
|
TemaApp.colorDorado.withValues(alpha: 0.95),
|
||||||
|
TemaApp.colorNaranja.withValues(alpha: 0.58),
|
||||||
|
Colors.black.withValues(alpha: 0.76),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
border: Border.all(color: TemaApp.colorDorado, width: 3),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: TemaApp.colorNaranja.withValues(alpha: 0.55),
|
||||||
|
blurRadius: 42,
|
||||||
|
spreadRadius: 5,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: const Icon(Icons.sports_esports_rounded, size: 48, color: Color(0xFF241103)),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 18),
|
||||||
|
Text(
|
||||||
|
'¿Cómo querés jugar?',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||||
|
color: TemaApp.colorDorado,
|
||||||
|
fontSize: 32,
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
shadows: [
|
||||||
|
Shadow(color: TemaApp.colorNaranja.withValues(alpha: 0.45), blurRadius: 16),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
'Elegí el tipo de partida y arrancá sin fricción.',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
|
color: TemaApp.colorTextoSecundario,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _ModoCard extends StatelessWidget {
|
class _ModoCard extends StatelessWidget {
|
||||||
final IconData icono;
|
final IconData icono;
|
||||||
final String titulo;
|
final String titulo;
|
||||||
|
final String subtitulo;
|
||||||
final String descripcion;
|
final String descripcion;
|
||||||
final bool destacado;
|
final bool destacado;
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
@@ -92,6 +153,7 @@ class _ModoCard extends StatelessWidget {
|
|||||||
const _ModoCard({
|
const _ModoCard({
|
||||||
required this.icono,
|
required this.icono,
|
||||||
required this.titulo,
|
required this.titulo,
|
||||||
|
required this.subtitulo,
|
||||||
required this.descripcion,
|
required this.descripcion,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
this.destacado = false,
|
this.destacado = false,
|
||||||
@@ -100,45 +162,86 @@ class _ModoCard extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final color = destacado ? TemaApp.colorNaranja : TemaApp.colorAcento;
|
final color = destacado ? TemaApp.colorNaranja : TemaApp.colorAcento;
|
||||||
return Card(
|
return Material(
|
||||||
color: TemaApp.colorTarjeta,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(28),
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Padding(
|
child: Ink(
|
||||||
padding: const EdgeInsets.all(18),
|
decoration: BoxDecoration(
|
||||||
child: Row(
|
gradient: LinearGradient(
|
||||||
children: [
|
colors: [
|
||||||
Container(
|
const Color(0xFF111C29).withValues(alpha: 0.94),
|
||||||
width: 52,
|
(destacado ? const Color(0xFF2A1620) : const Color(0xFF15111F)).withValues(alpha: 0.92),
|
||||||
height: 52,
|
],
|
||||||
decoration: BoxDecoration(
|
begin: Alignment.topLeft,
|
||||||
color: color.withValues(alpha: 0.18),
|
end: Alignment.bottomRight,
|
||||||
borderRadius: BorderRadius.circular(16),
|
),
|
||||||
border: Border.all(color: color.withValues(alpha: 0.7)),
|
borderRadius: BorderRadius.circular(28),
|
||||||
),
|
border: Border.all(color: color.withValues(alpha: destacado ? 0.78 : 0.48)),
|
||||||
child: Icon(icono, color: color, size: 30),
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: color.withValues(alpha: destacado ? 0.26 : 0.14),
|
||||||
|
blurRadius: destacado ? 34 : 22,
|
||||||
|
offset: const Offset(0, 14),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
],
|
||||||
Expanded(
|
),
|
||||||
child: Column(
|
child: Stack(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/ui/premium/card_sheen_overlay.png',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
opacity: AlwaysStoppedAnimation(destacado ? 0.34 : 0.22),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(titulo, style: Theme.of(context).textTheme.titleLarge),
|
Container(
|
||||||
const SizedBox(height: 6),
|
width: 64,
|
||||||
Text(
|
height: 64,
|
||||||
descripcion,
|
decoration: BoxDecoration(
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
color: color.withValues(alpha: 0.18),
|
||||||
|
borderRadius: BorderRadius.circular(22),
|
||||||
|
border: Border.all(color: color.withValues(alpha: 0.72)),
|
||||||
|
),
|
||||||
|
child: Icon(icono, color: color, size: 34),
|
||||||
),
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
titulo.toUpperCase(),
|
||||||
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||||
|
color: destacado ? TemaApp.colorDorado : Colors.white,
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
letterSpacing: 0.8,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 3),
|
||||||
|
Text(
|
||||||
|
subtitulo,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(color: color),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 7),
|
||||||
|
Text(descripcion, style: Theme.of(context).textTheme.bodyMedium),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Icon(Icons.chevron_right_rounded, color: color, size: 32),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
|
||||||
const Icon(Icons.chevron_right),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -443,28 +443,19 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(l10n.joinGameTitle)),
|
appBar: AppBar(title: Text(l10n.joinGameTitle)),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(32),
|
padding: const EdgeInsets.all(32),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(
|
EncabezadoFarolero(
|
||||||
Icons.bluetooth_searching,
|
icono: Icons.bluetooth_searching,
|
||||||
|
titulo: l10n.joinGameTitle,
|
||||||
|
subtitulo: l10n.enterNameToSearch,
|
||||||
color: TemaApp.colorAzul,
|
color: TemaApp.colorAzul,
|
||||||
size: 70,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
Text(
|
|
||||||
l10n.joinGameTitle,
|
|
||||||
style: Theme.of(context).textTheme.headlineMedium,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
l10n.enterNameToSearch,
|
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
@@ -481,13 +472,10 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
|||||||
onFieldSubmitted: (_) => _iniciarBusqueda(),
|
onFieldSubmitted: (_) => _iniciarBusqueda(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
SizedBox(
|
BotonFarolero(
|
||||||
width: double.infinity,
|
texto: l10n.searchGames,
|
||||||
child: ElevatedButton.icon(
|
icono: Icons.search,
|
||||||
onPressed: _iniciarBusqueda,
|
onPressed: _iniciarBusqueda,
|
||||||
icon: const Icon(Icons.search),
|
|
||||||
label: Text(l10n.searchGames),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (_error != null) ...[
|
if (_error != null) ...[
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
@@ -525,63 +513,41 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// Estado
|
EncabezadoFarolero(
|
||||||
if (_conectando) ...[
|
icono: _conectando ? Icons.sync : Icons.radar,
|
||||||
const CircularProgressIndicator(color: TemaApp.colorAcento),
|
titulo: _conectando
|
||||||
const SizedBox(height: 12),
|
? '${l10n.connectingTo} ${_salaSeleccionada ?? ""}...'
|
||||||
Text(
|
: l10n.searchingGames,
|
||||||
'${l10n.connectingTo} ${_salaSeleccionada ?? ""}...',
|
subtitulo: _conectando
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
? 'Preparando la sala segura'
|
||||||
|
: 'Buscando partidas cercanas por Bluetooth',
|
||||||
|
color: _conectando ? TemaApp.colorAcento : TemaApp.colorNaranja,
|
||||||
|
trailing: SizedBox(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2.4,
|
||||||
|
color: _conectando
|
||||||
|
? TemaApp.colorAcento
|
||||||
|
: TemaApp.colorNaranja,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
),
|
||||||
] else ...[
|
const SizedBox(height: 18),
|
||||||
// Buscando
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
const SizedBox(
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
strokeWidth: 2,
|
|
||||||
color: TemaApp.colorNaranja,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
Text(
|
|
||||||
l10n.searchingGames,
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
],
|
|
||||||
|
|
||||||
// Lista de hosts encontrados
|
// Lista de hosts encontrados
|
||||||
Expanded(
|
Expanded(
|
||||||
child: hosts.isEmpty && !_conectando
|
child: hosts.isEmpty && !_conectando
|
||||||
? Center(
|
? Center(
|
||||||
child: Column(
|
child: EstadoVacioFarolero(
|
||||||
mainAxisSize: MainAxisSize.min,
|
icono: Icons.radar,
|
||||||
children: [
|
titulo: l10n.noGamesFound,
|
||||||
const Text('📡', style: TextStyle(fontSize: 48)),
|
subtitulo: l10n.noGamesFoundHint,
|
||||||
const SizedBox(height: 16),
|
|
||||||
Text(
|
|
||||||
l10n.noGamesFound,
|
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
l10n.noGamesFoundHint,
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium
|
|
||||||
?.copyWith(color: Colors.grey),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
@@ -627,42 +593,50 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
|||||||
|
|
||||||
Widget _buildHostTile(String endpointId, String nombre) {
|
Widget _buildHostTile(String endpointId, String nombre) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(bottom: 8),
|
margin: const EdgeInsets.only(bottom: 10),
|
||||||
child: Material(
|
child: Material(
|
||||||
color: TemaApp.colorTarjeta,
|
color: Colors.transparent,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(18),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(18),
|
||||||
onTap: _conectando ? null : () => _conectarAHost(endpointId, nombre),
|
onTap: _conectando ? null : () => _conectarAHost(endpointId, nombre),
|
||||||
child: Padding(
|
child: Ink(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
decoration: TemaApp.decoracionPanel(
|
||||||
child: Row(
|
color: TemaApp.colorTarjeta.withValues(alpha: 0.90),
|
||||||
children: [
|
borderColor: TemaApp.colorNaranja.withValues(alpha: 0.42),
|
||||||
const Text('🎭', style: TextStyle(fontSize: 28)),
|
),
|
||||||
const SizedBox(width: 16),
|
child: Padding(
|
||||||
Expanded(
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
||||||
child: Column(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
children: [
|
const Icon(
|
||||||
Text(
|
Icons.theater_comedy,
|
||||||
nombre,
|
color: TemaApp.colorNaranja,
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
size: 30,
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'Toca para unirte',
|
|
||||||
style: Theme.of(
|
|
||||||
context,
|
|
||||||
).textTheme.bodySmall?.copyWith(color: Colors.grey),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 16),
|
||||||
const Icon(
|
Expanded(
|
||||||
Icons.arrow_forward_ios,
|
child: Column(
|
||||||
size: 16,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
color: Colors.grey,
|
children: [
|
||||||
),
|
Text(
|
||||||
],
|
nombre,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Toca para unirte',
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Icon(
|
||||||
|
Icons.arrow_forward_ios,
|
||||||
|
size: 16,
|
||||||
|
color: TemaApp.colorDorado,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -738,26 +712,26 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
// Estado de conexión
|
EncabezadoFarolero(
|
||||||
const Text('✅', style: TextStyle(fontSize: 64)),
|
icono: Icons.check_circle,
|
||||||
const SizedBox(height: 24),
|
titulo: l10n.connectedWaiting,
|
||||||
Text(
|
subtitulo: '${l10n.yourName}: ${_nombreController.text}',
|
||||||
l10n.connectedWaiting,
|
color: TemaApp.colorVerde,
|
||||||
style: Theme.of(context).textTheme.headlineMedium,
|
trailing: const SizedBox(
|
||||||
textAlign: TextAlign.center,
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2.4,
|
||||||
|
color: TemaApp.colorNaranja,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
|
||||||
Text(
|
|
||||||
'${l10n.yourName}: ${_nombreController.text}',
|
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 32),
|
|
||||||
const CircularProgressIndicator(color: TemaApp.colorNaranja),
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
l10n.waitingForHost,
|
l10n.waitingForHost,
|
||||||
|
|||||||
@@ -33,21 +33,15 @@ class _PantallaVerPalabraState extends State<PantallaVerPalabra> {
|
|||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
),
|
),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
EncabezadoFarolero(
|
||||||
l10n.eachPlayerMustSee,
|
icono: Icons.visibility,
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
titulo: l10n.roundNumber(partida.rondaActual),
|
||||||
textAlign: TextAlign.center,
|
subtitulo: l10n.eachPlayerMustSee,
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
l10n.roundNumber(partida.rondaActual),
|
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
||||||
color: TemaApp.colorNaranja,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ class _PantallaVotacionState extends State<PantallaVotacion> {
|
|||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
),
|
),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -68,9 +69,9 @@ class _PantallaVotacionState extends State<PantallaVotacion> {
|
|||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: TemaApp.decoracionPanel(
|
||||||
color: TemaApp.colorTarjeta,
|
color: TemaApp.colorTarjeta.withValues(alpha: 0.90),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderColor: TemaApp.colorNaranja.withValues(alpha: 0.38),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -105,9 +106,17 @@ class _PantallaVotacionState extends State<PantallaVotacion> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
Text(
|
EncabezadoFarolero(
|
||||||
l10n.whoIsImpostor,
|
icono: Icons.how_to_vote,
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
titulo: l10n.whoIsImpostor,
|
||||||
|
subtitulo: l10n.selectOnePlayer,
|
||||||
|
color: TemaApp.colorAcento,
|
||||||
|
trailing: Image.asset(
|
||||||
|
'assets/ui/premium/vote_danger_glow.png',
|
||||||
|
width: 42,
|
||||||
|
height: 42,
|
||||||
|
opacity: const AlwaysStoppedAnimation(0.64),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
@@ -178,6 +187,7 @@ class _PantallaVotacionState extends State<PantallaVotacion> {
|
|||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
),
|
),
|
||||||
body: FondoFarolero(
|
body: FondoFarolero(
|
||||||
|
intenso: true,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(32),
|
padding: const EdgeInsets.all(32),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:farolero/pantallas/pantalla_notas_online.dart';
|
|||||||
import 'package:farolero/pantallas/pantalla_revision_palabra.dart';
|
import 'package:farolero/pantallas/pantalla_revision_palabra.dart';
|
||||||
import 'package:farolero/pantallas/pantalla_resultado_online.dart';
|
import 'package:farolero/pantallas/pantalla_resultado_online.dart';
|
||||||
import 'package:farolero/servicios/servicio_nearby.dart';
|
import 'package:farolero/servicios/servicio_nearby.dart';
|
||||||
|
import 'package:farolero/tema/componentes_farolero.dart';
|
||||||
import 'package:farolero/tema/tema_app.dart';
|
import 'package:farolero/tema/tema_app.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@@ -126,21 +127,26 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: FondoFarolero(
|
||||||
padding: const EdgeInsets.all(16),
|
intenso: true,
|
||||||
child: Column(
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
EncabezadoFarolero(
|
||||||
l10n.whoDoYouThinkIsTheImpostor,
|
icono: Icons.how_to_vote,
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
titulo: l10n.whoDoYouThinkIsTheImpostor,
|
||||||
),
|
subtitulo: _modoMultiVotante
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
_modoMultiVotante
|
|
||||||
? 'Emití un voto por cada jugador que manejás.'
|
? 'Emití un voto por cada jugador que manejás.'
|
||||||
: l10n.selectOnePlayer,
|
: l10n.selectOnePlayer,
|
||||||
style: TextStyle(color: TemaApp.colorTextoSecundario),
|
color: TemaApp.colorAcento,
|
||||||
|
trailing: Image.asset(
|
||||||
|
'assets/ui/premium/vote_danger_glow.png',
|
||||||
|
width: 42,
|
||||||
|
height: 42,
|
||||||
|
opacity: const AlwaysStoppedAnimation(0.64),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -174,6 +180,7 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,9 +247,11 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: FondoFarolero(
|
||||||
padding: const EdgeInsets.all(24),
|
intenso: true,
|
||||||
child: Column(
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
@@ -339,6 +348,7 @@ class _PantallaVotacionClienteState extends State<PantallaVotacionCliente> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,9 +20,36 @@ class FondoFarolero extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DecoratedBox(
|
return DecoratedBox(
|
||||||
decoration: const BoxDecoration(gradient: TemaApp.gradienteFondo),
|
decoration: const BoxDecoration(gradient: TemaApp.gradienteFondo),
|
||||||
child: CustomPaint(
|
child: Stack(
|
||||||
painter: _FondoFaroleroPainter(intenso: intenso),
|
children: [
|
||||||
child: child,
|
Positioned.fill(
|
||||||
|
child: CustomPaint(painter: _FondoFaroleroPainter(intenso: intenso)),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
top: intenso ? -180 : -140,
|
||||||
|
left: -220,
|
||||||
|
right: -220,
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/ui/premium/lantern_radial_glow.png',
|
||||||
|
height: intenso ? 720 : 560,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
opacity: AlwaysStoppedAnimation(intenso ? 0.56 : 0.34),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned.fill(
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/ui/premium/sparks_overlay.png',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
repeat: ImageRepeat.repeat,
|
||||||
|
opacity: AlwaysStoppedAnimation(intenso ? 0.38 : 0.22),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned.fill(child: child),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -49,9 +76,138 @@ class PanelFarolero extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
margin: margin,
|
margin: margin,
|
||||||
padding: padding,
|
|
||||||
decoration: TemaApp.decoracionPanel(color: color, borderColor: borderColor),
|
decoration: TemaApp.decoracionPanel(color: color, borderColor: borderColor),
|
||||||
child: child,
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(14),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/ui/premium/card_sheen_overlay.png',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
opacity: const AlwaysStoppedAnimation(0.26),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(padding: padding, child: child),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EncabezadoFarolero extends StatelessWidget {
|
||||||
|
final IconData icono;
|
||||||
|
final String titulo;
|
||||||
|
final String? subtitulo;
|
||||||
|
final Color color;
|
||||||
|
final Widget? trailing;
|
||||||
|
final EdgeInsetsGeometry padding;
|
||||||
|
|
||||||
|
const EncabezadoFarolero({
|
||||||
|
super.key,
|
||||||
|
required this.icono,
|
||||||
|
required this.titulo,
|
||||||
|
this.subtitulo,
|
||||||
|
this.color = TemaApp.colorNaranja,
|
||||||
|
this.trailing,
|
||||||
|
this.padding = const EdgeInsets.symmetric(horizontal: 16, vertical: 18),
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return PanelFarolero(
|
||||||
|
padding: padding,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 52,
|
||||||
|
height: 52,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
gradient: RadialGradient(
|
||||||
|
colors: [
|
||||||
|
color.withValues(alpha: 0.34),
|
||||||
|
TemaApp.colorSuperficie.withValues(alpha: 0.72),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
border: Border.all(color: color.withValues(alpha: 0.72)),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: color.withValues(alpha: 0.22),
|
||||||
|
blurRadius: 22,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Icon(icono, color: color, size: 30),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 14),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
titulo,
|
||||||
|
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||||
|
color: TemaApp.colorDorado,
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (subtitulo != null) ...[
|
||||||
|
const SizedBox(height: 3),
|
||||||
|
Text(
|
||||||
|
subtitulo!,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (trailing != null) ...[
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
trailing!,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EstadoVacioFarolero extends StatelessWidget {
|
||||||
|
final IconData icono;
|
||||||
|
final String titulo;
|
||||||
|
final String subtitulo;
|
||||||
|
|
||||||
|
const EstadoVacioFarolero({
|
||||||
|
super.key,
|
||||||
|
required this.icono,
|
||||||
|
required this.titulo,
|
||||||
|
required this.subtitulo,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return PanelFarolero(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 28),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(icono, color: TemaApp.colorNaranja, size: 46),
|
||||||
|
const SizedBox(height: 14),
|
||||||
|
Text(
|
||||||
|
titulo,
|
||||||
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
subtitulo,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,17 +294,17 @@ class BotonFarolero extends StatelessWidget {
|
|||||||
return Material(
|
return Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(18),
|
||||||
onTap: onPressed,
|
onTap: onPressed,
|
||||||
child: Ink(
|
child: Ink(
|
||||||
height: 54,
|
height: 58,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: habilitado
|
gradient: habilitado
|
||||||
? gradient
|
? gradient
|
||||||
: const LinearGradient(
|
: const LinearGradient(
|
||||||
colors: [TemaApp.colorTarjeta, TemaApp.colorSuperficie],
|
colors: [TemaApp.colorTarjeta, TemaApp.colorSuperficie],
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(18),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: habilitado
|
color: habilitado
|
||||||
? TemaApp.colorDorado.withValues(alpha: 0.74)
|
? TemaApp.colorDorado.withValues(alpha: 0.74)
|
||||||
@@ -157,29 +313,46 @@ class BotonFarolero extends StatelessWidget {
|
|||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withValues(alpha: 0.34),
|
color: Colors.black.withValues(alpha: 0.34),
|
||||||
blurRadius: 14,
|
blurRadius: 18,
|
||||||
offset: const Offset(0, 8),
|
offset: const Offset(0, 10),
|
||||||
),
|
),
|
||||||
|
if (habilitado)
|
||||||
|
BoxShadow(
|
||||||
|
color: TemaApp.colorNaranja.withValues(alpha: 0.16),
|
||||||
|
blurRadius: 22,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
Positioned.fill(
|
||||||
width: 58,
|
child: Image.asset(
|
||||||
child: Icon(icono, color: foreground, size: 28),
|
'assets/ui/premium/card_sheen_overlay.png',
|
||||||
),
|
fit: BoxFit.cover,
|
||||||
Expanded(
|
opacity: const AlwaysStoppedAnimation(0.18),
|
||||||
child: Text(
|
|
||||||
texto.toUpperCase(),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
||||||
color: foreground,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.w800,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 58),
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 58,
|
||||||
|
child: Icon(icono, color: foreground, size: 28),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
texto.toUpperCase(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||||
|
color: foreground,
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
letterSpacing: 0.8,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 58),
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -254,15 +427,27 @@ class TarjetaPalabraFarolero extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Stack(
|
||||||
palabra.toUpperCase(),
|
alignment: Alignment.center,
|
||||||
textAlign: TextAlign.center,
|
children: [
|
||||||
style: GoogleFonts.oswald(
|
Positioned.fill(
|
||||||
color: const Color(0xFF1B0C05),
|
child: Image.asset(
|
||||||
fontSize: 42,
|
'assets/ui/premium/word_reveal_glow.png',
|
||||||
fontWeight: FontWeight.w900,
|
fit: BoxFit.cover,
|
||||||
letterSpacing: 0,
|
opacity: const AlwaysStoppedAnimation(0.28),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
palabra.toUpperCase(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: GoogleFonts.oswald(
|
||||||
|
color: const Color(0xFF1B0C05),
|
||||||
|
fontSize: 42,
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
letterSpacing: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,8 +89,8 @@ class TemaApp {
|
|||||||
elevation: 0,
|
elevation: 0,
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(18),
|
||||||
side: const BorderSide(color: colorBorde),
|
side: BorderSide(color: colorDorado.withValues(alpha: 0.34)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||||
@@ -99,12 +99,13 @@ class TemaApp {
|
|||||||
foregroundColor: Colors.black,
|
foregroundColor: Colors.black,
|
||||||
disabledBackgroundColor: colorTarjeta,
|
disabledBackgroundColor: colorTarjeta,
|
||||||
disabledForegroundColor: colorTextoSecundario,
|
disabledForegroundColor: colorTextoSecundario,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 15),
|
elevation: 0,
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)),
|
||||||
textStyle: GoogleFonts.oswald(
|
textStyle: GoogleFonts.oswald(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
fontSize: 16,
|
fontSize: 17,
|
||||||
letterSpacing: 0,
|
letterSpacing: 0.6,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -112,8 +113,8 @@ class TemaApp {
|
|||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
foregroundColor: colorTexto,
|
foregroundColor: colorTexto,
|
||||||
side: const BorderSide(color: colorBorde),
|
side: const BorderSide(color: colorBorde),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)),
|
||||||
textStyle: GoogleFonts.oswald(
|
textStyle: GoogleFonts.oswald(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -125,22 +126,22 @@ class TemaApp {
|
|||||||
filled: true,
|
filled: true,
|
||||||
fillColor: const Color(0xFF0B1117),
|
fillColor: const Color(0xFF0B1117),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(16),
|
||||||
borderSide: const BorderSide(color: colorBorde),
|
borderSide: const BorderSide(color: colorBorde),
|
||||||
),
|
),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(16),
|
||||||
borderSide: const BorderSide(color: colorBorde),
|
borderSide: const BorderSide(color: colorBorde),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(16),
|
||||||
borderSide: const BorderSide(color: colorNaranja),
|
borderSide: const BorderSide(color: colorNaranja),
|
||||||
),
|
),
|
||||||
labelStyle: const TextStyle(color: colorTextoSecundario),
|
labelStyle: const TextStyle(color: colorTextoSecundario),
|
||||||
hintStyle: const TextStyle(color: colorTextoSecundario),
|
hintStyle: const TextStyle(color: colorTextoSecundario),
|
||||||
),
|
),
|
||||||
appBarTheme: AppBarTheme(
|
appBarTheme: AppBarTheme(
|
||||||
backgroundColor: colorFondo,
|
backgroundColor: Colors.transparent,
|
||||||
foregroundColor: colorNaranja,
|
foregroundColor: colorNaranja,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
@@ -199,13 +200,19 @@ class TemaApp {
|
|||||||
}) {
|
}) {
|
||||||
return BoxDecoration(
|
return BoxDecoration(
|
||||||
color: color ?? colorTarjeta.withValues(alpha: 0.84),
|
color: color ?? colorTarjeta.withValues(alpha: 0.84),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(18),
|
||||||
border: Border.all(color: borderColor ?? colorBorde),
|
border: Border.all(
|
||||||
|
color: borderColor ?? colorDorado.withValues(alpha: 0.30),
|
||||||
|
),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withValues(alpha: 0.35),
|
color: Colors.black.withValues(alpha: 0.35),
|
||||||
blurRadius: 18,
|
blurRadius: 22,
|
||||||
offset: const Offset(0, 10),
|
offset: const Offset(0, 12),
|
||||||
|
),
|
||||||
|
BoxShadow(
|
||||||
|
color: colorNaranja.withValues(alpha: 0.10),
|
||||||
|
blurRadius: 24,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -38,3 +38,4 @@ flutter:
|
|||||||
- assets/avatars/
|
- assets/avatars/
|
||||||
- assets/medals/
|
- assets/medals/
|
||||||
- assets/rewards/
|
- assets/rewards/
|
||||||
|
- assets/ui/premium/
|
||||||
|
|||||||