From 01d5e7adb640f781b7d604660d7c2015fe293519 Mon Sep 17 00:00:00 2001 From: 230404 <230404@epvc.pt> Date: Wed, 14 Jan 2026 10:40:31 +0000 Subject: [PATCH] meter firebase --- lib/controllers/stats_controller.dart | 55 +++++++++++++ lib/screens/team_stats_page.dart | 112 ++++++++++++++++++++------ 2 files changed, 143 insertions(+), 24 deletions(-) diff --git a/lib/controllers/stats_controller.dart b/lib/controllers/stats_controller.dart index cb09e7d..cc93d51 100644 --- a/lib/controllers/stats_controller.dart +++ b/lib/controllers/stats_controller.dart @@ -29,6 +29,61 @@ class StatsController { .map((doc) => Person.fromFirestore(doc.data(), doc.id)) .toList()); } + // --- Adiciona estas funções dentro da classe StatsController --- + +// ELIMINAR: Remove o documento da sub-coleção +Future deletePerson(String teamId, String personId) async { + await _db + .collection('teams') + .doc(teamId) + .collection('members') + .doc(personId) + .delete(); +} + +// EDITAR (LOGICA): Abre o popup já preenchido com os dados atuais +void showEditPersonDialog(BuildContext context, String teamId, Person person) { + final nameController = TextEditingController(text: person.name); + final numberController = TextEditingController(text: person.number); + String selectedType = person.type; + + showDialog( + context: context, + builder: (context) => StatefulBuilder( + builder: (context, setPopupState) => AlertDialog( + title: const Text("Editar Personagem"), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + DropdownButtonFormField( + value: selectedType, + items: ['Jogador', 'Treinador'].map((t) => DropdownMenuItem(value: t, child: Text(t))).toList(), + onChanged: (val) => setPopupState(() => selectedType = val!), + decoration: const InputDecoration(labelText: 'Tipo'), + ), + TextField(controller: nameController, decoration: const InputDecoration(labelText: 'Nome')), + if (selectedType == 'Jogador') + TextField(controller: numberController, decoration: const InputDecoration(labelText: 'Número')), + ], + ), + actions: [ + TextButton(onPressed: () => Navigator.pop(context), child: const Text("Cancelar")), + ElevatedButton( + onPressed: () async { + await _db.collection('teams').doc(teamId).collection('members').doc(person.id).update({ + 'name': nameController.text, + 'type': selectedType, + 'number': selectedType == 'Jogador' ? numberController.text : '', + }); + if (context.mounted) Navigator.pop(context); + }, + child: const Text("Guardar Alterações"), + ), + ], + ), + ), + ); +} // --- LÓGICA DE INTERFACE (POPUP) --- diff --git a/lib/screens/team_stats_page.dart b/lib/screens/team_stats_page.dart index 812fc2d..6497ea5 100644 --- a/lib/screens/team_stats_page.dart +++ b/lib/screens/team_stats_page.dart @@ -1,11 +1,12 @@ import 'package:flutter/material.dart'; import '../models/team_model.dart'; +import '../models/person_model.dart'; import '../controllers/stats_controller.dart'; import '../widgets/stats_widgets.dart'; class TeamStatsPage extends StatelessWidget { final Team team; - final StatsController _controller = StatsController(); // Instancia o controller + final StatsController _controller = StatsController(); TeamStatsPage({super.key, required this.team}); @@ -15,27 +16,36 @@ class TeamStatsPage extends StatelessWidget { backgroundColor: const Color(0xFFF5F7FA), body: Column( children: [ - StatsHeader(team: team), // Widget extraído + StatsHeader(team: team), Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SummaryCard(), // Widget extraído - const SizedBox(height: 30), - _buildSectionTitle("Treinadores"), - const SizedBox(height: 30), - _buildSectionTitle("Jogadores"), - const SizedBox(height: 50), - const Center( - child: Text( - "Clica no botão + para adicionar membros", - style: TextStyle(color: Colors.grey, fontStyle: FontStyle.italic), - ), + child: StreamBuilder>( + stream: _controller.getMembers(team.id), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } + + final members = snapshot.data ?? []; + final coaches = members.where((m) => m.type == 'Treinador').toList(); + final players = members.where((m) => m.type == 'Jogador').toList(); + + return SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SummaryCard(), + const SizedBox(height: 30), + _buildSectionTitle("Treinadores"), + ...coaches.map((c) => _buildPersonCard(context, c, isCoach: true)), + const SizedBox(height: 30), + _buildSectionTitle("Jogadores"), + ...players.map((p) => _buildPersonCard(context, p, isCoach: false)), + const SizedBox(height: 80), + ], ), - ], - ), + ); + }, ), ), ], @@ -48,14 +58,68 @@ class TeamStatsPage extends StatelessWidget { ); } + // CORREÇÃO: Adicionado BuildContext context como argumento + Widget _buildPersonCard(BuildContext context, Person person, {required bool isCoach}) { + return Card( + margin: const EdgeInsets.only(top: 12), + elevation: 2, + color: isCoach ? const Color(0xFFFFF9C4) : Colors.white, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: ListTile( + leading: isCoach + ? const CircleAvatar(radius: 25, backgroundColor: Colors.orange, child: Icon(Icons.person, color: Colors.white)) + : Container( + width: 50, height: 50, + alignment: Alignment.center, + decoration: BoxDecoration(color: Colors.blue.withOpacity(0.1), borderRadius: BorderRadius.circular(10)), + child: Text(person.number, style: const TextStyle(color: Colors.blue, fontWeight: FontWeight.bold, fontSize: 18)), + ), + title: Text(person.name, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 17)), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon(Icons.edit_outlined, size: 24, color: Colors.blue), + onPressed: () => _controller.showEditPersonDialog(context, team.id, person), + ), + IconButton( + icon: const Icon(Icons.delete_outline, size: 24, color: Colors.red), + onPressed: () => _confirmDelete(context, person), + ), + ], + ), + ), + ), + ); + } + + void _confirmDelete(BuildContext context, Person person) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text("Eliminar?"), + content: Text("Queres mesmo remover ${person.name}?"), + actions: [ + TextButton(onPressed: () => Navigator.pop(context), child: const Text("Cancelar")), + TextButton( + onPressed: () { + _controller.deletePerson(team.id, person.id); + Navigator.pop(context); + }, + child: const Text("Eliminar", style: TextStyle(color: Colors.red)), + ), + ], + ), + ); + } + Widget _buildSectionTitle(String title) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - title, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFF2C3E50)), - ), + Text(title, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFF2C3E50))), const SizedBox(height: 10), const Divider(), ],