Milad akarie
Committed by David PHAM-VAN

Add custom pages builder to PdfPreview widget

1 # Changelog 1 # Changelog
2 2
3 -## 5.9.4 3 +## 5.10.0
4 4
5 - Remove deprecated Android embedding 5 - Remove deprecated Android embedding
  6 +- Add custom pages builder to PdfPreview widget [Milad akarie]
6 7
7 ## 5.9.3 8 ## 5.9.3
8 9
@@ -22,7 +22,12 @@ import 'package:pdf/pdf.dart'; @@ -22,7 +22,12 @@ import 'package:pdf/pdf.dart';
22 import '../callback.dart'; 22 import '../callback.dart';
23 import '../printing.dart'; 23 import '../printing.dart';
24 import '../printing_info.dart'; 24 import '../printing_info.dart';
  25 +import 'page.dart';
25 import 'raster.dart'; 26 import 'raster.dart';
  27 +/// Custom widget builder that's used for custom
  28 +/// rasterized pdf pages rendering
  29 +typedef CustomPdfPagesBuilder = Widget Function(
  30 + BuildContext context, List<PdfPreviewPageData> pages);
26 31
27 /// Flutter widget that uses the rasterized pdf pages to display a document. 32 /// Flutter widget that uses the rasterized pdf pages to display a document.
28 class PdfPreviewCustom extends StatefulWidget { 33 class PdfPreviewCustom extends StatefulWidget {
@@ -43,6 +48,7 @@ class PdfPreviewCustom extends StatefulWidget { @@ -43,6 +48,7 @@ class PdfPreviewCustom extends StatefulWidget {
43 this.dpi, 48 this.dpi,
44 this.scrollPhysics, 49 this.scrollPhysics,
45 this.shrinkWrap = false, 50 this.shrinkWrap = false,
  51 + this.pagesBuilder,
46 }) : super(key: key); 52 }) : super(key: key);
47 53
48 /// Pdf paper page format 54 /// Pdf paper page format
@@ -91,6 +97,10 @@ class PdfPreviewCustom extends StatefulWidget { @@ -91,6 +97,10 @@ class PdfPreviewCustom extends StatefulWidget {
91 /// If not provided, this value is calculated. 97 /// If not provided, this value is calculated.
92 final double? dpi; 98 final double? dpi;
93 99
  100 + /// clients can pass this builder to render
  101 + /// their own pages.
  102 + final CustomPdfPagesBuilder? pagesBuilder;
  103 +
94 @override 104 @override
95 PdfPreviewCustomState createState() => PdfPreviewCustomState(); 105 PdfPreviewCustomState createState() => PdfPreviewCustomState();
96 } 106 }
@@ -183,6 +193,9 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> @@ -183,6 +193,9 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom>
183 ); 193 );
184 } 194 }
185 195
  196 + if (widget.pagesBuilder != null) {
  197 + return widget.pagesBuilder!(context, pages);
  198 + }
186 return ListView.builder( 199 return ListView.builder(
187 controller: scrollController, 200 controller: scrollController,
188 shrinkWrap: widget.shrinkWrap, 201 shrinkWrap: widget.shrinkWrap,
@@ -197,7 +210,11 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> @@ -197,7 +210,11 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom>
197 transformationController.value.setIdentity(); 210 transformationController.value.setIdentity();
198 }); 211 });
199 }, 212 },
200 - child: pages[index], 213 + child: PdfPreviewPage(
  214 + pageData: pages[index],
  215 + pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration,
  216 + pageMargin: widget.previewPageMargin,
  217 + ),
201 ), 218 ),
202 ); 219 );
203 } 220 }
@@ -212,7 +229,13 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> @@ -212,7 +229,13 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom>
212 child: InteractiveViewer( 229 child: InteractiveViewer(
213 transformationController: transformationController, 230 transformationController: transformationController,
214 maxScale: 5, 231 maxScale: 5,
215 - child: Center(child: pages[preview!]), 232 + child: Center(
  233 + child: PdfPreviewPage(
  234 + pageData: pages[preview!],
  235 + pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration,
  236 + pageMargin: widget.previewPageMargin,
  237 + ),
  238 + ),
216 ), 239 ),
217 ); 240 );
218 } 241 }
@@ -15,25 +15,61 @@ @@ -15,25 +15,61 @@
15 */ 15 */
16 16
17 import 'package:flutter/material.dart'; 17 import 'package:flutter/material.dart';
  18 +/// A class that holds rasterized pdf data
  19 +class PdfPreviewPageData {
  20 + /// Default constructor
  21 + const PdfPreviewPageData({
  22 + required this.image,
  23 + required this.width,
  24 + required this.height,
  25 + });
  26 +
  27 + /// rasterized pdf image provider
  28 + final ImageProvider image;
  29 + /// rasterized image width
  30 + final int width;
  31 + /// rasterized image height
  32 + final int height;
  33 +
  34 + /// returns with to height aspect ratio
  35 + double get aspectRatio {
  36 + if (height != 0.0) {
  37 + return width / height;
  38 + }
  39 + if (width > 0.0) {
  40 + return double.infinity;
  41 + }
  42 + if (width < 0.0) {
  43 + return double.negativeInfinity;
  44 + }
  45 + return 0.0;
  46 + }
  47 +
  48 + @override
  49 + bool operator ==(Object other) =>
  50 + identical(this, other) ||
  51 + other is PdfPreviewPageData &&
  52 + runtimeType == other.runtimeType &&
  53 + image == other.image &&
  54 + width == other.width &&
  55 + height == other.height;
  56 +
  57 + @override
  58 + int get hashCode => image.hashCode ^ width.hashCode ^ height.hashCode;
  59 +}
18 60
19 /// Represents one PDF page 61 /// Represents one PDF page
20 class PdfPreviewPage extends StatelessWidget { 62 class PdfPreviewPage extends StatelessWidget {
21 /// Create a PDF page widget 63 /// Create a PDF page widget
22 const PdfPreviewPage({ 64 const PdfPreviewPage({
23 Key? key, 65 Key? key,
24 - required this.image,  
25 - required this.width,  
26 - required this.height, 66 + required this.pageData,
27 this.pdfPreviewPageDecoration, 67 this.pdfPreviewPageDecoration,
28 this.pageMargin, 68 this.pageMargin,
29 }) : super(key: key); 69 }) : super(key: key);
30 70
31 /// Image representing the content of the page 71 /// Image representing the content of the page
32 - final ImageProvider image;  
33 -  
34 - final int width;  
35 -  
36 - final int height; 72 + final PdfPreviewPageData pageData;
37 73
38 /// Decoration around the page 74 /// Decoration around the page
39 final Decoration? pdfPreviewPageDecoration; 75 final Decoration? pdfPreviewPageDecoration;
@@ -69,9 +105,9 @@ class PdfPreviewPage extends StatelessWidget { @@ -69,9 +105,9 @@ class PdfPreviewPage extends StatelessWidget {
69 ], 105 ],
70 ), 106 ),
71 child: AspectRatio( 107 child: AspectRatio(
72 - aspectRatio: width / height, 108 + aspectRatio: pageData.aspectRatio,
73 child: Image( 109 child: Image(
74 - image: image, 110 + image: pageData.image,
75 fit: BoxFit.cover, 111 fit: BoxFit.cover,
76 ), 112 ),
77 ), 113 ),
@@ -26,6 +26,7 @@ import 'controller.dart'; @@ -26,6 +26,7 @@ import 'controller.dart';
26 import 'custom.dart'; 26 import 'custom.dart';
27 27
28 export 'custom.dart'; 28 export 'custom.dart';
  29 +export 'page.dart' show PdfPreviewPageData;
29 30
30 /// Flutter widget that uses the rasterized pdf pages to display a document. 31 /// Flutter widget that uses the rasterized pdf pages to display a document.
31 class PdfPreview extends StatefulWidget { 32 class PdfPreview extends StatefulWidget {
@@ -61,7 +62,66 @@ class PdfPreview extends StatefulWidget { @@ -61,7 +62,66 @@ class PdfPreview extends StatefulWidget {
61 this.loadingWidget, 62 this.loadingWidget,
62 this.onPageFormatChanged, 63 this.onPageFormatChanged,
63 this.dpi, 64 this.dpi,
64 - }) : super(key: key); 65 + }) : _pagesBuilder = null,
  66 + super(key: key);
  67 +
  68 + /// Build a custom layout.
  69 + ///
  70 + /// ```dart
  71 + /// PdfPreview.builder(
  72 + /// build: (format) => _generatePdf(format, title),
  73 + /// pagesBuilder: (context, pages) => SingleChildScrollView(
  74 + /// child: Wrap(
  75 + /// spacing: 8,
  76 + /// runSpacing: 8,
  77 + /// children: [
  78 + /// for (final page in pages)
  79 + /// Container(
  80 + /// color: Colors.white,
  81 + /// child: Image(
  82 + /// image: page.image,
  83 + /// width: 300,
  84 + /// ),
  85 + /// )
  86 + /// ],
  87 + /// ),
  88 + /// ),
  89 + /// )
  90 + /// ```
  91 + const PdfPreview.builder({
  92 + Key? key,
  93 + required this.build,
  94 + this.initialPageFormat,
  95 + this.allowPrinting = true,
  96 + this.allowSharing = true,
  97 + this.maxPageWidth,
  98 + this.canChangePageFormat = true,
  99 + this.canChangeOrientation = true,
  100 + this.canDebug = true,
  101 + this.actions,
  102 + this.pageFormats = _defaultPageFormats,
  103 + this.onError,
  104 + this.onPrinted,
  105 + this.onPrintError,
  106 + this.onShared,
  107 + this.scrollViewDecoration,
  108 + this.pdfPreviewPageDecoration,
  109 + this.pdfFileName,
  110 + this.useActions = true,
  111 + this.pages,
  112 + this.dynamicLayout = true,
  113 + this.shareActionExtraBody,
  114 + this.shareActionExtraSubject,
  115 + this.shareActionExtraEmails,
  116 + this.previewPageMargin,
  117 + this.padding,
  118 + this.shouldRepaint = false,
  119 + this.loadingWidget,
  120 + this.onPageFormatChanged,
  121 + this.dpi,
  122 + required CustomPdfPagesBuilder pagesBuilder,
  123 + }) : _pagesBuilder = pagesBuilder,
  124 + super(key: key);
65 125
66 static const _defaultPageFormats = <String, PdfPageFormat>{ 126 static const _defaultPageFormats = <String, PdfPageFormat>{
67 'A4': PdfPageFormat.a4, 127 'A4': PdfPageFormat.a4,
@@ -163,6 +223,10 @@ class PdfPreview extends StatefulWidget { @@ -163,6 +223,10 @@ class PdfPreview extends StatefulWidget {
163 /// If not provided, this value is calculated. 223 /// If not provided, this value is calculated.
164 final double? dpi; 224 final double? dpi;
165 225
  226 + /// clients can pass this builder to render
  227 + /// their own pages.
  228 + final CustomPdfPagesBuilder? _pagesBuilder;
  229 +
166 @override 230 @override
167 _PdfPreviewState createState() => _PdfPreviewState(); 231 _PdfPreviewState createState() => _PdfPreviewState();
168 } 232 }
@@ -331,6 +395,7 @@ class _PdfPreviewState extends State<PdfPreview> { @@ -331,6 +395,7 @@ class _PdfPreviewState extends State<PdfPreview> {
331 previewPageMargin: widget.previewPageMargin, 395 previewPageMargin: widget.previewPageMargin,
332 scrollViewDecoration: widget.scrollViewDecoration, 396 scrollViewDecoration: widget.scrollViewDecoration,
333 shouldRepaint: widget.shouldRepaint, 397 shouldRepaint: widget.shouldRepaint,
  398 + pagesBuilder: widget._pagesBuilder,
334 dpi: widget.dpi, 399 dpi: widget.dpi,
335 ); 400 );
336 }), 401 }),
@@ -38,7 +38,7 @@ mixin PdfPreviewRaster on State<PdfPreviewCustom> { @@ -38,7 +38,7 @@ mixin PdfPreviewRaster on State<PdfPreviewCustom> {
38 PdfPageFormat get pageFormat => widget.pageFormat; 38 PdfPageFormat get pageFormat => widget.pageFormat;
39 39
40 /// Resulting pages 40 /// Resulting pages
41 - final pages = <PdfPreviewPage>[]; 41 + final pages = <PdfPreviewPageData>[];
42 42
43 /// Printing subsystem information 43 /// Printing subsystem information
44 PrintingInfo? info; 44 PrintingInfo? info;
@@ -167,23 +167,18 @@ mixin PdfPreviewRaster on State<PdfPreviewCustom> { @@ -167,23 +167,18 @@ mixin PdfPreviewRaster on State<PdfPreviewCustom> {
167 _rastering = false; 167 _rastering = false;
168 return; 168 return;
169 } 169 }
170 -  
171 if (pages.length <= pageNum) { 170 if (pages.length <= pageNum) {
172 - pages.add(PdfPreviewPage( 171 + pages.add(PdfPreviewPageData(
173 image: MemoryImage(await page.toPng()), 172 image: MemoryImage(await page.toPng()),
174 width: page.width, 173 width: page.width,
175 height: page.height, 174 height: page.height,
176 - pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration,  
177 - pageMargin: widget.previewPageMargin,  
178 )); 175 ));
179 } else { 176 } else {
180 pages[pageNum].image.evict(); 177 pages[pageNum].image.evict();
181 - pages[pageNum] = PdfPreviewPage( 178 + pages[pageNum] = PdfPreviewPageData(
182 image: MemoryImage(await page.toPng()), 179 image: MemoryImage(await page.toPng()),
183 width: page.width, 180 width: page.width,
184 height: page.height, 181 height: page.height,
185 - pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration,  
186 - pageMargin: widget.previewPageMargin,  
187 ); 182 );
188 } 183 }
189 184
@@ -6,7 +6,7 @@ description: > @@ -6,7 +6,7 @@ description: >
6 homepage: https://github.com/DavBfr/dart_pdf/tree/master/printing 6 homepage: https://github.com/DavBfr/dart_pdf/tree/master/printing
7 repository: https://github.com/DavBfr/dart_pdf 7 repository: https://github.com/DavBfr/dart_pdf
8 issue_tracker: https://github.com/DavBfr/dart_pdf/issues 8 issue_tracker: https://github.com/DavBfr/dart_pdf/issues
9 -version: 5.9.4 9 +version: 5.10.0
10 10
11 environment: 11 environment:
12 sdk: ">=2.12.0 <3.0.0" 12 sdk: ">=2.12.0 <3.0.0"