aplicadas correcciones
This commit is contained in:
@@ -55,8 +55,10 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
||||
final servicioPerfil = context.read<ServicioPerfilUsuario>();
|
||||
if (!servicioPerfil.cargado) return;
|
||||
final perfil = servicioPerfil.perfil;
|
||||
final nombre =
|
||||
perfil.nombre.trim().isEmpty ? 'Jugador' : perfil.nombre.trim();
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final nombre = perfil.nombre.trim().isEmpty
|
||||
? l10n.defaultPlayerName
|
||||
: perfil.nombre.trim();
|
||||
if (_jugadores.contains(nombre)) return;
|
||||
setState(() {
|
||||
_jugadores.insert(0, nombre);
|
||||
@@ -101,8 +103,10 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
||||
|
||||
void _eliminarJugador(int index) {
|
||||
final perfil = context.read<ServicioPerfilUsuario>().perfil;
|
||||
final nombrePerfil =
|
||||
perfil.nombre.trim().isEmpty ? 'Jugador' : perfil.nombre.trim();
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final nombrePerfil = perfil.nombre.trim().isEmpty
|
||||
? l10n.defaultPlayerName
|
||||
: perfil.nombre.trim();
|
||||
if (index == 0 && _jugadores[index] == nombrePerfil) return;
|
||||
setState(() {
|
||||
_jugadores.removeAt(index);
|
||||
@@ -146,13 +150,14 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
||||
}
|
||||
|
||||
Future<void> _iniciarPartidaMulti() async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
// 1. Pedir permisos automáticamente
|
||||
final permisosOk = await ServicioPermisos.solicitarPermisosNearby(context);
|
||||
if (!permisosOk) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Se necesitan permisos de Bluetooth y ubicación'),
|
||||
SnackBar(
|
||||
content: Text(l10n.bluetoothLocationPermissionsShort),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -182,8 +187,8 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
||||
if (!ok) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('No se pudo crear la sala. Verifica Bluetooth.'),
|
||||
SnackBar(
|
||||
content: Text(l10n.couldNotCreateRoom),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -207,7 +212,9 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'No se puede iniciar: ${validacion.codigo ?? "sala inválida"}',
|
||||
l10n.cannotStartWithReason(
|
||||
validacion.codigo ?? l10n.invalidRoom,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -301,7 +308,7 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
||||
final categorias = ['todas', ...?estado.banco?.nombresCategorias];
|
||||
final etiquetas = _etiquetasTiempo(l10n);
|
||||
final nombrePerfilActual = servicioPerfil.perfil.nombre.trim().isEmpty
|
||||
? 'Jugador'
|
||||
? l10n.defaultPlayerName
|
||||
: servicioPerfil.perfil.nombre.trim();
|
||||
if (!_modoMultimovil &&
|
||||
servicioPerfil.cargado &&
|
||||
@@ -383,8 +390,8 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
_modoMultimovil
|
||||
? 'Partida multidispositivo'
|
||||
: 'Partida en este dispositivo',
|
||||
? l10n.multiDeviceGameLabel
|
||||
: l10n.singleDeviceGameLabel,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
@@ -475,7 +482,7 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
||||
..._jugadores.asMap().entries.map((e) {
|
||||
final perfil = servicioPerfil.perfil;
|
||||
final nombrePerfil = perfil.nombre.trim().isEmpty
|
||||
? 'Jugador'
|
||||
? l10n.defaultPlayerName
|
||||
: perfil.nombre.trim();
|
||||
final inicialPerfil = nombrePerfil.isEmpty
|
||||
? '?'
|
||||
@@ -498,7 +505,7 @@ class _PantallaCrearPartidaState extends State<PantallaCrearPartida> {
|
||||
),
|
||||
title: Text(e.value),
|
||||
subtitle: esPerfilLocal
|
||||
? const Text('Usuario principal del dispositivo')
|
||||
? Text(l10n.mainDeviceUser)
|
||||
: null,
|
||||
trailing: esPerfilLocal
|
||||
? const Icon(Icons.lock, color: TemaApp.colorDorado)
|
||||
|
||||
@@ -220,6 +220,7 @@ class _HeroResultado extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final apertura = String.fromCharCode(0x00A1);
|
||||
final tituloLimpio = titulo
|
||||
.replaceAll(apertura, '')
|
||||
@@ -254,7 +255,7 @@ class _HeroResultado extends StatelessWidget {
|
||||
).animate().fadeIn(duration: 260.ms).slideY(begin: -0.18),
|
||||
const SizedBox(height: 62),
|
||||
Text(
|
||||
'RESULTADOS',
|
||||
l10n.result.toUpperCase(),
|
||||
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
||||
color: TemaApp.colorDorado,
|
||||
fontWeight: FontWeight.w900,
|
||||
|
||||
@@ -103,7 +103,7 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'Escanea este código desde otro móvil',
|
||||
l10n.scanThisCodeFromAnotherPhone,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -111,7 +111,12 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildResumenSala(context, seleccionados, nearby.jugadores.length),
|
||||
_buildResumenSala(
|
||||
context,
|
||||
l10n,
|
||||
seleccionados,
|
||||
nearby.jugadores.length,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Expanded(
|
||||
child: Card(
|
||||
@@ -124,7 +129,7 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Usuarios de la partida',
|
||||
l10n.gameUsers,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
@@ -141,7 +146,11 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
: ListView.builder(
|
||||
itemCount: usuarios.length,
|
||||
itemBuilder: (context, index) =>
|
||||
_buildUsuarioTile(context, usuarios[index]),
|
||||
_buildUsuarioTile(
|
||||
context,
|
||||
l10n,
|
||||
usuarios[index],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -152,7 +161,7 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
const SizedBox(height: 12),
|
||||
if (!puedeIniciar)
|
||||
Text(
|
||||
_mensajeValidacion(validacionInicio?.codigo),
|
||||
_mensajeValidacion(validacionInicio?.codigo, l10n),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
@@ -182,6 +191,7 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
|
||||
Widget _buildResumenSala(
|
||||
BuildContext context,
|
||||
AppLocalizations l10n,
|
||||
int seleccionados,
|
||||
int clientesRemotos,
|
||||
) {
|
||||
@@ -191,7 +201,7 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
child: _buildStat(
|
||||
context,
|
||||
icon: Icons.groups,
|
||||
label: 'Jugadores seleccionados',
|
||||
label: l10n.selectedPlayers,
|
||||
value: '$seleccionados',
|
||||
ok: seleccionados >= 3,
|
||||
),
|
||||
@@ -201,7 +211,7 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
child: _buildStat(
|
||||
context,
|
||||
icon: Icons.devices,
|
||||
label: 'Móviles conectados',
|
||||
label: l10n.connectedPhones,
|
||||
value: '${clientesRemotos + 1}',
|
||||
ok: true,
|
||||
),
|
||||
@@ -241,7 +251,11 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUsuarioTile(BuildContext context, Usuario usuario) {
|
||||
Widget _buildUsuarioTile(
|
||||
BuildContext context,
|
||||
AppLocalizations l10n,
|
||||
Usuario usuario,
|
||||
) {
|
||||
final nearby = context.read<ServicioNearby>();
|
||||
final miClientId = nearby.miClientId;
|
||||
final seleccionadoPorMi = usuario.clienteIdSeleccionado == miClientId;
|
||||
@@ -270,10 +284,10 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
children: [
|
||||
Text(
|
||||
seleccionadoPorMi
|
||||
? 'Seleccionado por este móvil'
|
||||
? l10n.selectedOnThisPhone
|
||||
: seleccionadoPorOtro
|
||||
? 'Seleccionado por otro cliente'
|
||||
: 'Disponible',
|
||||
? l10n.selectedByAnotherDevice
|
||||
: l10n.available,
|
||||
),
|
||||
if (usuario.medallas.isNotEmpty) ...[
|
||||
const SizedBox(height: 4),
|
||||
@@ -286,19 +300,19 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
children: [
|
||||
if (seleccionadoPorMi)
|
||||
IconButton(
|
||||
tooltip: 'Liberar',
|
||||
tooltip: l10n.release,
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () => nearby.liberarUsuarioSala(usuario.id),
|
||||
)
|
||||
else if (!seleccionadoPorOtro)
|
||||
IconButton(
|
||||
tooltip: 'Seleccionar',
|
||||
tooltip: l10n.select,
|
||||
icon: const Icon(Icons.check_circle_outline),
|
||||
onPressed: () => nearby.seleccionarUsuarioSala(usuario.id),
|
||||
),
|
||||
if (!usuario.estaSeleccionado)
|
||||
IconButton(
|
||||
tooltip: 'Eliminar',
|
||||
tooltip: l10n.delete,
|
||||
icon: const Icon(Icons.delete_outline, color: TemaApp.colorAcento),
|
||||
onPressed: () => nearby.eliminarUsuarioSala(usuario.id),
|
||||
),
|
||||
@@ -307,16 +321,16 @@ class _PantallaLobbyHostState extends State<PantallaLobbyHost> {
|
||||
);
|
||||
}
|
||||
|
||||
String _mensajeValidacion(String? codigo) {
|
||||
String _mensajeValidacion(String? codigo, AppLocalizations l10n) {
|
||||
switch (codigo) {
|
||||
case 'faltan_jugadores':
|
||||
return 'Seleccioná al menos 3 usuarios para iniciar.';
|
||||
return l10n.selectAtLeastThreeUsersToStart;
|
||||
case 'host_sin_usuario':
|
||||
return 'El móvil servidor debe seleccionar al menos un usuario.';
|
||||
return l10n.hostPhoneMustSelectUser;
|
||||
case 'sala_cerrada':
|
||||
return 'La sala ya no está en lobby.';
|
||||
return l10n.roomNoLongerInLobby;
|
||||
default:
|
||||
return 'Completá la selección de usuarios para iniciar.';
|
||||
return l10n.completeUserSelectionToStart;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,8 @@ class PantallaSeleccionModoJuego extends StatelessWidget {
|
||||
marcoAsset: 'assets/ui/generated/mode/mode_single_card_frame.png',
|
||||
icono: Icons.phone_android_rounded,
|
||||
titulo: l10n.singleDevice,
|
||||
subtitulo: 'Partida en este dispositivo',
|
||||
descripcion: 'Ideal para jugar todos juntos pasando el móvil. Configuración rápida y directa.',
|
||||
subtitulo: l10n.singleDeviceSubtitle,
|
||||
descripcion: l10n.singleDeviceDescription,
|
||||
onTap: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@@ -53,8 +53,8 @@ class PantallaSeleccionModoJuego extends StatelessWidget {
|
||||
marcoAsset: 'assets/ui/generated/mode/mode_multi_card_frame.png',
|
||||
icono: Icons.devices_rounded,
|
||||
titulo: l10n.multiDevice,
|
||||
subtitulo: 'Cada jugador en su móvil',
|
||||
descripcion: 'Crea una sala premium, comparte QR y gestiona usuarios desde el lobby.',
|
||||
subtitulo: l10n.multiDeviceSubtitle,
|
||||
descripcion: l10n.multiDeviceDescription,
|
||||
destacado: true,
|
||||
onTap: () => Navigator.push(
|
||||
context,
|
||||
|
||||
@@ -301,13 +301,13 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
||||
/// Paso 1: validar nombre, pedir permisos e iniciar discovery
|
||||
Future<void> _iniciarBusqueda() async {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
// Solicitar permisos automáticamente
|
||||
final permisosOk = await ServicioPermisos.solicitarPermisosNearby(context);
|
||||
if (!permisosOk) {
|
||||
setState(() {
|
||||
_error =
|
||||
'Se necesitan permisos de Bluetooth y ubicación para buscar partidas.';
|
||||
_error = l10n.bluetoothLocationPermissionsRequired;
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -332,14 +332,14 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_error =
|
||||
'No se pudo iniciar la búsqueda. Verifica Bluetooth y ubicación.';
|
||||
_error = l10n.couldNotStartSearch;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Conectar a un host de la lista
|
||||
Future<void> _conectarAHost(String endpointId, String nombreHost) async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
setState(() {
|
||||
_conectando = true;
|
||||
_salaSeleccionada = nombreHost;
|
||||
@@ -363,7 +363,7 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
||||
if (!ok && mounted) {
|
||||
setState(() {
|
||||
_conectando = false;
|
||||
_error = 'No se pudo conectar a $nombreHost';
|
||||
_error = l10n.couldNotConnectToHost(nombreHost);
|
||||
});
|
||||
// Reiniciar búsqueda
|
||||
_iniciarBusqueda();
|
||||
@@ -387,11 +387,12 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
||||
|
||||
final datos = ServicioNearby.parsearQR(valor);
|
||||
if (datos != null) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
setState(() {
|
||||
_escaneandoQR = false;
|
||||
_conectando = true;
|
||||
_salaSeleccionada =
|
||||
datos['host'] as String? ?? datos['sala'] as String? ?? 'Sala';
|
||||
datos['host'] as String? ?? datos['sala'] as String? ?? l10n.room;
|
||||
});
|
||||
|
||||
// Iniciar búsqueda para que Nearby encuentre al host
|
||||
@@ -530,8 +531,8 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
||||
? '${l10n.connectingTo} ${_salaSeleccionada ?? ""}...'
|
||||
: l10n.searchingGames,
|
||||
subtitulo: _conectando
|
||||
? 'Preparando la sala segura'
|
||||
: 'Buscando partidas cercanas por Bluetooth',
|
||||
? l10n.preparingSecureRoom
|
||||
: l10n.searchingNearbyBluetoothGames,
|
||||
color: _conectando ? TemaApp.colorAcento : TemaApp.colorNaranja,
|
||||
trailing: SizedBox(
|
||||
width: 24,
|
||||
@@ -560,7 +561,7 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
||||
itemCount: hosts.length,
|
||||
itemBuilder: (context, index) {
|
||||
final entry = hosts.entries.elementAt(index);
|
||||
return _buildHostTile(entry.key, entry.value);
|
||||
return _buildHostTile(l10n, entry.key, entry.value);
|
||||
},
|
||||
),
|
||||
),
|
||||
@@ -597,7 +598,11 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHostTile(String endpointId, String nombre) {
|
||||
Widget _buildHostTile(
|
||||
AppLocalizations l10n,
|
||||
String endpointId,
|
||||
String nombre,
|
||||
) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 10),
|
||||
child: Material(
|
||||
@@ -630,7 +635,7 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
Text(
|
||||
'Toca para unirte',
|
||||
l10n.tapToJoin,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
],
|
||||
@@ -842,16 +847,18 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Env?a el usuario seleccionado/creado al host
|
||||
/// Envía el usuario seleccionado/creado al host
|
||||
void _enviarUsuarioAlHost(Usuario usuario) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final nearby = context.read<ServicioNearby>();
|
||||
nearby.seleccionarUsuarioSala(usuario.id);
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text('${usuario.nombre} seleccionado')));
|
||||
).showSnackBar(SnackBar(content: Text(l10n.profileSelected)));
|
||||
}
|
||||
|
||||
Widget _buildUsuarioSalaTile(Usuario usuario) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final nearby = context.read<ServicioNearby>();
|
||||
final miClientId = nearby.miClientId;
|
||||
final seleccionadoPorMi = usuario.clienteIdSeleccionado == miClientId;
|
||||
@@ -872,10 +879,10 @@ class _PantallaUnirseState extends State<PantallaUnirse> {
|
||||
children: [
|
||||
Text(
|
||||
seleccionadoPorMi
|
||||
? 'Seleccionado por este móvil'
|
||||
? l10n.selectedOnThisPhone
|
||||
: seleccionadoPorOtro
|
||||
? 'No disponible'
|
||||
: 'Disponible',
|
||||
? l10n.notAvailable
|
||||
: l10n.available,
|
||||
),
|
||||
if (usuario.medallas.isNotEmpty) ...[
|
||||
const SizedBox(height: 4),
|
||||
|
||||
Reference in New Issue
Block a user