268 lines
10 KiB
Dart
268 lines
10 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:farolero/l10n/generated/app_localizations.dart';
|
|
import 'package:provider/provider.dart';
|
|
import '../servicios/servicio_idioma.dart';
|
|
import '../servicios/servicio_perfil_usuario.dart';
|
|
import '../tema/componentes_farolero.dart';
|
|
import '../tema/tema_app.dart';
|
|
|
|
class PantallaAjustes extends StatefulWidget {
|
|
const PantallaAjustes({super.key});
|
|
|
|
@override
|
|
State<PantallaAjustes> createState() => _PantallaAjustesState();
|
|
}
|
|
|
|
class _PantallaAjustesState extends State<PantallaAjustes> {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = AppLocalizations.of(context)!;
|
|
final servicioIdioma = context.watch<ServicioIdioma>();
|
|
final perfil = context.watch<ServicioPerfilUsuario>().perfil;
|
|
final nombrePerfil = perfil.nombre.trim().isEmpty
|
|
? l10n.defaultPlayerName
|
|
: perfil.nombre.trim();
|
|
final inicialPerfil = nombrePerfil.substring(0, 1).toUpperCase();
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(title: Text(l10n.settingsTitle)),
|
|
body: FondoFarolero(
|
|
intenso: true,
|
|
child: SingleChildScrollView(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Card(
|
|
child: InkWell(
|
|
borderRadius: BorderRadius.circular(12),
|
|
onTap: () => _editarPerfil(context),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Row(
|
|
children: [
|
|
AvatarFarolero(
|
|
texto: inicialPerfil,
|
|
assetPath: perfil.avatarAsset,
|
|
size: 96,
|
|
),
|
|
const SizedBox(width: 16),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
nombrePerfil,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: Theme.of(context).textTheme.titleLarge,
|
|
),
|
|
Text(
|
|
'@${perfil.nick}',
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: Theme.of(context).textTheme.bodyMedium,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
const Icon(Icons.edit),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
Card(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
l10n.language,
|
|
style: Theme.of(context).textTheme.titleLarge,
|
|
),
|
|
const SizedBox(height: 12),
|
|
_opcionIdioma(
|
|
context,
|
|
bandera: '\u{1F310}',
|
|
nombre: '${l10n.automaticLanguage} (${_nombreIdiomaDelSistema()})',
|
|
codigo: 'sistema',
|
|
seleccionado: servicioIdioma.codigoActual == 'sistema',
|
|
onTap: () => servicioIdioma.cambiarIdioma('sistema'),
|
|
),
|
|
const Divider(height: 1),
|
|
...ServicioIdioma.idiomasSoportados.entries.map((entrada) {
|
|
return _opcionIdioma(
|
|
context,
|
|
bandera: entrada.value.bandera,
|
|
nombre: entrada.value.nombre,
|
|
codigo: entrada.key,
|
|
seleccionado: servicioIdioma.codigoActual == entrada.key,
|
|
onTap: () => servicioIdioma.cambiarIdioma(entrada.key),
|
|
);
|
|
}),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _opcionIdioma(
|
|
BuildContext context, {
|
|
required String bandera,
|
|
required String nombre,
|
|
required String codigo,
|
|
required bool seleccionado,
|
|
required VoidCallback onTap,
|
|
}) {
|
|
return ListTile(
|
|
leading: Text(bandera, style: const TextStyle(fontSize: 24)),
|
|
title: Text(nombre),
|
|
trailing: seleccionado
|
|
? const Icon(Icons.check_circle, color: TemaApp.colorAcento)
|
|
: null,
|
|
onTap: onTap,
|
|
dense: true,
|
|
selected: seleccionado,
|
|
selectedTileColor: TemaApp.colorAcento.withValues(alpha: 0.1),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
);
|
|
}
|
|
|
|
Future<void> _editarPerfil(BuildContext context) async {
|
|
final l10n = AppLocalizations.of(context)!;
|
|
final servicioPerfil = context.read<ServicioPerfilUsuario>();
|
|
final actual = servicioPerfil.perfil;
|
|
final nombreController = TextEditingController(text: actual.nombre);
|
|
final nickController = TextEditingController(text: actual.nick);
|
|
var avatarSeleccionado = actual.avatarAsset;
|
|
|
|
await showDialog<void>(
|
|
context: context,
|
|
builder: (ctx) => StatefulBuilder(
|
|
builder: (ctx, setDialogState) => AlertDialog(
|
|
title: Text(l10n.deviceProfile),
|
|
content: SizedBox(
|
|
width: 520,
|
|
child: SingleChildScrollView(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
TextField(
|
|
controller: nombreController,
|
|
textCapitalization: TextCapitalization.words,
|
|
onChanged: (_) => setDialogState(() {}),
|
|
decoration: InputDecoration(
|
|
labelText: l10n.profileName,
|
|
prefixIcon: const Icon(Icons.person),
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
TextField(
|
|
controller: nickController,
|
|
decoration: InputDecoration(
|
|
labelText: l10n.profileNick,
|
|
prefixIcon: const Icon(Icons.alternate_email),
|
|
),
|
|
),
|
|
const SizedBox(height: 18),
|
|
AvatarFarolero(
|
|
texto: nombreController.text.isEmpty
|
|
? '?'
|
|
: nombreController.text.substring(0, 1).toUpperCase(),
|
|
assetPath: avatarSeleccionado,
|
|
size: 112,
|
|
),
|
|
const SizedBox(height: 18),
|
|
LayoutBuilder(
|
|
builder: (context, constraints) {
|
|
final columnas = constraints.maxWidth >= 420 ? 4 : 3;
|
|
return GridView.builder(
|
|
shrinkWrap: true,
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
|
crossAxisCount: columnas,
|
|
mainAxisSpacing: 14,
|
|
crossAxisSpacing: 14,
|
|
),
|
|
itemCount: ServicioPerfilUsuario.avatares.length,
|
|
itemBuilder: (context, index) {
|
|
final avatar = ServicioPerfilUsuario.avatares[index];
|
|
final seleccionado = avatar == avatarSeleccionado;
|
|
return InkWell(
|
|
borderRadius: BorderRadius.circular(999),
|
|
onTap: () => setDialogState(
|
|
() => avatarSeleccionado = avatar,
|
|
),
|
|
child: DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
border: Border.all(
|
|
color: seleccionado
|
|
? TemaApp.colorNaranja
|
|
: Colors.transparent,
|
|
width: 3,
|
|
),
|
|
),
|
|
child: Center(
|
|
child: AvatarFarolero(
|
|
texto: '',
|
|
assetPath: avatar,
|
|
size: 86,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(ctx),
|
|
child: Text(l10n.cancel),
|
|
),
|
|
TextButton(
|
|
onPressed: () async {
|
|
await servicioPerfil.guardar(
|
|
nombre: nombreController.text,
|
|
nick: nickController.text,
|
|
avatarAsset: avatarSeleccionado,
|
|
);
|
|
if (ctx.mounted) Navigator.pop(ctx);
|
|
},
|
|
child: Text(l10n.save),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
nombreController.dispose();
|
|
nickController.dispose();
|
|
}
|
|
|
|
String _nombreIdiomaDelSistema() {
|
|
final locale = WidgetsBinding.instance.platformDispatcher.locale;
|
|
final codigo = locale.countryCode != null && locale.countryCode!.isNotEmpty
|
|
? '${locale.languageCode}_${locale.countryCode}'
|
|
: locale.languageCode;
|
|
final info = ServicioIdioma.idiomasSoportados[codigo] ??
|
|
ServicioIdioma.idiomasSoportados[locale.languageCode];
|
|
return info?.nombre ?? locale.languageCode;
|
|
}
|
|
}
|