167e208ffa
- lib/utils/pdf/pdf_letterhead.dart: PdfBrand with load(), letterhead(), theme(), and pageFooter() shared across CRMC PDF documents - lib/widgets/pdf_preview_dialog.dart: showPdfPreviewDialog() with pdfrx PdfViewer.data preview, Print (Printing.layoutPdf) and Download (Printing.sharePdf) buttons - lib/screens/programmer_tasks/report/accomplishment_report_pdf.dart: buildAccomplishmentReportPdf() — A4 MultiPage with letterhead, info box, accomplishment table, footnote, summary, signatures, page footer - test/accomplishment_report_pdf_test.dart: 2 passing tests Co-Authored-By: claude-flow <ruv@ruv.net>
82 lines
2.5 KiB
Dart
82 lines
2.5 KiB
Dart
import 'package:flutter/services.dart' show rootBundle;
|
||
import 'package:pdf/pdf.dart' as pdf;
|
||
import 'package:pdf/widgets.dart' as pw;
|
||
|
||
/// Shared brand assets and letterhead widget for CRMC PDF documents.
|
||
class PdfBrand {
|
||
final pw.Font regular;
|
||
final pw.Font bold;
|
||
final pw.ImageProvider logo;
|
||
|
||
const PdfBrand({
|
||
required this.regular,
|
||
required this.bold,
|
||
required this.logo,
|
||
});
|
||
|
||
/// Load fonts and logo from the Flutter asset bundle.
|
||
static Future<PdfBrand> load() async {
|
||
final logoData = await rootBundle.load('assets/crmc_logo.png');
|
||
final logo = pw.MemoryImage(logoData.buffer.asUint8List());
|
||
|
||
final regular = pw.Font.ttf(
|
||
await rootBundle.load('assets/fonts/Roboto-Regular.ttf'),
|
||
);
|
||
final bold = pw.Font.ttf(
|
||
await rootBundle.load('assets/fonts/Roboto-Bold.ttf'),
|
||
);
|
||
|
||
return PdfBrand(regular: regular, bold: bold, logo: logo);
|
||
}
|
||
|
||
/// Standard CRMC letterhead: 60×60 logo + four-line organisation text.
|
||
pw.Widget letterhead() {
|
||
return pw.Row(
|
||
mainAxisAlignment: pw.MainAxisAlignment.center,
|
||
crossAxisAlignment: pw.CrossAxisAlignment.center,
|
||
children: [
|
||
pw.Image(logo, width: 60, height: 60),
|
||
pw.SizedBox(width: 16),
|
||
pw.Column(
|
||
crossAxisAlignment: pw.CrossAxisAlignment.center,
|
||
children: [
|
||
pw.Text(
|
||
'Republic of the Philippines',
|
||
style: pw.TextStyle(font: regular, fontSize: 9),
|
||
),
|
||
pw.Text(
|
||
'Department of Health',
|
||
style: pw.TextStyle(font: regular, fontSize: 9),
|
||
),
|
||
pw.Text(
|
||
'Cotabato Regional and Medical Center',
|
||
style: pw.TextStyle(font: regular, fontSize: 9),
|
||
),
|
||
pw.SizedBox(height: 3),
|
||
pw.Text(
|
||
'Integrated Hospital Operations and Management Program (IHOMP)',
|
||
style: pw.TextStyle(font: bold, fontSize: 9),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
/// Convenience: create a ThemeData from these fonts.
|
||
pw.ThemeData theme() => pw.ThemeData.withFont(base: regular, bold: bold);
|
||
|
||
/// Footer widget: right-aligned "Page x of y".
|
||
pw.Widget pageFooter(pw.Context ctx) => pw.Align(
|
||
alignment: pw.Alignment.centerRight,
|
||
child: pw.Text(
|
||
'Page ${ctx.pageNumber} of ${ctx.pagesCount}',
|
||
style: pw.TextStyle(
|
||
font: regular,
|
||
fontSize: 8,
|
||
color: pdf.PdfColors.grey600,
|
||
),
|
||
),
|
||
);
|
||
}
|