Files
farolero/lib/pantallas/pantalla_notas_online.dart
freetlab 031c190d74
All checks were successful
Build & Deploy Farolero / Análisis de código (push) Successful in 11s
Build & Deploy Farolero / Build APK + AAB release (push) Successful in 1m20s
Subidas para permitir compilación
2026-05-05 22:48:05 +02:00

230 lines
7.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import 'package:farolero/modelos/inicio_partida_multijugador.dart';
import 'package:farolero/modelos/jugador.dart';
import 'package:farolero/servicios/servicio_notas.dart';
import 'package:farolero/tema/tema_app.dart';
class PantallaNotasOnline extends StatefulWidget {
final String partidaId;
final List<Jugador> jugadores;
final List<JugadorInicioPartida> autoresControlados;
const PantallaNotasOnline({
super.key,
required this.partidaId,
required this.jugadores,
required this.autoresControlados,
});
@override
State<PantallaNotasOnline> createState() => _PantallaNotasOnlineState();
}
class _PantallaNotasOnlineState extends State<PantallaNotasOnline> {
JugadorInicioPartida? _autor;
final Map<String, TextEditingController> _controladores = {};
final TextEditingController _notaLibreController = TextEditingController();
bool _cargando = false;
List<Jugador> get _jugadoresActivos =>
widget.jugadores.where((jugador) => !jugador.eliminado).toList();
@override
void initState() {
super.initState();
for (final jugador in _jugadoresActivos) {
_controladores[jugador.id] = TextEditingController();
}
if (widget.autoresControlados.length == 1) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) _seleccionarAutor(widget.autoresControlados.first);
});
}
}
@override
void dispose() {
for (final controller in _controladores.values) {
controller.dispose();
}
_notaLibreController.dispose();
super.dispose();
}
Future<void> _seleccionarAutor(JugadorInicioPartida autor) async {
setState(() {
_autor = autor;
_cargando = true;
for (final controller in _controladores.values) {
controller.clear();
}
_notaLibreController.clear();
});
final datos = await ServicioNotas.cargarNotasPartida(
partidaId: widget.partidaId,
autorJugadorId: autor.jugadorId,
);
if (!mounted) return;
final notas = datos['notas'] as Map<String, String>;
for (final entry in notas.entries) {
_controladores[entry.key]?.text = entry.value;
}
_notaLibreController.text = datos['notaLibre'] as String;
setState(() => _cargando = false);
}
Future<void> _guardarNotas() async {
final autor = _autor;
if (autor == null) return;
final notas = <String, String>{};
for (final entry in _controladores.entries) {
final texto = entry.value.text.trim();
if (texto.isNotEmpty) notas[entry.key] = texto;
}
await ServicioNotas.guardarNotasPartida(
partidaId: widget.partidaId,
autorJugadorId: autor.jugadorId,
notasPorJugador: notas,
notaLibre: _notaLibreController.text,
);
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return PopScope(
canPop: true,
onPopInvokedWithResult: (didPop, result) => _guardarNotas(),
child: Scaffold(
appBar: AppBar(
title: Text(l10n.notesTitle),
actions: [
if (_autor != null)
IconButton(
icon: const Icon(Icons.save),
onPressed: () async {
await _guardarNotas();
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.notesSaved)),
);
},
),
],
),
body: _autor == null ? _buildSelector(context) : _buildNotas(context),
),
);
}
Widget _buildSelector(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context)!.whoAreYou,
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 16),
Expanded(
child: ListView(
children: widget.autoresControlados
.map(
(autor) => Card(
child: ListTile(
leading: const Icon(Icons.edit_note),
title: Text(autor.nombre),
onTap: () => _seleccionarAutor(autor),
),
),
)
.toList(),
),
),
],
),
);
}
Widget _buildNotas(BuildContext context) {
if (_cargando) return const Center(child: CircularProgressIndicator());
final l10n = AppLocalizations.of(context)!;
final autor = _autor!;
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
if (widget.autoresControlados.length > 1)
IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () async {
await _guardarNotas();
if (!mounted) return;
setState(() => _autor = null);
},
),
Expanded(
child: Text(
l10n.notesOf(autor.nombre),
style: Theme.of(context).textTheme.titleLarge,
),
),
],
),
const SizedBox(height: 16),
Text(
l10n.notesAboutPlayers,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: TemaApp.colorTextoSecundario,
),
),
const SizedBox(height: 8),
..._jugadoresActivos
.where((jugador) => jugador.id != autor.jugadorId)
.map(
(jugador) => Padding(
padding: const EdgeInsets.only(bottom: 8),
child: TextField(
controller: _controladores[jugador.id],
decoration: InputDecoration(
labelText: jugador.nombre,
prefixIcon: const Icon(Icons.person, size: 20),
hintText: l10n.playerNoteHint,
),
maxLines: 2,
minLines: 1,
),
),
),
const SizedBox(height: 16),
Text(
l10n.freeNote,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: TemaApp.colorTextoSecundario,
),
),
const SizedBox(height: 8),
TextField(
controller: _notaLibreController,
decoration: InputDecoration(
hintText: l10n.freeNoteHint,
prefixIcon: const Icon(Icons.note, size: 20),
),
maxLines: 5,
minLines: 3,
),
],
),
);
}
}