pdf e exel
This commit is contained in:
@@ -4,7 +4,6 @@ import 'package:pdf/widgets.dart' as pw;
|
||||
import 'package:printing/printing.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
// Modelo local para os tiros
|
||||
class _ShotDot {
|
||||
final double relX;
|
||||
final double relY;
|
||||
@@ -13,29 +12,22 @@ class _ShotDot {
|
||||
}
|
||||
|
||||
class PdfExportService {
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// ENTRY POINT
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
static Future<void> generateAndPrintBoxScore({
|
||||
required String gameId,
|
||||
required String myTeam,
|
||||
required String opponentTeam,
|
||||
required String myScore,
|
||||
required String opponentScore,
|
||||
required String season,
|
||||
required String season,
|
||||
required String targetTeam,
|
||||
}) async {
|
||||
final supabase = Supabase.instance.client;
|
||||
|
||||
// ── Jogo ────────────────────────────────────────────────────────────────
|
||||
final gameData =
|
||||
await supabase.from('games').select().eq('id', gameId).single();
|
||||
final gameData = await supabase.from('games').select().eq('id', gameId).single();
|
||||
|
||||
// ── Equipas ─────────────────────────────────────────────────────────────
|
||||
final teamsData = await supabase
|
||||
.from('teams')
|
||||
.select('id, name')
|
||||
.inFilter('name', [myTeam, opponentTeam]);
|
||||
final teamsData = await supabase.from('teams').select('id, name').inFilter('name', [myTeam, opponentTeam]);
|
||||
|
||||
String? myTeamId;
|
||||
for (var t in teamsData) {
|
||||
@@ -44,32 +36,19 @@ class PdfExportService {
|
||||
|
||||
// ── Jogadores (Apenas a minha equipa) ───────────────────────────────────
|
||||
List<dynamic> myPlayers = myTeamId != null
|
||||
? await supabase
|
||||
.from('members')
|
||||
.select()
|
||||
.eq('team_id', myTeamId)
|
||||
.eq('type', 'Jogador')
|
||||
? await supabase.from('members').select().eq('team_id', myTeamId).eq('type', 'Jogador')
|
||||
: [];
|
||||
|
||||
// ── Estatísticas ─────────────────────────────────────────────────────────
|
||||
final statsData =
|
||||
await supabase.from('player_stats').select().eq('game_id', gameId);
|
||||
final statsData = await supabase.from('player_stats').select().eq('game_id', gameId);
|
||||
Map<String, Map<String, dynamic>> statsMap = {};
|
||||
for (var s in statsData) {
|
||||
statsMap[s['member_id'].toString()] = s;
|
||||
}
|
||||
|
||||
// ── Tiros (para o mapa de calor da minha equipa) ──────────────────────
|
||||
final shotsData = await supabase
|
||||
.from('shot_locations')
|
||||
.select()
|
||||
.eq('game_id', gameId);
|
||||
|
||||
// IDs da minha equipa
|
||||
final Set<String> myPlayerIds =
|
||||
myPlayers.map((p) => p['id'].toString()).toSet();
|
||||
|
||||
// Separa os tiros: todos da minha equipa, depois por jogador
|
||||
// ── Tiros ──────────────────────
|
||||
final shotsData = await supabase.from('shot_locations').select().eq('game_id', gameId);
|
||||
final Set<String> myPlayerIds = myPlayers.map((p) => p['id'].toString()).toSet();
|
||||
final List<_ShotDot> myTeamShots = [];
|
||||
final Map<String, List<_ShotDot>> shotsByPlayer = {};
|
||||
|
||||
@@ -86,16 +65,14 @@ class PdfExportService {
|
||||
shotsByPlayer.putIfAbsent(memberId, () => []).add(dot);
|
||||
}
|
||||
|
||||
// ── Tabela de estatísticas (Apenas a minha equipa) ────────────────────
|
||||
List<List<String>> myTeamTable =
|
||||
_buildTeamTableData(myPlayers, statsMap);
|
||||
// ── Tabela de estatísticas ────────────────────
|
||||
List<List<String>> myTeamTable = _buildTeamTableData(myPlayers, statsMap);
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
// CONSTRUÇÃO DO PDF
|
||||
// ════════════════════════════════════════════════════════════════════════
|
||||
final pdf = pw.Document();
|
||||
|
||||
// ── PÁGINA 1: Box Score ──────────────────────────────────────────────
|
||||
pdf.addPage(
|
||||
pw.Page(
|
||||
pageFormat: PdfPageFormat.a4.landscape,
|
||||
@@ -110,71 +87,81 @@ class PdfExportService {
|
||||
children: [
|
||||
pw.Row(
|
||||
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||
children: [
|
||||
pw.Text('Relatório Estatístico',
|
||||
style: pw.TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: pw.FontWeight.bold)),
|
||||
pw.Column(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||
children: [
|
||||
pw.Text('Relatório Estatístico', style: pw.TextStyle(fontSize: 22, fontWeight: pw.FontWeight.bold)),
|
||||
pw.SizedBox(height: 10),
|
||||
pw.Text('Equipa: $myTeam', style: pw.TextStyle(fontSize: 14, fontWeight: pw.FontWeight.bold, color: const PdfColor.fromInt(0xFFA00000))),
|
||||
]
|
||||
),
|
||||
|
||||
pw.Column(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.end,
|
||||
children: [
|
||||
pw.Text('$myTeam vs $opponentTeam',
|
||||
style: pw.TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: pw.FontWeight.bold)),
|
||||
pw.Text('Resultado: $myScore — $opponentScore',
|
||||
style: const pw.TextStyle(fontSize: 13)),
|
||||
pw.Text('Época: $season',
|
||||
style: const pw.TextStyle(fontSize: 11)),
|
||||
pw.Text('$myTeam vs $opponentTeam', style: pw.TextStyle(fontSize: 15, fontWeight: pw.FontWeight.bold)),
|
||||
pw.Text('Resultado: $myScore — $opponentScore', style: const pw.TextStyle(fontSize: 13)),
|
||||
pw.Text('Época: $season', style: const pw.TextStyle(fontSize: 11)),
|
||||
pw.SizedBox(height: 10),
|
||||
|
||||
// 👇 NOVA TABELA: PONTUAÇÃO POR PERÍODO 👇
|
||||
pw.Table.fromTextArray(
|
||||
context: context,
|
||||
border: pw.TableBorder.all(color: PdfColors.grey400, width: 0.5),
|
||||
headerStyle: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 8),
|
||||
cellStyle: const pw.TextStyle(fontSize: 8),
|
||||
headerDecoration: const pw.BoxDecoration(color: PdfColors.grey200),
|
||||
cellAlignment: pw.Alignment.center,
|
||||
data: <List<String>>[
|
||||
['Equipa', '1ºQ', '2ºQ', '3ºQ', '4ºQ', 'F'],
|
||||
[
|
||||
myTeam,
|
||||
gameData['my_q1']?.toString() ?? '-',
|
||||
gameData['my_q2']?.toString() ?? '-',
|
||||
gameData['my_q3']?.toString() ?? '-',
|
||||
gameData['my_q4']?.toString() ?? '-',
|
||||
myScore
|
||||
],
|
||||
[
|
||||
opponentTeam,
|
||||
gameData['opp_q1']?.toString() ?? '-',
|
||||
gameData['opp_q2']?.toString() ?? '-',
|
||||
gameData['opp_q3']?.toString() ?? '-',
|
||||
gameData['opp_q4']?.toString() ?? '-',
|
||||
opponentScore
|
||||
],
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
pw.SizedBox(height: 12),
|
||||
|
||||
pw.Text('Equipa: $myTeam',
|
||||
style: pw.TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: pw.FontWeight.bold,
|
||||
color: const PdfColor.fromInt(0xFFA00000))),
|
||||
pw.SizedBox(height: 8),
|
||||
|
||||
pw.Text('Pontos e Lançamentos',
|
||||
style: pw.TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: pw.FontWeight.bold,
|
||||
color: PdfColors.grey700)),
|
||||
pw.Text('Pontos e Lançamentos', style: pw.TextStyle(fontSize: 10, fontWeight: pw.FontWeight.bold, color: PdfColors.grey700)),
|
||||
pw.SizedBox(height: 2),
|
||||
_buildPdfTablePart1(
|
||||
myTeamTable, const PdfColor.fromInt(0xFFA00000)),
|
||||
_buildPdfTablePart1(myTeamTable, const PdfColor.fromInt(0xFFA00000)),
|
||||
|
||||
pw.SizedBox(height: 14),
|
||||
|
||||
pw.Text('Outras Estatísticas (Ressaltos, Faltas, Turnovers, etc.)',
|
||||
style: pw.TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: pw.FontWeight.bold,
|
||||
color: PdfColors.grey700)),
|
||||
pw.Text('Outras Estatísticas (Ressaltos, Faltas, Turnovers, etc.)', style: pw.TextStyle(fontSize: 10, fontWeight: pw.FontWeight.bold, color: PdfColors.grey700)),
|
||||
pw.SizedBox(height: 2),
|
||||
_buildPdfTablePart2(
|
||||
myTeamTable, const PdfColor.fromInt(0xFFA00000)),
|
||||
_buildPdfTablePart2(myTeamTable, const PdfColor.fromInt(0xFFA00000)),
|
||||
|
||||
pw.SizedBox(height: 16),
|
||||
|
||||
pw.Row(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildSummaryBox('Melhor Marcador',
|
||||
gameData['top_pts_name'] ?? '---'),
|
||||
_buildSummaryBox('Melhor Marcador', gameData['top_pts_name'] ?? '---'),
|
||||
pw.SizedBox(width: 10),
|
||||
_buildSummaryBox('Melhor Ressaltador',
|
||||
gameData['top_rbs_name'] ?? '---'),
|
||||
_buildSummaryBox('Melhor Ressaltador', gameData['top_rbs_name'] ?? '---'),
|
||||
pw.SizedBox(width: 10),
|
||||
_buildSummaryBox('Melhor Passador',
|
||||
gameData['top_ast_name'] ?? '---'),
|
||||
_buildSummaryBox('Melhor Passador', gameData['top_ast_name'] ?? '---'),
|
||||
pw.SizedBox(width: 10),
|
||||
_buildSummaryBox(
|
||||
'MVP', gameData['mvp_name'] ?? '---'),
|
||||
_buildSummaryBox('MVP', gameData['mvp_name'] ?? '---'),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -195,15 +182,13 @@ class PdfExportService {
|
||||
return pw.Column(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||
children: [
|
||||
_heatmapPageHeader('MAPA DE CALOR — $myTeam (Equipa Completa)',
|
||||
const PdfColor.fromInt(0xFFA00000)),
|
||||
_heatmapPageHeader('MAPA DE CALOR — $myTeam (Equipa Completa)', const PdfColor.fromInt(0xFFA00000)),
|
||||
pw.SizedBox(height: 12),
|
||||
pw.Expanded(
|
||||
child: pw.Center(
|
||||
child: pw.CustomPaint(
|
||||
size: const PdfPoint(360, 360),
|
||||
painter: (canvas, size) =>
|
||||
_paintCourt(canvas, size, myTeamShots),
|
||||
painter: (canvas, size) => _paintCourt(canvas, size, myTeamShots),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -217,7 +202,6 @@ class PdfExportService {
|
||||
}
|
||||
|
||||
// ── PÁGINAS 3+: Mapa de Calor por Jogador (4 por folha) ──────────────
|
||||
// 👇 FILTRO ATIVO: Só entra aqui quem tiver tiros na lista "shotsByPlayer"!
|
||||
final activePlayers = myPlayers.where((p) {
|
||||
final pid = p['id'].toString();
|
||||
return shotsByPlayer[pid] != null && shotsByPlayer[pid]!.isNotEmpty;
|
||||
@@ -280,9 +264,6 @@ class PdfExportService {
|
||||
);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// WIDGET DO MAPA DE CALOR INDIVIDUAL
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
static pw.Widget _buildPlayerHeatmap(dynamic player, List<_ShotDot> shots, Map<String, dynamic> stats) {
|
||||
final String playerName = player['name']?.toString() ?? 'Jogador';
|
||||
final String playerNumber = player['number']?.toString() ?? '0';
|
||||
@@ -320,16 +301,11 @@ class PdfExportService {
|
||||
);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// CORREÇÃO: DESENHO DO CAMPO E LINHAS ADAPTADAS
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
static void _paintCourt(PdfGraphics canvas, PdfPoint size, List<_ShotDot> shots) {
|
||||
final double w = size.x;
|
||||
final double h = size.y;
|
||||
final double basketX = w / 2;
|
||||
|
||||
// Fundo Amarelo (Toda a área)
|
||||
canvas
|
||||
..setFillColor(const PdfColor.fromInt(0xFFDFAB00))
|
||||
..drawRect(0, 0, w, h)
|
||||
@@ -341,7 +317,6 @@ class PdfExportService {
|
||||
final double alturaDoArco = larguraDoArco * 0.30;
|
||||
final double totalArcoHeight = alturaDoArco * 4;
|
||||
|
||||
// ── 1. LINHAS BRANCAS ───────────────────────────────────────────────
|
||||
canvas.setStrokeColor(PdfColors.white);
|
||||
canvas.setLineWidth(2.0);
|
||||
|
||||
@@ -350,7 +325,6 @@ class PdfExportService {
|
||||
_drawLine(canvas, h, 0, length, margin, length);
|
||||
_drawLine(canvas, h, w - margin, length, w, length);
|
||||
|
||||
// Arco 3pts
|
||||
_drawEllipseArc(canvas, h, basketX, length, larguraDoArco, totalArcoHeight / 2, 0, math.pi);
|
||||
|
||||
double sXL = basketX + (larguraDoArco * math.cos(math.pi * 0.75));
|
||||
@@ -361,46 +335,34 @@ class PdfExportService {
|
||||
_drawLine(canvas, h, sXL, sYL, 0, h * 0.85);
|
||||
_drawLine(canvas, h, sXR, sYR, w, h * 0.85);
|
||||
|
||||
// ── 2. LINHAS PRETAS ─────────────────────────────────────────────────
|
||||
canvas.setStrokeColor(PdfColors.black);
|
||||
canvas.setLineWidth(1.5);
|
||||
|
||||
final double pW = w * 0.28;
|
||||
final double pH = h * 0.38;
|
||||
|
||||
// Garrafão
|
||||
_drawRect(canvas, h, basketX - pW / 2, 0, pW, pH);
|
||||
|
||||
// Círculo Lances Livres
|
||||
final double ftR = pW / 2;
|
||||
_drawEllipseArc(canvas, h, basketX, pH, ftR, ftR, 0, math.pi);
|
||||
// Tracejado
|
||||
for (int i = 0; i < 10; i++) {
|
||||
_drawEllipseArc(canvas, h, basketX, pH, ftR, ftR, math.pi + (i * 2 * (math.pi / 20)), math.pi / 20);
|
||||
}
|
||||
|
||||
// Linhas oblíquas do garrafão
|
||||
_drawLine(canvas, h, basketX - pW / 2, pH, sXL, sYL);
|
||||
_drawLine(canvas, h, basketX + pW / 2, pH, sXR, sYR);
|
||||
|
||||
// Meio Campo
|
||||
_drawEllipseArc(canvas, h, basketX, h, w * 0.12, w * 0.12, math.pi, math.pi);
|
||||
|
||||
// Cesto e Tabela
|
||||
_drawCircle(canvas, h, basketX, h * 0.12, w * 0.02);
|
||||
_drawLine(canvas, h, basketX - w * 0.08, h * 0.12 - 5, basketX + w * 0.08, h * 0.12 - 5);
|
||||
|
||||
// ── 3. TIROS ─────────────────────────────────────────────────────────
|
||||
for (final shot in shots) {
|
||||
final double px = shot.relX * w;
|
||||
final double py = shot.relY * h;
|
||||
|
||||
final PdfColor dotColor = shot.isMake ? PdfColors.green600 : PdfColors.red600;
|
||||
|
||||
// Desenha Círculo Colorido
|
||||
_fillCircle(canvas, h, px, py, 6, dotColor);
|
||||
|
||||
// Símbolos
|
||||
canvas.setStrokeColor(PdfColors.white);
|
||||
canvas.setLineWidth(1.2);
|
||||
if (shot.isMake) {
|
||||
@@ -413,19 +375,12 @@ class PdfExportService {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Helpers com inversão automática do Eixo Y para casar com Flutter ──
|
||||
static void _drawLine(PdfGraphics c, double canvasH, double x1, double y1, double x2, double y2) {
|
||||
c.moveTo(x1, canvasH - y1);
|
||||
c.lineTo(x2, canvasH - y2);
|
||||
c.strokePath();
|
||||
}
|
||||
|
||||
static void _lineRaw(PdfGraphics c, double x1, double y1, double x2, double y2) {
|
||||
c.moveTo(x1, y1);
|
||||
c.lineTo(x2, y2);
|
||||
c.strokePath();
|
||||
}
|
||||
|
||||
static void _drawRect(PdfGraphics c, double canvasH, double x, double y, double width, double height) {
|
||||
c.drawRect(x, canvasH - (y + height), width, height);
|
||||
c.strokePath();
|
||||
@@ -460,12 +415,7 @@ class PdfExportService {
|
||||
c.strokePath();
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// TABELAS DE ESTATÍSTICAS
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
static List<List<String>> _buildTeamTableData(
|
||||
List<dynamic> players, Map<String, Map<String, dynamic>> statsMap) {
|
||||
static List<List<String>> _buildTeamTableData(List<dynamic> players, Map<String, Map<String, dynamic>> statsMap) {
|
||||
List<List<String>> tableData = [];
|
||||
|
||||
int tPts = 0, tFgm = 0, tFga = 0, tFtm = 0, tFta = 0, tFls = 0;
|
||||
@@ -485,27 +435,16 @@ class PdfExportService {
|
||||
var s = statsMap[id] ?? {};
|
||||
|
||||
int pts = s['pts'] ?? 0;
|
||||
int fgm = s['fgm'] ?? 0;
|
||||
int fga = s['fga'] ?? 0;
|
||||
int ftm = s['ftm'] ?? 0;
|
||||
int fta = s['fta'] ?? 0;
|
||||
int p2m = s['p2m'] ?? 0;
|
||||
int p2a = s['p2a'] ?? 0;
|
||||
int p3m = s['p3m'] ?? 0;
|
||||
int p3a = s['p3a'] ?? 0;
|
||||
int fgm = s['fgm'] ?? 0; int fga = s['fga'] ?? 0;
|
||||
int ftm = s['ftm'] ?? 0; int fta = s['fta'] ?? 0;
|
||||
int p2m = s['p2m'] ?? 0; int p2a = s['p2a'] ?? 0;
|
||||
int p3m = s['p3m'] ?? 0; int p3a = s['p3a'] ?? 0;
|
||||
int fls = s['fls'] ?? 0;
|
||||
int orb = s['orb'] ?? 0;
|
||||
int drb = s['drb'] ?? 0;
|
||||
int stl = s['stl'] ?? 0;
|
||||
int ast = s['ast'] ?? 0;
|
||||
int tov = s['tov'] ?? 0;
|
||||
int blk = s['blk'] ?? 0;
|
||||
int so = s['so'] ?? 0;
|
||||
int il = s['il'] ?? 0;
|
||||
int li = s['li'] ?? 0;
|
||||
int pa = s['pa'] ?? 0;
|
||||
int tresS = s['tres_seg'] ?? 0;
|
||||
int dr = s['dr'] ?? 0;
|
||||
int orb = s['orb'] ?? 0; int drb = s['drb'] ?? 0;
|
||||
int stl = s['stl'] ?? 0; int ast = s['ast'] ?? 0;
|
||||
int tov = s['tov'] ?? 0; int blk = s['blk'] ?? 0;
|
||||
int so = s['so'] ?? 0; int il = s['il'] ?? 0; int li = s['li'] ?? 0;
|
||||
int pa = s['pa'] ?? 0; int tresS = s['tres_seg'] ?? 0; int dr = s['dr'] ?? 0;
|
||||
int sec = s['minutos_jogados'] ?? 0;
|
||||
|
||||
tPts += pts; tFgm += fgm; tFga += fga; tFtm += ftm; tFta += fta;
|
||||
@@ -525,8 +464,7 @@ class PdfExportService {
|
||||
tableData.add([
|
||||
p['number']?.toString() ?? '-',
|
||||
p['name']?.toString() ?? '?',
|
||||
minStr,
|
||||
pts.toString(),
|
||||
minStr, pts.toString(),
|
||||
p2m.toString(), p2a.toString(), p2Pct,
|
||||
p3m.toString(), p3a.toString(), p3Pct,
|
||||
fgm.toString(), fga.toString(), fgPct,
|
||||
@@ -717,8 +655,7 @@ class PdfExportService {
|
||||
);
|
||||
}
|
||||
|
||||
static pw.Widget _groupHeader(
|
||||
String title, pw.TextStyle hStyle, pw.TextStyle sStyle) {
|
||||
static pw.Widget _groupHeader(String title, pw.TextStyle hStyle, pw.TextStyle sStyle) {
|
||||
return pw.Column(
|
||||
children: [
|
||||
pw.Container(
|
||||
@@ -726,54 +663,28 @@ class PdfExportService {
|
||||
alignment: pw.Alignment.center,
|
||||
padding: const pw.EdgeInsets.symmetric(vertical: 2),
|
||||
decoration: const pw.BoxDecoration(
|
||||
border: pw.Border(
|
||||
bottom: pw.BorderSide(color: PdfColors.white, width: 0.5)),
|
||||
border: pw.Border(bottom: pw.BorderSide(color: PdfColors.white, width: 0.5)),
|
||||
),
|
||||
child: pw.Text(title, style: hStyle),
|
||||
),
|
||||
pw.Row(children: [
|
||||
pw.Expanded(
|
||||
child: pw.Container(
|
||||
alignment: pw.Alignment.center,
|
||||
padding: const pw.EdgeInsets.symmetric(vertical: 2),
|
||||
child: pw.Text('C', style: sStyle))),
|
||||
pw.Expanded(child: pw.Container(alignment: pw.Alignment.center, padding: const pw.EdgeInsets.symmetric(vertical: 2), child: pw.Text('C', style: sStyle))),
|
||||
pw.Container(width: 0.5, height: 10, color: PdfColors.white),
|
||||
pw.Expanded(
|
||||
child: pw.Container(
|
||||
alignment: pw.Alignment.center,
|
||||
padding: const pw.EdgeInsets.symmetric(vertical: 2),
|
||||
child: pw.Text('T', style: sStyle))),
|
||||
pw.Expanded(child: pw.Container(alignment: pw.Alignment.center, padding: const pw.EdgeInsets.symmetric(vertical: 2), child: pw.Text('T', style: sStyle))),
|
||||
pw.Container(width: 0.5, height: 10, color: PdfColors.white),
|
||||
pw.Expanded(
|
||||
child: pw.Container(
|
||||
alignment: pw.Alignment.center,
|
||||
padding: const pw.EdgeInsets.symmetric(vertical: 2),
|
||||
child: pw.Text('%', style: sStyle))),
|
||||
pw.Expanded(child: pw.Container(alignment: pw.Alignment.center, padding: const pw.EdgeInsets.symmetric(vertical: 2), child: pw.Text('%', style: sStyle))),
|
||||
]),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
static pw.Widget _groupData(
|
||||
String c, String t, String pct, pw.TextStyle style) {
|
||||
static pw.Widget _groupData(String c, String t, String pct, pw.TextStyle style) {
|
||||
return pw.Row(children: [
|
||||
pw.Expanded(
|
||||
child: pw.Container(
|
||||
alignment: pw.Alignment.center,
|
||||
padding: const pw.EdgeInsets.symmetric(vertical: 4),
|
||||
child: pw.Text(c, style: style))),
|
||||
pw.Expanded(child: pw.Container(alignment: pw.Alignment.center, padding: const pw.EdgeInsets.symmetric(vertical: 4), child: pw.Text(c, style: style))),
|
||||
pw.Container(width: 0.5, height: 12, color: PdfColors.grey400),
|
||||
pw.Expanded(
|
||||
child: pw.Container(
|
||||
alignment: pw.Alignment.center,
|
||||
padding: const pw.EdgeInsets.symmetric(vertical: 4),
|
||||
child: pw.Text(t, style: style))),
|
||||
pw.Expanded(child: pw.Container(alignment: pw.Alignment.center, padding: const pw.EdgeInsets.symmetric(vertical: 4), child: pw.Text(t, style: style))),
|
||||
pw.Container(width: 0.5, height: 12, color: PdfColors.grey400),
|
||||
pw.Expanded(
|
||||
child: pw.Container(
|
||||
alignment: pw.Alignment.center,
|
||||
padding: const pw.EdgeInsets.symmetric(vertical: 4),
|
||||
child: pw.Text(pct, style: style))),
|
||||
pw.Expanded(child: pw.Container(alignment: pw.Alignment.center, padding: const pw.EdgeInsets.symmetric(vertical: 4), child: pw.Text(pct, style: style))),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -781,17 +692,8 @@ class PdfExportService {
|
||||
return pw.Container(
|
||||
width: double.infinity,
|
||||
padding: const pw.EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
decoration: pw.BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: const pw.BorderRadius.all(pw.Radius.circular(6)),
|
||||
),
|
||||
child: pw.Text(
|
||||
title,
|
||||
style: pw.TextStyle(
|
||||
color: PdfColors.white,
|
||||
fontSize: 14,
|
||||
fontWeight: pw.FontWeight.bold),
|
||||
),
|
||||
decoration: pw.BoxDecoration(color: color, borderRadius: const pw.BorderRadius.all(pw.Radius.circular(6))),
|
||||
child: pw.Text(title, style: pw.TextStyle(color: PdfColors.white, fontSize: 14, fontWeight: pw.FontWeight.bold)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -799,15 +701,11 @@ class PdfExportService {
|
||||
return pw.Row(
|
||||
mainAxisAlignment: pw.MainAxisAlignment.center,
|
||||
children: [
|
||||
pw.Container(width: 12, height: 12,
|
||||
decoration: const pw.BoxDecoration(
|
||||
color: PdfColors.green600, shape: pw.BoxShape.circle)),
|
||||
pw.Container(width: 12, height: 12, decoration: const pw.BoxDecoration(color: PdfColors.green600, shape: pw.BoxShape.circle)),
|
||||
pw.SizedBox(width: 4),
|
||||
pw.Text('Cesto marcado', style: pw.TextStyle(fontSize: 10)),
|
||||
pw.SizedBox(width: 20),
|
||||
pw.Container(width: 12, height: 12,
|
||||
decoration: const pw.BoxDecoration(
|
||||
color: PdfColors.red600, shape: pw.BoxShape.circle)),
|
||||
pw.Container(width: 12, height: 12, decoration: const pw.BoxDecoration(color: PdfColors.red600, shape: pw.BoxShape.circle)),
|
||||
pw.SizedBox(width: 4),
|
||||
pw.Text('Cesto falhado', style: pw.TextStyle(fontSize: 10)),
|
||||
],
|
||||
@@ -817,28 +715,15 @@ class PdfExportService {
|
||||
static pw.Widget _buildSummaryBox(String title, String value) {
|
||||
return pw.Container(
|
||||
width: 120,
|
||||
decoration: pw.BoxDecoration(
|
||||
border: pw.TableBorder.all(color: PdfColors.black, width: 1),
|
||||
),
|
||||
decoration: pw.BoxDecoration(border: pw.TableBorder.all(color: PdfColors.black, width: 1)),
|
||||
child: pw.Column(children: [
|
||||
pw.Container(
|
||||
width: double.infinity,
|
||||
padding: const pw.EdgeInsets.all(6),
|
||||
color: const PdfColor.fromInt(0xFFA00000),
|
||||
child: pw.Text(title,
|
||||
style: pw.TextStyle(
|
||||
color: PdfColors.white,
|
||||
fontSize: 9,
|
||||
fontWeight: pw.FontWeight.bold),
|
||||
textAlign: pw.TextAlign.center),
|
||||
width: double.infinity, padding: const pw.EdgeInsets.all(6), color: const PdfColor.fromInt(0xFFA00000),
|
||||
child: pw.Text(title, style: pw.TextStyle(color: PdfColors.white, fontSize: 9, fontWeight: pw.FontWeight.bold), textAlign: pw.TextAlign.center),
|
||||
),
|
||||
pw.Container(
|
||||
width: double.infinity,
|
||||
padding: const pw.EdgeInsets.all(8),
|
||||
child: pw.Text(value,
|
||||
style: pw.TextStyle(
|
||||
fontSize: 10, fontWeight: pw.FontWeight.bold),
|
||||
textAlign: pw.TextAlign.center),
|
||||
width: double.infinity, padding: const pw.EdgeInsets.all(8),
|
||||
child: pw.Text(value, style: pw.TextStyle(fontSize: 10, fontWeight: pw.FontWeight.bold), textAlign: pw.TextAlign.center),
|
||||
),
|
||||
]),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user