mudar na tabela

This commit is contained in:
2026-04-20 15:02:00 +01:00
parent ce25fe6499
commit cc753b395d
3 changed files with 138 additions and 90 deletions

View File

@@ -193,8 +193,9 @@ class PlacarController extends ChangeNotifier {
"p2m": s['p2m'] ?? 0, "p2a": s['p2a'] ?? 0, "p3m": s['p3m'] ?? 0, "p3a": s['p3a'] ?? 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, "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_s": s['tres_seg'] ?? 0, "dr": s['dr'] ?? 0,
"min": s['minutos_jogados'] ?? 0, // 👇 AGORA CARREGA OS SEGUNDOS EXATOS DA BASE DE DADOS
"sec": (s['minutos_jogados'] ?? 0) * 60, "min": (s['minutos_jogados'] ?? 0) ~/ 60,
"sec": s['minutos_jogados'] ?? 0,
}; };
} }
@@ -291,6 +292,7 @@ class PlacarController extends ChangeNotifier {
} }
} }
} }
addTimeToCourt(myCourt); addTimeToCourt(myCourt);
addTimeToCourt(oppCourt); addTimeToCourt(oppCourt);
@@ -501,20 +503,19 @@ class PlacarController extends ChangeNotifier {
if (lastShotIndex != -1) { if (lastShotIndex != -1) {
matchShots.removeAt(lastShotIndex); matchShots.removeAt(lastShotIndex);
if (isOpponent) opponentScore -= ptsToAnul; else myScore -= ptsToAnul; if (isOpponent) opponentScore -= ptsToAnul; else myScore -= ptsToAnul;
stats["pts"] = stats["pts"]! - ptsToAnul; stats["pts"] = stats["pts"]! - ptsToAnul;
if (ptsToAnul == 2) { if (ptsToAnul == 2) {
if(stats["fgm"]! > 0) stats["fgm"] = stats["fgm"]! - 1;
if(stats["fga"]! > 0) stats["fga"] = stats["fga"]! - 1;
if(stats["p2m"]! > 0) stats["p2m"] = stats["p2m"]! - 1; if(stats["p2m"]! > 0) stats["p2m"] = stats["p2m"]! - 1;
if(stats["p2a"]! > 0) stats["p2a"] = stats["p2a"]! - 1; if(stats["p2a"]! > 0) stats["p2a"] = stats["p2a"]! - 1;
} else if (ptsToAnul == 3) {
if(stats["fgm"]! > 0) stats["fgm"] = stats["fgm"]! - 1; if(stats["fgm"]! > 0) stats["fgm"] = stats["fgm"]! - 1;
if(stats["fga"]! > 0) stats["fga"] = stats["fga"]! - 1; if(stats["fga"]! > 0) stats["fga"] = stats["fga"]! - 1;
} else if (ptsToAnul == 3) {
if(stats["p3m"]! > 0) stats["p3m"] = stats["p3m"]! - 1; if(stats["p3m"]! > 0) stats["p3m"] = stats["p3m"]! - 1;
if(stats["p3a"]! > 0) stats["p3a"] = stats["p3a"]! - 1; if(stats["p3a"]! > 0) stats["p3a"] = stats["p3a"]! - 1;
if(stats["fgm"]! > 0) stats["fgm"] = stats["fgm"]! - 1;
if(stats["fga"]! > 0) stats["fga"] = stats["fga"]! - 1;
} else if (ptsToAnul == 1) { } else if (ptsToAnul == 1) {
if(stats["ftm"]! > 0) stats["ftm"] = stats["ftm"]! - 1; if(stats["ftm"]! > 0) stats["ftm"] = stats["ftm"]! - 1;
if(stats["fta"]! > 0) stats["fta"] = stats["fta"]! - 1; if(stats["fta"]! > 0) stats["fta"] = stats["fta"]! - 1;
@@ -619,7 +620,9 @@ class PlacarController extends ChangeNotifier {
'fta': stats['fta'], 'orb': stats['orb'], 'drb': stats['drb'], 'p2m': stats['p2m'], 'p2a': stats['p2a'], 'fta': stats['fta'], 'orb': stats['orb'], 'drb': stats['drb'], 'p2m': stats['p2m'], 'p2a': stats['p2a'],
'p3m': stats['p3m'], 'p3a': stats['p3a'], 'p3m': stats['p3m'], 'p3a': stats['p3a'],
'so': stats['so'], 'il': stats['il'], 'li': stats['li'], 'pa': stats['pa'], 'tres_seg': stats['tres_s'], 'so': stats['so'], 'il': stats['il'], 'li': stats['li'], 'pa': stats['pa'], 'tres_seg': stats['tres_s'],
'dr': stats['dr'], 'minutos_jogados': stats['min'], 'dr': stats['dr'],
// 👇 AQUI GUARDA OS SEGUNDOS EXATOS NA BASE DE DADOS (IMPEDE A PERDA DE TEMPO)
'minutos_jogados': stats['sec'],
}); });
} }
}); });

View File

@@ -252,8 +252,7 @@ class _PlacarPageState extends State<PlacarPage> {
children: [ children: [
_buildCornerBtn(heroTag: 'btn_heatmap', icon: Icons.local_fire_department, color: Colors.orange.shade800, size: cornerBtnSize, onTap: () => _showHeatmap(context)), _buildCornerBtn(heroTag: 'btn_heatmap', icon: Icons.local_fire_department, color: Colors.orange.shade800, size: cornerBtnSize, onTap: () => _showHeatmap(context)),
SizedBox(height: 10 * sf), SizedBox(height: 10 * sf),
_buildCornerBtn(heroTag: 'btn_boxscore', icon: Icons.table_chart, color: Colors.indigo, size: cornerBtnSize, onTap: () => showDialog(context: context, builder: (ctx) => BoxScoreDialog(controller: _controller))), _buildCornerBtn(heroTag: 'btn_boxscore', icon: Icons.table_chart, color: Colors.indigo, size: cornerBtnSize, onTap: () => showDialog(context: context, builder: (ctx) => BoxScoreDialog(controller: _controller, sf: sf))), ],
],
), ),
), ),
@@ -1335,7 +1334,9 @@ class PlayByPlayDialog extends StatelessWidget {
class BoxScoreDialog extends StatelessWidget { class BoxScoreDialog extends StatelessWidget {
final PlacarController controller; final PlacarController controller;
const BoxScoreDialog({super.key, required this.controller}); final double sf;
const BoxScoreDialog({super.key, required this.controller, required this.sf});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -1344,38 +1345,62 @@ class BoxScoreDialog extends StatelessWidget {
builder: (context, child) { builder: (context, child) {
return Dialog( return Dialog(
backgroundColor: AppTheme.placarDarkSurface, backgroundColor: AppTheme.placarDarkSurface,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), shape: RoundedRectangleBorder(
child: Container( borderRadius: BorderRadius.circular(12 * sf),
width: MediaQuery.of(context).size.width * 0.9, side: BorderSide(color: Colors.white24, width: 1 * sf),
height: MediaQuery.of(context).size.height * 0.9, ),
padding: const EdgeInsets.all(16), // 👇 REDUZIMOS AS MARGENS PARA O POP-UP FICAR GIGANTE
insetPadding: EdgeInsets.all(8 * sf),
clipBehavior: Clip.antiAlias,
child: SizedBox(
// 👇 FORÇAMOS A LARGURA E ALTURA PARA 98% DO ECRÃ
width: MediaQuery.of(context).size.width * 0.98,
height: MediaQuery.of(context).size.height * 0.98,
child: DefaultTabController( child: DefaultTabController(
length: 2, length: 2,
child: Column( child: Column(
children: [ children: [
Row( Padding(
mainAxisAlignment: MainAxisAlignment.spaceBetween, padding: EdgeInsets.fromLTRB(16 * sf, 16 * sf, 8 * sf, 0),
children: [ child: Row(
const Text("BOX SCORE", style: TextStyle(color: Colors.white, fontSize: 22, fontWeight: FontWeight.bold)), mainAxisAlignment: MainAxisAlignment.spaceBetween,
IconButton(icon: const Icon(Icons.close, color: Colors.white), onPressed: () => Navigator.pop(context)) children: [
], Text("BOX SCORE", style: TextStyle(color: Colors.white, fontSize: 20 * sf, fontWeight: FontWeight.bold)),
IconButton(
icon: Icon(Icons.close, color: Colors.white, size: 24 * sf),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
onPressed: () => Navigator.pop(context)
)
],
),
), ),
SizedBox(height: 8 * sf),
TabBar( TabBar(
indicatorColor: AppTheme.warningAmber, indicatorColor: AppTheme.warningAmber,
labelColor: Colors.white, labelColor: Colors.white,
unselectedLabelColor: Colors.white54, unselectedLabelColor: Colors.white54,
// 👇 LETRAS DAS ABAS MAIORES
labelStyle: TextStyle(fontSize: 14 * sf, fontWeight: FontWeight.bold),
indicatorWeight: 3 * sf,
dividerColor: Colors.white10,
tabs: [ tabs: [
Tab(text: controller.myTeam.toUpperCase()), Tab(text: controller.myTeam.toUpperCase(), height: 40 * sf),
Tab(text: controller.opponentTeam.toUpperCase()), Tab(text: controller.opponentTeam.toUpperCase(), height: 40 * sf),
], ],
), ),
const SizedBox(height: 10),
Expanded( Expanded(
child: TabBarView( child: Container(
children: [ width: double.infinity,
_buildStatsTable(controller.myCourt + controller.myBench, controller), color: Colors.black12,
_buildStatsTable(controller.oppCourt + controller.oppBench, controller), child: TabBarView(
], children: [
_buildStatsTable(controller.myCourt + controller.myBench, controller, sf),
_buildStatsTable(controller.oppCourt + controller.oppBench, controller, sf),
],
),
), ),
), ),
], ],
@@ -1387,66 +1412,85 @@ class BoxScoreDialog extends StatelessWidget {
); );
} }
Widget _buildStatsTable(List<String> teamPlayers, PlacarController ctrl) { Widget _buildStatsTable(List<String> teamPlayers, PlacarController ctrl, double sf) {
return SingleChildScrollView( return LayoutBuilder(
scrollDirection: Axis.vertical, builder: (context, constraints) {
child: SingleChildScrollView( return SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.vertical,
child: DataTable( // 👇 O SEGREDO ESTÁ AQUI: Este BouncingScrollPhysics permite que o gesto de "swipe"
headingRowColor: WidgetStateProperty.all(Colors.black26), // passe para as abas quando chegas ao fim da tabela!
columns: const [ physics: const BouncingScrollPhysics(),
DataColumn(label: Text('JOGADOR', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), child: SingleChildScrollView(
DataColumn(label: Text('MIN', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), scrollDirection: Axis.horizontal,
DataColumn(label: Text('PTS', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), // 👇 E AQUI TAMBÉM
DataColumn(label: Text('REB', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), physics: const BouncingScrollPhysics(),
DataColumn(label: Text('AST', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), child: ConstrainedBox(
DataColumn(label: Text('STL', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), constraints: BoxConstraints(minWidth: constraints.maxWidth),
DataColumn(label: Text('BLK', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), child: DataTable(
DataColumn(label: Text('TOV', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), headingRowColor: WidgetStateProperty.all(AppTheme.placarListCard),
DataColumn(label: Text('FLS', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), columnSpacing: 18 * sf,
DataColumn(label: Text('SO', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), horizontalMargin: 16 * sf,
DataColumn(label: Text('IL', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), headingRowHeight: 45 * sf,
DataColumn(label: Text('LI', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), dataRowMinHeight: 40 * sf,
DataColumn(label: Text('PA', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), dataRowMaxHeight: 45 * sf,
DataColumn(label: Text('3S', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), headingTextStyle: TextStyle(color: Colors.white70, fontWeight: FontWeight.bold, fontSize: 13 * sf),
DataColumn(label: Text('DR', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), dataTextStyle: TextStyle(color: Colors.white, fontSize: 13 * sf),
DataColumn(label: Text('FG', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), columns: const [
], DataColumn(label: Text('JOGADOR')),
rows: teamPlayers.where((id) => !id.startsWith("fake_")).map((id) { DataColumn(label: Text('MIN')),
final name = ctrl.playerNames[id] ?? "---"; DataColumn(label: Text('PTS')),
final s = ctrl.playerStats[id]!; DataColumn(label: Text('REB')),
DataColumn(label: Text('AST')),
DataColumn(label: Text('STL')),
DataColumn(label: Text('BLK')),
DataColumn(label: Text('TOV')),
DataColumn(label: Text('FLS')),
DataColumn(label: Text('SO')),
DataColumn(label: Text('IL')),
DataColumn(label: Text('LI')),
DataColumn(label: Text('PA')),
DataColumn(label: Text('3S')),
DataColumn(label: Text('DR')),
DataColumn(label: Text('FG')),
],
rows: teamPlayers.where((id) => !id.startsWith("fake_")).map((id) {
final name = ctrl.playerNames[id] ?? "---";
final s = ctrl.playerStats[id]!;
int totalSecs = s['sec'] ?? 0; int totalSecs = s['sec'] ?? 0;
int minutes = totalSecs ~/ 60; int minutes = totalSecs ~/ 60;
int seconds = totalSecs % 60; int seconds = totalSecs % 60;
String timeStr = '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; String timeStr = '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
final rebs = s['orb']! + s['drb']!; final rebs = s['orb']! + s['drb']!;
final fgText = "${s['fgm']}/${s['fga']}"; final fgText = "${s['fgm']}/${s['fga']}";
return DataRow( return DataRow(
cells: [ cells: [
DataCell(Text(name, style: const TextStyle(color: Colors.white))), DataCell(Text(name, style: const TextStyle(fontWeight: FontWeight.bold))),
DataCell(Text(timeStr, style: const TextStyle(color: Colors.white70))), DataCell(Text(timeStr, style: const TextStyle(color: Colors.white70))),
DataCell(Text(s['pts'].toString(), style: const TextStyle(color: AppTheme.warningAmber, fontWeight: FontWeight.bold))), DataCell(Text(s['pts'].toString(), style: TextStyle(color: AppTheme.warningAmber, fontWeight: FontWeight.bold, fontSize: 14 * sf))),
DataCell(Text(rebs.toString(), style: const TextStyle(color: Colors.white))), DataCell(Text(rebs.toString())),
DataCell(Text(s['ast'].toString(), style: const TextStyle(color: Colors.white))), DataCell(Text(s['ast'].toString())),
DataCell(Text(s['stl'].toString(), style: const TextStyle(color: Colors.white))), DataCell(Text(s['stl'].toString())),
DataCell(Text(s['blk'].toString(), style: const TextStyle(color: Colors.white))), DataCell(Text(s['blk'].toString())),
DataCell(Text(s['tov'].toString(), style: const TextStyle(color: Colors.redAccent))), DataCell(Text(s['tov'].toString(), style: const TextStyle(color: Colors.redAccent))),
DataCell(Text(s['fls'].toString(), style: const TextStyle(color: Colors.white))), DataCell(Text(s['fls'].toString())),
DataCell(Text((s['so'] ?? 0).toString(), style: const TextStyle(color: Colors.greenAccent))), DataCell(Text((s['so'] ?? 0).toString(), style: const TextStyle(color: Colors.greenAccent))),
DataCell(Text((s['il'] ?? 0).toString(), style: const TextStyle(color: Colors.lightBlue))), DataCell(Text((s['il'] ?? 0).toString(), style: const TextStyle(color: Colors.lightBlue))),
DataCell(Text((s['li'] ?? 0).toString(), style: const TextStyle(color: Colors.orangeAccent))), DataCell(Text((s['li'] ?? 0).toString(), style: const TextStyle(color: Colors.orangeAccent))),
DataCell(Text((s['pa'] ?? 0).toString(), style: const TextStyle(color: Colors.redAccent))), DataCell(Text((s['pa'] ?? 0).toString(), style: const TextStyle(color: Colors.redAccent))),
DataCell(Text((s['tres_s'] ?? 0).toString(), style: const TextStyle(color: Colors.redAccent))), DataCell(Text((s['tres_s'] ?? 0).toString(), style: const TextStyle(color: Colors.redAccent))),
DataCell(Text((s['dr'] ?? 0).toString(), style: const TextStyle(color: Colors.redAccent))), DataCell(Text((s['dr'] ?? 0).toString(), style: const TextStyle(color: Colors.redAccent))),
DataCell(Text(fgText, style: const TextStyle(color: Colors.white54))), DataCell(Text(fgText, style: const TextStyle(color: Colors.white54))),
], ],
); );
}).toList(), }).toList(),
), ),
), ),
),
);
}
); );
} }
} }

View File

@@ -6,6 +6,7 @@ import '../controllers/team_controller.dart';
import '../controllers/game_controller.dart'; import '../controllers/game_controller.dart';
import '../models/game_model.dart'; import '../models/game_model.dart';
import '../utils/size_extension.dart'; import '../utils/size_extension.dart';
import 'pdf_export_service.dart'; import 'pdf_export_service.dart';
class GameResultCard extends StatelessWidget { class GameResultCard extends StatelessWidget {