melhorar o sensor de calor

This commit is contained in:
2026-03-13 18:08:15 +00:00
parent cae3bbfe3b
commit 0369b5376c
10 changed files with 1053 additions and 926 deletions

View File

@@ -8,6 +8,7 @@ import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:playmaker/pages/status_page.dart';
import '../utils/size_extension.dart';
import 'package:playmaker/grafico%20de%20pizza/controllers/contollers_grafico.dart';
import 'dart:math' as math; // 👇 IMPORTANTE
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@@ -30,10 +31,10 @@ class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
// Já não precisamos calcular o sf aqui!
final double safeSf = math.min(context.sf, 1.15); // TRAVÃO
final List<Widget> pages = [
_buildHomeContent(context), // Passamos só o context
_buildHomeContent(context, safeSf), // Passamos o safeSf
const GamePage(),
const TeamsPage(),
const StatusPage(),
@@ -42,11 +43,11 @@ class _HomeScreenState extends State<HomeScreen> {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('PlayMaker', style: TextStyle(fontSize: 20 * context.sf)),
title: Text('PlayMaker', style: TextStyle(fontSize: 20 * safeSf)),
backgroundColor: HomeConfig.primaryColor,
foregroundColor: Colors.white,
leading: IconButton(
icon: Icon(Icons.person, size: 24 * context.sf),
icon: Icon(Icons.person, size: 24 * safeSf),
onPressed: () {},
),
),
@@ -62,8 +63,7 @@ class _HomeScreenState extends State<HomeScreen> {
backgroundColor: Theme.of(context).colorScheme.surface,
surfaceTintColor: Theme.of(context).colorScheme.surfaceTint,
elevation: 1,
// O math.min não é necessário se já tens o sf. Mas podes usar context.sf
height: 70 * (context.sf < 1.2 ? context.sf : 1.2),
height: 70 * safeSf,
destinations: const [
NavigationDestination(icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home_filled), label: 'Home'),
NavigationDestination(icon: Icon(Icons.sports_soccer_outlined), selectedIcon: Icon(Icons.sports_soccer), label: 'Jogo'),
@@ -74,16 +74,16 @@ class _HomeScreenState extends State<HomeScreen> {
);
}
void _showTeamSelector(BuildContext context) {
void _showTeamSelector(BuildContext context, double safeSf) {
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(20 * context.sf))),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(20 * safeSf))),
builder: (context) {
return StreamBuilder<List<Map<String, dynamic>>>(
stream: _teamController.teamsStream,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) return const SizedBox(height: 200, child: Center(child: CircularProgressIndicator()));
if (!snapshot.hasData || snapshot.data!.isEmpty) return SizedBox(height: 200 * context.sf, child: const Center(child: Text("Nenhuma equipa criada.")));
if (!snapshot.hasData || snapshot.data!.isEmpty) return SizedBox(height: 200 * safeSf, child: const Center(child: Text("Nenhuma equipa criada.")));
final teams = snapshot.data!;
return ListView.builder(
@@ -92,7 +92,7 @@ class _HomeScreenState extends State<HomeScreen> {
itemBuilder: (context, index) {
final team = teams[index];
return ListTile(
title: Text(team['name']),
title: Text(team['name'], style: TextStyle(fontSize: 16 * safeSf)),
onTap: () {
setState(() {
_selectedTeamId = team['id'];
@@ -112,9 +112,10 @@ class _HomeScreenState extends State<HomeScreen> {
);
}
Widget _buildHomeContent(BuildContext context) {
Widget _buildHomeContent(BuildContext context, double safeSf) {
final double wScreen = MediaQuery.of(context).size.width;
final double cardHeight = wScreen * 0.5;
// Evita que os cartões fiquem muito altos no tablet:
final double cardHeight = math.min(wScreen * 0.5, 200 * safeSf);
return StreamBuilder<List<Map<String, dynamic>>>(
stream: _selectedTeamId != null
@@ -125,44 +126,44 @@ class _HomeScreenState extends State<HomeScreen> {
return SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 22.0 * context.sf, vertical: 16.0 * context.sf),
padding: EdgeInsets.symmetric(horizontal: 22.0 * safeSf, vertical: 16.0 * safeSf),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () => _showTeamSelector(context),
onTap: () => _showTeamSelector(context, safeSf),
child: Container(
padding: EdgeInsets.all(12 * context.sf),
decoration: BoxDecoration(color: Colors.grey.shade100, borderRadius: BorderRadius.circular(15 * context.sf), border: Border.all(color: Colors.grey.shade300)),
padding: EdgeInsets.all(12 * safeSf),
decoration: BoxDecoration(color: Colors.grey.shade100, borderRadius: BorderRadius.circular(15 * safeSf), border: Border.all(color: Colors.grey.shade300)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(children: [Icon(Icons.shield, color: HomeConfig.primaryColor, size: 24 * context.sf), SizedBox(width: 10 * context.sf), Text(_selectedTeamName, style: TextStyle(fontSize: 16 * context.sf, fontWeight: FontWeight.bold))]),
Row(children: [Icon(Icons.shield, color: HomeConfig.primaryColor, size: 24 * safeSf), SizedBox(width: 10 * safeSf), Text(_selectedTeamName, style: TextStyle(fontSize: 16 * safeSf, fontWeight: FontWeight.bold))]),
const Icon(Icons.arrow_drop_down),
],
),
),
),
SizedBox(height: 20 * context.sf),
SizedBox(height: 20 * safeSf),
SizedBox(
height: cardHeight,
child: Row(
children: [
Expanded(child: _buildStatCard(context: context, title: 'Mais Pontos', playerName: leaders['pts_name'], statValue: leaders['pts_val'].toString(), statLabel: 'TOTAL', color: const Color(0xFF1565C0), isHighlighted: true)),
SizedBox(width: 12 * context.sf),
SizedBox(width: 12 * safeSf),
Expanded(child: _buildStatCard(context: context, title: 'Assistências', playerName: leaders['ast_name'], statValue: leaders['ast_val'].toString(), statLabel: 'TOTAL', color: const Color(0xFF2E7D32))),
],
),
),
SizedBox(height: 12 * context.sf),
SizedBox(height: 12 * safeSf),
SizedBox(
height: cardHeight,
child: Row(
children: [
Expanded(child: _buildStatCard(context: context, title: 'Rebotes', playerName: leaders['rbs_name'], statValue: leaders['rbs_val'].toString(), statLabel: 'TOTAL', color: const Color(0xFF6A1B9A))),
SizedBox(width: 12 * context.sf),
SizedBox(width: 12 * safeSf),
Expanded(
child: PieChartCard(
victories: _teamWins,
@@ -171,22 +172,22 @@ class _HomeScreenState extends State<HomeScreen> {
title: 'DESEMPENHO',
subtitle: 'Temporada',
backgroundColor: const Color(0xFFC62828),
sf: context.sf // Aqui o PieChartCard ainda usa sf, então passamos
sf: safeSf
),
),
],
),
),
SizedBox(height: 40 * context.sf),
SizedBox(height: 40 * safeSf),
Text('Histórico de Jogos', style: TextStyle(fontSize: 20 * context.sf, fontWeight: FontWeight.bold, color: Colors.grey[800])),
SizedBox(height: 16 * context.sf),
Text('Histórico de Jogos', style: TextStyle(fontSize: 20 * safeSf, fontWeight: FontWeight.bold, color: Colors.grey[800])),
SizedBox(height: 16 * safeSf),
_selectedTeamName == "Selecionar Equipa"
? Container(
padding: EdgeInsets.all(20 * context.sf),
padding: EdgeInsets.all(20 * safeSf),
alignment: Alignment.center,
child: Text("Seleciona uma equipa no topo.", style: TextStyle(color: Colors.grey, fontSize: 14 * context.sf)),
child: Text("Seleciona uma equipa no topo.", style: TextStyle(color: Colors.grey, fontSize: 14 * safeSf)),
)
: StreamBuilder<List<Map<String, dynamic>>>(
stream: _supabase.from('games').stream(primaryKey: ['id'])
@@ -206,7 +207,7 @@ class _HomeScreenState extends State<HomeScreen> {
if (gamesList.isEmpty) {
return Container(
padding: EdgeInsets.all(20 * context.sf),
padding: EdgeInsets.all(20 * safeSf),
decoration: BoxDecoration(color: Colors.grey.shade50, borderRadius: BorderRadius.circular(14)),
alignment: Alignment.center,
child: Text("Ainda não há jogos terminados para $_selectedTeamName.", style: TextStyle(color: Colors.grey)),
@@ -236,7 +237,7 @@ class _HomeScreenState extends State<HomeScreen> {
if (myScore < oppScore) result = 'D';
return _buildGameHistoryCard(
context: context, // Usamos o context para o sf
context: context,
opponent: opponent,
result: result,
myScore: myScore,
@@ -247,13 +248,14 @@ class _HomeScreenState extends State<HomeScreen> {
topRbs: game['top_rbs_name'] ?? '---',
topDef: game['top_def_name'] ?? '---',
mvp: game['mvp_name'] ?? '---',
safeSf: safeSf // Passa a escala aqui
);
}).toList(),
);
},
),
SizedBox(height: 20 * context.sf),
SizedBox(height: 20 * safeSf),
],
),
),
@@ -323,14 +325,14 @@ class _HomeScreenState extends State<HomeScreen> {
Widget _buildGameHistoryCard({
required BuildContext context, required String opponent, required String result, required int myScore, required int oppScore, required String date,
required String topPts, required String topAst, required String topRbs, required String topDef, required String mvp
required String topPts, required String topAst, required String topRbs, required String topDef, required String mvp, required double safeSf
}) {
bool isWin = result == 'V';
bool isDraw = result == 'E';
Color statusColor = isWin ? Colors.green : (isDraw ? Colors.yellow.shade700 : Colors.red);
return Container(
margin: EdgeInsets.only(bottom: 14 * context.sf),
margin: EdgeInsets.only(bottom: 14 * safeSf),
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(16),
border: Border.all(color: Colors.grey.shade200), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.04), blurRadius: 8, offset: const Offset(0, 4))],
@@ -338,34 +340,34 @@ class _HomeScreenState extends State<HomeScreen> {
child: Column(
children: [
Padding(
padding: EdgeInsets.all(14 * context.sf),
padding: EdgeInsets.all(14 * safeSf),
child: Row(
children: [
Container(
width: 36 * context.sf, height: 36 * context.sf,
width: 36 * safeSf, height: 36 * safeSf,
decoration: BoxDecoration(color: statusColor.withOpacity(0.15), shape: BoxShape.circle),
child: Center(child: Text(result, style: TextStyle(color: statusColor, fontWeight: FontWeight.bold, fontSize: 16 * context.sf))),
child: Center(child: Text(result, style: TextStyle(color: statusColor, fontWeight: FontWeight.bold, fontSize: 16 * safeSf))),
),
SizedBox(width: 14 * context.sf),
SizedBox(width: 14 * safeSf),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(date, style: TextStyle(fontSize: 11 * context.sf, color: Colors.grey, fontWeight: FontWeight.w600)),
SizedBox(height: 6 * context.sf),
Text(date, style: TextStyle(fontSize: 11 * safeSf, color: Colors.grey, fontWeight: FontWeight.w600)),
SizedBox(height: 6 * safeSf),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(_selectedTeamName == "Selecionar Equipa" ? "Minha Equipa" : _selectedTeamName, style: TextStyle(fontSize: 14 * context.sf, fontWeight: FontWeight.bold), maxLines: 1, overflow: TextOverflow.ellipsis)),
Expanded(child: Text(_selectedTeamName == "Selecionar Equipa" ? "Minha Equipa" : _selectedTeamName, style: TextStyle(fontSize: 14 * safeSf, fontWeight: FontWeight.bold), maxLines: 1, overflow: TextOverflow.ellipsis)),
Padding(
padding: EdgeInsets.symmetric(horizontal: 8 * context.sf),
padding: EdgeInsets.symmetric(horizontal: 8 * safeSf),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8 * context.sf, vertical: 4 * context.sf),
padding: EdgeInsets.symmetric(horizontal: 8 * safeSf, vertical: 4 * safeSf),
decoration: BoxDecoration(color: Colors.grey.shade100, borderRadius: BorderRadius.circular(8)),
child: Text('$myScore - $oppScore', style: TextStyle(fontSize: 15 * context.sf, fontWeight: FontWeight.w900, letterSpacing: 1.5, color: Colors.black87)),
child: Text('$myScore - $oppScore', style: TextStyle(fontSize: 15 * safeSf, fontWeight: FontWeight.w900, letterSpacing: 1.5, color: Colors.black87)),
),
),
Expanded(child: Text(opponent, style: TextStyle(fontSize: 14 * context.sf, fontWeight: FontWeight.bold), textAlign: TextAlign.right, maxLines: 1, overflow: TextOverflow.ellipsis)),
Expanded(child: Text(opponent, style: TextStyle(fontSize: 14 * safeSf, fontWeight: FontWeight.bold), textAlign: TextAlign.right, maxLines: 1, overflow: TextOverflow.ellipsis)),
],
),
],
@@ -376,27 +378,27 @@ class _HomeScreenState extends State<HomeScreen> {
),
Divider(height: 1, color: Colors.grey.shade100, thickness: 1.5),
Container(
width: double.infinity, padding: EdgeInsets.symmetric(horizontal: 16 * context.sf, vertical: 12 * context.sf),
width: double.infinity, padding: EdgeInsets.symmetric(horizontal: 16 * safeSf, vertical: 12 * safeSf),
decoration: BoxDecoration(color: Colors.grey.shade50, borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(16), bottomRight: Radius.circular(16))),
child: Column(
children: [
Row(
children: [
Expanded(child: _buildGridStatRow(context, Icons.workspace_premium, Colors.amber.shade700, "MVP", mvp, isMvp: true)),
Expanded(child: _buildGridStatRow(context, Icons.shield, Colors.deepOrange.shade700, "Defesa", topDef)),
Expanded(child: _buildGridStatRow(Icons.workspace_premium, Colors.amber.shade700, "MVP", mvp, safeSf, isMvp: true)),
Expanded(child: _buildGridStatRow(Icons.shield, Colors.deepOrange.shade700, "Defesa", topDef, safeSf)),
],
),
SizedBox(height: 8 * context.sf),
SizedBox(height: 8 * safeSf),
Row(
children: [
Expanded(child: _buildGridStatRow(context, Icons.bolt, Colors.blue.shade700, "Pontos", topPts)),
Expanded(child: _buildGridStatRow(context, Icons.trending_up, Colors.purple.shade700, "Rebotes", topRbs)),
Expanded(child: _buildGridStatRow(Icons.bolt, Colors.blue.shade700, "Pontos", topPts, safeSf)),
Expanded(child: _buildGridStatRow(Icons.trending_up, Colors.purple.shade700, "Rebotes", topRbs, safeSf)),
],
),
SizedBox(height: 8 * context.sf),
SizedBox(height: 8 * safeSf),
Row(
children: [
Expanded(child: _buildGridStatRow(context, Icons.star, Colors.green.shade700, "Assists", topAst)),
Expanded(child: _buildGridStatRow(Icons.star, Colors.green.shade700, "Assists", topAst, safeSf)),
const Expanded(child: SizedBox()),
],
),
@@ -408,17 +410,17 @@ class _HomeScreenState extends State<HomeScreen> {
);
}
Widget _buildGridStatRow(BuildContext context, IconData icon, Color color, String label, String value, {bool isMvp = false}) {
Widget _buildGridStatRow(IconData icon, Color color, String label, String value, double safeSf, {bool isMvp = false}) {
return Row(
children: [
Icon(icon, size: 14 * context.sf, color: color),
SizedBox(width: 4 * context.sf),
Text('$label: ', style: TextStyle(fontSize: 11 * context.sf, color: Colors.grey.shade600, fontWeight: FontWeight.bold)),
Icon(icon, size: 14 * safeSf, color: color),
SizedBox(width: 4 * safeSf),
Text('$label: ', style: TextStyle(fontSize: 11 * safeSf, color: Colors.grey.shade600, fontWeight: FontWeight.bold)),
Expanded(
child: Text(
value,
style: TextStyle(
fontSize: 11 * context.sf,
fontSize: 11 * safeSf,
color: isMvp ? Colors.amber.shade900 : Colors.black87,
fontWeight: FontWeight.bold
),