Resolve all lints and deprecation warnings
This commit is contained in:
@@ -1,105 +1,109 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:pdf/pdf.dart';
|
||||
import 'package:pdf/widgets.dart' as pw;
|
||||
import 'package:printing/printing.dart';
|
||||
import 'package:intl/intl.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 {
|
||||
static Future<void> generateCycleReport(
|
||||
UserProfile user, List<CycleEntry> entries) async {
|
||||
final pdf = pw.Document();
|
||||
final font = await PdfGoogleFonts.outfitRegular();
|
||||
final boldFont = await PdfGoogleFonts.outfitBold();
|
||||
|
||||
final logo = pw.MemoryImage(
|
||||
(await rootBundle.load('assets/images/logo.png')).buffer.asUint8List(),
|
||||
);
|
||||
|
||||
// Group entries by month
|
||||
final entriesByMonth = <String, List<CycleEntry>>{};
|
||||
final Map<String, List<CycleEntry>> groupedEntries = {};
|
||||
for (var entry in entries) {
|
||||
final month = DateFormat('MMMM yyyy').format(entry.date);
|
||||
if (!entriesByMonth.containsKey(month)) {
|
||||
entriesByMonth[month] = [];
|
||||
if (!groupedEntries.containsKey(month)) {
|
||||
groupedEntries[month] = [];
|
||||
}
|
||||
entriesByMonth[month]!.add(entry);
|
||||
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,
|
||||
theme: pw.ThemeData.withFont(
|
||||
base: font,
|
||||
bold: boldFont,
|
||||
),
|
||||
margin: const pw.EdgeInsets.all(32),
|
||||
build: (pw.Context context) {
|
||||
return [
|
||||
pw.Header(
|
||||
level: 0,
|
||||
child: pw.Row(
|
||||
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
pw.Text('Cycle Report', style: pw.TextStyle(fontSize: 24, fontWeight: pw.FontWeight.bold)),
|
||||
pw.Text(DateFormat.yMMMd().format(DateTime.now()), style: const pw.TextStyle(color: PdfColors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (user != null)
|
||||
pw.Padding(
|
||||
padding: const pw.EdgeInsets.only(bottom: 20),
|
||||
child: pw.Column(
|
||||
pw.Row(
|
||||
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
pw.Column(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||
children: [
|
||||
pw.Text('Name: ${user.name}'),
|
||||
pw.Text('Average Cycle Length: ${user.averageCycleLength} days'),
|
||||
pw.Text('Average Period Length: ${user.averagePeriodLength} days'),
|
||||
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)),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
...entriesByMonth.entries.map((entry) {
|
||||
final month = entry.key;
|
||||
final monthEntries = entry.value;
|
||||
// Sort by date
|
||||
monthEntries.sort((a, b) => a.date.compareTo(b.date));
|
||||
|
||||
return pw.Column(
|
||||
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.Text(month,
|
||||
style: pw.TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: pw.FontWeight.bold,
|
||||
color: PdfColors.blueGrey800)),
|
||||
pw.SizedBox(height: 5),
|
||||
pw.Table.fromTextArray(
|
||||
pw.TableHelper.fromTextArray(
|
||||
context: context,
|
||||
headerStyle: pw.TextStyle(fontWeight: pw.FontWeight.bold),
|
||||
headers: ['Date', 'Phase', 'Details', 'Notes'],
|
||||
data: monthEntries.map((e) {
|
||||
final details = <String>[];
|
||||
if (e.isPeriodDay) details.add('Period');
|
||||
if (e.mood != null) details.add('Mood: ${e.mood!.label}');
|
||||
if (e.symptomCount > 0) details.add('${e.symptomCount} symptoms');
|
||||
|
||||
data: groupedEntries[month]!.map((e) {
|
||||
return [
|
||||
DateFormat('d, E').format(e.date),
|
||||
'${e.isPeriodDay ? "Menstrual" : "-"}', // Simplified for report
|
||||
details.join(', '),
|
||||
e.notes ?? '',
|
||||
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(),
|
||||
columnWidths: {
|
||||
0: const pw.FlexColumnWidth(1),
|
||||
1: const pw.FlexColumnWidth(1),
|
||||
2: const pw.FlexColumnWidth(2),
|
||||
3: const pw.FlexColumnWidth(2),
|
||||
},
|
||||
),
|
||||
pw.SizedBox(height: 15),
|
||||
pw.SizedBox(height: 20),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
];
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
await Printing.sharePdf(bytes: await pdf.save(), filename: 'cycle_report.pdf');
|
||||
await Printing.layoutPdf(
|
||||
onLayout: (PdfPageFormat format) async => pdf.save(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user