David PHAM-VAN

Merge branch 'MacDeveloper1-feature/bar'

1 # Changelog 1 # Changelog
2 2
3 -## 5.11.2 3 +## 5.12.0
4 4
5 - Refactor html imports 5 - Refactor html imports
  6 +- Implement PdfActionBarTheme for actions bar and add method scrollToPage [Aleksei]
6 7
7 ## 5.11.1 8 ## 5.11.1
8 9
@@ -24,6 +24,7 @@ export 'src/asset_utils.dart'; @@ -24,6 +24,7 @@ export 'src/asset_utils.dart';
24 export 'src/cache.dart'; 24 export 'src/cache.dart';
25 export 'src/callback.dart'; 25 export 'src/callback.dart';
26 export 'src/fonts/gfonts.dart'; 26 export 'src/fonts/gfonts.dart';
  27 +export 'src/preview/action_bar_theme.dart';
27 export 'src/preview/actions.dart'; 28 export 'src/preview/actions.dart';
28 export 'src/preview/pdf_preview.dart'; 29 export 'src/preview/pdf_preview.dart';
29 export 'src/printer.dart'; 30 export 'src/printer.dart';
  1 +import 'package:flutter/foundation.dart';
  2 +import 'package:flutter/material.dart';
  3 +
  4 +class PdfActionBarTheme with Diagnosticable {
  5 + /// Creates a theme for action bar of [PdfPreviewController].
  6 + const PdfActionBarTheme({
  7 + this.backgroundColor,
  8 + this.iconColor,
  9 + this.height,
  10 + this.textStyle,
  11 + this.elevation = 4.0,
  12 + this.actionSpacing = 0.0,
  13 + this.alignment = WrapAlignment.spaceAround,
  14 + this.runAlignment = WrapAlignment.center,
  15 + this.crossAxisAlignment = WrapCrossAlignment.center,
  16 + });
  17 +
  18 + final Color? backgroundColor;
  19 + final Color? iconColor;
  20 + final double? height;
  21 + final TextStyle? textStyle;
  22 + final double elevation;
  23 + final double actionSpacing;
  24 + final WrapAlignment alignment;
  25 + final WrapAlignment runAlignment;
  26 + final WrapCrossAlignment crossAxisAlignment;
  27 +
  28 + /// Creates a copy of this object but with the given fields replaced with the
  29 + /// new values.
  30 + PdfActionBarTheme copyWith({
  31 + Color? backgroundColor,
  32 + Color? iconColor,
  33 + double? height,
  34 + TextStyle? textStyle,
  35 + double? elevation,
  36 + double? actionSpacing,
  37 + WrapAlignment? alignment,
  38 + WrapAlignment? runAlignment,
  39 + WrapCrossAlignment? crossAxisAlignment,
  40 + }) {
  41 + return PdfActionBarTheme(
  42 + backgroundColor: backgroundColor ?? this.backgroundColor,
  43 + iconColor: iconColor ?? this.iconColor,
  44 + height: height ?? this.height,
  45 + textStyle: textStyle ?? this.textStyle,
  46 + elevation: elevation ?? this.elevation,
  47 + actionSpacing: actionSpacing ?? this.actionSpacing,
  48 + alignment: alignment ?? this.alignment,
  49 + runAlignment: runAlignment ?? this.runAlignment,
  50 + crossAxisAlignment: crossAxisAlignment ?? this.crossAxisAlignment,
  51 + );
  52 + }
  53 +
  54 + @override
  55 + int get hashCode => Object.hashAll([
  56 + backgroundColor,
  57 + iconColor,
  58 + height,
  59 + textStyle,
  60 + elevation,
  61 + actionSpacing,
  62 + alignment,
  63 + runAlignment,
  64 + crossAxisAlignment,
  65 + ]);
  66 +
  67 + @override
  68 + bool operator ==(Object other) {
  69 + if (identical(this, other)) {
  70 + return true;
  71 + }
  72 + if (other.runtimeType != runtimeType) {
  73 + return false;
  74 + }
  75 + return other is PdfActionBarTheme &&
  76 + other.backgroundColor == backgroundColor &&
  77 + other.iconColor == iconColor &&
  78 + other.height == height &&
  79 + other.textStyle == textStyle &&
  80 + other.elevation == elevation &&
  81 + other.actionSpacing == actionSpacing &&
  82 + other.alignment == alignment &&
  83 + other.runAlignment == runAlignment &&
  84 + other.crossAxisAlignment == crossAxisAlignment;
  85 + }
  86 +
  87 + @override
  88 + void debugFillProperties(DiagnosticPropertiesBuilder properties) {
  89 + super.debugFillProperties(properties);
  90 + properties.add(ColorProperty('backgroundColor', backgroundColor));
  91 + properties.add(ColorProperty('iconColor', iconColor));
  92 + properties.add(DoubleProperty('height', height));
  93 + properties.add(DiagnosticsProperty<TextStyle>('textStyle', textStyle));
  94 + properties.add(DoubleProperty('elevation', elevation));
  95 + properties.add(DoubleProperty('actionSpacing', actionSpacing));
  96 + properties.add(DiagnosticsProperty<WrapAlignment>('alignment', alignment,
  97 + defaultValue: WrapAlignment.spaceAround));
  98 + properties.add(DiagnosticsProperty<WrapAlignment>(
  99 + 'runAlignment', runAlignment,
  100 + defaultValue: WrapAlignment.center));
  101 + properties.add(DiagnosticsProperty<WrapCrossAlignment>(
  102 + 'crossAxisAlignment', crossAxisAlignment,
  103 + defaultValue: WrapCrossAlignment.center));
  104 + }
  105 +}
@@ -50,6 +50,7 @@ class PdfPreviewCustom extends StatefulWidget { @@ -50,6 +50,7 @@ class PdfPreviewCustom extends StatefulWidget {
50 this.scrollPhysics, 50 this.scrollPhysics,
51 this.shrinkWrap = false, 51 this.shrinkWrap = false,
52 this.pagesBuilder, 52 this.pagesBuilder,
  53 + this.enableScrollToPage = false,
53 }) : super(key: key); 54 }) : super(key: key);
54 55
55 /// Pdf paper page format 56 /// Pdf paper page format
@@ -102,6 +103,9 @@ class PdfPreviewCustom extends StatefulWidget { @@ -102,6 +103,9 @@ class PdfPreviewCustom extends StatefulWidget {
102 /// their own pages. 103 /// their own pages.
103 final CustomPdfPagesBuilder? pagesBuilder; 104 final CustomPdfPagesBuilder? pagesBuilder;
104 105
  106 + /// Whether scroll to page functionality enabled.
  107 + final bool enableScrollToPage;
  108 +
105 @override 109 @override
106 PdfPreviewCustomState createState() => PdfPreviewCustomState(); 110 PdfPreviewCustomState createState() => PdfPreviewCustomState();
107 } 111 }
@@ -110,6 +114,8 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> @@ -110,6 +114,8 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom>
110 with PdfPreviewRaster { 114 with PdfPreviewRaster {
111 final listView = GlobalKey(); 115 final listView = GlobalKey();
112 116
  117 + List<GlobalKey> _pageGlobalKeys = <GlobalKey>[];
  118 +
113 bool infoLoaded = false; 119 bool infoLoaded = false;
114 120
115 int? preview; 121 int? preview;
@@ -172,6 +178,24 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> @@ -172,6 +178,24 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom>
172 super.didChangeDependencies(); 178 super.didChangeDependencies();
173 } 179 }
174 180
  181 + /// Ensures that page with [index] is become visible.
  182 + Future<void> scrollToPage(
  183 + int index, {
  184 + Duration duration = const Duration(milliseconds: 300),
  185 + Curve curve = Curves.ease,
  186 + ScrollPositionAlignmentPolicy alignmentPolicy =
  187 + ScrollPositionAlignmentPolicy.explicit,
  188 + }) {
  189 + assert(index >= 0, 'Index of page cannot be negative');
  190 + final pageContext = _pageGlobalKeys[index].currentContext;
  191 + assert(pageContext != null, 'Context of GlobalKey cannot be null');
  192 + return Scrollable.ensureVisible(pageContext!,
  193 + duration: duration, curve: curve, alignmentPolicy: alignmentPolicy);
  194 + }
  195 +
  196 + /// Returns the global key for page with [index].
  197 + Key getPageKey(int index) => _pageGlobalKeys[index];
  198 +
175 Widget _showError(Object error) { 199 Widget _showError(Object error) {
176 if (widget.onError != null) { 200 if (widget.onError != null) {
177 return widget.onError!(context, error); 201 return widget.onError!(context, error);
@@ -197,30 +221,53 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> @@ -197,30 +221,53 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom>
197 ); 221 );
198 } 222 }
199 223
  224 + if (widget.enableScrollToPage) {
  225 + _pageGlobalKeys = List.generate(pages.length, (_) => GlobalKey());
  226 + }
  227 +
200 if (widget.pagesBuilder != null) { 228 if (widget.pagesBuilder != null) {
201 return widget.pagesBuilder!(context, pages); 229 return widget.pagesBuilder!(context, pages);
202 } 230 }
203 - return ListView.builder(  
204 - controller: scrollController,  
205 - shrinkWrap: widget.shrinkWrap,  
206 - physics: widget.scrollPhysics,  
207 - padding: widget.padding,  
208 - itemCount: pages.length,  
209 - itemBuilder: (BuildContext context, int index) => GestureDetector(  
210 - onDoubleTap: () {  
211 - setState(() {  
212 - updatePosition = scrollController.position.pixels;  
213 - preview = index;  
214 - transformationController.value.setIdentity();  
215 - });  
216 - },  
217 - child: PdfPreviewPage(  
218 - pageData: pages[index],  
219 - pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration,  
220 - pageMargin: widget.previewPageMargin,  
221 - ),  
222 - ),  
223 - ); 231 +
  232 + Widget pageWidget(int index, {Key? key}) => GestureDetector(
  233 + onDoubleTap: () {
  234 + setState(() {
  235 + updatePosition = scrollController.position.pixels;
  236 + preview = index;
  237 + transformationController.value.setIdentity();
  238 + });
  239 + },
  240 + child: PdfPreviewPage(
  241 + key: key,
  242 + pageData: pages[index],
  243 + pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration,
  244 + pageMargin: widget.previewPageMargin,
  245 + ),
  246 + );
  247 +
  248 + return widget.enableScrollToPage
  249 + ? Scrollbar(
  250 + controller: scrollController,
  251 + child: SingleChildScrollView(
  252 + controller: scrollController,
  253 + physics: widget.scrollPhysics,
  254 + padding: widget.padding,
  255 + child: Column(
  256 + children: List.generate(
  257 + pages.length,
  258 + (index) => pageWidget(index, key: getPageKey(index)),
  259 + ),
  260 + ),
  261 + ),
  262 + )
  263 + : ListView.builder(
  264 + controller: scrollController,
  265 + shrinkWrap: widget.shrinkWrap,
  266 + physics: widget.scrollPhysics,
  267 + padding: widget.padding,
  268 + itemCount: pages.length,
  269 + itemBuilder: (BuildContext context, int index) => pageWidget(index),
  270 + );
224 } 271 }
225 272
226 Widget _zoomPreview() { 273 Widget _zoomPreview() {
@@ -21,6 +21,7 @@ import 'package:pdf/widgets.dart' as pw; @@ -21,6 +21,7 @@ import 'package:pdf/widgets.dart' as pw;
21 import '../callback.dart'; 21 import '../callback.dart';
22 import '../printing.dart'; 22 import '../printing.dart';
23 import '../printing_info.dart'; 23 import '../printing_info.dart';
  24 +import 'action_bar_theme.dart';
24 import 'actions.dart'; 25 import 'actions.dart';
25 import 'controller.dart'; 26 import 'controller.dart';
26 import 'custom.dart'; 27 import 'custom.dart';
@@ -62,6 +63,8 @@ class PdfPreview extends StatefulWidget { @@ -62,6 +63,8 @@ class PdfPreview extends StatefulWidget {
62 this.loadingWidget, 63 this.loadingWidget,
63 this.onPageFormatChanged, 64 this.onPageFormatChanged,
64 this.dpi, 65 this.dpi,
  66 + this.actionBarTheme = const PdfActionBarTheme(),
  67 + this.enableScrollToPage = false,
65 }) : _pagesBuilder = null, 68 }) : _pagesBuilder = null,
66 super(key: key); 69 super(key: key);
67 70
@@ -119,7 +122,9 @@ class PdfPreview extends StatefulWidget { @@ -119,7 +122,9 @@ class PdfPreview extends StatefulWidget {
119 this.loadingWidget, 122 this.loadingWidget,
120 this.onPageFormatChanged, 123 this.onPageFormatChanged,
121 this.dpi, 124 this.dpi,
  125 + this.actionBarTheme = const PdfActionBarTheme(),
122 required CustomPdfPagesBuilder pagesBuilder, 126 required CustomPdfPagesBuilder pagesBuilder,
  127 + this.enableScrollToPage = false,
123 }) : _pagesBuilder = pagesBuilder, 128 }) : _pagesBuilder = pagesBuilder,
124 super(key: key); 129 super(key: key);
125 130
@@ -223,10 +228,16 @@ class PdfPreview extends StatefulWidget { @@ -223,10 +228,16 @@ class PdfPreview extends StatefulWidget {
223 /// If not provided, this value is calculated. 228 /// If not provided, this value is calculated.
224 final double? dpi; 229 final double? dpi;
225 230
  231 + /// The style of actions bar.
  232 + final PdfActionBarTheme actionBarTheme;
  233 +
226 /// clients can pass this builder to render 234 /// clients can pass this builder to render
227 /// their own pages. 235 /// their own pages.
228 final CustomPdfPagesBuilder? _pagesBuilder; 236 final CustomPdfPagesBuilder? _pagesBuilder;
229 237
  238 + /// Whether scroll to page functionality enabled.
  239 + final bool enableScrollToPage;
  240 +
230 @override 241 @override
231 PdfPreviewState createState() => PdfPreviewState(); 242 PdfPreviewState createState() => PdfPreviewState();
232 } 243 }
@@ -296,7 +307,6 @@ class PdfPreviewState extends State<PdfPreview> { @@ -296,7 +307,6 @@ class PdfPreviewState extends State<PdfPreview> {
296 initialPageFormat: previewData.pageFormat, 307 initialPageFormat: previewData.pageFormat,
297 onComputeActualPageFormat: computeActualPageFormat, 308 onComputeActualPageFormat: computeActualPageFormat,
298 ); 309 );
299 - setState(() {});  
300 } 310 }
301 super.didUpdateWidget(oldWidget); 311 super.didUpdateWidget(oldWidget);
302 } 312 }
@@ -400,22 +410,30 @@ class PdfPreviewState extends State<PdfPreview> { @@ -400,22 +410,30 @@ class PdfPreviewState extends State<PdfPreview> {
400 shouldRepaint: widget.shouldRepaint, 410 shouldRepaint: widget.shouldRepaint,
401 pagesBuilder: widget._pagesBuilder, 411 pagesBuilder: widget._pagesBuilder,
402 dpi: widget.dpi, 412 dpi: widget.dpi,
  413 + enableScrollToPage: widget.enableScrollToPage,
403 ); 414 );
404 }), 415 }),
405 ), 416 ),
406 if (actions.isNotEmpty) 417 if (actions.isNotEmpty)
407 IconTheme.merge( 418 IconTheme.merge(
408 data: IconThemeData( 419 data: IconThemeData(
409 - color: iconColor, 420 + color: widget.actionBarTheme.iconColor ?? iconColor,
410 ), 421 ),
411 child: Material( 422 child: Material(
412 - elevation: 4,  
413 - color: theme.primaryColor, 423 + elevation: widget.actionBarTheme.elevation,
  424 + color:
  425 + widget.actionBarTheme.backgroundColor ?? theme.primaryColor,
  426 + textStyle: widget.actionBarTheme.textStyle,
414 child: SizedBox( 427 child: SizedBox(
415 width: double.infinity, 428 width: double.infinity,
  429 + height: widget.actionBarTheme.height,
416 child: SafeArea( 430 child: SafeArea(
417 child: Wrap( 431 child: Wrap(
418 - alignment: WrapAlignment.spaceAround, 432 + spacing: widget.actionBarTheme.actionSpacing,
  433 + alignment: widget.actionBarTheme.alignment,
  434 + runAlignment: widget.actionBarTheme.runAlignment,
  435 + crossAxisAlignment:
  436 + widget.actionBarTheme.crossAxisAlignment,
419 children: actions, 437 children: actions,
420 ), 438 ),
421 ), 439 ),
@@ -15,7 +15,7 @@ topics: @@ -15,7 +15,7 @@ topics:
15 - print 15 - print
16 - printing 16 - printing
17 - report 17 - report
18 -version: 5.11.2 18 +version: 5.12.0
19 19
20 environment: 20 environment:
21 sdk: ">=3.0.0 <4.0.0" 21 sdk: ">=3.0.0 <4.0.0"