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,
"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,
};
}
@@ -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'],
});
}
});

View File

@@ -252,8 +252,7 @@ class _PlacarPageState extends State<PlacarPage> {
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<String> 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]!;
Widget _buildStatsTable(List<String> 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')}';
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']}";
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(),
),
),
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(),
),
),
),
);
}
);
}
}

View File

@@ -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 {