I want to download a complex pdf on my app which takes a series of lists (image and string)
I need the pdf to be structured in a particular way as shown below. there are 9 categories all together for each sections (items you identified correctly, items that you failed to identify correctly and bonus item you identify). the categories are Roofing, HVAC, interior, exterior, plumbing, electric, structure, kitchen and bathroom
PDF Generation and download
I've tried this code
import 'package:pdf/widgets.dart' as pw;
import 'package:pdf/pdf.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
Future<String> generateAndDownloadPDF({
required List<String> roofingImages,
required List<String> roofingDescriptions,
required List<String> exteriorImages,
required List<String> exteriorDescriptions,
required List<String> plumbingImages,
required List<String> plumbingDescriptions,
required List<String> structureImages,
required List<String> structureDescriptions,
required List<String> electricImages,
required List<String> electricDescriptions,
required List<String> hvacImages,
required List<String> hvacDescriptions,
required List<String> kitchenImages,
required List<String> kitchenDescriptions,
required List<String> bathroomImages,
required List<String> bathroomDescriptions,
required List<String> interiorImages,
required List<String> interiorDescriptions,
}) async {
try {
final pdf = pw.Document();
pdf.addPage(
pw.MultiPage(
build: (pw.Context context) => [
pw.Header(level: 0, text: 'Field Exam Results'),
..._buildDynamicSections('Items You Identified Correctly', [
['Roofing', roofingImages, roofingDescriptions],
['Exterior', exteriorImages, exteriorDescriptions],
['Plumbing', plumbingImages, plumbingDescriptions],
['Structure', structureImages, structureDescriptions],
['Electric', electricImages, electricDescriptions],
['HVAC', hvacImages, hvacDescriptions],
['Kitchen', kitchenImages, kitchenDescriptions],
['Bathroom', bathroomImages, bathroomDescriptions],
['Interior', interiorImages, interiorDescriptions],
]),
],
),
);
// Get local directory for saving the file
final directory = await getApplicationDocumentsDirectory();
final filePath = '${directory.path}/FieldExamResult.pdf';
final file = File(filePath);
await file.writeAsBytes(await pdf.save());
// Convert file path to a downloadable URI
final downloadUri = Uri.file(filePath).toString();
return downloadUri; // โ Always returns a valid string
} catch (e) {
print('Error generating PDF: $e');
return 'Error generating PDF: $e'; // โ Returning an error message instead of null
}
}
// Function to Generate Sections Dynamically
List<pw.Widget> _buildDynamicSections(String title, List<List<dynamic>> sectionData) {
List<pw.Widget> sections = [
pw.SizedBox(height: 20),
pw.Text(title, style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 14)),
pw.SizedBox(height: 10),
];
for (var section in sectionData) {
String category = section[0];
List<String> imagePaths = section[1];
List<String> descriptions = section[2];
if (imagePaths.isNotEmpty && descriptions.isNotEmpty) {
sections.add(pw.Text(category, style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 12)));
sections.add(_buildSubSection(category, imagePaths, descriptions));
}
}
return sections;
}
// Function to Create Individual Subsections
pw.Widget _buildSubSection(String title, List<String> imagePaths, List<String> descriptions) {
if (imagePaths.isEmpty || descriptions.isEmpty) return pw.Container();
return pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
pw.Text(title, style: pw.TextStyle(fontSize: 14, fontWeight: pw.FontWeight.bold)),
pw.SizedBox(height: 5),
pw.Wrap(
spacing: 10,
runSpacing: 10,
alignment: pw.WrapAlignment.start,
children: List.generate(imagePaths.length, (index) => pw.Container(
width: 120,
padding: const pw.EdgeInsets.all(5),
decoration: pw.BoxDecoration(
border: pw.Border.all(color: PdfColors.grey),
borderRadius: pw.BorderRadius.circular(5),
),
child: pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.center,
children: [
pw.Container(
width: 100,
height: 100,
child: pw.Image(pw.MemoryImage(File(imagePaths[index]).readAsBytesSync())),
),
pw.SizedBox(height: 5),
pw.Text(descriptions[index], textAlign: pw.TextAlign.center, style: pw.TextStyle(fontSize: 10)),
],
),
)),
),
pw.SizedBox(height: 10),
],
);
}
I use all the variables as argument and the return type to be a string which will be a download url