corrigido

This commit is contained in:
2026-04-28 17:15:34 +01:00
parent 309a2f98bc
commit 6d51c3f56e
5 changed files with 1407 additions and 1664 deletions

View File

@@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
revision: "9f455d2486bcb28cad87b062475f42edc959f636"
revision: "b45fa18946ecc2d9b4009952c636ba7e2ffbb787"
channel: "stable"
project_type: app
@@ -13,26 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: 9f455d2486bcb28cad87b062475f42edc959f636
base_revision: 9f455d2486bcb28cad87b062475f42edc959f636
- platform: android
create_revision: 9f455d2486bcb28cad87b062475f42edc959f636
base_revision: 9f455d2486bcb28cad87b062475f42edc959f636
- platform: ios
create_revision: 9f455d2486bcb28cad87b062475f42edc959f636
base_revision: 9f455d2486bcb28cad87b062475f42edc959f636
- platform: linux
create_revision: 9f455d2486bcb28cad87b062475f42edc959f636
base_revision: 9f455d2486bcb28cad87b062475f42edc959f636
- platform: macos
create_revision: 9f455d2486bcb28cad87b062475f42edc959f636
base_revision: 9f455d2486bcb28cad87b062475f42edc959f636
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: web
create_revision: 9f455d2486bcb28cad87b062475f42edc959f636
base_revision: 9f455d2486bcb28cad87b062475f42edc959f636
- platform: windows
create_revision: 9f455d2486bcb28cad87b062475f42edc959f636
base_revision: 9f455d2486bcb28cad87b062475f42edc959f636
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
# User provided section

View File

@@ -89,7 +89,6 @@ class PlacarController extends ChangeNotifier {
double arcRadius = 0.459;
double cornerY = 0.440;
// 👇 NOVO: Temporizador para o Auto-Save não travar a App
Timer? _autoSaveTimer;
Future<void> loadPlayers() async {
@@ -195,7 +194,7 @@ class PlacarController extends ChangeNotifier {
"ftm": s['ftm'] ?? 0, "fta": s['fta'] ?? 0, "orb": s['orb'] ?? 0, "drb": s['drb'] ?? 0,
"p2m": s['p2m'] ?? 0, "p2a": s['p2a'] ?? 0, "p3m": s['p3m'] ?? 0, "p3a": s['p3a'] ?? 0,
"so": s['so'] ?? 0, "il": s['il'] ?? 0, "li": s['li'] ?? 0,
"pa": s['pa'] ?? 0, "tres_s": s['tres_seg'] ?? 0, "dr": s['dr'] ?? 0,
"pa": s['pa'] ?? 0, "tres_seg": s['tres_seg'] ?? 0, "dr": s['dr'] ?? 0,
"min": (s['minutos_jogados'] ?? 0) ~/ 60,
"sec": s['minutos_jogados'] ?? 0,
};
@@ -211,7 +210,7 @@ class PlacarController extends ChangeNotifier {
"pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0,
"fls": 0, "fgm": 0, "fga": 0, "ftm": 0, "fta": 0, "orb": 0, "drb": 0,
"p2m": 0, "p2a": 0, "p3m": 0, "p3a": 0,
"so": 0, "il": 0, "li": 0, "pa": 0, "tres_s": 0, "dr": 0,
"so": 0, "il": 0, "li": 0, "pa": 0, "tres_seg": 0, "dr": 0,
"min": 0, "sec": 0
};
@@ -228,7 +227,6 @@ class PlacarController extends ChangeNotifier {
}
}
// 👇 MÁGICA 1: O "Anti-Spam". Ele acumula as mudanças e só grava 1.5s depois de parares de clicar!
void _scheduleAutoSave() {
_autoSaveTimer?.cancel();
_autoSaveTimer = Timer(const Duration(milliseconds: 1500), () {
@@ -304,7 +302,6 @@ class PlacarController extends ChangeNotifier {
addTimeToCourt(myCourt);
addTimeToCourt(oppCourt);
// Avisa APENAS o relógio (e não a App inteira)
durationNotifier.value -= const Duration(seconds: 1);
} else {
@@ -324,6 +321,7 @@ class PlacarController extends ChangeNotifier {
isRunning = !isRunning;
notifyListeners();
}
void useTimeout(bool isOpponent) {
if (isOpponent) {
if (opponentTimeoutsUsed < 3) opponentTimeoutsUsed++;
@@ -485,33 +483,54 @@ class PlacarController extends ChangeNotifier {
void commitStat(String action, String playerData) {
bool isOpponent = playerData.startsWith("player_opp_");
String playerId = playerData.replaceAll("player_my_", "").replaceAll("player_opp_", "");
String playerId = playerData
.replaceAll("player_my_", "")
.replaceAll("player_opp_", "");
final stats = playerStats[playerId]!;
final name = playerNames[playerId] ?? "Jogador";
String logText = "";
// ── PONTOS ──────────────────────────────────────────────────────────────
if (action.startsWith("add_pts_")) {
int pts = int.parse(action.split("_").last);
if (isOpponent) opponentScore += pts; else myScore += pts;
if (isOpponent)
opponentScore += pts;
else
myScore += pts;
stats["pts"] = stats["pts"]! + pts;
if (pts == 2) { stats["fgm"] = stats["fgm"]! + 1; stats["fga"] = stats["fga"]! + 1; stats["p2m"] = stats["p2m"]! + 1; stats["p2a"] = stats["p2a"]! + 1; }
if (pts == 3) { stats["fgm"] = stats["fgm"]! + 1; stats["fga"] = stats["fga"]! + 1; stats["p3m"] = stats["p3m"]! + 1; stats["p3a"] = stats["p3a"]! + 1; }
if (pts == 1) { stats["ftm"] = stats["ftm"]! + 1; stats["fta"] = stats["fta"]! + 1; }
if (pts == 2) {
stats["fgm"] = stats["fgm"]! + 1;
stats["fga"] = stats["fga"]! + 1;
stats["p2m"] = stats["p2m"]! + 1;
stats["p2a"] = stats["p2a"]! + 1;
}
if (pts == 3) {
stats["fgm"] = stats["fgm"]! + 1;
stats["fga"] = stats["fga"]! + 1;
stats["p3m"] = stats["p3m"]! + 1;
stats["p3a"] = stats["p3a"]! + 1;
}
if (pts == 1) {
stats["ftm"] = stats["ftm"]! + 1;
stats["fta"] = stats["fta"]! + 1;
}
logText = "marcou $pts pontos 🏀";
}
// ── ANULAR PONTOS ────────────────────────────────────────────────────────
else if (action.startsWith("sub_pts_")) {
int ptsToAnul = int.parse(action.split("_").last);
int lastShotIndex = matchShots.lastIndexWhere((s) =>
s.playerId == playerId &&
s.isMake == true &&
s.points == ptsToAnul
);
s.playerId == playerId && s.isMake == true && s.points == ptsToAnul);
if (lastShotIndex != -1) {
matchShots.removeAt(lastShotIndex);
if (isOpponent) opponentScore -= ptsToAnul; else myScore -= ptsToAnul;
if (isOpponent)
opponentScore -= ptsToAnul;
else
myScore -= ptsToAnul;
stats["pts"] = stats["pts"]! - ptsToAnul;
if (ptsToAnul == 2) {
@@ -533,33 +552,113 @@ class PlacarController extends ChangeNotifier {
return;
}
}
else if (action == "miss_1") { stats["fta"] = stats["fta"]! + 1; logText = "falhou lance livre ❌"; }
else if (action == "miss_2") { stats["fga"] = stats["fga"]! + 1; stats["p2a"] = stats["p2a"]! + 1; logText = "falhou lançamento de 2 ❌"; }
else if (action == "miss_3") { stats["fga"] = stats["fga"]! + 1; stats["p3a"] = stats["p3a"]! + 1; logText = "falhou lançamento de 3 ❌"; }
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_blk") { stats["blk"] = stats["blk"]! + 1; logText = "fez um desarme (bloco) ✋"; }
else if (action == "add_so") { stats["so"] = stats["so"]! + 1; logText = "sofreu uma falta 🤕"; }
else if (action == "add_il") { stats["il"] = stats["il"]! + 1; logText = "intercetou um lançamento 🛑"; }
else if (action == "add_li") { stats["li"] = stats["li"]! + 1; logText = "teve o lançamento intercetado 🚫"; }
// ── FALHAS ───────────────────────────────────────────────────────────────
else if (action == "miss_1") {
stats["fta"] = stats["fta"]! + 1;
logText = "falhou lance livre ❌";
} else if (action == "miss_2") {
stats["fga"] = stats["fga"]! + 1;
stats["p2a"] = stats["p2a"]! + 1;
logText = "falhou lançamento de 2 ❌";
} else if (action == "miss_3") {
stats["fga"] = stats["fga"]! + 1;
stats["p3a"] = stats["p3a"]! + 1;
logText = "falhou lançamento de 3 ❌";
}
else if (action == "add_tov") { stats["tov"] = stats["tov"]! + 1; logText = "fez um passe ruim 🤦"; }
else if (action == "add_pa") { stats["pa"] = stats["pa"]! + 1; stats["tov"] = stats["tov"]! + 1; logText = "cometeu passos 🚶"; }
else if (action == "add_3s") { stats["tres_s"] = stats["tres_s"]! + 1; stats["tov"] = stats["tov"]! + 1; logText = "violação de 3 segundos ⏱️"; }
else if (action == "add_24s") { stats["tov"] = stats["tov"]! + 1; logText = "violação de 24 segundos ⏱️"; }
else if (action == "add_dr") { stats["dr"] = stats["dr"]! + 1; stats["tov"] = stats["tov"]! + 1; logText = "fez drible duplo 🏀"; }
// ── RESSALTOS ─────────────────────────────────────────────────────────────
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 🛡️";
}
// ── ASSISTÊNCIA ───────────────────────────────────────────────────────────
else if (action == "add_ast") {
stats["ast"] = stats["ast"]! + 1;
logText = "fez uma assistência 🤝";
}
// ── SOFRIDAS ──────────────────────────────────────────────────────────────
else if (action == "add_so") {
stats["so"] = stats["so"]! + 1;
logText = "sofreu uma falta 🤕";
}
// ══════════════════════════════════════════════════════════════════════════
// STEAL — ROUBO DE BOLA
// ══════════════════════════════════════════════════════════════════════════
else if (action == "add_stl" || action == "stl_steal") {
stats["stl"] = stats["stl"]! + 1;
logText = "roubou a bola 🥷";
} else if (action == "stl_intercept") {
stats["stl"] = stats["stl"]! + 1;
stats["il"] = stats["il"]! + 1;
logText = "intercetou um lançamento 🛑";
}
// ══════════════════════════════════════════════════════════════════════════
// BLOCK — DESARME
// ══════════════════════════════════════════════════════════════════════════
else if (action == "add_blk" || action == "blk_made") {
stats["blk"] = stats["blk"]! + 1;
logText = "fez um desarme (bloco) ✋";
} else if (action == "blk_suffered") {
stats["li"] = stats["li"]! + 1;
logText = "sofreu um desarme 🚫";
}
// Ações independentes legadas
else if (action == "add_il") {
stats["il"] = stats["il"]! + 1;
logText = "intercetou um lançamento 🛑";
} else if (action == "add_li") {
stats["li"] = stats["li"]! + 1;
logText = "teve o lançamento intercetado 🚫";
}
// ══════════════════════════════════════════════════════════════════════════
// TURNOVER — PERDE DE BOLA E INFRAÇÕES
// ══════════════════════════════════════════════════════════════════════════
else if (action == "add_tov" || action == "tov_badpass") {
stats["tov"] = stats["tov"]! + 1;
logText = "fez um passe ruim 🤦";
} else if (action == "tov_3s") {
stats["tres_seg"] = stats["tres_seg"]! + 1; // SOMA AOS 3 SEGUNDOS
stats["tov"] = stats["tov"]! + 1; // SOMA AO TURNOVER GERAL
logText = "violação de 3 segundos ⏱️";
} else if (action == "tov_clock") {
stats["tov"] = stats["tov"]! + 1;
logText = "violação de 24 segundos ⏱️";
} else if (action == "tov_travel") {
stats["pa"] = stats["pa"]! + 1; // SOMA AOS PASSOS
stats["tov"] = stats["tov"]! + 1; // SOMA AO TURNOVER GERAL
logText = "cometeu passos 🚶";
} else if (action == "tov_double") {
stats["dr"] = stats["dr"]! + 1; // SOMA AOS DRIBLES DUPLOS
stats["tov"] = stats["tov"]! + 1; // SOMA AO TURNOVER GERAL
logText = "fez drible duplo 🏀";
}
// ── ANULAR 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--; }
if (isOpponent) {
if (opponentFouls > 0) opponentFouls--;
} else {
if (myFouls > 0) myFouls--;
}
logText = "teve falta anulada 🔄";
}
if (logText.isNotEmpty) {
String time = "${durationNotifier.value.inMinutes.toString().padLeft(2, '0')}:${durationNotifier.value.inSeconds.remainder(60).toString().padLeft(2, '0')}";
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");
}
@@ -567,19 +666,31 @@ class PlacarController extends ChangeNotifier {
notifyListeners();
}
@override
void dispose() {
timer?.cancel();
_autoSaveTimer?.cancel();
super.dispose();
}
Future<void> saveGameStats(BuildContext context) async {
final supabase = Supabase.instance.client;
isSaving = true;
notifyListeners();
try {
bool isGameFinishedNow = currentQuarter >= 4 && durationNotifier.value.inSeconds == 0;
bool isGameFinishedNow =
currentQuarter >= 4 && durationNotifier.value.inSeconds == 0;
String newStatus = isGameFinishedNow ? 'Terminado' : 'Pausado';
String topPtsName = '---'; int maxPts = -1;
String topAstName = '---'; int maxAst = -1;
String topRbsName = '---'; int maxRbs = -1;
String mvpName = '---'; double maxMvpScore = -999.0;
String topPtsName = '---';
int maxPts = -1;
String topAstName = '---';
int maxAst = -1;
String topRbsName = '---';
int maxRbs = -1;
String mvpName = '---';
double maxMvpScore = -999.0;
playerStats.forEach((playerId, stats) {
int pts = stats['pts'] ?? 0;
@@ -595,65 +706,106 @@ class PlacarController extends ChangeNotifier {
int lFalhados = (stats['fga'] ?? 0) - (stats['fgm'] ?? 0);
int llFalhados = (stats['fta'] ?? 0) - (stats['ftm'] ?? 0);
double mvpScore = ((pts * 0.30) + (tr * 0.20) + (ast * 0.35) + (br * 0.15)) -
double mvpScore =
((pts * 0.30) + (tr * 0.20) + (ast * 0.35) + (br * 0.15)) -
((bp * 0.35) + (lFalhados * 0.30) + (llFalhados * 0.35));
mvpScore = mvpScore * (minJogados / 40.0);
String pName = playerNames[playerId] ?? '---';
if (pts > maxPts && pts > 0) { maxPts = pts; topPtsName = '$pName ($pts)'; }
if (ast > maxAst && ast > 0) { maxAst = ast; topAstName = '$pName ($ast)'; }
if (rbs > maxRbs && rbs > 0) { maxRbs = rbs; topRbsName = '$pName ($rbs)'; }
if (mvpScore > maxMvpScore) { maxMvpScore = mvpScore; mvpName = '$pName (${mvpScore.toStringAsFixed(1)})'; }
if (pts > maxPts && pts > 0) {
maxPts = pts;
topPtsName = '$pName ($pts)';
}
if (ast > maxAst && ast > 0) {
maxAst = ast;
topAstName = '$pName ($ast)';
}
if (rbs > maxRbs && rbs > 0) {
maxRbs = rbs;
topRbsName = '$pName ($rbs)';
}
if (mvpScore > maxMvpScore) {
maxMvpScore = mvpScore;
mvpName = '$pName (${mvpScore.toStringAsFixed(1)})';
}
});
await supabase.from('games').update({
'my_score': myScore, 'opponent_score': opponentScore,
'my_score': myScore,
'opponent_score': opponentScore,
'remaining_seconds': durationNotifier.value.inSeconds,
'my_timeouts': myTimeoutsUsed, 'opp_timeouts': opponentTimeoutsUsed,
'current_quarter': currentQuarter, 'status': newStatus,
'top_pts_name': topPtsName, 'top_ast_name': topAstName,
'top_rbs_name': topRbsName, 'mvp_name': mvpName,
'my_timeouts': myTimeoutsUsed,
'opp_timeouts': opponentTimeoutsUsed,
'current_quarter': currentQuarter,
'status': newStatus,
'top_pts_name': topPtsName,
'top_ast_name': topAstName,
'top_rbs_name': topRbsName,
'mvp_name': mvpName,
'play_by_play': playByPlay,
}).eq('id', gameId);
List<Map<String, dynamic>> batchStats = [];
playerStats.forEach((playerId, stats) {
if (!playerId.startsWith("fake_")) {
bool isMyTeamPlayer = myCourt.contains(playerId) || myBench.contains(playerId);
bool isMyTeamPlayer =
myCourt.contains(playerId) || myBench.contains(playerId);
batchStats.add({
'game_id': gameId, 'member_id': playerId, 'team_id': isMyTeamPlayer ? myTeamDbId! : oppTeamDbId!,
'pts': stats['pts'], 'rbs': stats['rbs'], 'ast': stats['ast'], 'stl': stats['stl'], 'blk': stats['blk'],
'tov': stats['tov'], 'fls': stats['fls'], 'fgm': stats['fgm'], 'fga': stats['fga'], 'ftm': stats['ftm'],
'fta': stats['fta'], 'orb': stats['orb'], 'drb': stats['drb'], 'p2m': stats['p2m'], 'p2a': stats['p2a'],
'p3m': stats['p3m'], 'p3a': stats['p3a'],
'so': stats['so'], 'il': stats['il'], 'li': stats['li'], 'pa': stats['pa'], 'tres_seg': stats['tres_s'],
'dr': stats['dr'], 'minutos_jogados': stats['sec'],
'game_id': gameId,
'member_id': playerId,
'team_id': isMyTeamPlayer ? myTeamDbId! : oppTeamDbId!,
'pts': stats['pts'],
'rbs': stats['rbs'],
'ast': stats['ast'],
'stl': stats['stl'],
'blk': stats['blk'],
'tov': stats['tov'],
'fls': stats['fls'],
'fgm': stats['fgm'],
'fga': stats['fga'],
'ftm': stats['ftm'],
'fta': stats['fta'],
'orb': stats['orb'],
'drb': stats['drb'],
'p2m': stats['p2m'],
'p2a': stats['p2a'],
'p3m': stats['p3m'],
'p3a': stats['p3a'],
'so': stats['so'], // As Faltas Sofridas
'il': stats['il'],
'li': stats['li'],
'pa': stats['pa'],
'tres_seg': stats['tres_seg'], // Os 3 Segundos com o nome correto
'dr': stats['dr'],
'minutos_jogados': stats['sec'],
});
}
});
await supabase.from('player_stats').delete().eq('game_id', gameId);
if (batchStats.isNotEmpty) await supabase.from('player_stats').insert(batchStats);
if (batchStats.isNotEmpty) {
await supabase.from('player_stats').insert(batchStats);
}
final prefs = await SharedPreferences.getInstance();
await prefs.remove('backup_$gameId');
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Guardado com Sucesso!'), backgroundColor: Colors.green));
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Guardado com Sucesso!'),
backgroundColor: Colors.green));
}
} catch (e) {
debugPrint("Erro ao gravar estatísticas: $e");
if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Erro ao guardar: $e'), backgroundColor: Colors.red));
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Erro ao guardar: $e'),
backgroundColor: Colors.red));
}
} finally {
isSaving = false;
notifyListeners();
}
}
@override
void dispose() {
timer?.cancel();
_autoSaveTimer?.cancel();
super.dispose();
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -109,10 +109,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.4.0"
clock:
dependency: transitive
description:
@@ -468,18 +468,18 @@ packages:
dependency: transitive
description:
name: matcher
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.18"
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.13.0"
version: "0.11.1"
meta:
dependency: transitive
description:
@@ -873,10 +873,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
url: "https://pub.dev"
source: hosted
version: "0.7.9"
version: "0.7.7"
typed_data:
dependency: transitive
description: