tempo e reservas e outos
This commit is contained in:
@@ -24,20 +24,17 @@ class ShotRecord {
|
||||
this.points,
|
||||
});
|
||||
|
||||
// 👇 Para o Auto-Save converter em Texto
|
||||
Map<String, dynamic> toJson() => {
|
||||
'relativeX': relativeX, 'relativeY': relativeY, 'isMake': isMake,
|
||||
'playerId': playerId, 'playerName': playerName, 'zone': zone, 'points': points,
|
||||
};
|
||||
|
||||
// 👇 Para o Auto-Save ler do Texto
|
||||
factory ShotRecord.fromJson(Map<String, dynamic> json) => ShotRecord(
|
||||
relativeX: json['relativeX'], relativeY: json['relativeY'], isMake: json['isMake'],
|
||||
playerId: json['playerId'], playerName: json['playerName'], zone: json['zone'], points: json['points'],
|
||||
);
|
||||
}
|
||||
|
||||
// 👇 AGORA É UM CHANGENOTIFIER (Gestor de Estado Profissional) 👇
|
||||
class PlacarController extends ChangeNotifier {
|
||||
final String gameId;
|
||||
final String myTeam;
|
||||
@@ -80,8 +77,10 @@ class PlacarController extends ChangeNotifier {
|
||||
String? pendingAction;
|
||||
String? pendingPlayerId;
|
||||
List<ShotRecord> matchShots = [];
|
||||
|
||||
// 👇 LISTA PARA O HISTÓRICO (PLAY-BY-PLAY)
|
||||
List<String> playByPlay = [];
|
||||
|
||||
// 👇 O CRONÓMETRO AGORA TEM VIDA PRÓPRIA (ValueNotifier) PARA NÃO ENCRAVAR A APP 👇
|
||||
ValueNotifier<Duration> durationNotifier = ValueNotifier(const Duration(minutes: 10));
|
||||
Timer? timer;
|
||||
bool isRunning = false;
|
||||
@@ -98,7 +97,7 @@ class PlacarController extends ChangeNotifier {
|
||||
|
||||
myCourt.clear(); myBench.clear(); oppCourt.clear(); oppBench.clear();
|
||||
playerNames.clear(); playerStats.clear(); playerNumbers.clear();
|
||||
matchShots.clear(); myFouls = 0; opponentFouls = 0;
|
||||
matchShots.clear(); playByPlay.clear(); myFouls = 0; opponentFouls = 0;
|
||||
|
||||
final gameResponse = await supabase.from('games').select().eq('id', gameId).single();
|
||||
|
||||
@@ -179,11 +178,10 @@ class PlacarController extends ChangeNotifier {
|
||||
));
|
||||
}
|
||||
|
||||
// 👇 AUTO-SAVE: SE O JOGO FOI ABAIXO A MEIO, RECUPERA TUDO AQUI! 👇
|
||||
await _loadLocalBackup();
|
||||
|
||||
isLoading = false;
|
||||
notifyListeners(); // Substitui o antigo onUpdate!
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
debugPrint("Erro ao retomar jogo: $e");
|
||||
isLoading = false;
|
||||
@@ -215,9 +213,6 @@ class PlacarController extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 👇 AS DUAS FUNÇÕES MÁGICAS DO AUTO-SAVE 👇
|
||||
// =========================================================================
|
||||
Future<void> _saveLocalBackup() async {
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
@@ -229,6 +224,7 @@ class PlacarController extends ChangeNotifier {
|
||||
'playerStats': playerStats,
|
||||
'myCourt': myCourt, 'myBench': myBench, 'oppCourt': oppCourt, 'oppBench': oppBench,
|
||||
'matchShots': matchShots.map((s) => s.toJson()).toList(),
|
||||
'playByPlay': playByPlay, // 👇 Guarda o histórico
|
||||
};
|
||||
await prefs.setString('backup_$gameId', jsonEncode(backupData));
|
||||
} catch (e) {
|
||||
@@ -257,6 +253,8 @@ class PlacarController extends ChangeNotifier {
|
||||
|
||||
List<dynamic> decodedShots = data['matchShots'];
|
||||
matchShots = decodedShots.map((s) => ShotRecord.fromJson(s)).toList();
|
||||
|
||||
playByPlay = List<String>.from(data['playByPlay'] ?? []); // 👇 Carrega o histórico
|
||||
|
||||
debugPrint("🔄 AUTO-SAVE RECUPERADO COM SUCESSO!");
|
||||
}
|
||||
@@ -268,11 +266,11 @@ class PlacarController extends ChangeNotifier {
|
||||
void toggleTimer(BuildContext context) {
|
||||
if (isRunning) {
|
||||
timer?.cancel();
|
||||
_saveLocalBackup(); // Grava no telemóvel quando pausa!
|
||||
_saveLocalBackup();
|
||||
} else {
|
||||
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
if (durationNotifier.value.inSeconds > 0) {
|
||||
durationNotifier.value -= const Duration(seconds: 1); // 👈 Só o relógio atualiza, a app não pisca!
|
||||
durationNotifier.value -= const Duration(seconds: 1);
|
||||
} else {
|
||||
timer.cancel();
|
||||
isRunning = false;
|
||||
@@ -281,9 +279,9 @@ class PlacarController extends ChangeNotifier {
|
||||
durationNotifier.value = const Duration(minutes: 10);
|
||||
myFouls = 0; opponentFouls = 0;
|
||||
myTimeoutsUsed = 0; opponentTimeoutsUsed = 0;
|
||||
_saveLocalBackup(); // Grava mudança de período
|
||||
_saveLocalBackup();
|
||||
}
|
||||
notifyListeners(); // Aqui sim, redesenhamos o ecrã para mudar o Quarto
|
||||
notifyListeners();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -364,7 +362,7 @@ class PlacarController extends ChangeNotifier {
|
||||
|
||||
matchShots.add(ShotRecord(relativeX: relativeX, relativeY: relativeY, isMake: isMake, playerId: playerId, playerName: name, zone: zone, points: points));
|
||||
|
||||
_saveLocalBackup(); // 👈 Grava logo para não perder o cesto!
|
||||
_saveLocalBackup();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -389,7 +387,7 @@ class PlacarController extends ChangeNotifier {
|
||||
commitStat(pendingAction!, pendingPlayerId!);
|
||||
|
||||
isSelectingShotLocation = false; pendingAction = null; pendingPlayerId = null;
|
||||
_saveLocalBackup(); // 👈 Grava logo
|
||||
_saveLocalBackup();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -428,6 +426,9 @@ class PlacarController extends ChangeNotifier {
|
||||
bool isOpponent = playerData.startsWith("player_opp_");
|
||||
String playerId = playerData.replaceAll("player_my_", "").replaceAll("player_opp_", "");
|
||||
final stats = playerStats[playerId]!;
|
||||
final name = playerNames[playerId] ?? "Jogador";
|
||||
|
||||
String logText = "";
|
||||
|
||||
if (action.startsWith("add_pts_")) {
|
||||
int pts = int.parse(action.split("_").last);
|
||||
@@ -435,6 +436,7 @@ class PlacarController extends ChangeNotifier {
|
||||
stats["pts"] = stats["pts"]! + pts;
|
||||
if (pts == 2 || pts == 3) { stats["fgm"] = stats["fgm"]! + 1; stats["fga"] = stats["fga"]! + 1; }
|
||||
if (pts == 1) { stats["ftm"] = stats["ftm"]! + 1; stats["fta"] = stats["fta"]! + 1; }
|
||||
logText = "marcou $pts pontos 🏀";
|
||||
}
|
||||
else if (action.startsWith("sub_pts_")) {
|
||||
int pts = int.parse(action.split("_").last);
|
||||
@@ -449,24 +451,33 @@ class PlacarController extends ChangeNotifier {
|
||||
if (stats["ftm"]! > 0) stats["ftm"] = stats["ftm"]! - 1;
|
||||
if (stats["fta"]! > 0) stats["fta"] = stats["fta"]! - 1;
|
||||
}
|
||||
logText = "teve $pts pontos retirados ❌";
|
||||
}
|
||||
else if (action == "miss_1") { stats["fta"] = stats["fta"]! + 1; }
|
||||
else if (action == "miss_2" || action == "miss_3") { stats["fga"] = stats["fga"]! + 1; }
|
||||
else if (action == "add_orb") { stats["orb"] = stats["orb"]! + 1; stats["rbs"] = stats["rbs"]! + 1; }
|
||||
else if (action == "add_drb") { stats["drb"] = stats["drb"]! + 1; stats["rbs"] = stats["rbs"]! + 1; }
|
||||
else if (action == "add_ast") { stats["ast"] = stats["ast"]! + 1; }
|
||||
else if (action == "add_stl") { stats["stl"] = stats["stl"]! + 1; }
|
||||
else if (action == "add_tov") { stats["tov"] = stats["tov"]! + 1; }
|
||||
else if (action == "add_blk") { stats["blk"] = stats["blk"]! + 1; }
|
||||
else if (action == "miss_1") { stats["fta"] = stats["fta"]! + 1; logText = "falhou lance livre ❌"; }
|
||||
else if (action == "miss_2" || action == "miss_3") { stats["fga"] = stats["fga"]! + 1; logText = "falhou lançamento ❌"; }
|
||||
else if (action == "add_orb") { stats["orb"] = stats["orb"]! + 1; stats["rbs"] = stats["rbs"]! + 1; logText = "ganhou ressalto ofensivo 🔄"; }
|
||||
else if (action == "add_drb") { stats["drb"] = stats["drb"]! + 1; stats["rbs"] = stats["rbs"]! + 1; logText = "ganhou ressalto defensivo 🛡️"; }
|
||||
else if (action == "add_ast") { stats["ast"] = stats["ast"]! + 1; logText = "fez uma assistência 🤝"; }
|
||||
else if (action == "add_stl") { stats["stl"] = stats["stl"]! + 1; logText = "roubou a bola 🥷"; }
|
||||
else if (action == "add_tov") { stats["tov"] = stats["tov"]! + 1; logText = "perdeu a bola (turnover) 🤦"; }
|
||||
else if (action == "add_blk") { stats["blk"] = stats["blk"]! + 1; logText = "fez um desarme (bloco) ✋"; }
|
||||
else if (action == "add_foul") {
|
||||
stats["fls"] = stats["fls"]! + 1;
|
||||
if (isOpponent) { opponentFouls++; } else { myFouls++; }
|
||||
logText = "cometeu falta ⚠️";
|
||||
}
|
||||
else if (action == "sub_foul") {
|
||||
if (stats["fls"]! > 0) stats["fls"] = stats["fls"]! - 1;
|
||||
if (isOpponent) { if (opponentFouls > 0) opponentFouls--; } else { if (myFouls > 0) myFouls--; }
|
||||
logText = "teve falta anulada 🔄";
|
||||
}
|
||||
_saveLocalBackup(); // 👈 Grava na memória!
|
||||
|
||||
if (logText.isNotEmpty) {
|
||||
String time = "${durationNotifier.value.inMinutes.toString().padLeft(2, '0')}:${durationNotifier.value.inSeconds.remainder(60).toString().padLeft(2, '0')}";
|
||||
playByPlay.insert(0, "P$currentQuarter - $time: $name $logText");
|
||||
}
|
||||
|
||||
_saveLocalBackup();
|
||||
}
|
||||
|
||||
Future<void> saveGameStats(BuildContext context) async {
|
||||
@@ -570,7 +581,6 @@ class PlacarController extends ChangeNotifier {
|
||||
await supabase.from('shot_locations').delete().eq('game_id', gameId);
|
||||
if (batchShots.isNotEmpty) await supabase.from('shot_locations').insert(batchShots);
|
||||
|
||||
// 👇 SE O SUPABASE GUARDOU COM SUCESSO, LIMPA A MEMÓRIA DO TELEMÓVEL! 👇
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.remove('backup_$gameId');
|
||||
|
||||
@@ -590,5 +600,4 @@ class PlacarController extends ChangeNotifier {
|
||||
timer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user