From 7aa85ac379a6b6ace6a98c11195e33e392591c38 Mon Sep 17 00:00:00 2001 From: 230404 <230404@epvc.pt> Date: Thu, 26 Feb 2026 10:41:12 +0000 Subject: [PATCH] corrigir os botoes novos --- lib/icons.dart/resaltosicon.dart | 27 +++++ lib/pages/PlacarPage.dart | 180 +++++++++++++++++++------------ lib/widgets/game_widgets.dart | 1 + 3 files changed, 142 insertions(+), 66 deletions(-) create mode 100644 lib/icons.dart/resaltosicon.dart diff --git a/lib/icons.dart/resaltosicon.dart b/lib/icons.dart/resaltosicon.dart new file mode 100644 index 0000000..17c96f5 --- /dev/null +++ b/lib/icons.dart/resaltosicon.dart @@ -0,0 +1,27 @@ + import 'package:flutter/material.dart'; + + void main() { + runApp(const MyApp()); + } + + class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Ícone de Basquete'), + ), + body: const Center( + child: Icon( + Icons.sports_basketball, + size: 100.0, // Tamanho do ícone + color: Colors.black, // Cor do ícone (preto, como na imagem) + ), + ), + ), + ); + } + } \ No newline at end of file diff --git a/lib/pages/PlacarPage.dart b/lib/pages/PlacarPage.dart index 529b81f..c9d84fa 100644 --- a/lib/pages/PlacarPage.dart +++ b/lib/pages/PlacarPage.dart @@ -336,18 +336,18 @@ class _PlacarPageState extends State { int _myTimeoutsUsed = 0; int _opponentTimeoutsUsed = 0; - // MAPA PARA GUARDAR ESTATÍSTICAS INDIVIDUAIS (Key: Nome do Jogador) + // MAPA PARA GUARDAR ESTATÍSTICAS (Guarda tudo na memória, mas só mostra Pts, Rbs e Ast no campo) final Map> _playerStats = { - "Russell": {"pts": 0, "rbs": 0, "ast": 0}, - "Reaves": {"pts": 0, "rbs": 0, "ast": 0}, - "Davis": {"pts": 0, "rbs": 0, "ast": 0}, - "James": {"pts": 0, "rbs": 0, "ast": 0}, - "Hachimura": {"pts": 0, "rbs": 0, "ast": 0}, - "Kyle": {"pts": 0, "rbs": 0, "ast": 0}, - "Serge": {"pts": 0, "rbs": 0, "ast": 0}, - "Kawhi": {"pts": 0, "rbs": 0, "ast": 0}, - "Danny": {"pts": 0, "rbs": 0, "ast": 0}, - "Fred": {"pts": 0, "rbs": 0, "ast": 0}, + "Russell": {"pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0}, + "Reaves": {"pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0}, + "Davis": {"pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0}, + "James": {"pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0}, + "Hachimura": {"pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0}, + "Kyle": {"pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0}, + "Serge": {"pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0}, + "Kawhi": {"pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0}, + "Danny": {"pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0}, + "Fred": {"pts": 0, "rbs": 0, "ast": 0, "stl": 0, "tov": 0, "blk": 0}, }; Duration _duration = const Duration(minutes: 10); @@ -378,7 +378,6 @@ class _PlacarPageState extends State { setState(() => _isRunning = !_isRunning); } - // FUNÇÃO PARA USAR TIME-OUT void _useTimeout(bool isOpponent) { setState(() { if (isOpponent) { @@ -386,7 +385,6 @@ class _PlacarPageState extends State { } else { if (_myTimeoutsUsed < 3) _myTimeoutsUsed++; } - // Para o cronómetro automaticamente ao pedir Time-Out _isRunning = false; _timer?.cancel(); }); @@ -430,7 +428,8 @@ class _PlacarPageState extends State { ), Positioned(top: 0, left: 0, right: 0, child: Center(child: _buildTopScoreboard())), - Positioned(bottom: 20, left: 0, right: 0, child: _buildActionButtonsPanel()), + + Positioned(bottom: 10, left: 0, right: 0, child: _buildActionButtonsPanel()), Positioned( bottom: 20, right: 20, @@ -448,14 +447,12 @@ class _PlacarPageState extends State { List _buildTacticalFormation(double w, double h) { return [ - // CASA Positioned(top: h * 0.25, left: w * 0.02, child: _buildPlayerCard("1", "Russell", false)), Positioned(top: h * 0.68, left: w * 0.02, child: _buildPlayerCard("15", "Reaves", false)), Positioned(top: h * 0.48, left: w * 0.20, child: _buildPlayerCard("3", "Davis", false)), Positioned(top: h * 0.15, left: w * 0.20, child: _buildPlayerCard("6", "James", false)), Positioned(top: h * 0.80, left: w * 0.20, child: _buildPlayerCard("28", "Hachimura", false)), - // VISITANTE Positioned(top: h * 0.25, right: w * 0.02, child: _buildPlayerCard("7", "Kyle", true)), Positioned(top: h * 0.68, right: w * 0.02, child: _buildPlayerCard("9", "Serge", true)), Positioned(top: h * 0.48, right: w * 0.20, child: _buildPlayerCard("2", "Kawhi", true)), @@ -468,13 +465,31 @@ class _PlacarPageState extends State { final teamColor = isOpponent ? const Color(0xFFD92C2C) : const Color(0xFF1E5BB2); final stats = _playerStats[name]!; - return DragTarget( + return DragTarget( onAcceptWithDetails: (details) { + final action = details.data; + setState(() { - // Atualiza Placard Geral - if (isOpponent) _opponentScore += details.data; else _myScore += details.data; - // ATUALIZA ESTATÍSTICA INDIVIDUAL DO JOGADOR - stats["pts"] = stats["pts"]! + details.data; + if (action.startsWith("add_pts_")) { + int pts = int.parse(action.split("_").last); + if (isOpponent) _opponentScore += pts; else _myScore += pts; + stats["pts"] = stats["pts"]! + pts; + } + else if (action.startsWith("sub_pts_")) { + int pts = int.parse(action.split("_").last); + if (isOpponent) { + _opponentScore = (_opponentScore - pts < 0) ? 0 : _opponentScore - pts; + } else { + _myScore = (_myScore - pts < 0) ? 0 : _myScore - pts; + } + stats["pts"] = (stats["pts"]! - pts < 0) ? 0 : stats["pts"]! - pts; + } + else if (action == "add_rbs") { stats["rbs"] = stats["rbs"]! + 1; } + else if (action == "add_ast") { stats["ast"] = stats["ast"]! + 1; } + // Guarda STL, TOV e BLK na memória, mas não mostra no ecrã do campo + 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; } }); }, builder: (context, candidateData, rejectedData) { @@ -502,6 +517,7 @@ class _PlacarPageState extends State { children: [ Text(name, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87)), const SizedBox(height: 2), + // MOSTRA APENAS O MAIS IMPORTANTE NO CAMPO Text( "${stats["pts"]} Pts | ${stats["rbs"]} Rbs | ${stats["ast"]} Ast", style: const TextStyle(fontSize: 12, color: Colors.grey, fontWeight: FontWeight.w500) @@ -526,7 +542,6 @@ class _PlacarPageState extends State { child: Row( mainAxisSize: MainAxisSize.min, children: [ - // Passamos os Time-outs usados para a secção da Casa _buildTeamSection(widget.myTeam, _myScore, _myFouls, _myTimeoutsUsed, const Color(0xFF1E5BB2), false), const SizedBox(width: 25), Column( @@ -537,7 +552,6 @@ class _PlacarPageState extends State { ], ), const SizedBox(width: 25), - // Passamos os Time-outs usados para a secção Visitante _buildTeamSection(widget.opponentTeam, _opponentScore, _opponentFouls, _opponentTimeoutsUsed, const Color(0xFFD92C2C), true), ], ), @@ -545,7 +559,6 @@ class _PlacarPageState extends State { } Widget _buildTeamSection(String name, int score, int fouls, int timeouts, Color color, bool isOpp) { - // AS 3 BOLAS DE TIME-OUT final timeoutIndicators = Row( mainAxisSize: MainAxisSize.min, children: List.generate(3, (index) => Container( @@ -553,7 +566,6 @@ class _PlacarPageState extends State { width: 12, height: 12, decoration: BoxDecoration( shape: BoxShape.circle, - // Se o index for menor que os usados, fica Amarelo. Se não, fica Cinzento. color: index < timeouts ? Colors.yellow : Colors.grey.shade600, border: Border.all(color: Colors.black26), ), @@ -566,7 +578,7 @@ class _PlacarPageState extends State { const SizedBox(height: 4), Text("FALTAS: $fouls", style: const TextStyle(color: Colors.yellowAccent, fontSize: 12)), const SizedBox(height: 4), - timeoutIndicators, // Adicionamos os indicadores aqui + timeoutIndicators, ] ); @@ -591,30 +603,64 @@ class _PlacarPageState extends State { child: Text(score.toString(), style: const TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold)), ); + // --- PAINEL EM COLUNAS ORGANIZADAS COM TODOS OS BOTÕES --- Widget _buildActionButtonsPanel() { - return Column( + return Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, + // COLUNA 1: T.O Azul, 1, -1, AST + Column( + mainAxisSize: MainAxisSize.min, children: [ - // Botão Time-Out EQUIPA DA CASA (Azul) - _actionBtn("T.O", const Color(0xFF1E5BB2), () => _useTimeout(false)), - _dragBtn("1", Colors.orange, 1), - _dragBtn("2", Colors.orange, 2), - _dragBtn("3", Colors.orange, 3), - _actionBtn("ORB", const Color(0xFF1E2A38), () {}, icon: Icons.shopping_basket), + _actionBtn("T.O", const Color(0xFF1E5BB2), () => _useTimeout(false), labelSize: 20), + const SizedBox(height: 8), + _dragBtn("1", Colors.orange, "add_pts_1"), + const SizedBox(height: 8), + _dragBtn("1", Colors.orange, "sub_pts_1", isX: true), + const SizedBox(height: 8), + _dragBtn("AST", Colors.blueGrey, "add_ast"), ], ), - const SizedBox(height: 8), - Row( - mainAxisAlignment: MainAxisAlignment.center, + const SizedBox(width: 15), + + // COLUNA 2: 2, -2, STL (Roubos - guardados na memória) + Column( + mainAxisSize: MainAxisSize.min, children: [ - // Botão Time-Out EQUIPA VISITANTE (Vermelho) - _actionBtn("T.O", const Color(0xFFD92C2C), () => _useTimeout(true)), - _actionBtn("1", Colors.orange, () {}, isX: true), - _actionBtn("2", Colors.orange, () {}, isX: true), - _actionBtn("3", Colors.orange, () {}, isX: true), - _actionBtn("DRB", const Color(0xFF1E2A38), () {}, icon: Icons.shield), + _dragBtn("2", Colors.orange, "add_pts_2"), + const SizedBox(height: 8), + _dragBtn("2", Colors.orange, "sub_pts_2", isX: true), + const SizedBox(height: 8), + _dragBtn("STL", Colors.green, "add_stl"), + ], + ), + const SizedBox(width: 15), + + // COLUNA 3: 3, -3, TOV (Perdas - guardadas na memória) + Column( + mainAxisSize: MainAxisSize.min, + children: [ + _dragBtn("3", Colors.orange, "add_pts_3"), + const SizedBox(height: 8), + _dragBtn("3", Colors.orange, "sub_pts_3", isX: true), + const SizedBox(height: 8), + _dragBtn("TOV", Colors.redAccent, "add_tov"), + ], + ), + const SizedBox(width: 15), + + // COLUNA 4: T.O Vermelho, ORB, DRB, BLK (Desarmes - guardados na memória) + Column( + mainAxisSize: MainAxisSize.min, + children: [ + _actionBtn("T.O", const Color(0xFFD92C2C), () => _useTimeout(true), labelSize: 20), + const SizedBox(height: 8), + _dragBtn("ORB", const Color(0xFF1E2A38), "add_rbs", icon: Icons.sports_basketball), + const SizedBox(height: 8), + _dragBtn("DRB", const Color(0xFF1E2A38), "add_rbs", icon: Icons.sports_basketball), + const SizedBox(height: 8), + _dragBtn("BLK", Colors.deepPurple, "add_blk"), ], ), ], @@ -622,42 +668,44 @@ class _PlacarPageState extends State { } // BOTÃO ARRASTÁVEL - Widget _dragBtn(String label, Color color, int val) { + Widget _dragBtn(String label, Color color, String actionData, {IconData? icon, bool isX = false}) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 4), - child: Draggable( - data: val, - feedback: _circle(label, color, null, true), - childWhenDragging: Opacity(opacity: 0.5, child: _circle(label, color, null, false)), - child: _circle(label, color, null, false), + child: Draggable( + data: actionData, + feedback: _circle(label, color, icon, true, isX: isX), + childWhenDragging: Opacity(opacity: 0.5, child: _circle(label, color, icon, false, isX: isX)), + child: _circle(label, color, icon, false, isX: isX), ), ); } - // BOTÃO CLICÁVEL - Widget _actionBtn(String label, Color color, VoidCallback onTap, {IconData? icon, bool isX = false}) { + // BOTÃO CLICÁVEL (Usado para o Time-Out) + Widget _actionBtn(String label, Color color, VoidCallback onTap, {IconData? icon, bool isX = false, double labelSize = 24}) { return GestureDetector( onTap: onTap, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4), - child: Stack( - alignment: Alignment.bottomRight, - children: [ - _circle(label, color, icon, false), - if (isX) const Icon(Icons.cancel, color: Colors.red, size: 25), - ], - ), + child: _circle(label, color, icon, false, fontSize: labelSize, isX: isX), ), ); } - Widget _circle(String label, Color color, IconData? icon, bool isFeed) { - return Container( - width: isFeed ? 70 : 60, height: isFeed ? 70 : 60, - decoration: BoxDecoration(color: color, shape: BoxShape.circle), - alignment: Alignment.center, - child: icon != null ? Icon(icon, color: Colors.white, size: 35) - : Text(label, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 24, decoration: TextDecoration.none)), + // DESENHO DO CÍRCULO + Widget _circle(String label, Color color, IconData? icon, bool isFeed, {double fontSize = 20, bool isX = false}) { + return Stack( + alignment: Alignment.bottomRight, + children: [ + Container( + width: isFeed ? 70 : 60, height: isFeed ? 70 : 60, + decoration: BoxDecoration(color: color, shape: BoxShape.circle, boxShadow: const [BoxShadow(color: Colors.black26, blurRadius: 4)]), + alignment: Alignment.center, + child: icon != null + ? Icon(icon, color: Colors.white, size: 35) + : Text(label, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: fontSize, decoration: TextDecoration.none)), + ), + if (isX) Icon(Icons.cancel, color: Colors.red, size: isFeed ? 30 : 25), + ], ); } } \ No newline at end of file diff --git a/lib/widgets/game_widgets.dart b/lib/widgets/game_widgets.dart index 09a0bd1..cc8cd37 100644 --- a/lib/widgets/game_widgets.dart +++ b/lib/widgets/game_widgets.dart @@ -205,6 +205,7 @@ class _CreateGameDialogManualState extends State { ], ); } + Widget _buildSearch({required String label, required TextEditingController controller}) { return StreamBuilder>>(