110 lines
4.0 KiB
Dart
110 lines
4.0 KiB
Dart
import 'package:flutter/services.dart';
|
|
import 'package:pdf/pdf.dart';
|
|
import 'package:pdf/widgets.dart' as pw;
|
|
import 'package:printing/printing.dart';
|
|
import '../models/user_profile.dart';
|
|
import '../models/cycle_entry.dart';
|
|
import 'package:intl/intl.dart';
|
|
|
|
class PdfService {
|
|
static Future<void> generateCycleReport(
|
|
UserProfile user, List<CycleEntry> entries) async {
|
|
final pdf = pw.Document();
|
|
|
|
final logo = pw.MemoryImage(
|
|
(await rootBundle.load('assets/images/logo.png')).buffer.asUint8List(),
|
|
);
|
|
|
|
// Group entries by month
|
|
final Map<String, List<CycleEntry>> groupedEntries = {};
|
|
for (var entry in entries) {
|
|
final month = DateFormat('MMMM yyyy').format(entry.date);
|
|
if (!groupedEntries.containsKey(month)) {
|
|
groupedEntries[month] = [];
|
|
}
|
|
groupedEntries[month]!.add(entry);
|
|
}
|
|
|
|
// Sort months chronologically (most recent first)
|
|
final sortedMonths = groupedEntries.keys.toList()
|
|
..sort((a, b) {
|
|
final dateA = DateFormat('MMMM yyyy').parse(a);
|
|
final dateB = DateFormat('MMMM yyyy').parse(b);
|
|
return dateB.compareTo(dateA);
|
|
});
|
|
|
|
pdf.addPage(
|
|
pw.MultiPage(
|
|
pageFormat: PdfPageFormat.a4,
|
|
margin: const pw.EdgeInsets.all(32),
|
|
build: (pw.Context context) {
|
|
return [
|
|
pw.Row(
|
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
pw.Column(
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
|
children: [
|
|
pw.Text('Cycle History Report',
|
|
style: pw.TextStyle(
|
|
fontSize: 24,
|
|
fontWeight: pw.FontWeight.bold,
|
|
color: PdfColors.blueGrey900)),
|
|
pw.Text('Generated for ${user.name}',
|
|
style: const pw.TextStyle(
|
|
fontSize: 14, color: PdfColors.blueGrey600)),
|
|
pw.Text(
|
|
'Date Range: ${DateFormat('MMM yyyy').format(entries.last.date)} - ${DateFormat('MMM yyyy').format(entries.first.date)}',
|
|
style: const pw.TextStyle(
|
|
fontSize: 12, color: PdfColors.blueGrey400)),
|
|
],
|
|
),
|
|
pw.SizedBox(height: 50, width: 50, child: pw.Image(logo)),
|
|
],
|
|
),
|
|
pw.SizedBox(height: 30),
|
|
for (var month in sortedMonths) ...[
|
|
pw.Column(
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
|
children: [
|
|
pw.SizedBox(height: 10),
|
|
pw.Text(month,
|
|
style: pw.TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: pw.FontWeight.bold,
|
|
color: PdfColors.blueGrey800)),
|
|
pw.SizedBox(height: 5),
|
|
pw.TableHelper.fromTextArray(
|
|
context: context,
|
|
headerStyle: pw.TextStyle(fontWeight: pw.FontWeight.bold),
|
|
headers: ['Date', 'Phase', 'Details', 'Notes'],
|
|
data: groupedEntries[month]!.map((e) {
|
|
return [
|
|
DateFormat('MMM d').format(e.date),
|
|
e.isPeriodDay
|
|
? 'Period'
|
|
: (e.flowIntensity == FlowIntensity.spotting
|
|
? 'Spotting'
|
|
: 'Other'),
|
|
e.flowIntensity != null
|
|
? 'Flow: ${e.flowIntensity.toString().split('.').last}'
|
|
: '-',
|
|
e.notes ?? '-',
|
|
];
|
|
}).toList(),
|
|
),
|
|
pw.SizedBox(height: 20),
|
|
],
|
|
),
|
|
],
|
|
];
|
|
},
|
|
),
|
|
);
|
|
|
|
await Printing.layoutPdf(
|
|
onLayout: (PdfPageFormat format) async => pdf.save(),
|
|
);
|
|
}
|
|
}
|