diff --git a/lib/controllers/placar_controller.dart b/lib/controllers/placar_controller.dart index b205202..b76713c 100644 --- a/lib/controllers/placar_controller.dart +++ b/lib/controllers/placar_controller.dart @@ -89,6 +89,9 @@ 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 loadPlayers() async { final supabase = Supabase.instance.client; try { @@ -193,7 +196,6 @@ 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, - // 馃憞 AGORA CARREGA OS SEGUNDOS EXATOS DA BASE DE DADOS "min": (s['minutos_jogados'] ?? 0) ~/ 60, "sec": s['minutos_jogados'] ?? 0, }; @@ -226,6 +228,14 @@ 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), () { + _saveLocalBackup(); + }); + } + Future _saveLocalBackup() async { try { final prefs = await SharedPreferences.getInstance(); @@ -277,12 +287,11 @@ class PlacarController extends ChangeNotifier { void toggleTimer(BuildContext context) { if (isRunning) { timer?.cancel(); - _saveLocalBackup(); + _scheduleAutoSave(); } else { timer = Timer.periodic(const Duration(seconds: 1), (timer) { if (durationNotifier.value.inSeconds > 0) { - durationNotifier.value -= const Duration(seconds: 1); - + void addTimeToCourt(List court) { for (String id in court) { if (playerStats.containsKey(id)) { @@ -292,11 +301,11 @@ class PlacarController extends ChangeNotifier { } } } - addTimeToCourt(myCourt); addTimeToCourt(oppCourt); - notifyListeners(); + // Avisa APENAS o rel贸gio (e n茫o a App inteira) + durationNotifier.value -= const Duration(seconds: 1); } else { timer.cancel(); @@ -306,7 +315,7 @@ class PlacarController extends ChangeNotifier { durationNotifier.value = const Duration(minutes: 10); myFouls = 0; opponentFouls = 0; myTimeoutsUsed = 0; opponentTimeoutsUsed = 0; - _saveLocalBackup(); + _scheduleAutoSave(); } notifyListeners(); } @@ -315,7 +324,6 @@ class PlacarController extends ChangeNotifier { isRunning = !isRunning; notifyListeners(); } - void useTimeout(bool isOpponent) { if (isOpponent) { if (opponentTimeoutsUsed < 3) opponentTimeoutsUsed++; @@ -324,7 +332,7 @@ class PlacarController extends ChangeNotifier { } isRunning = false; timer?.cancel(); - _saveLocalBackup(); + _scheduleAutoSave(); notifyListeners(); } @@ -367,7 +375,7 @@ class PlacarController extends ChangeNotifier { oppBench[benchIndex] = courtPlayerId; showOppBench = false; } - _saveLocalBackup(); + _scheduleAutoSave(); notifyListeners(); } @@ -407,7 +415,7 @@ class PlacarController extends ChangeNotifier { commitStat(pendingAction!, pendingPlayerId!); isSelectingShotLocation = false; pendingAction = null; pendingPlayerId = null; - _saveLocalBackup(); + _scheduleAutoSave(); notifyListeners(); } @@ -471,7 +479,7 @@ class PlacarController extends ChangeNotifier { String time = "${durationNotifier.value.inMinutes.toString().padLeft(2, '0')}:${durationNotifier.value.inSeconds.remainder(60).toString().padLeft(2, '0')}"; playByPlay.insert(0, "P$currentQuarter - $time: $committerName $logText"); - _saveLocalBackup(); + _scheduleAutoSave(); notifyListeners(); } @@ -555,7 +563,7 @@ class PlacarController extends ChangeNotifier { playByPlay.insert(0, "P$currentQuarter - $time: $name $logText"); } - _saveLocalBackup(); + _scheduleAutoSave(); notifyListeners(); } @@ -620,9 +628,7 @@ 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'], - // 馃憞 AQUI GUARDA OS SEGUNDOS EXATOS NA BASE DE DADOS (IMPEDE A PERDA DE TEMPO) - 'minutos_jogados': stats['sec'], + 'dr': stats['dr'], 'minutos_jogados': stats['sec'], }); } }); @@ -647,6 +653,7 @@ class PlacarController extends ChangeNotifier { @override void dispose() { timer?.cancel(); + _autoSaveTimer?.cancel(); super.dispose(); } } \ No newline at end of file diff --git a/lib/icons.dart/resaltosicon.dart b/lib/icons.dart/resaltosicon.dart index 17c96f5..0803b25 100644 --- a/lib/icons.dart/resaltosicon.dart +++ b/lib/icons.dart/resaltosicon.dart @@ -1,27 +1,237 @@ - import 'package:flutter/material.dart'; + import 'package:flutter/material.dart'; + import 'package:playmaker/classe/theme.dart'; +import 'package:playmaker/controllers/placar_controller.dart'; +import 'package:flutter/material.dart'; +import 'package:playmaker/classe/theme.dart'; +import 'package:playmaker/controllers/placar_controller.dart'; - void main() { - runApp(const MyApp()); +// ============================================================================ +// 4. PAINEL DE BOT脮ES DE AC脟脙O (DRAG & DROP) +// ============================================================================ +class ActionButtonsPanel extends StatelessWidget { + final PlacarController controller; + final double sf; + + const ActionButtonsPanel({super.key, required this.controller, required this.sf}); + + @override + Widget build(BuildContext context) { + final double baseSize = 58 * sf; + final double feedSize = 73 * sf; + final double gap = 5 * sf; + + return Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + _columnBtn([ + _dragAndTargetBtn("M1", AppTheme.actionMiss, "miss_1", baseSize, feedSize, sf), + _dragAndTargetBtn("1", AppTheme.actionPoints, "add_pts_1", baseSize, feedSize, sf), + _dragAndTargetBtn("1", AppTheme.actionPoints, "sub_pts_1", baseSize, feedSize, sf, isX: true), + _dragAndTargetBtn("STL", AppTheme.actionSteal, "add_stl", baseSize, feedSize, sf), + ], gap), + SizedBox(width: gap * 1), + _columnBtn([ + _dragAndTargetBtn("M2", AppTheme.actionMiss, "miss_2", baseSize, feedSize, sf), + _dragAndTargetBtn("2", AppTheme.actionPoints, "add_pts_2", baseSize, feedSize, sf), + _dragAndTargetBtn("2", AppTheme.actionPoints, "sub_pts_2", baseSize, feedSize, sf, isX: true), + _dragAndTargetBtn("AST", AppTheme.actionAssist, "add_ast", baseSize, feedSize, sf), + ], gap), + SizedBox(width: gap * 1), + _columnBtn([ + _dragAndTargetBtn("M3", AppTheme.actionMiss, "miss_3", baseSize, feedSize, sf), + _dragAndTargetBtn("3", AppTheme.actionPoints, "add_pts_3", baseSize, feedSize, sf), + _dragAndTargetBtn("3", AppTheme.actionPoints, "sub_pts_3", baseSize, feedSize, sf, isX: true), + _dragAndTargetBtn("TOV", AppTheme.actionMiss, "add_tov", baseSize, feedSize, sf), + ], gap), + SizedBox(width: gap * 1), + _columnBtn([ + _dragAndTargetBtn("O", AppTheme.actionRebound, "add_orb", baseSize, feedSize, sf), + _dragAndTargetBtn("D", AppTheme.actionRebound, "add_drb", baseSize, feedSize, sf), + _dragAndTargetBtn("BLK", AppTheme.actionBlock, "add_blk", baseSize, feedSize, sf), + ], gap), + ], + ); } - class MyApp extends StatelessWidget { - const MyApp({super.key}); + Widget _columnBtn(List children, double gap) { + return Column( + mainAxisSize: MainAxisSize.min, + children: children.map((c) => Padding(padding: EdgeInsets.only(bottom: gap), child: c)).toList() + ); + } - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - appBar: AppBar( - title: const Text('脥cone de Basquete'), + Widget _dragAndTargetBtn(String label, Color color, String actionData, double baseSize, double feedSize, double sf, {IconData? icon, bool isX = false}) { + return Draggable( + data: actionData, + feedback: _circle(label, color, icon, true, baseSize, feedSize, sf, isX: isX), + childWhenDragging: Opacity( + opacity: 0.5, + child: _circle(label, color, icon, false, baseSize, feedSize, sf, isX: isX) + ), + child: DragTarget( + onAcceptWithDetails: (details) {}, + builder: (context, candidateData, rejectedData) { + bool isHovered = candidateData.any((data) => data != null && data.startsWith("player_")); + return Transform.scale( + scale: isHovered ? 1.15 : 1.0, + child: Container( + decoration: isHovered ? BoxDecoration(shape: BoxShape.circle, boxShadow: [BoxShadow(color: Colors.white, blurRadius: 10 * sf, spreadRadius: 3 * sf)]) : null, + child: _circle(label, color, icon, false, baseSize, feedSize, sf, isX: isX) + ), + ); + } + ), + ); + } + + Widget _circle(String label, Color color, IconData? icon, bool isFeed, double baseSize, double feedSize, double sf, {bool isX = false}) { + double size = isFeed ? feedSize : baseSize; + Widget content; + bool isPointBtn = label == "1" || label == "2" || label == "3" || label == "M1" || label == "M2" || label == "M3"; + bool isRebBtn = label == "O" || label == "D"; + bool isBlkBtn = label == "BLK"; + + if (isPointBtn) { + content = Stack( + alignment: Alignment.center, + children: [ + Container(width: size * 0.75, height: size * 0.75, decoration: const BoxDecoration(color: Colors.black, shape: BoxShape.circle)), + Icon(Icons.sports_basketball, color: color, size: size * 0.9), + Stack( + children: [ + Text(label, style: TextStyle(fontSize: size * 0.38, fontWeight: FontWeight.w900, foreground: Paint()..style = PaintingStyle.stroke..strokeWidth = size * 0.05..color = Colors.white, decoration: TextDecoration.none)), + Text(label, style: TextStyle(fontSize: size * 0.38, fontWeight: FontWeight.w900, color: Colors.black, decoration: TextDecoration.none)), + ], ), - body: const Center( - child: Icon( - Icons.sports_basketball, - size: 100.0, // Tamanho do 铆cone - color: Colors.black, // Cor do 铆cone (preto, como na imagem) + ], + ); + } + else if (isRebBtn) { + content = Stack( + children: [ + Center( + child: SizedBox( + width: size * 0.80, + height: size * 0.80, + child: CustomPaint(painter: HoopIconPainter()), ), ), - ), + Positioned( + top: size * -0.05, // Mantido no topo conforme solicitado + right: size * 0.05, + child: Stack( + children: [ + Text(label, style: TextStyle( + fontSize: size * 0.48, // Tamanho aumentado conforme c贸digo anterior + fontWeight: FontWeight.w900, + foreground: Paint()..style = PaintingStyle.stroke..strokeWidth = size * 0.07..color = Colors.black, + decoration: TextDecoration.none + )), + Text(label, style: TextStyle( + fontSize: size * 0.48, // Tamanho aumentado conforme c贸digo anterior + fontWeight: FontWeight.w900, + color: Colors.white, + decoration: TextDecoration.none + )), + ], + ), + ), + ], ); + } + else if (isBlkBtn) { + content = Stack( + alignment: Alignment.center, + children: [ + Icon(Icons.front_hand, color: const Color.fromARGB(207, 56, 52, 52), size: size * 0.75), + Stack( + alignment: Alignment.center, + children: [ + Text(label, style: TextStyle(fontSize: size * 0.28, fontWeight: FontWeight.w900, foreground: Paint()..style = PaintingStyle.stroke..strokeWidth = size * 0.05..color = Colors.black, decoration: TextDecoration.none)), + Text(label, style: TextStyle(fontSize: size * 0.28, fontWeight: FontWeight.w900, color: Colors.white, decoration: TextDecoration.none)), + ], + ), + ], + ); + } else { + content = Text(label, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: size * 0.35, decoration: TextDecoration.none)); } - } \ No newline at end of file + + return Stack( + clipBehavior: Clip.none, + alignment: Alignment.bottomRight, + children: [ + Container( + width: size, height: size, + decoration: (isPointBtn || isBlkBtn || isRebBtn) + ? const BoxDecoration(color: Colors.transparent) + : BoxDecoration(gradient: RadialGradient(colors: [color.withOpacity(0.7), color], radius: 0.8), shape: BoxShape.circle, boxShadow: [BoxShadow(color: Colors.black38, blurRadius: 6 * sf, offset: Offset(0, 3 * sf))]), + alignment: Alignment.center, + child: content, + ), + if (isX) Positioned(top: 0, right: 0, child: Container(decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle), child: Icon(Icons.cancel, color: Colors.red, size: size * 0.4))), + ], + ); + } +} + +// ===================================================================== +// PAINTER DA CESTA (MAIOR E PRETO) +// ===================================================================== +class HoopIconPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final double w = size.width; + final double h = size.height; + + final Paint paint = Paint() + ..color = Colors.black + ..style = PaintingStyle.stroke + ..strokeWidth = w * 0.08 + ..strokeCap = StrokeCap.round + ..strokeJoin = StrokeJoin.round; + + // 1. Tabela Grande + canvas.drawRRect( + RRect.fromRectAndRadius( + Rect.fromLTRB(w * 0.02, h * 0.02, w * 0.98, h * 0.70), + Radius.circular(w * 0.05) + ), + paint + ); + + // 2. Quadrado do Alvo + canvas.drawRect( + Rect.fromLTRB(w * 0.28, h * 0.30, w * 0.72, h * 0.70), + paint + ); + + // 3. Aro (Laranja) + final Paint rimPaint = Paint() + ..color = Colors.orange + ..style = PaintingStyle.stroke + ..strokeWidth = w * 0.09 + ..strokeCap = StrokeCap.round; + + canvas.drawLine( + Offset(w * 0.20, h * 0.75), + Offset(w * 0.80, h * 0.75), + rimPaint + ); + + // 4. Rede + final Paint netPaint = Paint() + ..color = Colors.black + ..style = PaintingStyle.stroke + ..strokeWidth = w * 0.05; + + canvas.drawLine(Offset(w * 0.25, h * 0.75), Offset(w * 0.40, h * 0.98), netPaint); + canvas.drawLine(Offset(w * 0.75, h * 0.75), Offset(w * 0.60, h * 0.98), netPaint); + canvas.drawLine(Offset(w * 0.40, h * 0.75), Offset(w * 0.30, h * 0.98), netPaint); + canvas.drawLine(Offset(w * 0.60, h * 0.75), Offset(w * 0.70, h * 0.98), netPaint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +} \ No newline at end of file diff --git a/lib/pages/PlacarPage.dart b/lib/pages/PlacarPage.dart index 71ed7a4..de86ed2 100644 --- a/lib/pages/PlacarPage.dart +++ b/lib/pages/PlacarPage.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:playmaker/icons.dart/resaltosicon.dart'; import 'package:playmaker/widgets/placar_widgets.dart'; import 'dart:math' as math; @@ -252,7 +253,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, sf: sf))), ], + _buildCornerBtn(heroTag: 'btn_boxscore', icon: Icons.table_chart, color: Colors.indigo, size: cornerBtnSize, onTap: () => showDialog(context: context, builder: (ctx) => BoxScoreDialog(controller: _controller, sf: sf))), ], ), ), @@ -694,7 +695,7 @@ class PlayerCourtCard extends StatelessWidget { ); } else if (action == "add_tov") { - showDialog(context: context, builder: (ctx) => ActionSubtypeDialog( + showDialog(context: context, builder: (ctx) => ActionSubtypeDialog( title: "Escolha o tipo de turnover", options: { "add_3s": "3\nsegundos", @@ -1349,11 +1350,9 @@ class BoxScoreDialog extends StatelessWidget { 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( @@ -1395,11 +1394,18 @@ class BoxScoreDialog extends StatelessWidget { 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), - ], + // 馃憞 M脕GICA DE PERFORMANCE: S贸 a zona da tabela 茅 que redesenha por segundo! + child: ValueListenableBuilder( + valueListenable: controller.durationNotifier, + builder: (context, duration, _) { + return TabBarView( + physics: const NeverScrollableScrollPhysics(), + children: [ + _buildStatsTable(controller.myCourt + controller.myBench, controller, sf), + _buildStatsTable(controller.oppCourt + controller.oppBench, controller, sf), + ], + ); + } ), ), ), @@ -1412,18 +1418,15 @@ class BoxScoreDialog extends StatelessWidget { ); } -Widget _buildStatsTable(List teamPlayers, PlacarController ctrl, double sf) { + 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(), + physics: const BouncingScrollPhysics(), child: SingleChildScrollView( scrollDirection: Axis.horizontal, - // 馃憞 E AQUI TAMB脡M - physics: const BouncingScrollPhysics(), + physics: const ClampingScrollPhysics(), child: ConstrainedBox( constraints: BoxConstraints(minWidth: constraints.maxWidth), child: DataTable( diff --git a/lib/widgets/placar_widgets.dart b/lib/widgets/placar_widgets.dart index 9563fbb..4faeebc 100644 --- a/lib/widgets/placar_widgets.dart +++ b/lib/widgets/placar_widgets.dart @@ -333,141 +333,6 @@ class PlayerCourtCard extends StatelessWidget { } } -class ActionButtonsPanel extends StatelessWidget { - final PlacarController controller; - final double sf; - - const ActionButtonsPanel({super.key, required this.controller, required this.sf}); - - @override - Widget build(BuildContext context) { - final double baseSize = 58 * sf; - final double feedSize = 73 * sf; - final double gap = 5 * sf; - - return Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - _columnBtn([ - _dragAndTargetBtn("M1", AppTheme.actionMiss, "miss_1", baseSize, feedSize, sf), - _dragAndTargetBtn("1", AppTheme.actionPoints, "add_pts_1", baseSize, feedSize, sf), - _dragAndTargetBtn("1", AppTheme.actionPoints, "sub_pts_1", baseSize, feedSize, sf, isX: true), - _dragAndTargetBtn("STL", AppTheme.actionSteal, "add_stl", baseSize, feedSize, sf), - ], gap), - SizedBox(width: gap * 1), - _columnBtn([ - _dragAndTargetBtn("M2", AppTheme.actionMiss, "miss_2", baseSize, feedSize, sf), - _dragAndTargetBtn("2", AppTheme.actionPoints, "add_pts_2", baseSize, feedSize, sf), - _dragAndTargetBtn("2", AppTheme.actionPoints, "sub_pts_2", baseSize, feedSize, sf, isX: true), - _dragAndTargetBtn("AST", AppTheme.actionAssist, "add_ast", baseSize, feedSize, sf), - ], gap), - SizedBox(width: gap * 1), - _columnBtn([ - _dragAndTargetBtn("M3", AppTheme.actionMiss, "miss_3", baseSize, feedSize, sf), - _dragAndTargetBtn("3", AppTheme.actionPoints, "add_pts_3", baseSize, feedSize, sf), - _dragAndTargetBtn("3", AppTheme.actionPoints, "sub_pts_3", baseSize, feedSize, sf, isX: true), - _dragAndTargetBtn("TOV", AppTheme.actionMiss, "add_tov", baseSize, feedSize, sf), - ], gap), - SizedBox(width: gap * 1), - _columnBtn([ - _dragAndTargetBtn("ORB", AppTheme.actionRebound, "add_orb", baseSize, feedSize, sf, icon: Icons.sports_basketball), - _dragAndTargetBtn("DRB", AppTheme.actionRebound, "add_drb", baseSize, feedSize, sf, icon: Icons.sports_basketball), - _dragAndTargetBtn("BLK", AppTheme.actionBlock, "add_blk", baseSize, feedSize, sf, icon: Icons.front_hand), - ], gap), - ], - ); - } - - Widget _columnBtn(List children, double gap) { - return Column( - mainAxisSize: MainAxisSize.min, - children: children.map((c) => Padding(padding: EdgeInsets.only(bottom: gap), child: c)).toList() - ); - } - - Widget _dragAndTargetBtn(String label, Color color, String actionData, double baseSize, double feedSize, double sf, {IconData? icon, bool isX = false}) { - return Draggable( - data: actionData, - feedback: _circle(label, color, icon, true, baseSize, feedSize, sf, isX: isX), - childWhenDragging: Opacity( - opacity: 0.5, - child: _circle(label, color, icon, false, baseSize, feedSize, sf, isX: isX) - ), - child: DragTarget( - onAcceptWithDetails: (details) {}, - builder: (context, candidateData, rejectedData) { - bool isHovered = candidateData.any((data) => data != null && data.startsWith("player_")); - return Transform.scale( - scale: isHovered ? 1.15 : 1.0, - child: Container( - decoration: isHovered ? BoxDecoration(shape: BoxShape.circle, boxShadow: [BoxShadow(color: Colors.white, blurRadius: 10 * sf, spreadRadius: 3 * sf)]) : null, - child: _circle(label, color, icon, false, baseSize, feedSize, sf, isX: isX) - ), - ); - } - ), - ); - } - - Widget _circle(String label, Color color, IconData? icon, bool isFeed, double baseSize, double feedSize, double sf, {bool isX = false}) { - double size = isFeed ? feedSize : baseSize; - Widget content; - bool isPointBtn = label == "1" || label == "2" || label == "3" || label == "M1" || label == "M2" || label == "M3"; - bool isBlkBtn = label == "BLK"; - - if (isPointBtn) { - content = Stack( - alignment: Alignment.center, - children: [ - Container(width: size * 0.75, height: size * 0.75, decoration: const BoxDecoration(color: Colors.black, shape: BoxShape.circle)), - Icon(Icons.sports_basketball, color: color, size: size * 0.9), - Stack( - children: [ - Text(label, style: TextStyle(fontSize: size * 0.38, fontWeight: FontWeight.w900, foreground: Paint()..style = PaintingStyle.stroke..strokeWidth = size * 0.05..color = Colors.white, decoration: TextDecoration.none)), - Text(label, style: TextStyle(fontSize: size * 0.38, fontWeight: FontWeight.w900, color: Colors.black, decoration: TextDecoration.none)), - ], - ), - ], - ); - } else if (isBlkBtn) { - content = Stack( - alignment: Alignment.center, - children: [ - Icon(Icons.front_hand, color: const Color.fromARGB(207, 56, 52, 52), size: size * 0.75), - Stack( - alignment: Alignment.center, - children: [ - Text(label, style: TextStyle(fontSize: size * 0.28, fontWeight: FontWeight.w900, foreground: Paint()..style = PaintingStyle.stroke..strokeWidth = size * 0.05..color = Colors.black, decoration: TextDecoration.none)), - Text(label, style: TextStyle(fontSize: size * 0.28, fontWeight: FontWeight.w900, color: Colors.white, decoration: TextDecoration.none)), - ], - ), - ], - ); - } else if (icon != null) { - content = Icon(icon, color: Colors.white, size: size * 0.5); - } else { - content = Text(label, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: size * 0.35, decoration: TextDecoration.none)); - } - - return Stack( - clipBehavior: Clip.none, - alignment: Alignment.bottomRight, - children: [ - Container( - width: size, height: size, - decoration: (isPointBtn || isBlkBtn) - ? const BoxDecoration(color: Colors.transparent) - : BoxDecoration(gradient: RadialGradient(colors: [color.withOpacity(0.7), color], radius: 0.8), shape: BoxShape.circle, boxShadow: [BoxShadow(color: Colors.black38, blurRadius: 6 * sf, offset: Offset(0, 3 * sf))]), - alignment: Alignment.center, - child: content, - ), - if (isX) Positioned(top: 0, right: 0, child: Container(decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle), child: Icon(Icons.cancel, color: Colors.red, size: size * 0.4))), - ], - ); - } -} - class HeatmapDialog extends StatefulWidget { final List shots; final String myTeamName; diff --git a/pubspec.lock b/pubspec.lock index d5e3b37..0daf6be 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -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: diff --git a/pubspec.yaml b/pubspec.yaml index d8392a8..6a54bba 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -66,6 +66,10 @@ flutter: - assets/playmaker-logo.png - assets/campo.png - assets/playmaker-logos.png +fonts: + - family: playmaker + fonts: + - asset: fonts/MyFlutterApp.ttf # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images