esta melhor des que comecei
This commit is contained in:
@@ -4,25 +4,34 @@ import '../models/game_model.dart';
|
||||
class GameController {
|
||||
final _supabase = Supabase.instance.client;
|
||||
|
||||
// 1. LER JOGOS (Stream em Tempo Real)
|
||||
Stream<List<Game>> get gamesStream {
|
||||
// 1. LER JOGOS (Com Filtros Opcionais)
|
||||
Stream<List<Game>> getFilteredGames({String? teamFilter, String? seasonFilter}) {
|
||||
return _supabase
|
||||
.from('games') // 1. Fica à escuta da tabela original (Garante o Tempo Real!)
|
||||
.from('games')
|
||||
.stream(primaryKey: ['id'])
|
||||
.asyncMap((event) async {
|
||||
// 2. Sempre que a tabela 'games' mudar (novo jogo, alteração de resultado),
|
||||
// vamos buscar os dados já misturados com as imagens à nossa View.
|
||||
final viewData = await _supabase
|
||||
.from('games_with_logos')
|
||||
.select()
|
||||
.order('game_date', ascending: false);
|
||||
|
||||
// 👇 A CORREÇÃO ESTÁ AQUI: Lê diretamente da tabela 'games'
|
||||
var query = _supabase.from('games').select();
|
||||
|
||||
// Aplica o filtro de Temporada
|
||||
if (seasonFilter != null && seasonFilter.isNotEmpty && seasonFilter != 'Todas') {
|
||||
query = query.eq('season', seasonFilter);
|
||||
}
|
||||
|
||||
// Aplica o filtro de Equipa (Procura em casa ou fora)
|
||||
if (teamFilter != null && teamFilter.isNotEmpty && teamFilter != 'Todas') {
|
||||
query = query.or('my_team.eq.$teamFilter,opponent_team.eq.$teamFilter');
|
||||
}
|
||||
|
||||
// Executa a query com a ordenação por data
|
||||
final viewData = await query.order('game_date', ascending: false);
|
||||
|
||||
// 3. Convertemos para a nossa lista de objetos Game
|
||||
return viewData.map((json) => Game.fromMap(json)).toList();
|
||||
});
|
||||
}
|
||||
|
||||
// 2. CRIAR JOGO
|
||||
// Retorna o ID do jogo criado para podermos navegar para o placar
|
||||
Future<String?> createGame(String myTeam, String opponent, String season) async {
|
||||
try {
|
||||
final response = await _supabase.from('games').insert({
|
||||
@@ -31,18 +40,16 @@ Stream<List<Game>> get gamesStream {
|
||||
'season': season,
|
||||
'my_score': 0,
|
||||
'opponent_score': 0,
|
||||
'status': 'Decorrer', // Começa como "Decorrer"
|
||||
'status': 'Decorrer',
|
||||
'game_date': DateTime.now().toIso8601String(),
|
||||
}).select().single(); // .select().single() retorna o objeto criado
|
||||
}).select().single();
|
||||
|
||||
return response['id']; // Retorna o UUID gerado pelo Supabase
|
||||
return response['id'];
|
||||
} catch (e) {
|
||||
print("Erro ao criar jogo: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
// Não é necessário fechar streams do Supabase manualmente aqui
|
||||
}
|
||||
void dispose() {}
|
||||
}
|
||||
@@ -187,16 +187,16 @@ class PlacarController {
|
||||
timer.cancel();
|
||||
isRunning = false;
|
||||
if (currentQuarter < 4) {
|
||||
currentQuarter++;
|
||||
duration = const Duration(minutes: 10);
|
||||
myFouls = 0;
|
||||
opponentFouls = 0;
|
||||
myTimeoutsUsed = 0;
|
||||
opponentTimeoutsUsed = 0;
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Período $currentQuarter iniciado. Faltas e Timeouts resetados!'), backgroundColor: Colors.blue));
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('FIM DO JOGO! Clica em Guardar para fechar a partida.'), backgroundColor: Colors.red));
|
||||
}
|
||||
currentQuarter++;
|
||||
duration = const Duration(minutes: 10);
|
||||
myFouls = 0;
|
||||
opponentFouls = 0;
|
||||
myTimeoutsUsed = 0;
|
||||
opponentTimeoutsUsed = 0;
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Período $currentQuarter iniciado. Faltas e Timeouts resetados!'), backgroundColor: Colors.blue));
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('FIM DO JOGO! Clica em Guardar para fechar a partida.'), backgroundColor: Colors.red));
|
||||
}
|
||||
}
|
||||
onUpdate();
|
||||
});
|
||||
@@ -355,7 +355,34 @@ class PlacarController {
|
||||
bool isGameFinishedNow = currentQuarter >= 4 && duration.inSeconds == 0;
|
||||
String newStatus = isGameFinishedNow ? 'Terminado' : 'Pausado';
|
||||
|
||||
// 1. Atualizar o Jogo na BD
|
||||
// 👇👇👇 0. CÉREBRO: CALCULAR OS LÍDERES E MVP DO JOGO 👇👇👇
|
||||
String topPtsName = '---'; int maxPts = -1;
|
||||
String topAstName = '---'; int maxAst = -1;
|
||||
String topRbsName = '---'; int maxRbs = -1;
|
||||
String topDefName = '---'; int maxDef = -1;
|
||||
String mvpName = '---'; int maxMvpScore = -1;
|
||||
|
||||
// Passa por todos os jogadores e calcula a matemática
|
||||
playerStats.forEach((playerName, stats) {
|
||||
int pts = stats['pts'] ?? 0;
|
||||
int ast = stats['ast'] ?? 0;
|
||||
int rbs = stats['rbs'] ?? 0;
|
||||
int stl = stats['stl'] ?? 0;
|
||||
int blk = stats['blk'] ?? 0;
|
||||
|
||||
int defScore = stl + blk; // Defesa: Roubos + Cortes
|
||||
int mvpScore = pts + ast + rbs + defScore; // Impacto Total (MVP)
|
||||
|
||||
// Compara com o máximo atual e substitui se for maior
|
||||
if (pts > maxPts && pts > 0) { maxPts = pts; topPtsName = '$playerName ($pts)'; }
|
||||
if (ast > maxAst && ast > 0) { maxAst = ast; topAstName = '$playerName ($ast)'; }
|
||||
if (rbs > maxRbs && rbs > 0) { maxRbs = rbs; topRbsName = '$playerName ($rbs)'; }
|
||||
if (defScore > maxDef && defScore > 0) { maxDef = defScore; topDefName = '$playerName ($defScore)'; }
|
||||
if (mvpScore > maxMvpScore && mvpScore > 0) { maxMvpScore = mvpScore; mvpName = playerName; } // MVP não leva nº à frente, fica mais limpo
|
||||
});
|
||||
// 👆👆👆 FIM DO CÉREBRO 👆👆👆
|
||||
|
||||
// 1. Atualizar o Jogo na BD (Agora inclui os Reis da partida!)
|
||||
await supabase.from('games').update({
|
||||
'my_score': myScore,
|
||||
'opponent_score': opponentScore,
|
||||
@@ -364,12 +391,18 @@ class PlacarController {
|
||||
'opp_timeouts': opponentTimeoutsUsed,
|
||||
'current_quarter': currentQuarter,
|
||||
'status': newStatus,
|
||||
|
||||
// ENVIA A MATEMÁTICA PARA A TUA BASE DE DADOS
|
||||
'top_pts_name': topPtsName,
|
||||
'top_ast_name': topAstName,
|
||||
'top_rbs_name': topRbsName,
|
||||
'top_def_name': topDefName,
|
||||
'mvp_name': mvpName,
|
||||
}).eq('id', gameId);
|
||||
|
||||
// 👇 2. LÓGICA DE VITÓRIAS, DERROTAS E EMPATES 👇
|
||||
// 2. LÓGICA DE VITÓRIAS, DERROTAS E EMPATES
|
||||
if (isGameFinishedNow && !gameWasAlreadyFinished && myTeamDbId != null && oppTeamDbId != null) {
|
||||
|
||||
// Vai buscar os dados atuais das equipas
|
||||
final teamsData = await supabase.from('teams').select('id, wins, losses, draws').inFilter('id', [myTeamDbId, oppTeamDbId]);
|
||||
|
||||
Map<String, dynamic> myTeamUpdate = {};
|
||||
@@ -380,7 +413,6 @@ class PlacarController {
|
||||
if(t['id'].toString() == oppTeamDbId) oppTeamUpdate = Map.from(t);
|
||||
}
|
||||
|
||||
// Calcula os resultados
|
||||
if (myScore > opponentScore) {
|
||||
myTeamUpdate['wins'] = (myTeamUpdate['wins'] ?? 0) + 1;
|
||||
oppTeamUpdate['losses'] = (oppTeamUpdate['losses'] ?? 0) + 1;
|
||||
@@ -388,12 +420,10 @@ class PlacarController {
|
||||
myTeamUpdate['losses'] = (myTeamUpdate['losses'] ?? 0) + 1;
|
||||
oppTeamUpdate['wins'] = (oppTeamUpdate['wins'] ?? 0) + 1;
|
||||
} else {
|
||||
// Empate
|
||||
myTeamUpdate['draws'] = (myTeamUpdate['draws'] ?? 0) + 1;
|
||||
oppTeamUpdate['draws'] = (oppTeamUpdate['draws'] ?? 0) + 1;
|
||||
}
|
||||
|
||||
// Envia as atualizações para a tabela 'teams'
|
||||
await supabase.from('teams').update({
|
||||
'wins': myTeamUpdate['wins'], 'losses': myTeamUpdate['losses'], 'draws': myTeamUpdate['draws']
|
||||
}).eq('id', myTeamDbId!);
|
||||
@@ -402,7 +432,6 @@ class PlacarController {
|
||||
'wins': oppTeamUpdate['wins'], 'losses': oppTeamUpdate['losses'], 'draws': oppTeamUpdate['draws']
|
||||
}).eq('id', oppTeamDbId!);
|
||||
|
||||
// Bloqueia o trinco para não contar 2 vezes se o utilizador clicar "Guardar" outra vez
|
||||
gameWasAlreadyFinished = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ class TeamController {
|
||||
final _supabase = Supabase.instance.client;
|
||||
|
||||
// 1. STREAM (Realtime)
|
||||
// Adicionei o .map() no final para garantir que o Dart entende que é uma List<Map>
|
||||
Stream<List<Map<String, dynamic>>> get teamsStream {
|
||||
return _supabase
|
||||
.from('teams')
|
||||
@@ -15,7 +14,6 @@ class TeamController {
|
||||
}
|
||||
|
||||
// 2. CRIAR
|
||||
// Alterei imageUrl para String? (pode ser nulo) para evitar erros se não houver imagem
|
||||
Future<void> createTeam(String name, String season, String? imageUrl) async {
|
||||
try {
|
||||
await _supabase.from('teams').insert({
|
||||
@@ -51,21 +49,14 @@ class TeamController {
|
||||
}
|
||||
}
|
||||
|
||||
// 5. CONTAR JOGADORES
|
||||
// CORRIGIDO: A sintaxe antiga dava erro. O método .count() é o correto agora.
|
||||
Future<int> getPlayerCount(String teamId) async {
|
||||
try {
|
||||
final count = await _supabase
|
||||
.from('members')
|
||||
.count() // Retorna diretamente o número inteiro
|
||||
.eq('team_id', teamId);
|
||||
return count;
|
||||
} catch (e) {
|
||||
print("Erro ao contar jogadores: $e");
|
||||
return 0;
|
||||
}
|
||||
// 5. CONTAR JOGADORES (AGORA EM TEMPO REAL COM STREAM!)
|
||||
Stream<int> getPlayerCountStream(String teamId) {
|
||||
return _supabase
|
||||
.from('members')
|
||||
.stream(primaryKey: ['id'])
|
||||
.eq('team_id', teamId)
|
||||
.map((data) => data.length); // O tamanho da lista é o número de jogadores
|
||||
}
|
||||
|
||||
// Mantemos o dispose vazio para não quebrar a chamada na TeamsPage
|
||||
void dispose() {}
|
||||
}
|
||||
Reference in New Issue
Block a user