diff --git a/printing/CHANGELOG.md b/printing/CHANGELOG.md index badbf2f4..e8d2766c 100644 --- a/printing/CHANGELOG.md +++ b/printing/CHANGELOG.md @@ -1,8 +1,9 @@ # Changelog -## 5.11.2 +## 5.12.0 - Refactor html imports +- Implement PdfActionBarTheme for actions bar and add method scrollToPage [Aleksei] ## 5.11.1 diff --git a/printing/lib/printing.dart b/printing/lib/printing.dart index 1dc67269..06e1ba7d 100644 --- a/printing/lib/printing.dart +++ b/printing/lib/printing.dart @@ -24,6 +24,7 @@ export 'src/asset_utils.dart'; export 'src/cache.dart'; export 'src/callback.dart'; export 'src/fonts/gfonts.dart'; +export 'src/preview/action_bar_theme.dart'; export 'src/preview/actions.dart'; export 'src/preview/pdf_preview.dart'; export 'src/printer.dart'; diff --git a/printing/lib/src/preview/action_bar_theme.dart b/printing/lib/src/preview/action_bar_theme.dart new file mode 100644 index 00000000..f245cd9d --- /dev/null +++ b/printing/lib/src/preview/action_bar_theme.dart @@ -0,0 +1,105 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +class PdfActionBarTheme with Diagnosticable { + /// Creates a theme for action bar of [PdfPreviewController]. + const PdfActionBarTheme({ + this.backgroundColor, + this.iconColor, + this.height, + this.textStyle, + this.elevation = 4.0, + this.actionSpacing = 0.0, + this.alignment = WrapAlignment.spaceAround, + this.runAlignment = WrapAlignment.center, + this.crossAxisAlignment = WrapCrossAlignment.center, + }); + + final Color? backgroundColor; + final Color? iconColor; + final double? height; + final TextStyle? textStyle; + final double elevation; + final double actionSpacing; + final WrapAlignment alignment; + final WrapAlignment runAlignment; + final WrapCrossAlignment crossAxisAlignment; + + /// Creates a copy of this object but with the given fields replaced with the + /// new values. + PdfActionBarTheme copyWith({ + Color? backgroundColor, + Color? iconColor, + double? height, + TextStyle? textStyle, + double? elevation, + double? actionSpacing, + WrapAlignment? alignment, + WrapAlignment? runAlignment, + WrapCrossAlignment? crossAxisAlignment, + }) { + return PdfActionBarTheme( + backgroundColor: backgroundColor ?? this.backgroundColor, + iconColor: iconColor ?? this.iconColor, + height: height ?? this.height, + textStyle: textStyle ?? this.textStyle, + elevation: elevation ?? this.elevation, + actionSpacing: actionSpacing ?? this.actionSpacing, + alignment: alignment ?? this.alignment, + runAlignment: runAlignment ?? this.runAlignment, + crossAxisAlignment: crossAxisAlignment ?? this.crossAxisAlignment, + ); + } + + @override + int get hashCode => Object.hashAll([ + backgroundColor, + iconColor, + height, + textStyle, + elevation, + actionSpacing, + alignment, + runAlignment, + crossAxisAlignment, + ]); + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + if (other.runtimeType != runtimeType) { + return false; + } + return other is PdfActionBarTheme && + other.backgroundColor == backgroundColor && + other.iconColor == iconColor && + other.height == height && + other.textStyle == textStyle && + other.elevation == elevation && + other.actionSpacing == actionSpacing && + other.alignment == alignment && + other.runAlignment == runAlignment && + other.crossAxisAlignment == crossAxisAlignment; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(ColorProperty('backgroundColor', backgroundColor)); + properties.add(ColorProperty('iconColor', iconColor)); + properties.add(DoubleProperty('height', height)); + properties.add(DiagnosticsProperty('textStyle', textStyle)); + properties.add(DoubleProperty('elevation', elevation)); + properties.add(DoubleProperty('actionSpacing', actionSpacing)); + properties.add(DiagnosticsProperty('alignment', alignment, + defaultValue: WrapAlignment.spaceAround)); + properties.add(DiagnosticsProperty( + 'runAlignment', runAlignment, + defaultValue: WrapAlignment.center)); + properties.add(DiagnosticsProperty( + 'crossAxisAlignment', crossAxisAlignment, + defaultValue: WrapCrossAlignment.center)); + } +} diff --git a/printing/lib/src/preview/custom.dart b/printing/lib/src/preview/custom.dart index 2d554335..4ec78075 100644 --- a/printing/lib/src/preview/custom.dart +++ b/printing/lib/src/preview/custom.dart @@ -50,6 +50,7 @@ class PdfPreviewCustom extends StatefulWidget { this.scrollPhysics, this.shrinkWrap = false, this.pagesBuilder, + this.enableScrollToPage = false, }) : super(key: key); /// Pdf paper page format @@ -102,6 +103,9 @@ class PdfPreviewCustom extends StatefulWidget { /// their own pages. final CustomPdfPagesBuilder? pagesBuilder; + /// Whether scroll to page functionality enabled. + final bool enableScrollToPage; + @override PdfPreviewCustomState createState() => PdfPreviewCustomState(); } @@ -110,6 +114,8 @@ class PdfPreviewCustomState extends State with PdfPreviewRaster { final listView = GlobalKey(); + List _pageGlobalKeys = []; + bool infoLoaded = false; int? preview; @@ -172,6 +178,24 @@ class PdfPreviewCustomState extends State super.didChangeDependencies(); } + /// Ensures that page with [index] is become visible. + Future scrollToPage( + int index, { + Duration duration = const Duration(milliseconds: 300), + Curve curve = Curves.ease, + ScrollPositionAlignmentPolicy alignmentPolicy = + ScrollPositionAlignmentPolicy.explicit, + }) { + assert(index >= 0, 'Index of page cannot be negative'); + final pageContext = _pageGlobalKeys[index].currentContext; + assert(pageContext != null, 'Context of GlobalKey cannot be null'); + return Scrollable.ensureVisible(pageContext!, + duration: duration, curve: curve, alignmentPolicy: alignmentPolicy); + } + + /// Returns the global key for page with [index]. + Key getPageKey(int index) => _pageGlobalKeys[index]; + Widget _showError(Object error) { if (widget.onError != null) { return widget.onError!(context, error); @@ -197,30 +221,53 @@ class PdfPreviewCustomState extends State ); } + if (widget.enableScrollToPage) { + _pageGlobalKeys = List.generate(pages.length, (_) => GlobalKey()); + } + if (widget.pagesBuilder != null) { return widget.pagesBuilder!(context, pages); } - return ListView.builder( - controller: scrollController, - shrinkWrap: widget.shrinkWrap, - physics: widget.scrollPhysics, - padding: widget.padding, - itemCount: pages.length, - itemBuilder: (BuildContext context, int index) => GestureDetector( - onDoubleTap: () { - setState(() { - updatePosition = scrollController.position.pixels; - preview = index; - transformationController.value.setIdentity(); - }); - }, - child: PdfPreviewPage( - pageData: pages[index], - pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration, - pageMargin: widget.previewPageMargin, - ), - ), - ); + + Widget pageWidget(int index, {Key? key}) => GestureDetector( + onDoubleTap: () { + setState(() { + updatePosition = scrollController.position.pixels; + preview = index; + transformationController.value.setIdentity(); + }); + }, + child: PdfPreviewPage( + key: key, + pageData: pages[index], + pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration, + pageMargin: widget.previewPageMargin, + ), + ); + + return widget.enableScrollToPage + ? Scrollbar( + controller: scrollController, + child: SingleChildScrollView( + controller: scrollController, + physics: widget.scrollPhysics, + padding: widget.padding, + child: Column( + children: List.generate( + pages.length, + (index) => pageWidget(index, key: getPageKey(index)), + ), + ), + ), + ) + : ListView.builder( + controller: scrollController, + shrinkWrap: widget.shrinkWrap, + physics: widget.scrollPhysics, + padding: widget.padding, + itemCount: pages.length, + itemBuilder: (BuildContext context, int index) => pageWidget(index), + ); } Widget _zoomPreview() { diff --git a/printing/lib/src/preview/pdf_preview.dart b/printing/lib/src/preview/pdf_preview.dart index 87ee3de5..c322e64d 100644 --- a/printing/lib/src/preview/pdf_preview.dart +++ b/printing/lib/src/preview/pdf_preview.dart @@ -21,6 +21,7 @@ import 'package:pdf/widgets.dart' as pw; import '../callback.dart'; import '../printing.dart'; import '../printing_info.dart'; +import 'action_bar_theme.dart'; import 'actions.dart'; import 'controller.dart'; import 'custom.dart'; @@ -62,6 +63,8 @@ class PdfPreview extends StatefulWidget { this.loadingWidget, this.onPageFormatChanged, this.dpi, + this.actionBarTheme = const PdfActionBarTheme(), + this.enableScrollToPage = false, }) : _pagesBuilder = null, super(key: key); @@ -119,7 +122,9 @@ class PdfPreview extends StatefulWidget { this.loadingWidget, this.onPageFormatChanged, this.dpi, + this.actionBarTheme = const PdfActionBarTheme(), required CustomPdfPagesBuilder pagesBuilder, + this.enableScrollToPage = false, }) : _pagesBuilder = pagesBuilder, super(key: key); @@ -223,10 +228,16 @@ class PdfPreview extends StatefulWidget { /// If not provided, this value is calculated. final double? dpi; + /// The style of actions bar. + final PdfActionBarTheme actionBarTheme; + /// clients can pass this builder to render /// their own pages. final CustomPdfPagesBuilder? _pagesBuilder; + /// Whether scroll to page functionality enabled. + final bool enableScrollToPage; + @override PdfPreviewState createState() => PdfPreviewState(); } @@ -296,7 +307,6 @@ class PdfPreviewState extends State { initialPageFormat: previewData.pageFormat, onComputeActualPageFormat: computeActualPageFormat, ); - setState(() {}); } super.didUpdateWidget(oldWidget); } @@ -400,22 +410,30 @@ class PdfPreviewState extends State { shouldRepaint: widget.shouldRepaint, pagesBuilder: widget._pagesBuilder, dpi: widget.dpi, + enableScrollToPage: widget.enableScrollToPage, ); }), ), if (actions.isNotEmpty) IconTheme.merge( data: IconThemeData( - color: iconColor, + color: widget.actionBarTheme.iconColor ?? iconColor, ), child: Material( - elevation: 4, - color: theme.primaryColor, + elevation: widget.actionBarTheme.elevation, + color: + widget.actionBarTheme.backgroundColor ?? theme.primaryColor, + textStyle: widget.actionBarTheme.textStyle, child: SizedBox( width: double.infinity, + height: widget.actionBarTheme.height, child: SafeArea( child: Wrap( - alignment: WrapAlignment.spaceAround, + spacing: widget.actionBarTheme.actionSpacing, + alignment: widget.actionBarTheme.alignment, + runAlignment: widget.actionBarTheme.runAlignment, + crossAxisAlignment: + widget.actionBarTheme.crossAxisAlignment, children: actions, ), ), diff --git a/printing/pubspec.yaml b/printing/pubspec.yaml index 115c777d..caa5877e 100644 --- a/printing/pubspec.yaml +++ b/printing/pubspec.yaml @@ -15,7 +15,7 @@ topics: - print - printing - report -version: 5.11.2 +version: 5.12.0 environment: sdk: ">=3.0.0 <4.0.0"