Files
PlayMaker/lib/pages/PlacarPage.dart
2026-02-24 17:17:34 +00:00

611 lines
23 KiB
Dart

/*import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class PlacarPage extends StatefulWidget {
final String gameId, myTeam, opponentTeam;
const PlacarPage({super.key, required this.gameId, required this.myTeam, required this.opponentTeam});
@override
State<PlacarPage> createState() => _PlacarPageState();
}
class _PlacarPageState extends State<PlacarPage> {
int _myScore = 0;
int _opponentScore = 0;
int _myFouls = 0;
int _opponentFouls = 0;
int _currentQuarter = 1;
Duration _duration = const Duration(minutes: 10);
Timer? _timer;
bool _isRunning = false;
@override
void initState() {
super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
}
void _toggleTimer() {
if (_isRunning) {
_timer?.cancel();
} else {
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
setState(() {
if (_duration.inSeconds > 0) {
_duration -= const Duration(seconds: 1);
} else {
_timer?.cancel();
_isRunning = false;
}
});
});
}
setState(() => _isRunning = !_isRunning);
}
String _formatTime(Duration d) =>
"${d.inMinutes.toString().padLeft(2, '0')}:${d.inSeconds.remainder(60).toString().padLeft(2, '0')}";
@override
void dispose() {
_timer?.cancel();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
super.dispose();
}
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
return Scaffold(
body: Stack(
children: [
// Fundo do Campo
Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/campo.png'),
fit: BoxFit.cover,
alignment: Alignment(0.0, 0.2),
),
),
),
// Posicionamento Tático (Jogadores como DragTargets)
..._buildTacticalFormation(screenWidth, screenHeight),
// Botão Central Play/Pause
Center(
child: GestureDetector(
onTap: _toggleTimer,
child: CircleAvatar(
radius: 35,
backgroundColor: Colors.white,
child: Icon(_isRunning ? Icons.pause : Icons.play_arrow,
color: const Color(0xFF1E2A38), size: 40),
),
),
),
// Placard Superior
Positioned(top: 0, left: 0, right: 0, child: Center(child: _buildTopScoreboard())),
// Painel de Ações Inferior (Botões de pontos como Draggables)
Positioned(bottom: 20, left: 0, right: 0, child: _buildActionButtonsPanel()),
// Botão Fechar
Positioned(
bottom: 20,
right: 20,
child: FloatingActionButton(
backgroundColor: const Color(0xFF1E2A38),
mini: true,
onPressed: () => Navigator.pop(context),
child: const Icon(Icons.close, color: Colors.white),
),
),
],
),
);
}
List<Widget> _buildTacticalFormation(double w, double h) {
return [
// CASA (Azul)
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 (Vermelho)
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)),
Positioned(top: h * 0.15, right: w * 0.20, child: _buildPlayerCard("14", "Danny", true)),
Positioned(top: h * 0.80, right: w * 0.20, child: _buildPlayerCard("23", "Fred", true)),
];
}
// JOGADOR COMO DRAG TARGET (Recebe os pontos)
Widget _buildPlayerCard(String number, String name, bool isOpponent) {
final teamColor = isOpponent ? const Color(0xFFD92C2C) : const Color(0xFF1E5BB2);
return DragTarget<int>(
onWillAcceptWithDetails: (details) => true,
onAcceptWithDetails: (details) {
setState(() {
if (isOpponent) {
_opponentScore += details.data;
} else {
_myScore += details.data;
}
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("$name marcou ${details.data} pontos!"), duration: const Duration(seconds: 1)),
);
},
builder: (context, candidateData, rejectedData) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
decoration: BoxDecoration(
color: candidateData.isNotEmpty ? Colors.yellow.shade100 : Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: candidateData.isNotEmpty ? Colors.orange : Colors.transparent,
width: 2,
),
boxShadow: const [BoxShadow(color: Colors.black26, blurRadius: 6, offset: Offset(0, 3))],
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 40, height: 40,
decoration: BoxDecoration(color: teamColor, borderRadius: BorderRadius.circular(8)),
alignment: Alignment.center,
child: Text(number, style: const TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold)),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(name, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87)),
const Text("0 Pts | 0 Rbs | 0 Ast", style: TextStyle(fontSize: 12, color: Colors.grey)),
],
),
],
),
);
},
);
}
Widget _buildTopScoreboard() {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 30),
decoration: BoxDecoration(
color: const Color(0xFF16202C),
borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(15), bottomRight: Radius.circular(15)),
border: Border.all(color: Colors.white, width: 2),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
_buildTeamSection(widget.myTeam, _myScore, _myFouls, const Color(0xFF1E5BB2), false),
const SizedBox(width: 25),
Column(
children: [
_timeDisplay(),
const SizedBox(height: 5),
Text("PERÍODO $_currentQuarter", style: const TextStyle(color: Colors.orangeAccent, fontSize: 14, fontWeight: FontWeight.bold)),
],
),
const SizedBox(width: 25),
_buildTeamSection(widget.opponentTeam, _opponentScore, _opponentFouls, const Color(0xFFD92C2C), true),
],
),
);
}
Widget _buildTeamSection(String name, int score, int fouls, Color color, bool isOpponent) {
final info = Column(
children: [
_scoreBox(score, color),
Text("FALTAS: $fouls", style: const TextStyle(color: Colors.yellowAccent, fontSize: 12)),
],
);
final teamName = Text(name.toUpperCase(), style: const TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold));
return Row(
children: isOpponent ? [info, const SizedBox(width: 15), teamName] : [teamName, const SizedBox(width: 15), info],
);
}
Widget _timeDisplay() => Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
decoration: BoxDecoration(color: const Color(0xFF2C3E50), borderRadius: BorderRadius.circular(5)),
child: Text(_formatTime(_duration), style: const TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, fontFamily: 'monospace')),
);
Widget _scoreBox(int score, Color color) => Container(
width: 55, height: 45,
alignment: Alignment.center,
decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(8)),
child: Text(score.toString(), style: const TextStyle(color: Colors.white, fontSize: 26, fontWeight: FontWeight.bold)),
);
// PAINEL DE AÇÕES (Botões de pontos são DRAGGABLE)
Widget _buildActionButtonsPanel() {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_draggableActionBtn("1", Colors.orange, 1),
_draggableActionBtn("2", Colors.orange, 2),
_draggableActionBtn("3", Colors.orange, 3),
_simpleActionBtn(null, const Color(0xFF1E2A38), Icons.shopping_basket),
],
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_simpleActionBtn("1", Colors.orange, null, isX: true),
_simpleActionBtn("2", Colors.orange, null, isX: true),
_simpleActionBtn("3", Colors.orange, null, isX: true),
_simpleActionBtn(null, const Color(0xFF1E2A38), Icons.shield),
],
),
],
);
}
// BOTÃO ARRASTÁVEL (PONTOS)
Widget _draggableActionBtn(String label, Color color, int points) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 6),
child: Draggable<int>(
data: points,
feedback: _buildCircleContent(label, color, null, true), // O que voa com o dedo
childWhenDragging: Opacity(opacity: 0.3, child: _buildCircleContent(label, color, null, false)),
child: _buildCircleContent(label, color, null, false),
),
);
}
// BOTÃO SIMPLES (REBOTES/DEFESA)
Widget _simpleActionBtn(String? label, Color color, IconData? icon, {bool isX = false}) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 6),
child: Stack(
alignment: Alignment.bottomRight,
children: [
_buildCircleContent(label, color, icon, false),
if (isX) const Icon(Icons.cancel, color: Colors.red, size: 25),
],
),
);
}
Widget _buildCircleContent(String? label, Color color, IconData? icon, bool isFeedback) {
return Container(
width: isFeedback ? 70 : 60,
height: isFeedback ? 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: const TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, decoration: TextDecoration.none)),
);
}
}*/import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class PlacarPage extends StatefulWidget {
final String gameId, myTeam, opponentTeam;
const PlacarPage({super.key, required this.gameId, required this.myTeam, required this.opponentTeam});
@override
State<PlacarPage> createState() => _PlacarPageState();
}
class _PlacarPageState extends State<PlacarPage> {
int _myScore = 0;
int _opponentScore = 0;
int _myFouls = 0;
int _opponentFouls = 0;
int _currentQuarter = 1;
// MAPA PARA GUARDAR ESTATÍSTICAS INDIVIDUAIS (Key: Nome do Jogador)
final Map<String, Map<String, int>> _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},
};
Duration _duration = const Duration(minutes: 10);
Timer? _timer;
bool _isRunning = false;
@override
void initState() {
super.initState();
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeRight, DeviceOrientation.landscapeLeft]);
}
void _toggleTimer() {
if (_isRunning) {
_timer?.cancel();
} else {
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
setState(() {
if (_duration.inSeconds > 0) {
_duration -= const Duration(seconds: 1);
} else {
_timer?.cancel();
_isRunning = false;
}
});
});
}
setState(() => _isRunning = !_isRunning);
}
String _formatTime(Duration d) =>
"${d.inMinutes.toString().padLeft(2, '0')}:${d.inSeconds.remainder(60).toString().padLeft(2, '0')}";
@override
void dispose() {
_timer?.cancel();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
super.dispose();
}
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
return Scaffold(
body: Stack(
children: [
Container(
decoration: const BoxDecoration(
image: DecorationImage(image: AssetImage('assets/campo.png'), fit: BoxFit.cover, alignment: Alignment(0.0, 0.2)),
),
),
..._buildTacticalFormation(screenWidth, screenHeight),
Center(
child: GestureDetector(
onTap: _toggleTimer,
child: CircleAvatar(
radius: 35,
backgroundColor: Colors.white,
child: Icon(_isRunning ? Icons.pause : Icons.play_arrow, color: const Color(0xFF1E2A38), size: 40),
),
),
),
Positioned(top: 0, left: 0, right: 0, child: Center(child: _buildTopScoreboard())),
Positioned(bottom: 20, left: 0, right: 0, child: _buildActionButtonsPanel()),
Positioned(
bottom: 20, right: 20,
child: FloatingActionButton(
backgroundColor: const Color(0xFF1E2A38),
mini: true,
onPressed: () => Navigator.pop(context),
child: const Icon(Icons.close, color: Colors.white),
),
),
],
),
);
}
List<Widget> _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)),
Positioned(top: h * 0.15, right: w * 0.20, child: _buildPlayerCard("14", "Danny", true)),
Positioned(top: h * 0.80, right: w * 0.20, child: _buildPlayerCard("23", "Fred", true)),
];
}
Widget _buildPlayerCard(String number, String name, bool isOpponent) {
final teamColor = isOpponent ? const Color(0xFFD92C2C) : const Color(0xFF1E5BB2);
final stats = _playerStats[name]!;
return DragTarget<int>(
onAcceptWithDetails: (details) {
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;
});
},
builder: (context, candidateData, rejectedData) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
decoration: BoxDecoration(
color: candidateData.isNotEmpty ? Colors.orange.shade50 : Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: candidateData.isNotEmpty ? Colors.orange : Colors.transparent, width: 2),
boxShadow: const [BoxShadow(color: Colors.black26, blurRadius: 6, offset: Offset(0, 3))],
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 40, height: 40,
decoration: BoxDecoration(color: teamColor, borderRadius: BorderRadius.circular(8)),
alignment: Alignment.center,
child: Text(number, style: const TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold)),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(name, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87)),
const SizedBox(height: 2),
// AGORA MOSTRA OS PONTOS REAIS DO MAPA
Text(
"${stats["pts"]} Pts | ${stats["rbs"]} Rbs | ${stats["ast"]} Ast",
style: const TextStyle(fontSize: 12, color: Colors.grey, fontWeight: FontWeight.w500)
),
],
),
],
),
);
},
);
}
Widget _buildTopScoreboard() {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 30),
decoration: BoxDecoration(
color: const Color(0xFF16202C),
borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(15), bottomRight: Radius.circular(15)),
border: Border.all(color: Colors.white, width: 2),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
_buildTeamSection(widget.myTeam, _myScore, _myFouls, const Color(0xFF1E5BB2), false),
const SizedBox(width: 25),
Column(
children: [
_timeDisplay(),
const SizedBox(height: 5),
Text("PERÍODO $_currentQuarter", style: const TextStyle(color: Colors.orangeAccent, fontSize: 14, fontWeight: FontWeight.bold)),
],
),
const SizedBox(width: 25),
_buildTeamSection(widget.opponentTeam, _opponentScore, _opponentFouls, const Color(0xFFD92C2C), true),
],
),
);
}
Widget _buildTeamSection(String name, int score, int fouls, Color color, bool isOpp) {
final info = Column(children: [_scoreBox(score, color), Text("FALTAS: $fouls", style: const TextStyle(color: Colors.yellowAccent, fontSize: 12))]);
return Row(children: isOpp ? [info, const SizedBox(width: 15), Text(name.toUpperCase(), style: const TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold))]
: [Text(name.toUpperCase(), style: const TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(width: 15), info]);
}
Widget _timeDisplay() => Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 6),
decoration: BoxDecoration(color: const Color(0xFF2C3E50), borderRadius: BorderRadius.circular(6)),
child: Text(_formatTime(_duration), style: const TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, fontFamily: 'monospace')),
);
Widget _scoreBox(int score, Color color) => Container(
width: 50, height: 40,
alignment: Alignment.center,
decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(6)),
child: Text(score.toString(), style: const TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold)),
);
Widget _buildActionButtonsPanel() {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_dragBtn("1", Colors.orange, 1),
_dragBtn("2", Colors.orange, 2),
_dragBtn("3", Colors.orange, 3),
_actionBtn("ORB", const Color(0xFF1E2A38), () {}, icon: Icons.shopping_basket),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_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),
],
),
],
);
}
// BOTÃO ARRASTÁVEL
Widget _dragBtn(String label, Color color, int val) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Draggable<int>(
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),
),
);
}
// BOTÃO CLICÁVEL
Widget _actionBtn(String label, Color color, VoidCallback onTap, {IconData? icon, bool isX = false}) {
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),
],
),
),
);
}
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)),
);
}
}