From cc753b395d1fc140692305d839a30179cf5b3243 Mon Sep 17 00:00:00 2001 From: 230404 <230404@epvc.pt> Date: Mon, 20 Apr 2026 15:02:00 +0100 Subject: [PATCH] mudar na tabela --- lib/controllers/placar_controller.dart | 19 ++- lib/pages/PlacarPage.dart | 208 +++++++++++++++---------- lib/pages/gamePage.dart | 1 + 3 files changed, 138 insertions(+), 90 deletions(-) diff --git a/lib/controllers/placar_controller.dart b/lib/controllers/placar_controller.dart index 54c6da2..b205202 100644 --- a/lib/controllers/placar_controller.dart +++ b/lib/controllers/placar_controller.dart @@ -193,8 +193,9 @@ class PlacarController extends ChangeNotifier { "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, - "min": s['minutos_jogados'] ?? 0, - "sec": (s['minutos_jogados'] ?? 0) * 60, + // 👇 AGORA CARREGA OS SEGUNDOS EXATOS DA BASE DE DADOS + "min": (s['minutos_jogados'] ?? 0) ~/ 60, + "sec": s['minutos_jogados'] ?? 0, }; } @@ -209,7 +210,7 @@ class PlacarController extends ChangeNotifier { "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, - "min": 0, "sec": 0 + "min": 0, "sec": 0 }; if (isMyTeam) { @@ -291,6 +292,7 @@ class PlacarController extends ChangeNotifier { } } } + addTimeToCourt(myCourt); addTimeToCourt(oppCourt); @@ -501,20 +503,19 @@ class PlacarController extends ChangeNotifier { if (lastShotIndex != -1) { matchShots.removeAt(lastShotIndex); - if (isOpponent) opponentScore -= ptsToAnul; else myScore -= ptsToAnul; stats["pts"] = stats["pts"]! - ptsToAnul; 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["p2a"]! > 0) stats["p2a"] = stats["p2a"]! - 1; - } else if (ptsToAnul == 3) { if(stats["fgm"]! > 0) stats["fgm"] = stats["fgm"]! - 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["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) { if(stats["ftm"]! > 0) stats["ftm"] = stats["ftm"]! - 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'], '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['min'], + 'dr': stats['dr'], + // 👇 AQUI GUARDA OS SEGUNDOS EXATOS NA BASE DE DADOS (IMPEDE A PERDA DE TEMPO) + 'minutos_jogados': stats['sec'], }); } }); diff --git a/lib/pages/PlacarPage.dart b/lib/pages/PlacarPage.dart index 3d5f9f0..71ed7a4 100644 --- a/lib/pages/PlacarPage.dart +++ b/lib/pages/PlacarPage.dart @@ -252,8 +252,7 @@ class _PlacarPageState extends State { children: [ _buildCornerBtn(heroTag: 'btn_heatmap', icon: Icons.local_fire_department, color: Colors.orange.shade800, size: cornerBtnSize, onTap: () => _showHeatmap(context)), 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 { final PlacarController controller; - const BoxScoreDialog({super.key, required this.controller}); + final double sf; + + const BoxScoreDialog({super.key, required this.controller, required this.sf}); @override Widget build(BuildContext context) { @@ -1344,38 +1345,62 @@ class BoxScoreDialog extends StatelessWidget { builder: (context, child) { return Dialog( backgroundColor: AppTheme.placarDarkSurface, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - child: Container( - width: MediaQuery.of(context).size.width * 0.9, - height: MediaQuery.of(context).size.height * 0.9, - padding: const EdgeInsets.all(16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12 * sf), + side: BorderSide(color: Colors.white24, width: 1 * sf), + ), + // 👇 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( length: 2, child: Column( children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text("BOX SCORE", style: TextStyle(color: Colors.white, fontSize: 22, fontWeight: FontWeight.bold)), - IconButton(icon: const Icon(Icons.close, color: Colors.white), onPressed: () => Navigator.pop(context)) - ], + Padding( + padding: EdgeInsets.fromLTRB(16 * sf, 16 * sf, 8 * sf, 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + 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( indicatorColor: AppTheme.warningAmber, labelColor: Colors.white, unselectedLabelColor: Colors.white54, + // 👇 LETRAS DAS ABAS MAIORES + labelStyle: TextStyle(fontSize: 14 * sf, fontWeight: FontWeight.bold), + indicatorWeight: 3 * sf, + dividerColor: Colors.white10, tabs: [ - Tab(text: controller.myTeam.toUpperCase()), - Tab(text: controller.opponentTeam.toUpperCase()), + Tab(text: controller.myTeam.toUpperCase(), height: 40 * sf), + Tab(text: controller.opponentTeam.toUpperCase(), height: 40 * sf), ], ), - const SizedBox(height: 10), + Expanded( - child: TabBarView( - children: [ - _buildStatsTable(controller.myCourt + controller.myBench, controller), - _buildStatsTable(controller.oppCourt + controller.oppBench, controller), - ], + child: Container( + width: double.infinity, + color: Colors.black12, + 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 teamPlayers, PlacarController ctrl) { - return SingleChildScrollView( - scrollDirection: Axis.vertical, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: DataTable( - headingRowColor: WidgetStateProperty.all(Colors.black26), - columns: const [ - DataColumn(label: Text('JOGADOR', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('MIN', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('PTS', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('REB', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('AST', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('STL', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('BLK', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('TOV', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('FLS', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('SO', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('IL', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('LI', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('PA', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('3S', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('DR', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - DataColumn(label: Text('FG', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))), - ], - 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 minutes = totalSecs ~/ 60; - int seconds = totalSecs % 60; - String timeStr = '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; - - final rebs = s['orb']! + s['drb']!; - final fgText = "${s['fgm']}/${s['fga']}"; - - return DataRow( - cells: [ - DataCell(Text(name, style: const TextStyle(color: Colors.white))), - 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(rebs.toString(), style: const TextStyle(color: Colors.white))), - DataCell(Text(s['ast'].toString(), style: const TextStyle(color: Colors.white))), - DataCell(Text(s['stl'].toString(), style: const TextStyle(color: Colors.white))), - DataCell(Text(s['blk'].toString(), style: const TextStyle(color: Colors.white))), - 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['so'] ?? 0).toString(), style: const TextStyle(color: Colors.greenAccent))), - 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['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['dr'] ?? 0).toString(), style: const TextStyle(color: Colors.redAccent))), - DataCell(Text(fgText, style: const TextStyle(color: Colors.white54))), - ], - ); - }).toList(), - ), - ), +Widget _buildStatsTable(List teamPlayers, PlacarController ctrl, double sf) { + return LayoutBuilder( + builder: (context, constraints) { + return SingleChildScrollView( + scrollDirection: Axis.vertical, + // 👇 O SEGREDO ESTÁ AQUI: Este BouncingScrollPhysics permite que o gesto de "swipe" + // passe para as abas quando chegas ao fim da tabela! + physics: const BouncingScrollPhysics(), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + // 👇 E AQUI TAMBÉM + physics: const BouncingScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: constraints.maxWidth), + child: DataTable( + headingRowColor: WidgetStateProperty.all(AppTheme.placarListCard), + columnSpacing: 18 * sf, + horizontalMargin: 16 * sf, + headingRowHeight: 45 * sf, + dataRowMinHeight: 40 * sf, + dataRowMaxHeight: 45 * sf, + headingTextStyle: TextStyle(color: Colors.white70, fontWeight: FontWeight.bold, fontSize: 13 * sf), + dataTextStyle: TextStyle(color: Colors.white, fontSize: 13 * sf), + columns: const [ + DataColumn(label: Text('JOGADOR')), + DataColumn(label: Text('MIN')), + DataColumn(label: Text('PTS')), + 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 minutes = totalSecs ~/ 60; + int seconds = totalSecs % 60; + String timeStr = '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; + + final rebs = s['orb']! + s['drb']!; + final fgText = "${s['fgm']}/${s['fga']}"; + + return DataRow( + cells: [ + DataCell(Text(name, style: const TextStyle(fontWeight: FontWeight.bold))), + DataCell(Text(timeStr, style: const TextStyle(color: Colors.white70))), + DataCell(Text(s['pts'].toString(), style: TextStyle(color: AppTheme.warningAmber, fontWeight: FontWeight.bold, fontSize: 14 * sf))), + DataCell(Text(rebs.toString())), + DataCell(Text(s['ast'].toString())), + DataCell(Text(s['stl'].toString())), + DataCell(Text(s['blk'].toString())), + DataCell(Text(s['tov'].toString(), style: const TextStyle(color: Colors.redAccent))), + DataCell(Text(s['fls'].toString())), + 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['li'] ?? 0).toString(), style: const TextStyle(color: Colors.orangeAccent))), + 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['dr'] ?? 0).toString(), style: const TextStyle(color: Colors.redAccent))), + DataCell(Text(fgText, style: const TextStyle(color: Colors.white54))), + ], + ); + }).toList(), + ), + ), + ), + ); + } ); } } \ No newline at end of file diff --git a/lib/pages/gamePage.dart b/lib/pages/gamePage.dart index 102b02d..1fd8e21 100644 --- a/lib/pages/gamePage.dart +++ b/lib/pages/gamePage.dart @@ -6,6 +6,7 @@ import '../controllers/team_controller.dart'; import '../controllers/game_controller.dart'; import '../models/game_model.dart'; import '../utils/size_extension.dart'; + import 'pdf_export_service.dart'; class GameResultCard extends StatelessWidget {