David PHAM-VAN

Passthrough SpanningWidget on SingleChildWidget and StatelessWidget

@@ -26,8 +26,8 @@ Future<Uint8List> generateDocument( @@ -26,8 +26,8 @@ Future<Uint8List> generateDocument(
26 final doc = pw.Document(pageMode: PdfPageMode.outlines); 26 final doc = pw.Document(pageMode: PdfPageMode.outlines);
27 27
28 doc.addPage(pw.MultiPage( 28 doc.addPage(pw.MultiPage(
29 - pageFormat:  
30 - PdfPageFormat.letter.copyWith(marginBottom: 1.5 * PdfPageFormat.cm), 29 + pageFormat: format.copyWith(marginBottom: 1.5 * PdfPageFormat.cm),
  30 + orientation: pw.PageOrientation.portrait,
31 crossAxisAlignment: pw.CrossAxisAlignment.start, 31 crossAxisAlignment: pw.CrossAxisAlignment.start,
32 header: (pw.Context context) { 32 header: (pw.Context context) {
33 if (context.pageNumber == 1) { 33 if (context.pageNumber == 1) {
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 - ImageProvider.resolve returns non-null object 10 - ImageProvider.resolve returns non-null object
11 - Fix textScalingFactor with lineSpacing 11 - Fix textScalingFactor with lineSpacing
12 - Implement SpanningWidget on RichText 12 - Implement SpanningWidget on RichText
  13 +- Passthrough SpanningWidget on SingleChildWidget and StatelessWidget
13 14
14 ## 3.2.0 15 ## 3.2.0
15 16
@@ -133,12 +133,13 @@ class Header extends StatelessWidget { @@ -133,12 +133,13 @@ class Header extends StatelessWidget {
133 } 133 }
134 134
135 class Paragraph extends StatelessWidget { 135 class Paragraph extends StatelessWidget {
136 - Paragraph(  
137 - {this.text,  
138 - this.textAlign = TextAlign.justify,  
139 - this.style,  
140 - this.margin = const EdgeInsets.only(bottom: 5.0 * PdfPageFormat.mm),  
141 - this.padding}); 136 + Paragraph({
  137 + this.text,
  138 + this.textAlign = TextAlign.justify,
  139 + this.style,
  140 + this.margin = const EdgeInsets.only(bottom: 5.0 * PdfPageFormat.mm),
  141 + this.padding,
  142 + });
142 143
143 final String? text; 144 final String? text;
144 145
@@ -159,6 +160,7 @@ class Paragraph extends StatelessWidget { @@ -159,6 +160,7 @@ class Paragraph extends StatelessWidget {
159 text!, 160 text!,
160 textAlign: textAlign, 161 textAlign: textAlign,
161 style: style ?? Theme.of(context).paragraphStyle, 162 style: style ?? Theme.of(context).paragraphStyle,
  163 + overflow: TextOverflow.span,
162 ), 164 ),
163 ); 165 );
164 } 166 }
@@ -81,7 +81,7 @@ class _FlexContext extends WidgetContext { @@ -81,7 +81,7 @@ class _FlexContext extends WidgetContext {
81 String toString() => '$runtimeType first:$firstChild last:$lastChild'; 81 String toString() => '$runtimeType first:$firstChild last:$lastChild';
82 } 82 }
83 83
84 -class Flex extends MultiChildWidget implements SpanningWidget { 84 +class Flex extends MultiChildWidget with SpanningWidget {
85 Flex({ 85 Flex({
86 required this.direction, 86 required this.direction,
87 this.mainAxisAlignment = MainAxisAlignment.start, 87 this.mainAxisAlignment = MainAxisAlignment.start,
@@ -53,7 +53,7 @@ class _GridViewContext extends WidgetContext { @@ -53,7 +53,7 @@ class _GridViewContext extends WidgetContext {
53 '$runtimeType first:$firstChild last:$lastChild size:${childCrossAxis}x$childMainAxis'; 53 '$runtimeType first:$firstChild last:$lastChild size:${childCrossAxis}x$childMainAxis';
54 } 54 }
55 55
56 -class GridView extends MultiChildWidget implements SpanningWidget { 56 +class GridView extends MultiChildWidget with SpanningWidget {
57 GridView( 57 GridView(
58 {this.direction = Axis.vertical, 58 {this.direction = Axis.vertical,
59 this.padding = EdgeInsets.zero, 59 this.padding = EdgeInsets.zero,
@@ -37,7 +37,7 @@ abstract class WidgetContext { @@ -37,7 +37,7 @@ abstract class WidgetContext {
37 void apply(covariant WidgetContext other); 37 void apply(covariant WidgetContext other);
38 } 38 }
39 39
40 -abstract class SpanningWidget extends Widget { 40 +mixin SpanningWidget on Widget {
41 bool get canSpan; 41 bool get canSpan;
42 42
43 bool get hasMoreWidgets; 43 bool get hasMoreWidgets;
@@ -46,7 +46,7 @@ abstract class SpanningWidget extends Widget { @@ -46,7 +46,7 @@ abstract class SpanningWidget extends Widget {
46 @protected 46 @protected
47 WidgetContext saveContext(); 47 WidgetContext saveContext();
48 48
49 - /// Aplpy the context for next layout 49 + /// Apply the context for next layout
50 @protected 50 @protected
51 void restoreContext(covariant WidgetContext context); 51 void restoreContext(covariant WidgetContext context);
52 } 52 }
@@ -230,10 +230,6 @@ class MultiPage extends Page { @@ -230,10 +230,6 @@ class MultiPage extends Page {
230 230
231 while (_index < children.length) { 231 while (_index < children.length) {
232 final child = children[_index]; 232 final child = children[_index];
233 - var canSpan = false;  
234 - if (child is SpanningWidget) {  
235 - canSpan = child.canSpan;  
236 - }  
237 233
238 assert(() { 234 assert(() {
239 // Detect too big widgets 235 // Detect too big widgets
@@ -292,7 +288,7 @@ class MultiPage extends Page { @@ -292,7 +288,7 @@ class MultiPage extends Page {
292 } 288 }
293 289
294 // If we are processing a multi-page widget, we restore its context 290 // If we are processing a multi-page widget, we restore its context
295 - if (widgetContext != null && canSpan && child is SpanningWidget) { 291 + if (widgetContext != null && child is SpanningWidget) {
296 child.restoreContext(widgetContext); 292 child.restoreContext(widgetContext);
297 widgetContext = null; 293 widgetContext = null;
298 } 294 }
@@ -300,6 +296,8 @@ class MultiPage extends Page { @@ -300,6 +296,8 @@ class MultiPage extends Page {
300 child.layout(context, constraints, parentUsesSize: false); 296 child.layout(context, constraints, parentUsesSize: false);
301 assert(child.box != null); 297 assert(child.box != null);
302 298
  299 + final canSpan = child is SpanningWidget && child.canSpan;
  300 +
303 // What to do if the widget is too big for the page? 301 // What to do if the widget is too big for the page?
304 if (offsetStart! - child.box!.height < offsetEnd) { 302 if (offsetStart! - child.box!.height < offsetEnd) {
305 // If it is not a multi-page widget and its height 303 // If it is not a multi-page widget and its height
@@ -475,7 +473,8 @@ class MultiPage extends Page { @@ -475,7 +473,8 @@ class MultiPage extends Page {
475 final flex = child is Flexible ? child.flex : 0; 473 final flex = child is Flexible ? child.flex : 0;
476 final fit = child is Flexible ? child.fit : FlexFit.loose; 474 final fit = child is Flexible ? child.fit : FlexFit.loose;
477 if (flex > 0) { 475 if (flex > 0) {
478 - assert(child is! SpanningWidget); 476 + assert(child is! SpanningWidget || child.canSpan == false,
  477 + 'Cannot have a spanning widget flexible');
479 final maxChildExtent = child == lastFlexChild 478 final maxChildExtent = child == lastFlexChild
480 ? (freeSpace - allocatedFlexSpace) 479 ? (freeSpace - allocatedFlexSpace)
481 : spacePerFlex * flex; 480 : spacePerFlex * flex;
@@ -24,7 +24,7 @@ import 'geometry.dart'; @@ -24,7 +24,7 @@ import 'geometry.dart';
24 import 'multi_page.dart'; 24 import 'multi_page.dart';
25 import 'widget.dart'; 25 import 'widget.dart';
26 26
27 -class Partition implements SpanningWidget { 27 +class Partition extends Widget with SpanningWidget {
28 Partition({ 28 Partition({
29 required this.child, 29 required this.child,
30 this.width, 30 this.width,
@@ -59,6 +59,7 @@ class Partition implements SpanningWidget { @@ -59,6 +59,7 @@ class Partition implements SpanningWidget {
59 59
60 @override 60 @override
61 void paint(Context context) { 61 void paint(Context context) {
  62 + super.paint(context);
62 child.paint(context); 63 child.paint(context);
63 } 64 }
64 65
@@ -102,7 +103,7 @@ class _PartitionsContext extends WidgetContext { @@ -102,7 +103,7 @@ class _PartitionsContext extends WidgetContext {
102 } 103 }
103 } 104 }
104 105
105 -class Partitions extends Widget implements SpanningWidget { 106 +class Partitions extends Widget with SpanningWidget {
106 Partitions({ 107 Partitions({
107 required this.children, 108 required this.children,
108 this.mainAxisSize = MainAxisSize.max, 109 this.mainAxisSize = MainAxisSize.max,
@@ -236,7 +236,7 @@ typedef OnCellDecoration = BoxDecoration Function( @@ -236,7 +236,7 @@ typedef OnCellDecoration = BoxDecoration Function(
236 int index, dynamic data, int rowNum); 236 int index, dynamic data, int rowNum);
237 237
238 /// A widget that uses the table layout algorithm for its children. 238 /// A widget that uses the table layout algorithm for its children.
239 -class Table extends Widget implements SpanningWidget { 239 +class Table extends Widget with SpanningWidget {
240 Table({ 240 Table({
241 this.children = const <TableRow>[], 241 this.children = const <TableRow>[],
242 this.border, 242 this.border,
@@ -575,7 +575,7 @@ class _RichTextContext extends WidgetContext { @@ -575,7 +575,7 @@ class _RichTextContext extends WidgetContext {
575 '$runtimeType Offset: $startOffset -> $endOffset Span: $spanStart -> $spanEnd'; 575 '$runtimeType Offset: $startOffset -> $endOffset Span: $spanStart -> $spanEnd';
576 } 576 }
577 577
578 -class RichText extends Widget implements SpanningWidget { 578 +class RichText extends Widget with SpanningWidget {
579 RichText({ 579 RichText({
580 required this.text, 580 required this.text,
581 this.textAlign, 581 this.textAlign,
@@ -19,6 +19,7 @@ import 'dart:math' as math; @@ -19,6 +19,7 @@ import 'dart:math' as math;
19 19
20 import 'package:meta/meta.dart'; 20 import 'package:meta/meta.dart';
21 import 'package:pdf/pdf.dart'; 21 import 'package:pdf/pdf.dart';
  22 +import 'package:pdf/widgets.dart';
22 import 'package:vector_math/vector_math_64.dart'; 23 import 'package:vector_math/vector_math_64.dart';
23 24
24 import 'document.dart'; 25 import 'document.dart';
@@ -210,7 +211,7 @@ abstract class Widget { @@ -210,7 +211,7 @@ abstract class Widget {
210 } 211 }
211 } 212 }
212 213
213 -abstract class StatelessWidget extends Widget { 214 +abstract class StatelessWidget extends Widget with SpanningWidget {
214 StatelessWidget() : super(); 215 StatelessWidget() : super();
215 216
216 Widget? _child; 217 Widget? _child;
@@ -246,9 +247,33 @@ abstract class StatelessWidget extends Widget { @@ -246,9 +247,33 @@ abstract class StatelessWidget extends Widget {
246 247
247 @protected 248 @protected
248 Widget build(Context context); 249 Widget build(Context context);
  250 +
  251 + @override
  252 + bool get canSpan =>
  253 + _child is SpanningWidget && (_child as SpanningWidget).canSpan;
  254 +
  255 + @override
  256 + bool get hasMoreWidgets =>
  257 + _child is SpanningWidget && (_child as SpanningWidget).hasMoreWidgets;
  258 +
  259 + @override
  260 + void restoreContext(covariant WidgetContext context) {
  261 + if (_child is SpanningWidget) {
  262 + (_child as SpanningWidget).restoreContext(context);
  263 + }
  264 + }
  265 +
  266 + @override
  267 + WidgetContext saveContext() {
  268 + if (_child is SpanningWidget) {
  269 + return (_child as SpanningWidget).saveContext();
  270 + }
  271 +
  272 + throw UnimplementedError();
  273 + }
249 } 274 }
250 275
251 -abstract class SingleChildWidget extends Widget { 276 +abstract class SingleChildWidget extends Widget with SpanningWidget {
252 SingleChildWidget({this.child}) : super(); 277 SingleChildWidget({this.child}) : super();
253 278
254 final Widget? child; 279 final Widget? child;
@@ -277,6 +302,30 @@ abstract class SingleChildWidget extends Widget { @@ -277,6 +302,30 @@ abstract class SingleChildWidget extends Widget {
277 context.canvas.restoreContext(); 302 context.canvas.restoreContext();
278 } 303 }
279 } 304 }
  305 +
  306 + @override
  307 + bool get canSpan =>
  308 + child is SpanningWidget && (child as SpanningWidget).canSpan;
  309 +
  310 + @override
  311 + bool get hasMoreWidgets =>
  312 + child is SpanningWidget && (child as SpanningWidget).hasMoreWidgets;
  313 +
  314 + @override
  315 + void restoreContext(covariant WidgetContext context) {
  316 + if (child is SpanningWidget) {
  317 + (child as SpanningWidget).restoreContext(context);
  318 + }
  319 + }
  320 +
  321 + @override
  322 + WidgetContext saveContext() {
  323 + if (child is SpanningWidget) {
  324 + return (child as SpanningWidget).saveContext();
  325 + }
  326 +
  327 + throw UnimplementedError();
  328 + }
280 } 329 }
281 330
282 abstract class MultiChildWidget extends Widget { 331 abstract class MultiChildWidget extends Widget {
@@ -285,8 +334,8 @@ abstract class MultiChildWidget extends Widget { @@ -285,8 +334,8 @@ abstract class MultiChildWidget extends Widget {
285 final List<Widget> children; 334 final List<Widget> children;
286 } 335 }
287 336
288 -class InheritedWidget extends Widget {  
289 - InheritedWidget({this.build, this.inherited}); 337 +class InheritedWidget extends SingleChildWidget {
  338 + InheritedWidget({this.build, this.inherited}) : super();
290 339
291 final BuildCallback? build; 340 final BuildCallback? build;
292 341
@@ -294,6 +343,9 @@ class InheritedWidget extends Widget { @@ -294,6 +343,9 @@ class InheritedWidget extends Widget {
294 343
295 Context? _context; 344 Context? _context;
296 345
  346 + @override
  347 + Widget? get child => _child;
  348 +
297 Widget? _child; 349 Widget? _child;
298 350
299 @override 351 @override
@@ -301,29 +353,13 @@ class InheritedWidget extends Widget { @@ -301,29 +353,13 @@ class InheritedWidget extends Widget {
301 {bool parentUsesSize = false}) { 353 {bool parentUsesSize = false}) {
302 _context = inherited != null ? context.inheritFrom(inherited!) : context; 354 _context = inherited != null ? context.inheritFrom(inherited!) : context;
303 _child = build!(_context!); 355 _child = build!(_context!);
304 -  
305 - if (_child != null) {  
306 - _child!.layout(_context!, constraints, parentUsesSize: parentUsesSize);  
307 - assert(_child!.box != null);  
308 - box = _child!.box;  
309 - } else {  
310 - box = PdfRect.fromPoints(PdfPoint.zero, constraints.smallest);  
311 - } 356 + super.layout(_context!, constraints);
312 } 357 }
313 358
314 @override 359 @override
315 void paint(Context context) { 360 void paint(Context context) {
316 assert(_context != null); 361 assert(_context != null);
317 super.paint(_context!); 362 super.paint(_context!);
318 -  
319 - if (_child != null) {  
320 - final mat = Matrix4.identity();  
321 - mat.translate(box!.x, box!.y);  
322 - context.canvas  
323 - ..saveContext()  
324 - ..setTransform(mat);  
325 - _child!.paint(_context!);  
326 - context.canvas.restoreContext();  
327 - } 363 + paintChild(_context!);
328 } 364 }
329 } 365 }
@@ -67,7 +67,7 @@ class _WrapContext extends WidgetContext { @@ -67,7 +67,7 @@ class _WrapContext extends WidgetContext {
67 } 67 }
68 68
69 /// A widget that displays its children in multiple horizontal or vertical runs. 69 /// A widget that displays its children in multiple horizontal or vertical runs.
70 -class Wrap extends MultiChildWidget implements SpanningWidget { 70 +class Wrap extends MultiChildWidget with SpanningWidget {
71 /// Creates a wrap layout. 71 /// Creates a wrap layout.
72 72
73 Wrap({ 73 Wrap({