bora para o relatorio
This commit is contained in:
@@ -404,293 +404,336 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 22.0 * context.sf,
|
||||
vertical: 16.0 * context.sf),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () => _showTeamSelector(context),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(12 * context.sf),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).cardTheme.color,
|
||||
borderRadius:
|
||||
BorderRadius.circular(15 * context.sf),
|
||||
border:
|
||||
Border.all(color: Colors.grey.withOpacity(0.2)),
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final bool isWide = constraints.maxWidth >= 1100;
|
||||
final double effectiveCardHeight =
|
||||
isWide ? 280 * context.sf : cardHeight;
|
||||
|
||||
Widget statsSection = Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: effectiveCardHeight,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildStatCard(
|
||||
context: context,
|
||||
title: 'Mais Pontos',
|
||||
playerName: leaders['pts_name'],
|
||||
statValue: leaders['pts_val'].toString(),
|
||||
statLabel: 'TOTAL',
|
||||
color: AppTheme.statPtsBg,
|
||||
isHighlighted: true)),
|
||||
SizedBox(width: 12 * context.sf),
|
||||
Expanded(
|
||||
child: _buildStatCard(
|
||||
context: context,
|
||||
title: 'Assistências',
|
||||
playerName: leaders['ast_name'],
|
||||
statValue: leaders['ast_val'].toString(),
|
||||
statLabel: 'TOTAL',
|
||||
color: AppTheme.statAstBg)),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(children: [
|
||||
(_selectedTeamLogo != null &&
|
||||
_selectedTeamLogo!.isNotEmpty)
|
||||
? ClipOval(
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: _selectedTeamLogo!,
|
||||
width: 24 * context.sf,
|
||||
height: 24 * context.sf,
|
||||
fit: BoxFit.cover,
|
||||
placeholder: (context, url) => Icon(
|
||||
Icons.shield,
|
||||
color: AppTheme.primaryRed,
|
||||
size: 24 * context.sf),
|
||||
errorWidget:
|
||||
(context, url, error) => Icon(
|
||||
SizedBox(height: 12 * context.sf),
|
||||
SizedBox(
|
||||
height: effectiveCardHeight,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildStatCard(
|
||||
context: context,
|
||||
title: 'Rebotes',
|
||||
playerName: leaders['rbs_name'],
|
||||
statValue: leaders['rbs_val'].toString(),
|
||||
statLabel: 'TOTAL',
|
||||
color: AppTheme.statRebBg)),
|
||||
SizedBox(width: 12 * context.sf),
|
||||
Expanded(
|
||||
child: PieChartCard(
|
||||
victories: _teamWins,
|
||||
defeats: _teamLosses,
|
||||
draws: _teamDraws,
|
||||
title: 'DESEMPENHO',
|
||||
subtitle: 'Temporada',
|
||||
backgroundColor: AppTheme.statPieBg,
|
||||
sf: context.sf)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Widget historySection = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Histórico de Jogos',
|
||||
style: TextStyle(
|
||||
fontSize: 20 * context.sf,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: textColor)),
|
||||
SizedBox(height: 16 * context.sf),
|
||||
_selectedTeamName == "Selecionar Equipa"
|
||||
? Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.all(24.0 * context.sf),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).cardTheme.color ??
|
||||
Colors.white,
|
||||
borderRadius:
|
||||
BorderRadius.circular(16 * context.sf),
|
||||
border: Border.all(
|
||||
color: Colors.grey.withOpacity(0.1)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.04),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4))
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(18 * context.sf),
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.primaryRed
|
||||
.withOpacity(0.08),
|
||||
shape: BoxShape.circle),
|
||||
child: Icon(Icons.shield_outlined,
|
||||
color: AppTheme.primaryRed,
|
||||
size: 42 * context.sf),
|
||||
),
|
||||
SizedBox(height: 20 * context.sf),
|
||||
Text("Nenhuma Equipa Ativa",
|
||||
style: TextStyle(
|
||||
fontSize: 18 * context.sf,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: textColor)),
|
||||
SizedBox(height: 8 * context.sf),
|
||||
Text(
|
||||
"Escolha uma equipa no seletor acima para ver as estatísticas e o histórico.",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 13 * context.sf,
|
||||
color: Colors.grey.shade600,
|
||||
height: 1.4),
|
||||
),
|
||||
SizedBox(height: 24 * context.sf),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 48 * context.sf,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _showTeamSelector(context),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppTheme.primaryRed,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
10 * context.sf)),
|
||||
),
|
||||
icon: Icon(Icons.touch_app,
|
||||
size: 20 * context.sf),
|
||||
label: Text("Selecionar Agora",
|
||||
style: TextStyle(
|
||||
fontSize: 15 * context.sf,
|
||||
fontWeight: FontWeight.bold)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: StreamBuilder<List<Map<String, dynamic>>>(
|
||||
stream: _supabase
|
||||
.from('games')
|
||||
.stream(primaryKey: ['id'])
|
||||
.order('game_date', ascending: false),
|
||||
builder: (context, gameSnapshot) {
|
||||
if (gameSnapshot.hasError) {
|
||||
return Text(
|
||||
"Erro: ${gameSnapshot.error}",
|
||||
style: const TextStyle(
|
||||
color: Colors.red));
|
||||
}
|
||||
if (!gameSnapshot.hasData &&
|
||||
gameSnapshot.connectionState ==
|
||||
ConnectionState.waiting) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
final todosOsJogos = gameSnapshot.data ?? [];
|
||||
final gamesList = todosOsJogos.where((game) {
|
||||
String myT =
|
||||
game['my_team']?.toString() ?? '';
|
||||
String oppT =
|
||||
game['opponent_team']?.toString() ?? '';
|
||||
String status =
|
||||
game['status']?.toString() ?? '';
|
||||
return (myT == _selectedTeamName ||
|
||||
oppT == _selectedTeamName) &&
|
||||
status == 'Terminado';
|
||||
}).take(3).toList();
|
||||
|
||||
if (gamesList.isEmpty) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.all(20 * context.sf),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).cardTheme.color,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: const Text(
|
||||
"Ainda não há jogos terminados.",
|
||||
style: TextStyle(color: Colors.grey)),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: gamesList.map((game) {
|
||||
String dbMyTeam =
|
||||
game['my_team']?.toString() ?? '';
|
||||
String dbOppTeam =
|
||||
game['opponent_team']?.toString() ?? '';
|
||||
int dbMyScore = int.tryParse(
|
||||
game['my_score']?.toString() ??
|
||||
'0') ??
|
||||
0;
|
||||
int dbOppScore = int.tryParse(
|
||||
game['opponent_score']
|
||||
?.toString() ??
|
||||
'0') ??
|
||||
0;
|
||||
String opponent;
|
||||
int myScore;
|
||||
int oppScore;
|
||||
|
||||
if (dbMyTeam == _selectedTeamName) {
|
||||
opponent = dbOppTeam;
|
||||
myScore = dbMyScore;
|
||||
oppScore = dbOppScore;
|
||||
} else {
|
||||
opponent = dbMyTeam;
|
||||
myScore = dbOppScore;
|
||||
oppScore = dbMyScore;
|
||||
}
|
||||
|
||||
String rawDate =
|
||||
game['game_date']?.toString() ?? '---';
|
||||
String date = rawDate.length >= 10
|
||||
? rawDate.substring(0, 10)
|
||||
: rawDate;
|
||||
String result = myScore > oppScore
|
||||
? 'V'
|
||||
: (myScore < oppScore ? 'D' : 'E');
|
||||
|
||||
return _buildGameHistoryCard(
|
||||
context: context,
|
||||
opponent: opponent,
|
||||
result: result,
|
||||
myScore: myScore,
|
||||
oppScore: oppScore,
|
||||
date: date,
|
||||
topPts:
|
||||
game['top_pts_name'] ?? '---',
|
||||
topAst:
|
||||
game['top_ast_name'] ?? '---',
|
||||
topRbs:
|
||||
game['top_rbs_name'] ?? '---',
|
||||
topDef:
|
||||
game['top_def_name'] ?? '---',
|
||||
mvp: game['mvp_name'] ?? '---',
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Widget mainContent = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () => _showTeamSelector(context),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(12 * context.sf),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).cardTheme.color,
|
||||
borderRadius:
|
||||
BorderRadius.circular(15 * context.sf),
|
||||
border:
|
||||
Border.all(color: Colors.grey.withOpacity(0.2)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(children: [
|
||||
(_selectedTeamLogo != null &&
|
||||
_selectedTeamLogo!.isNotEmpty)
|
||||
? ClipOval(
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: _selectedTeamLogo!,
|
||||
width: 24 * context.sf,
|
||||
height: 24 * context.sf,
|
||||
fit: BoxFit.cover,
|
||||
placeholder: (context, url) => Icon(
|
||||
Icons.shield,
|
||||
color: AppTheme.primaryRed,
|
||||
size: 24 * context.sf),
|
||||
),
|
||||
)
|
||||
: Icon(Icons.shield,
|
||||
color: AppTheme.primaryRed,
|
||||
size: 24 * context.sf),
|
||||
SizedBox(width: 10 * context.sf),
|
||||
Text(_selectedTeamName,
|
||||
style: TextStyle(
|
||||
fontSize: 16 * context.sf,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: textColor)),
|
||||
]),
|
||||
Icon(Icons.arrow_drop_down, color: textColor),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20 * context.sf),
|
||||
|
||||
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: AppTheme.statPtsBg,
|
||||
isHighlighted: true)),
|
||||
SizedBox(width: 12 * context.sf),
|
||||
Expanded(
|
||||
child: _buildStatCard(
|
||||
context: context,
|
||||
title: 'Assistências',
|
||||
playerName: leaders['ast_name'],
|
||||
statValue: leaders['ast_val'].toString(),
|
||||
statLabel: 'TOTAL',
|
||||
color: AppTheme.statAstBg)),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12 * context.sf),
|
||||
|
||||
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: AppTheme.statRebBg)),
|
||||
SizedBox(width: 12 * context.sf),
|
||||
Expanded(
|
||||
child: PieChartCard(
|
||||
victories: _teamWins,
|
||||
defeats: _teamLosses,
|
||||
draws: _teamDraws,
|
||||
title: 'DESEMPENHO',
|
||||
subtitle: 'Temporada',
|
||||
backgroundColor: AppTheme.statPieBg,
|
||||
sf: context.sf)),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 40 * context.sf),
|
||||
|
||||
Text('Histórico de Jogos',
|
||||
style: TextStyle(
|
||||
fontSize: 20 * context.sf,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: textColor)),
|
||||
SizedBox(height: 16 * context.sf),
|
||||
|
||||
_selectedTeamName == "Selecionar Equipa"
|
||||
? Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.all(24.0 * context.sf),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).cardTheme.color ??
|
||||
Colors.white,
|
||||
borderRadius:
|
||||
BorderRadius.circular(16 * context.sf),
|
||||
border: Border.all(
|
||||
color: Colors.grey.withOpacity(0.1)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.04),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4))
|
||||
errorWidget:
|
||||
(context, url, error) => Icon(
|
||||
Icons.shield,
|
||||
color: AppTheme.primaryRed,
|
||||
size: 24 * context.sf),
|
||||
),
|
||||
)
|
||||
: Icon(Icons.shield,
|
||||
color: AppTheme.primaryRed,
|
||||
size: 24 * context.sf),
|
||||
SizedBox(width: 10 * context.sf),
|
||||
Text(_selectedTeamName,
|
||||
style: TextStyle(
|
||||
fontSize: 16 * context.sf,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: textColor)),
|
||||
]),
|
||||
Icon(Icons.arrow_drop_down, color: textColor),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(18 * context.sf),
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.primaryRed.withOpacity(0.08),
|
||||
shape: BoxShape.circle),
|
||||
child: Icon(Icons.shield_outlined,
|
||||
color: AppTheme.primaryRed,
|
||||
size: 42 * context.sf),
|
||||
),
|
||||
SizedBox(height: 20 * context.sf),
|
||||
Text("Nenhuma Equipa Ativa",
|
||||
style: TextStyle(
|
||||
fontSize: 18 * context.sf,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: textColor)),
|
||||
SizedBox(height: 8 * context.sf),
|
||||
Text(
|
||||
"Escolha uma equipa no seletor acima para ver as estatísticas e o histórico.",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 13 * context.sf,
|
||||
color: Colors.grey.shade600,
|
||||
height: 1.4),
|
||||
),
|
||||
SizedBox(height: 24 * context.sf),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 48 * context.sf,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _showTeamSelector(context),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppTheme.primaryRed,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
10 * context.sf)),
|
||||
),
|
||||
icon: Icon(Icons.touch_app,
|
||||
size: 20 * context.sf),
|
||||
label: Text("Selecionar Agora",
|
||||
style: TextStyle(
|
||||
fontSize: 15 * context.sf,
|
||||
fontWeight: FontWeight.bold)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: StreamBuilder<List<Map<String, dynamic>>>(
|
||||
stream: _supabase
|
||||
.from('games')
|
||||
.stream(primaryKey: ['id']).order('game_date',
|
||||
ascending: false),
|
||||
builder: (context, gameSnapshot) {
|
||||
if (gameSnapshot.hasError) {
|
||||
return Text("Erro: ${gameSnapshot.error}",
|
||||
style:
|
||||
const TextStyle(color: Colors.red));
|
||||
}
|
||||
if (!gameSnapshot.hasData &&
|
||||
gameSnapshot.connectionState ==
|
||||
ConnectionState.waiting) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
final todosOsJogos = gameSnapshot.data ?? [];
|
||||
final gamesList = todosOsJogos.where((game) {
|
||||
String myT =
|
||||
game['my_team']?.toString() ?? '';
|
||||
String oppT =
|
||||
game['opponent_team']?.toString() ?? '';
|
||||
String status =
|
||||
game['status']?.toString() ?? '';
|
||||
return (myT == _selectedTeamName ||
|
||||
oppT == _selectedTeamName) &&
|
||||
status == 'Terminado';
|
||||
}).take(3).toList();
|
||||
|
||||
if (gamesList.isEmpty) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.all(20 * context.sf),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).cardTheme.color,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: const Text(
|
||||
"Ainda não há jogos terminados.",
|
||||
style: TextStyle(color: Colors.grey)),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: gamesList.map((game) {
|
||||
String dbMyTeam =
|
||||
game['my_team']?.toString() ?? '';
|
||||
String dbOppTeam =
|
||||
game['opponent_team']?.toString() ?? '';
|
||||
int dbMyScore = int.tryParse(
|
||||
game['my_score']?.toString() ??
|
||||
'0') ??
|
||||
0;
|
||||
int dbOppScore = int.tryParse(
|
||||
game['opponent_score']
|
||||
?.toString() ??
|
||||
'0') ??
|
||||
0;
|
||||
String opponent;
|
||||
int myScore;
|
||||
int oppScore;
|
||||
|
||||
if (dbMyTeam == _selectedTeamName) {
|
||||
opponent = dbOppTeam;
|
||||
myScore = dbMyScore;
|
||||
oppScore = dbOppScore;
|
||||
} else {
|
||||
opponent = dbMyTeam;
|
||||
myScore = dbOppScore;
|
||||
oppScore = dbMyScore;
|
||||
}
|
||||
|
||||
String rawDate =
|
||||
game['game_date']?.toString() ?? '---';
|
||||
String date = rawDate.length >= 10
|
||||
? rawDate.substring(0, 10)
|
||||
: rawDate;
|
||||
String result = myScore > oppScore
|
||||
? 'V'
|
||||
: (myScore < oppScore ? 'D' : 'E');
|
||||
|
||||
return _buildGameHistoryCard(
|
||||
context: context,
|
||||
opponent: opponent,
|
||||
result: result,
|
||||
myScore: myScore,
|
||||
oppScore: oppScore,
|
||||
date: date,
|
||||
topPts: game['top_pts_name'] ?? '---',
|
||||
topAst: game['top_ast_name'] ?? '---',
|
||||
topRbs: game['top_rbs_name'] ?? '---',
|
||||
topDef: game['top_def_name'] ?? '---',
|
||||
mvp: game['mvp_name'] ?? '---',
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20 * context.sf),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20 * context.sf),
|
||||
if (!isWide) ...[
|
||||
statsSection,
|
||||
SizedBox(height: 40 * context.sf),
|
||||
historySection,
|
||||
]
|
||||
],
|
||||
);
|
||||
|
||||
if (isWide) {
|
||||
mainContent = Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(flex: 5, child: statsSection),
|
||||
SizedBox(width: 20 * context.sf),
|
||||
Expanded(flex: 6, child: historySection),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
mainContent,
|
||||
SizedBox(height: 20 * context.sf),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user