From 808db3c645bfb68ce5f2ffaa0b73aa34b1921948 Mon Sep 17 00:00:00 2001 From: Alfred Schilken Date: Tue, 20 Sep 2022 19:25:46 +0200 Subject: [PATCH 01/11] make CapacityIndicator work with other values of splits, not only with splits:10 --- example/lib/pages/indicators_page.dart | 1 + lib/src/indicators/capacity_indicators.dart | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/example/lib/pages/indicators_page.dart b/example/lib/pages/indicators_page.dart index 506f961d..8b8bf223 100644 --- a/example/lib/pages/indicators_page.dart +++ b/example/lib/pages/indicators_page.dart @@ -40,6 +40,7 @@ class _IndicatorsPageState extends State { CapacityIndicator( value: sliderValue, onChanged: (v) => setState(() => sliderValue = v), + splits: 20, discrete: true, ), const SizedBox(height: 20), diff --git a/lib/src/indicators/capacity_indicators.dart b/lib/src/indicators/capacity_indicators.dart index 461f3055..ed26f90f 100644 --- a/lib/src/indicators/capacity_indicators.dart +++ b/lib/src/indicators/capacity_indicators.dart @@ -90,7 +90,7 @@ class CapacityIndicator extends StatelessWidget { } void _handleUpdate(Offset lp, double width) { - double value = (lp.dx / width) * splits; + double value = (lp.dx / width) * 100 / splits; onChanged?.call(value.clamp(0.0, 100.0)); } @@ -108,7 +108,7 @@ class CapacityIndicator extends StatelessWidget { if (width.isInfinite) width = 100; final splitWidth = width / splits; if (discrete) { - final fillToIndex = value / splits - 1; + final fillToIndex = (value / 100) * splits - 1; return SizedBox( width: width, child: GestureDetector( From cdbe94fa5bb0f33a1d63c49c5d239db0e6bcec57 Mon Sep 17 00:00:00 2001 From: Alfred Schilken Date: Sun, 15 Jan 2023 17:46:20 +0100 Subject: [PATCH 02/11] add unit test for CapacityIndicator with splits 20 --- test/indicators/capacity_indicators_test.dart | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/test/indicators/capacity_indicators_test.dart b/test/indicators/capacity_indicators_test.dart index 25b274cf..7124397e 100644 --- a/test/indicators/capacity_indicators_test.dart +++ b/test/indicators/capacity_indicators_test.dart @@ -3,7 +3,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:macos_ui/macos_ui.dart'; void main() { - testWidgets('debugFillProperties', (tester) async { + testWidgets('debugFillProperties with splits = 10', (tester) async { final builder = DiagnosticPropertiesBuilder(); const CapacityIndicator( value: 50, @@ -27,4 +27,30 @@ void main() { ], ); }); + + testWidgets('debugFillProperties with splits = 20', (tester) async { + final builder = DiagnosticPropertiesBuilder(); + const CapacityIndicator( + value: 50, + splits: 20, + ).debugFillProperties(builder); + + final description = builder.properties + .where((node) => !node.isFiltered(DiagnosticLevel.info)) + .map((node) => node.toString()) + .toList(); + + expect( + description, + [ + 'value: 50.0', + 'continuous', + 'splits: 20', + 'color: systemGreen(*color = Color(0xff34c759)*, darkColor = Color(0xff30d158), highContrastColor = Color(0xff248a3d), darkHighContrastColor = Color(0xff30db5b), resolved by: UNRESOLVED)', + 'backgroundColor: tertiarySystemGroupedBackground(*color = Color(0xfff2f2f7)*, darkColor = Color(0xff2c2c2e), highContrastColor = Color(0xffebebf0), darkHighContrastColor = Color(0xff363638), *elevatedColor = Color(0xfff2f2f7)*, darkElevatedColor = Color(0xff3a3a3c), highContrastElevatedColor = Color(0xffebebf0), darkHighContrastElevatedColor = Color(0xff444446), resolved by: UNRESOLVED)', + 'borderColor: tertiaryLabel(*color = Color(0x4c3c3c43)*, darkColor = Color(0x4cebebf5), highContrastColor = Color(0x603c3c43), darkHighContrastColor = Color(0x60ebebf5), resolved by: UNRESOLVED)', + 'semanticLabel: null', + ], + ); + }); } From 752d9e2c1c9567673dec9a9dbb005cc60e3c408b Mon Sep 17 00:00:00 2001 From: Alfred Schilken Date: Sun, 15 Jan 2023 17:54:39 +0100 Subject: [PATCH 03/11] add bugfix line to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06984cb8..896659f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## [1.7.6] * Fixed a bug where `MacosPopupButton` would report that a `ScrollController` was not attached to any views +* Fixed a bug where `CapacityIndicator` did only work correctly for splits = 10 ## [1.7.5] * Addressed Flutter 3.3 analyzer warnings From 3e8cf2a74496590a92b07bd1c98c60726eaf49ee Mon Sep 17 00:00:00 2001 From: Alfred Schilken Date: Tue, 17 Jan 2023 11:49:08 +0100 Subject: [PATCH 04/11] update version to 1.7.7, move change in CHANGELOG.md to version 1.7.7 --- CHANGELOG.md | 4 +++- example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 896659f8..2377eb79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ +## [1.7.7] +* Fixed a bug where `CapacityIndicator` did only work correctly for splits = 10 + ## [1.7.6] * Fixed a bug where `MacosPopupButton` would report that a `ScrollController` was not attached to any views -* Fixed a bug where `CapacityIndicator` did only work correctly for splits = 10 ## [1.7.5] * Addressed Flutter 3.3 analyzer warnings diff --git a/example/pubspec.lock b/example/pubspec.lock index 89ae8821..66ba028a 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -80,7 +80,7 @@ packages: path: ".." relative: true source: path - version: "1.7.6" + version: "1.7.7" matcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 12962428..5739fc1f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: macos_ui description: Flutter widgets and themes implementing the current macOS design language. -version: 1.7.6 +version: 1.7.7 homepage: "https://macosui.dev" repository: "https://github.com/GroovinChip/macos_ui" From 94de910875459d9200fa4c80fe5e25deaf13e6a3 Mon Sep 17 00:00:00 2001 From: Alfred Schilken Date: Fri, 27 Jan 2023 11:31:35 +0100 Subject: [PATCH 05/11] add test to check the number of filled segments of discrete CapacityIndicator --- test/indicators/capacity_indicators_test.dart | 145 +- test/mock_canvas.dart | 1593 +++++++++++++++++ test/recording_canvas.dart | 245 +++ 3 files changed, 1980 insertions(+), 3 deletions(-) create mode 100644 test/mock_canvas.dart create mode 100644 test/recording_canvas.dart diff --git a/test/indicators/capacity_indicators_test.dart b/test/indicators/capacity_indicators_test.dart index 7124397e..60d0ea1c 100644 --- a/test/indicators/capacity_indicators_test.dart +++ b/test/indicators/capacity_indicators_test.dart @@ -1,9 +1,14 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + import 'package:flutter_test/flutter_test.dart'; + import 'package:macos_ui/macos_ui.dart'; +import '../mock_canvas.dart'; + void main() { - testWidgets('debugFillProperties with splits = 10', (tester) async { + testWidgets('debugFillProperties', (tester) async { final builder = DiagnosticPropertiesBuilder(); const CapacityIndicator( value: 50, @@ -28,11 +33,12 @@ void main() { ); }); - testWidgets('debugFillProperties with splits = 20', (tester) async { + testWidgets('debugFillProperties with discrete splits = 20', (tester) async { final builder = DiagnosticPropertiesBuilder(); const CapacityIndicator( value: 50, splits: 20, + discrete: true, ).debugFillProperties(builder); final description = builder.properties @@ -44,7 +50,6 @@ void main() { description, [ 'value: 50.0', - 'continuous', 'splits: 20', 'color: systemGreen(*color = Color(0xff34c759)*, darkColor = Color(0xff30d158), highContrastColor = Color(0xff248a3d), darkHighContrastColor = Color(0xff30db5b), resolved by: UNRESOLVED)', 'backgroundColor: tertiarySystemGroupedBackground(*color = Color(0xfff2f2f7)*, darkColor = Color(0xff2c2c2e), highContrastColor = Color(0xffebebf0), darkHighContrastColor = Color(0xff363638), *elevatedColor = Color(0xfff2f2f7)*, darkElevatedColor = Color(0xff3a3a3c), highContrastElevatedColor = Color(0xffebebf0), darkHighContrastElevatedColor = Color(0xff444446), resolved by: UNRESOLVED)', @@ -53,4 +58,138 @@ void main() { ], ); }); + +testWidgets( + 'CapacityIndicator paints the correct number of segments', + (WidgetTester tester) async { + await tester.pumpWidget( + const Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: SizedBox( + width: 200.0, + child: CapacityIndicator( + value: 50, + splits: 20, + discrete: true, + ), + ), + ), + ), + ); + + expect( + find.byType(CapacityIndicator), + // each discrete segment is drawn 3 times, two times with fill, last time with stroke + paintsExactlyCountTimes(#drawRRect, 20 * 3), + ); + }, + ); + + testWidgets( + 'CapacityIndicator paints two filled segments for value=10 and 20 segments', + (WidgetTester tester) async { + await tester.pumpWidget( + const Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: SizedBox( + width: 200.0, + child: CapacityIndicator( + value: 10, + splits: 20, + discrete: true, + ), + ), + ), + ), + ); + + expect( + find.byType(CapacityIndicator), + // each discrete segment is drawn 3 times, background - fill - stroke + // a filled segment is drawn by fromLTRBR with LTRB=0,0,8,16 + // an empty segment is drawnby fromLTRBAndCorners with LTRB=0,0,0,16 + paints + ..rrect( + rrect: RRect.fromLTRBR( + 0.0, + 0.0, + 8.0, + 16.0, + const Radius.circular(2.0), + ), + ) + ..rrect( + rrect: RRect.fromLTRBR( + 0.0, + 0.0, + 8.0, + 16.0, + const Radius.circular(2.0), + ), + ) + ..rrect( + rrect: RRect.fromLTRBR( + 0.0, + 0.0, + 8.0, + 16.0, + const Radius.circular(2.0), + ), + ) + ..translate(x: 10.0, y: 0.0) + ..rrect( + rrect: RRect.fromLTRBR( + 0.0, + 0.0, + 8.0, + 16.0, + const Radius.circular(2.0), + ), + ) + ..rrect( + rrect: RRect.fromLTRBR( + 0.0, + 0.0, + 8.0, + 16.0, + const Radius.circular(2.0), + ), + ) + ..rrect( + rrect: RRect.fromLTRBR( + 0.0, + 0.0, + 8.0, + 16.0, + const Radius.circular(2.0), + ), + ) + ..translate(x: 20.0, y: 0.0) + + ..rrect( + rrect: RRect.fromLTRBR( + 0.0, + 0.0, + 8.0, + 16.0, + const Radius.circular(2.0), + ), + ) + ..rrect( + rrect: RRect.fromLTRBAndCorners( + 0.0, + 0.0, + 0.0, + 16.0, + topLeft: const Radius.circular(2.0), + topRight: const Radius.circular(0.0), + bottomRight: const Radius.circular(0.0), + bottomLeft: const Radius.circular(2.0), + ), + ), + ); + }, + ); } diff --git a/test/mock_canvas.dart b/test/mock_canvas.dart new file mode 100644 index 00000000..57a63373 --- /dev/null +++ b/test/mock_canvas.dart @@ -0,0 +1,1593 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui' as ui show Paragraph, Image; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'recording_canvas.dart'; + +/// Matches objects or functions that paint a display list that matches the +/// canvas calls described by the pattern. +/// +/// Specifically, this can be applied to [RenderObject]s, [Finder]s that +/// correspond to a single [RenderObject], and functions that have either of the +/// following signatures: +/// +/// ```dart +/// void function(PaintingContext context, Offset offset); +/// void function(Canvas canvas); +/// ``` +/// +/// In the case of functions that take a [PaintingContext] and an [Offset], the +/// [paints] matcher will always pass a zero offset. +/// +/// To specify the pattern, call the methods on the returned object. For example: +/// +/// ```dart +/// expect(myRenderObject, paints..circle(radius: 10.0)..circle(radius: 20.0)); +/// ``` +/// +/// This particular pattern would verify that the render object `myRenderObject` +/// paints, among other things, two circles of radius 10.0 and 20.0 (in that +/// order). +/// +/// See [PaintPattern] for a discussion of the semantics of paint patterns. +/// +/// To match something which paints nothing, see [paintsNothing]. +/// +/// To match something which asserts instead of painting, see [paintsAssertion]. +PaintPattern get paints => _TestRecordingCanvasPatternMatcher(); + +/// Matches objects or functions that does not paint anything on the canvas. +Matcher get paintsNothing => _TestRecordingCanvasPaintsNothingMatcher(); + +/// Matches objects or functions that assert when they try to paint. +Matcher get paintsAssertion => _TestRecordingCanvasPaintsAssertionMatcher(); + +/// Matches objects or functions that draw `methodName` exactly `count` number of times. +Matcher paintsExactlyCountTimes(Symbol methodName, int count) { + return _TestRecordingCanvasPaintsCountMatcher(methodName, count); +} + +/// Signature for the [PaintPattern.something] and [PaintPattern.everything] +/// predicate argument. +/// +/// Used by the [paints] matcher. +/// +/// The `methodName` argument is a [Symbol], and can be compared with the symbol +/// literal syntax, for example: +/// +/// ```dart +/// if (methodName == #drawCircle) { ... } +/// ``` +typedef PaintPatternPredicate = bool Function(Symbol methodName, List arguments); + +/// The signature of [RenderObject.paint] functions. +typedef _ContextPainterFunction = void Function(PaintingContext context, Offset offset); + +/// The signature of functions that paint directly on a canvas. +typedef _CanvasPainterFunction = void Function(Canvas canvas); + +/// Builder interface for patterns used to match display lists (canvas calls). +/// +/// The [paints] matcher returns a [PaintPattern] so that you can build the +/// pattern in the [expect] call. +/// +/// Patterns are subset matches, meaning that any calls not described by the +/// pattern are ignored. This allows, for instance, transforms to be skipped. +abstract class PaintPattern { + /// Indicates that a transform is expected next. + /// + /// Calls are skipped until a call to [Canvas.transform] is found. The call's + /// arguments are compared to those provided here. If any fail to match, or if + /// no call to [Canvas.transform] is found, then the matcher fails. + /// + /// Dynamic so matchers can be more easily passed in. + /// + /// The `matrix4` argument is dynamic so it can be either a [Matcher], or a + /// [Float64List] of [double]s. If it is a [Float64List] of [double]s then + /// each value in the matrix must match in the expected matrix. A deep + /// matching [Matcher] such as [equals] can be used to test each value in the + /// matrix with utilities such as [moreOrLessEquals]. + void transform({ dynamic matrix4 }); + + /// Indicates that a translation transform is expected next. + /// + /// Calls are skipped until a call to [Canvas.translate] is found. The call's + /// arguments are compared to those provided here. If any fail to match, or if + /// no call to [Canvas.translate] is found, then the matcher fails. + void translate({ double? x, double? y }); + + /// Indicates that a scale transform is expected next. + /// + /// Calls are skipped until a call to [Canvas.scale] is found. The call's + /// arguments are compared to those provided here. If any fail to match, or if + /// no call to [Canvas.scale] is found, then the matcher fails. + void scale({ double? x, double? y }); + + /// Indicates that a rotate transform is expected next. + /// + /// Calls are skipped until a call to [Canvas.rotate] is found. If the `angle` + /// argument is provided here, the call's argument is compared to it. If that + /// fails to match, or if no call to [Canvas.rotate] is found, then the + /// matcher fails. + void rotate({ double? angle }); + + /// Indicates that a save is expected next. + /// + /// Calls are skipped until a call to [Canvas.save] is found. If none is + /// found, the matcher fails. + /// + /// See also: + /// + /// * [restore], which indicates that a restore is expected next. + /// * [saveRestore], which indicates that a matching pair of save/restore + /// calls is expected next. + void save(); + + /// Indicates that a restore is expected next. + /// + /// Calls are skipped until a call to [Canvas.restore] is found. If none is + /// found, the matcher fails. + /// + /// See also: + /// + /// * [save], which indicates that a save is expected next. + /// * [saveRestore], which indicates that a matching pair of save/restore + /// calls is expected next. + void restore(); + + /// Indicates that a matching pair of save/restore calls is expected next. + /// + /// Calls are skipped until a call to [Canvas.save] is found, then, calls are + /// skipped until the matching [Canvas.restore] call is found. If no matching + /// pair of calls could be found, the matcher fails. + /// + /// See also: + /// + /// * [save], which indicates that a save is expected next. + /// * [restore], which indicates that a restore is expected next. + void saveRestore(); + + /// Indicates that a rectangular clip is expected next. + /// + /// The next rectangular clip is examined. Any arguments that are passed to + /// this method are compared to the actual [Canvas.clipRect] call's argument + /// and any mismatches result in failure. + /// + /// If no call to [Canvas.clipRect] was made, then this results in failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.clipRect] call are ignored. + void clipRect({ Rect? rect }); + + /// Indicates that a path clip is expected next. + /// + /// The next path clip is examined. + /// The path that is passed to the actual [Canvas.clipPath] call is matched + /// using [pathMatcher]. + /// + /// If no call to [Canvas.clipPath] was made, then this results in failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.clipPath] call are ignored. + void clipPath({ Matcher? pathMatcher }); + + /// Indicates that a rectangle is expected next. + /// + /// The next rectangle is examined. Any arguments that are passed to this + /// method are compared to the actual [Canvas.drawRect] call's arguments + /// and any mismatches result in failure. + /// + /// If no call to [Canvas.drawRect] was made, then this results in failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.drawRect] call are ignored. + /// + /// The [Paint]-related arguments (`color`, `strokeWidth`, `hasMaskFilter`, + /// `style`) are compared against the state of the [Paint] object after the + /// painting has completed, not at the time of the call. If the same [Paint] + /// object is reused multiple times, then this may not match the actual + /// arguments as they were seen by the method. + void rect({ Rect? rect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + + /// Indicates that a rounded rectangle clip is expected next. + /// + /// The next rounded rectangle clip is examined. Any arguments that are passed + /// to this method are compared to the actual [Canvas.clipRRect] call's + /// argument and any mismatches result in failure. + /// + /// If no call to [Canvas.clipRRect] was made, then this results in failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.clipRRect] call are ignored. + void clipRRect({ RRect? rrect }); + + /// Indicates that a rounded rectangle is expected next. + /// + /// The next rounded rectangle is examined. Any arguments that are passed to + /// this method are compared to the actual [Canvas.drawRRect] call's arguments + /// and any mismatches result in failure. + /// + /// If no call to [Canvas.drawRRect] was made, then this results in failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.drawRRect] call are ignored. + /// + /// The [Paint]-related arguments (`color`, `strokeWidth`, `hasMaskFilter`, + /// `style`) are compared against the state of the [Paint] object after the + /// painting has completed, not at the time of the call. If the same [Paint] + /// object is reused multiple times, then this may not match the actual + /// arguments as they were seen by the method. + void rrect({ RRect? rrect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + + /// Indicates that a rounded rectangle outline is expected next. + /// + /// The next call to [Canvas.drawRRect] is examined. Any arguments that are + /// passed to this method are compared to the actual [Canvas.drawRRect] call's + /// arguments and any mismatches result in failure. + /// + /// If no call to [Canvas.drawRRect] was made, then this results in failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.drawRRect] call are ignored. + /// + /// The [Paint]-related arguments (`color`, `strokeWidth`, `hasMaskFilter`, + /// `style`) are compared against the state of the [Paint] object after the + /// painting has completed, not at the time of the call. If the same [Paint] + /// object is reused multiple times, then this may not match the actual + /// arguments as they were seen by the method. + void drrect({ RRect? outer, RRect? inner, Color? color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }); + + /// Indicates that a circle is expected next. + /// + /// The next circle is examined. Any arguments that are passed to this method + /// are compared to the actual [Canvas.drawCircle] call's arguments and any + /// mismatches result in failure. + /// + /// If no call to [Canvas.drawCircle] was made, then this results in failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.drawCircle] call are ignored. + /// + /// The [Paint]-related arguments (`color`, `strokeWidth`, `hasMaskFilter`, + /// `style`) are compared against the state of the [Paint] object after the + /// painting has completed, not at the time of the call. If the same [Paint] + /// object is reused multiple times, then this may not match the actual + /// arguments as they were seen by the method. + void circle({ double? x, double? y, double? radius, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + + /// Indicates that a path is expected next. + /// + /// The next path is examined. Any arguments that are passed to this method + /// are compared to the actual [Canvas.drawPath] call's `paint` argument, and + /// any mismatches result in failure. + /// + /// To introspect the Path object (as it stands after the painting has + /// completed), the `includes` and `excludes` arguments can be provided to + /// specify points that should be considered inside or outside the path + /// (respectively). + /// + /// If no call to [Canvas.drawPath] was made, then this results in failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.drawPath] call are ignored. + /// + /// The [Paint]-related arguments (`color`, `strokeWidth`, `hasMaskFilter`, + /// `style`) are compared against the state of the [Paint] object after the + /// painting has completed, not at the time of the call. If the same [Paint] + /// object is reused multiple times, then this may not match the actual + /// arguments as they were seen by the method. + void path({ Iterable? includes, Iterable? excludes, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + + /// Indicates that a line is expected next. + /// + /// The next line is examined. Any arguments that are passed to this method + /// are compared to the actual [Canvas.drawLine] call's `p1`, `p2`, and + /// `paint` arguments, and any mismatches result in failure. + /// + /// If no call to [Canvas.drawLine] was made, then this results in failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.drawLine] call are ignored. + /// + /// The [Paint]-related arguments (`color`, `strokeWidth`, `hasMaskFilter`, + /// `style`) are compared against the state of the [Paint] object after the + /// painting has completed, not at the time of the call. If the same [Paint] + /// object is reused multiple times, then this may not match the actual + /// arguments as they were seen by the method. + void line({ Offset? p1, Offset? p2, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + + /// Indicates that an arc is expected next. + /// + /// The next arc is examined. Any arguments that are passed to this method + /// are compared to the actual [Canvas.drawArc] call's `paint` argument, and + /// any mismatches result in failure. + /// + /// If no call to [Canvas.drawArc] was made, then this results in failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.drawArc] call are ignored. + /// + /// The [Paint]-related arguments (`color`, `strokeWidth`, `hasMaskFilter`, + /// `style`) are compared against the state of the [Paint] object after the + /// painting has completed, not at the time of the call. If the same [Paint] + /// object is reused multiple times, then this may not match the actual + /// arguments as they were seen by the method. + void arc({ Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + + /// Indicates that a paragraph is expected next. + /// + /// Calls are skipped until a call to [Canvas.drawParagraph] is found. Any + /// arguments that are passed to this method are compared to the actual + /// [Canvas.drawParagraph] call's argument, and any mismatches result in failure. + /// + /// The `offset` argument can be either an [Offset] or a [Matcher]. If it is + /// an [Offset] then the actual value must match the expected offset + /// precisely. If it is a [Matcher] then the comparison is made according to + /// the semantics of the [Matcher]. For example, [within] can be used to + /// assert that the actual offset is within a given distance from the expected + /// offset. + /// + /// If no call to [Canvas.drawParagraph] was made, then this results in failure. + void paragraph({ ui.Paragraph? paragraph, dynamic offset }); + + /// Indicates that a shadow is expected next. + /// + /// The next shadow is examined. Any arguments that are passed to this method + /// are compared to the actual [Canvas.drawShadow] call's `paint` argument, + /// and any mismatches result in failure. + /// + /// In tests, shadows from framework features such as [BoxShadow] or + /// [Material] are disabled by default, and thus this predicate would not + /// match. The [debugDisableShadows] flag controls this. + /// + /// To introspect the Path object (as it stands after the painting has + /// completed), the `includes` and `excludes` arguments can be provided to + /// specify points that should be considered inside or outside the path + /// (respectively). + /// + /// If no call to [Canvas.drawShadow] was made, then this results in failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.drawShadow] call are ignored. + void shadow({ Iterable? includes, Iterable? excludes, Color? color, double? elevation, bool? transparentOccluder }); + + /// Indicates that an image is expected next. + /// + /// The next call to [Canvas.drawImage] is examined, and its arguments + /// compared to those passed to _this_ method. + /// + /// If no call to [Canvas.drawImage] was made, then this results in + /// failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.drawImage] call are ignored. + /// + /// The [Paint]-related arguments (`color`, `strokeWidth`, `hasMaskFilter`, + /// `style`) are compared against the state of the [Paint] object after the + /// painting has completed, not at the time of the call. If the same [Paint] + /// object is reused multiple times, then this may not match the actual + /// arguments as they were seen by the method. + void image({ ui.Image? image, double? x, double? y, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + + /// Indicates that an image subsection is expected next. + /// + /// The next call to [Canvas.drawImageRect] is examined, and its arguments + /// compared to those passed to _this_ method. + /// + /// If no call to [Canvas.drawImageRect] was made, then this results in + /// failure. + /// + /// Any calls made between the last matched call (if any) and the + /// [Canvas.drawImageRect] call are ignored. + /// + /// The [Paint]-related arguments (`color`, `strokeWidth`, `hasMaskFilter`, + /// `style`) are compared against the state of the [Paint] object after the + /// painting has completed, not at the time of the call. If the same [Paint] + /// object is reused multiple times, then this may not match the actual + /// arguments as they were seen by the method. + void drawImageRect({ ui.Image? image, Rect? source, Rect? destination, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + + /// Provides a custom matcher. + /// + /// Each method call after the last matched call (if any) will be passed to + /// the given predicate, along with the values of its (positional) arguments. + /// + /// For each one, the predicate must either return a boolean or throw a [String]. + /// + /// If the predicate returns true, the call is considered a successful match + /// and the next step in the pattern is examined. If this was the last step, + /// then any calls that were not yet matched are ignored and the [paints] + /// [Matcher] is considered a success. + /// + /// If the predicate returns false, then the call is considered uninteresting + /// and the predicate will be called again for the next [Canvas] call that was + /// made by the [RenderObject] under test. If this was the last call, then the + /// [paints] [Matcher] is considered to have failed. + /// + /// If the predicate throws a [String], then the [paints] [Matcher] is + /// considered to have failed. The thrown string is used in the message + /// displayed from the test framework and should be complete sentence + /// describing the problem. + void something(PaintPatternPredicate predicate); + + /// Provides a custom matcher. + /// + /// Each method call after the last matched call (if any) will be passed to + /// the given predicate, along with the values of its (positional) arguments. + /// + /// For each one, the predicate must either return a boolean or throw a [String]. + /// + /// The predicate will be applied to each [Canvas] call until it returns false + /// or all of the method calls have been tested. + /// + /// If the predicate returns false, then the [paints] [Matcher] is considered + /// to have failed. If all calls are tested without failing, then the [paints] + /// [Matcher] is considered a success. + /// + /// If the predicate throws a [String], then the [paints] [Matcher] is + /// considered to have failed. The thrown string is used in the message + /// displayed from the test framework and should be complete sentence + /// describing the problem. + void everything(PaintPatternPredicate predicate); +} + +/// Matches a [Path] that contains (as defined by [Path.contains]) the given +/// `includes` points and does not contain the given `excludes` points. +Matcher isPathThat({ + Iterable includes = const [], + Iterable excludes = const [], +}) { + return _PathMatcher(includes.toList(), excludes.toList()); +} + +class _PathMatcher extends Matcher { + _PathMatcher(this.includes, this.excludes); + + List includes; + List excludes; + + @override + bool matches(Object? object, Map matchState) { + if (object is! Path) { + matchState[this] = 'The given object ($object) was not a Path.'; + return false; + } + final Path path = object; + final List errors = [ + for (final Offset offset in includes) + if (!path.contains(offset)) + 'Offset $offset should be inside the path, but is not.', + for (final Offset offset in excludes) + if (path.contains(offset)) + 'Offset $offset should be outside the path, but is not.', + ]; + if (errors.isEmpty) { + return true; + } + matchState[this] = 'Not all the given points were inside or outside the path as expected:\n ${errors.join("\n ")}'; + return false; + } + + @override + Description describe(Description description) { + String points(List list) { + final int count = list.length; + if (count == 1) { + return 'one particular point'; + } + return '$count particular points'; + } + return description.add('A Path that contains ${points(includes)} but does not contain ${points(excludes)}.'); + } + + @override + Description describeMismatch( + dynamic item, + Description description, + Map matchState, + bool verbose, + ) { + return description.add(matchState[this] as String); + } +} + +class _MismatchedCall { + const _MismatchedCall(this.message, this.callIntroduction, this.call) : assert(call != null); + final String message; + final String callIntroduction; + final RecordedInvocation call; +} + +bool _evaluatePainter(Object? object, Canvas canvas, PaintingContext context) { + if (object is _ContextPainterFunction) { + final _ContextPainterFunction function = object; + function(context, Offset.zero); + } else if (object is _CanvasPainterFunction) { + final _CanvasPainterFunction function = object; + function(canvas); + } else { + if (object is Finder) { + TestAsyncUtils.guardSync(); + final Finder finder = object; + object = finder.evaluate().single.renderObject; + } + if (object is RenderObject) { + final RenderObject renderObject = object; + renderObject.paint(context, Offset.zero); + } else { + return false; + } + } + return true; +} + +abstract class _TestRecordingCanvasMatcher extends Matcher { + @override + bool matches(Object? object, Map matchState) { + final TestRecordingCanvas canvas = TestRecordingCanvas(); + final TestRecordingPaintingContext context = TestRecordingPaintingContext(canvas); + final StringBuffer description = StringBuffer(); + String prefixMessage = 'unexpectedly failed.'; + bool result = false; + try { + if (!_evaluatePainter(object, canvas, context)) { + matchState[this] = 'was not one of the supported objects for the "paints" matcher.'; + return false; + } + result = _evaluatePredicates(canvas.invocations, description); + if (!result) { + prefixMessage = 'did not match the pattern.'; + } + } catch (error, stack) { + prefixMessage = 'threw the following exception:'; + description.writeln(error.toString()); + description.write(stack.toString()); + result = false; + } + if (!result) { + if (canvas.invocations.isNotEmpty) { + description.write('The complete display list was:'); + for (final RecordedInvocation call in canvas.invocations) { + description.write('\n * $call'); + } + } + matchState[this] = '$prefixMessage\n$description'; + } + return result; + } + + bool _evaluatePredicates(Iterable calls, StringBuffer description); + + @override + Description describeMismatch( + dynamic item, + Description description, + Map matchState, + bool verbose, + ) { + return description.add(matchState[this] as String); + } +} + +class _TestRecordingCanvasPaintsCountMatcher extends _TestRecordingCanvasMatcher { + _TestRecordingCanvasPaintsCountMatcher(Symbol methodName, int count) + : _methodName = methodName, + _count = count; + + final Symbol _methodName; + final int _count; + + @override + Description describe(Description description) { + return description.add('Object or closure painting $_methodName exactly $_count times'); + } + + @override + bool _evaluatePredicates(Iterable calls, StringBuffer description) { + int count = 0; + for (final RecordedInvocation call in calls) { + if (call.invocation.isMethod && call.invocation.memberName == _methodName) { + count++; + } + } + if (count != _count) { + description.write('It painted $_methodName $count times instead of $_count times.'); + } + return count == _count; + } +} + +class _TestRecordingCanvasPaintsNothingMatcher extends _TestRecordingCanvasMatcher { + @override + Description describe(Description description) { + return description.add('An object or closure that paints nothing.'); + } + + @override + bool _evaluatePredicates(Iterable calls, StringBuffer description) { + final Iterable paintingCalls = _filterCanvasCalls(calls); + if (paintingCalls.isEmpty) { + return true; + } + description.write( + 'painted something, the first call having the following stack:\n' + '${paintingCalls.first.stackToString(indent: " ")}\n', + ); + return false; + } + + static const List _nonPaintingOperations = [ + #save, + #restore, + ]; + + // Filters out canvas calls that are not painting anything. + static Iterable _filterCanvasCalls(Iterable canvasCalls) { + return canvasCalls.where((RecordedInvocation canvasCall) => + !_nonPaintingOperations.contains(canvasCall.invocation.memberName), + ); + } +} + +class _TestRecordingCanvasPaintsAssertionMatcher extends Matcher { + @override + bool matches(Object? object, Map matchState) { + final TestRecordingCanvas canvas = TestRecordingCanvas(); + final TestRecordingPaintingContext context = TestRecordingPaintingContext(canvas); + final StringBuffer description = StringBuffer(); + String prefixMessage = 'unexpectedly failed.'; + bool result = false; + try { + if (!_evaluatePainter(object, canvas, context)) { + matchState[this] = 'was not one of the supported objects for the "paints" matcher.'; + return false; + } + prefixMessage = 'did not assert.'; + } on AssertionError { + result = true; + } catch (error, stack) { + prefixMessage = 'threw the following exception:'; + description.writeln(error.toString()); + description.write(stack.toString()); + result = false; + } + if (!result) { + if (canvas.invocations.isNotEmpty) { + description.write('The complete display list was:'); + for (final RecordedInvocation call in canvas.invocations) { + description.write('\n * $call'); + } + } + matchState[this] = '$prefixMessage\n$description'; + } + return result; + } + + @override + Description describe(Description description) { + return description.add('An object or closure that asserts when it tries to paint.'); + } + + @override + Description describeMismatch( + dynamic item, + Description description, + Map matchState, + bool verbose, + ) { + return description.add(matchState[this] as String); + } +} + +class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher implements PaintPattern { + final List<_PaintPredicate> _predicates = <_PaintPredicate>[]; + + @override + void transform({ dynamic matrix4 }) { + _predicates.add(_FunctionPaintPredicate(#transform, [matrix4])); + } + + @override + void translate({ double? x, double? y }) { + _predicates.add(_FunctionPaintPredicate(#translate, [x, y])); + } + + @override + void scale({ double? x, double? y }) { + _predicates.add(_FunctionPaintPredicate(#scale, [x, y])); + } + + @override + void rotate({ double? angle }) { + _predicates.add(_FunctionPaintPredicate(#rotate, [angle])); + } + + @override + void save() { + _predicates.add(_FunctionPaintPredicate(#save, [])); + } + + @override + void restore() { + _predicates.add(_FunctionPaintPredicate(#restore, [])); + } + + @override + void saveRestore() { + _predicates.add(_SaveRestorePairPaintPredicate()); + } + + @override + void clipRect({ Rect? rect }) { + _predicates.add(_FunctionPaintPredicate(#clipRect, [rect])); + } + + @override + void clipPath({ Matcher? pathMatcher }) { + _predicates.add(_FunctionPaintPredicate(#clipPath, [pathMatcher])); + } + + @override + void rect({ Rect? rect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { + _predicates.add(_RectPaintPredicate(rect: rect, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); + } + + @override + void clipRRect({ RRect? rrect }) { + _predicates.add(_FunctionPaintPredicate(#clipRRect, [rrect])); + } + + @override + void rrect({ RRect? rrect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { + _predicates.add(_RRectPaintPredicate(rrect: rrect, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); + } + + @override + void drrect({ RRect? outer, RRect? inner, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { + _predicates.add(_DRRectPaintPredicate(outer: outer, inner: inner, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); + } + + @override + void circle({ double? x, double? y, double? radius, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { + _predicates.add(_CirclePaintPredicate(x: x, y: y, radius: radius, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); + } + + @override + void path({ Iterable? includes, Iterable? excludes, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { + _predicates.add(_PathPaintPredicate(includes: includes, excludes: excludes, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); + } + + @override + void line({ Offset? p1, Offset? p2, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { + _predicates.add(_LinePaintPredicate(p1: p1, p2: p2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); + } + + @override + void arc({ Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { + _predicates.add(_ArcPaintPredicate(color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); + } + + @override + void paragraph({ ui.Paragraph? paragraph, dynamic offset }) { + _predicates.add(_FunctionPaintPredicate(#drawParagraph, [paragraph, offset])); + } + + @override + void shadow({ Iterable? includes, Iterable? excludes, Color? color, double? elevation, bool? transparentOccluder }) { + _predicates.add(_ShadowPredicate(includes: includes, excludes: excludes, color: color, elevation: elevation, transparentOccluder: transparentOccluder)); + } + + @override + void image({ ui.Image? image, double? x, double? y, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { + _predicates.add(_DrawImagePaintPredicate(image: image, x: x, y: y, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); + } + + @override + void drawImageRect({ ui.Image? image, Rect? source, Rect? destination, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { + _predicates.add(_DrawImageRectPaintPredicate(image: image, source: source, destination: destination, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); + } + + @override + void something(PaintPatternPredicate predicate) { + _predicates.add(_SomethingPaintPredicate(predicate)); + } + + @override + void everything(PaintPatternPredicate predicate) { + _predicates.add(_EverythingPaintPredicate(predicate)); + } + + @override + Description describe(Description description) { + if (_predicates.isEmpty) { + return description.add('An object or closure and a paint pattern.'); + } + description.add('Object or closure painting:\n'); + return description.addAll( + '', '\n', '', + _predicates.map((_PaintPredicate predicate) => predicate.toString()), + ); + } + + @override + bool _evaluatePredicates(Iterable calls, StringBuffer description) { + if (calls.isEmpty) { + description.writeln('It painted nothing.'); + return false; + } + if (_predicates.isEmpty) { + description.writeln( + 'It painted something, but you must now add a pattern to the paints matcher ' + 'in the test to verify that it matches the important parts of the following.', + ); + return false; + } + final Iterator<_PaintPredicate> predicate = _predicates.iterator; + final Iterator call = calls.iterator..moveNext(); + try { + while (predicate.moveNext()) { + predicate.current.match(call); + } + // We allow painting more than expected. + } on _MismatchedCall catch (data) { + description.writeln(data.message); + description.writeln(data.callIntroduction); + description.writeln(data.call.stackToString(indent: ' ')); + return false; + } on String catch (s) { + description.writeln(s); + try { + description.write('The stack of the offending call was:\n${call.current.stackToString(indent: " ")}\n'); + } on TypeError catch (_) { + // All calls have been evaluated + } + return false; + } + return true; + } +} + +abstract class _PaintPredicate { + void match(Iterator call); + + @protected + void checkMethod(Iterator call, Symbol symbol) { + int others = 0; + final RecordedInvocation firstCall = call.current; + while (!call.current.invocation.isMethod || call.current.invocation.memberName != symbol) { + others += 1; + if (!call.moveNext()) { + throw _MismatchedCall( + 'It called $others other method${ others == 1 ? "" : "s" } on the canvas, ' + 'the first of which was $firstCall, but did not ' + 'call ${_symbolName(symbol)}() at the time where $this was expected.', + 'The first method that was called when the call to ${_symbolName(symbol)}() ' + 'was expected, $firstCall, was called with the following stack:', + firstCall, + ); + } + } + } + + @override + String toString() { + throw FlutterError('$runtimeType does not implement toString.'); + } +} + +abstract class _DrawCommandPaintPredicate extends _PaintPredicate { + _DrawCommandPaintPredicate( + this.symbol, + this.name, + this.argumentCount, + this.paintArgumentIndex, { + this.color, + this.strokeWidth, + this.hasMaskFilter, + this.style, + }); + + final Symbol symbol; + final String name; + final int argumentCount; + final int paintArgumentIndex; + final Color? color; + final double? strokeWidth; + final bool? hasMaskFilter; + final PaintingStyle? style; + + String get methodName => _symbolName(symbol); + + @override + void match(Iterator call) { + checkMethod(call, symbol); + final int actualArgumentCount = call.current.invocation.positionalArguments.length; + if (actualArgumentCount != argumentCount) { + throw 'It called $methodName with $actualArgumentCount argument${actualArgumentCount == 1 ? "" : "s"}; expected $argumentCount.'; + } + verifyArguments(call.current.invocation.positionalArguments); + call.moveNext(); + } + + @protected + @mustCallSuper + void verifyArguments(List arguments) { + final Paint paintArgument = arguments[paintArgumentIndex] as Paint; + if (color != null && paintArgument.color != color) { + throw 'It called $methodName with a paint whose color, ${paintArgument.color}, was not exactly the expected color ($color).'; + } + if (strokeWidth != null && paintArgument.strokeWidth != strokeWidth) { + throw 'It called $methodName with a paint whose strokeWidth, ${paintArgument.strokeWidth}, was not exactly the expected strokeWidth ($strokeWidth).'; + } + if (hasMaskFilter != null && (paintArgument.maskFilter != null) != hasMaskFilter) { + if (hasMaskFilter!) { + throw 'It called $methodName with a paint that did not have a mask filter, despite expecting one.'; + } else { + throw 'It called $methodName with a paint that did have a mask filter, despite not expecting one.'; + } + } + if (style != null && paintArgument.style != style) { + throw 'It called $methodName with a paint whose style, ${paintArgument.style}, was not exactly the expected style ($style).'; + } + } + + @override + String toString() { + final List description = []; + debugFillDescription(description); + String result = name; + if (description.isNotEmpty) { + result += ' with ${description.join(", ")}'; + } + return result; + } + + @protected + @mustCallSuper + void debugFillDescription(List description) { + if (color != null) { + description.add('$color'); + } + if (strokeWidth != null) { + description.add('strokeWidth: $strokeWidth'); + } + if (hasMaskFilter != null) { + description.add(hasMaskFilter! ? 'a mask filter' : 'no mask filter'); + } + if (style != null) { + description.add('$style'); + } + } +} + +class _OneParameterPaintPredicate extends _DrawCommandPaintPredicate { + _OneParameterPaintPredicate( + Symbol symbol, + String name, { + required this.expected, + required Color? color, + required double? strokeWidth, + required bool? hasMaskFilter, + required PaintingStyle? style, + }) : super( + symbol, + name, + 2, + 1, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); + + final T? expected; + + @override + void verifyArguments(List arguments) { + super.verifyArguments(arguments); + final T actual = arguments[0] as T; + if (expected != null && actual != expected) { + throw 'It called $methodName with $T, $actual, which was not exactly the expected $T ($expected).'; + } + } + + @override + void debugFillDescription(List description) { + super.debugFillDescription(description); + if (expected != null) { + if (expected.toString().contains(T.toString())) { + description.add('$expected'); + } else { + description.add('$T: $expected'); + } + } + } +} + +class _TwoParameterPaintPredicate extends _DrawCommandPaintPredicate { + _TwoParameterPaintPredicate( + Symbol symbol, + String name, { + required this.expected1, + required this.expected2, + required Color? color, + required double? strokeWidth, + required bool? hasMaskFilter, + required PaintingStyle? style, + }) : super( + symbol, + name, + 3, + 2, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); + + final T1? expected1; + + final T2? expected2; + + @override + void verifyArguments(List arguments) { + super.verifyArguments(arguments); + final T1 actual1 = arguments[0] as T1; + if (expected1 != null && actual1 != expected1) { + throw 'It called $methodName with its first argument (a $T1), $actual1, which was not exactly the expected $T1 ($expected1).'; + } + final T2 actual2 = arguments[1] as T2; + if (expected2 != null && actual2 != expected2) { + throw 'It called $methodName with its second argument (a $T2), $actual2, which was not exactly the expected $T2 ($expected2).'; + } + } + + @override + void debugFillDescription(List description) { + super.debugFillDescription(description); + if (expected1 != null) { + if (expected1.toString().contains(T1.toString())) { + description.add('$expected1'); + } else { + description.add('$T1: $expected1'); + } + } + if (expected2 != null) { + if (expected2.toString().contains(T2.toString())) { + description.add('$expected2'); + } else { + description.add('$T2: $expected2'); + } + } + } +} + +class _RectPaintPredicate extends _OneParameterPaintPredicate { + _RectPaintPredicate({ Rect? rect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( + #drawRect, + 'a rectangle', + expected: rect, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); +} + +class _RRectPaintPredicate extends _DrawCommandPaintPredicate { + _RRectPaintPredicate({ this.rrect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( + #drawRRect, + 'a rounded rectangle', + 2, + 1, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); + + final RRect? rrect; + + @override + void verifyArguments(List arguments) { + super.verifyArguments(arguments); + const double eps = .0001; + final RRect actual = arguments[0] as RRect; + if (rrect != null && + ((actual.left - rrect!.left).abs() > eps || + (actual.right - rrect!.right).abs() > eps || + (actual.top - rrect!.top).abs() > eps || + (actual.bottom - rrect!.bottom).abs() > eps || + (actual.blRadiusX - rrect!.blRadiusX).abs() > eps || + (actual.blRadiusY - rrect!.blRadiusY).abs() > eps || + (actual.brRadiusX - rrect!.brRadiusX).abs() > eps || + (actual.brRadiusY - rrect!.brRadiusY).abs() > eps || + (actual.tlRadiusX - rrect!.tlRadiusX).abs() > eps || + (actual.tlRadiusY - rrect!.tlRadiusY).abs() > eps || + (actual.trRadiusX - rrect!.trRadiusX).abs() > eps || + (actual.trRadiusY - rrect!.trRadiusY).abs() > eps)) { + throw 'It called $methodName with RRect, $actual, which was not exactly the expected RRect ($rrect).'; + } + } + + @override + void debugFillDescription(List description) { + super.debugFillDescription(description); + if (rrect != null) { + description.add('RRect: $rrect'); + } + } +} + +class _DRRectPaintPredicate extends _TwoParameterPaintPredicate { + _DRRectPaintPredicate({ RRect? inner, RRect? outer, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( + #drawDRRect, + 'a rounded rectangle outline', + expected1: outer, + expected2: inner, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); +} + +class _CirclePaintPredicate extends _DrawCommandPaintPredicate { + _CirclePaintPredicate({ this.x, this.y, this.radius, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( + #drawCircle, 'a circle', 3, 2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, + ); + + final double? x; + final double? y; + final double? radius; + + @override + void verifyArguments(List arguments) { + super.verifyArguments(arguments); + final Offset pointArgument = arguments[0] as Offset; + if (x != null && y != null) { + final Offset point = Offset(x!, y!); + if (point != pointArgument) { + throw 'It called $methodName with a center coordinate, $pointArgument, which was not exactly the expected coordinate ($point).'; + } + } else { + if (x != null && pointArgument.dx != x) { + throw 'It called $methodName with a center coordinate, $pointArgument, whose x-coordinate not exactly the expected coordinate (${x!.toStringAsFixed(1)}).'; + } + if (y != null && pointArgument.dy != y) { + throw 'It called $methodName with a center coordinate, $pointArgument, whose y-coordinate not exactly the expected coordinate (${y!.toStringAsFixed(1)}).'; + } + } + final double radiusArgument = arguments[1] as double; + if (radius != null && radiusArgument != radius) { + throw 'It called $methodName with radius, ${radiusArgument.toStringAsFixed(1)}, which was not exactly the expected radius (${radius!.toStringAsFixed(1)}).'; + } + } + + @override + void debugFillDescription(List description) { + super.debugFillDescription(description); + if (x != null && y != null) { + description.add('point ${Offset(x!, y!)}'); + } else { + if (x != null) { + description.add('x-coordinate ${x!.toStringAsFixed(1)}'); + } + if (y != null) { + description.add('y-coordinate ${y!.toStringAsFixed(1)}'); + } + } + if (radius != null) { + description.add('radius ${radius!.toStringAsFixed(1)}'); + } + } +} + +class _PathPaintPredicate extends _DrawCommandPaintPredicate { + _PathPaintPredicate({ this.includes, this.excludes, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( + #drawPath, 'a path', 2, 1, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, + ); + + final Iterable? includes; + final Iterable? excludes; + + @override + void verifyArguments(List arguments) { + super.verifyArguments(arguments); + final Path pathArgument = arguments[0] as Path; + if (includes != null) { + for (final Offset offset in includes!) { + if (!pathArgument.contains(offset)) { + throw 'It called $methodName with a path that unexpectedly did not contain $offset.'; + } + } + } + if (excludes != null) { + for (final Offset offset in excludes!) { + if (pathArgument.contains(offset)) { + throw 'It called $methodName with a path that unexpectedly contained $offset.'; + } + } + } + } + + @override + void debugFillDescription(List description) { + super.debugFillDescription(description); + if (includes != null && excludes != null) { + description.add('that contains $includes and does not contain $excludes'); + } else if (includes != null) { + description.add('that contains $includes'); + } else if (excludes != null) { + description.add('that does not contain $excludes'); + } + } +} + +// TODO(ianh): add arguments to test the length, angle, that kind of thing +class _LinePaintPredicate extends _DrawCommandPaintPredicate { + _LinePaintPredicate({ this.p1, this.p2, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( + #drawLine, 'a line', 3, 2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, + ); + + final Offset? p1; + final Offset? p2; + + @override + void verifyArguments(List arguments) { + super.verifyArguments(arguments); // Checks the 3rd argument, a Paint + if (arguments.length != 3) { + throw 'It called $methodName with ${arguments.length} arguments; expected 3.'; + } + final Offset p1Argument = arguments[0] as Offset; + final Offset p2Argument = arguments[1] as Offset; + if (p1 != null && p1Argument != p1) { + throw 'It called $methodName with p1 endpoint, $p1Argument, which was not exactly the expected endpoint ($p1).'; + } + if (p2 != null && p2Argument != p2) { + throw 'It called $methodName with p2 endpoint, $p2Argument, which was not exactly the expected endpoint ($p2).'; + } + } + + @override + void debugFillDescription(List description) { + super.debugFillDescription(description); + if (p1 != null) { + description.add('end point p1: $p1'); + } + if (p2 != null) { + description.add('end point p2: $p2'); + } + } +} + +class _ArcPaintPredicate extends _DrawCommandPaintPredicate { + _ArcPaintPredicate({ Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( + #drawArc, 'an arc', 5, 4, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, + ); +} + +class _ShadowPredicate extends _PaintPredicate { + _ShadowPredicate({ this.includes, this.excludes, this.color, this.elevation, this.transparentOccluder }); + + final Iterable? includes; + final Iterable? excludes; + final Color? color; + final double? elevation; + final bool? transparentOccluder; + + static const Symbol symbol = #drawShadow; + String get methodName => _symbolName(symbol); + + @protected + void verifyArguments(List arguments) { + if (arguments.length != 4) { + throw 'It called $methodName with ${arguments.length} arguments; expected 4.'; + } + final Path pathArgument = arguments[0] as Path; + if (includes != null) { + for (final Offset offset in includes!) { + if (!pathArgument.contains(offset)) { + throw 'It called $methodName with a path that unexpectedly did not contain $offset.'; + } + } + } + if (excludes != null) { + for (final Offset offset in excludes!) { + if (pathArgument.contains(offset)) { + throw 'It called $methodName with a path that unexpectedly contained $offset.'; + } + } + } + final Color actualColor = arguments[1] as Color; + if (color != null && actualColor != color) { + throw 'It called $methodName with a color, $actualColor, which was not exactly the expected color ($color).'; + } + final double actualElevation = arguments[2] as double; + if (elevation != null && actualElevation != elevation) { + throw 'It called $methodName with an elevation, $actualElevation, which was not exactly the expected value ($elevation).'; + } + final bool actualTransparentOccluder = arguments[3] as bool; + if (transparentOccluder != null && actualTransparentOccluder != transparentOccluder) { + throw 'It called $methodName with a transparentOccluder value, $actualTransparentOccluder, which was not exactly the expected value ($transparentOccluder).'; + } + } + + @override + void match(Iterator call) { + checkMethod(call, symbol); + verifyArguments(call.current.invocation.positionalArguments); + call.moveNext(); + } + + @protected + void debugFillDescription(List description) { + if (includes != null && excludes != null) { + description.add('that contains $includes and does not contain $excludes'); + } else if (includes != null) { + description.add('that contains $includes'); + } else if (excludes != null) { + description.add('that does not contain $excludes'); + } + if (color != null) { + description.add('$color'); + } + if (elevation != null) { + description.add('elevation: $elevation'); + } + if (transparentOccluder != null) { + description.add('transparentOccluder: $transparentOccluder'); + } + } + + @override + String toString() { + final List description = []; + debugFillDescription(description); + String result = methodName; + if (description.isNotEmpty) { + result += ' with ${description.join(", ")}'; + } + return result; + } +} + +class _DrawImagePaintPredicate extends _DrawCommandPaintPredicate { + _DrawImagePaintPredicate({ this.image, this.x, this.y, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( + #drawImage, 'an image', 3, 2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, + ); + + final ui.Image? image; + final double? x; + final double? y; + + @override + void verifyArguments(List arguments) { + super.verifyArguments(arguments); + final ui.Image imageArgument = arguments[0] as ui.Image; + if (image != null && !image!.isCloneOf(imageArgument)) { + throw 'It called $methodName with an image, $imageArgument, which was not exactly the expected image ($image).'; + } + final Offset pointArgument = arguments[0] as Offset; + if (x != null && y != null) { + final Offset point = Offset(x!, y!); + if (point != pointArgument) { + throw 'It called $methodName with an offset coordinate, $pointArgument, which was not exactly the expected coordinate ($point).'; + } + } else { + if (x != null && pointArgument.dx != x) { + throw 'It called $methodName with an offset coordinate, $pointArgument, whose x-coordinate not exactly the expected coordinate (${x!.toStringAsFixed(1)}).'; + } + if (y != null && pointArgument.dy != y) { + throw 'It called $methodName with an offset coordinate, $pointArgument, whose y-coordinate not exactly the expected coordinate (${y!.toStringAsFixed(1)}).'; + } + } + } + + @override + void debugFillDescription(List description) { + super.debugFillDescription(description); + if (image != null) { + description.add('image $image'); + } + if (x != null && y != null) { + description.add('point ${Offset(x!, y!)}'); + } else { + if (x != null) { + description.add('x-coordinate ${x!.toStringAsFixed(1)}'); + } + if (y != null) { + description.add('y-coordinate ${y!.toStringAsFixed(1)}'); + } + } + } +} + +class _DrawImageRectPaintPredicate extends _DrawCommandPaintPredicate { + _DrawImageRectPaintPredicate({ this.image, this.source, this.destination, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( + #drawImageRect, 'an image', 4, 3, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, + ); + + final ui.Image? image; + final Rect? source; + final Rect? destination; + + @override + void verifyArguments(List arguments) { + super.verifyArguments(arguments); + final ui.Image imageArgument = arguments[0] as ui.Image; + if (image != null && !image!.isCloneOf(imageArgument)) { + throw 'It called $methodName with an image, $imageArgument, which was not exactly the expected image ($image).'; + } + final Rect sourceArgument = arguments[1] as Rect; + if (source != null && sourceArgument != source) { + throw 'It called $methodName with a source rectangle, $sourceArgument, which was not exactly the expected rectangle ($source).'; + } + final Rect destinationArgument = arguments[2] as Rect; + if (destination != null && destinationArgument != destination) { + throw 'It called $methodName with a destination rectangle, $destinationArgument, which was not exactly the expected rectangle ($destination).'; + } + } + + @override + void debugFillDescription(List description) { + super.debugFillDescription(description); + if (image != null) { + description.add('image $image'); + } + if (source != null) { + description.add('source $source'); + } + if (destination != null) { + description.add('destination $destination'); + } + } +} + +class _SomethingPaintPredicate extends _PaintPredicate { + _SomethingPaintPredicate(this.predicate); + + final PaintPatternPredicate predicate; + + @override + void match(Iterator call) { + RecordedInvocation currentCall; + bool testedAllCalls = false; + do { + if (testedAllCalls) { + throw 'It painted methods that the predicate passed to a "something" step, ' + 'in the paint pattern, none of which were considered correct.'; + } + currentCall = call.current; + if (!currentCall.invocation.isMethod) { + throw 'It called $currentCall, which was not a method, when the paint pattern expected a method call'; + } + testedAllCalls = !call.moveNext(); + } while (!_runPredicate(currentCall.invocation.memberName, currentCall.invocation.positionalArguments)); + } + + bool _runPredicate(Symbol methodName, List arguments) { + try { + return predicate(methodName, arguments); + } on String catch (s) { + throw 'It painted something that the predicate passed to a "something" step ' + 'in the paint pattern considered incorrect:\n $s\n '; + } + } + + @override + String toString() => 'a "something" step'; +} + +class _EverythingPaintPredicate extends _PaintPredicate { + _EverythingPaintPredicate(this.predicate); + + final PaintPatternPredicate predicate; + + @override + void match(Iterator call) { + do { + final RecordedInvocation currentCall = call.current; + if (!currentCall.invocation.isMethod) { + throw 'It called $currentCall, which was not a method, when the paint pattern expected a method call'; + } + if (!_runPredicate(currentCall.invocation.memberName, currentCall.invocation.positionalArguments)) { + throw 'It painted something that the predicate passed to an "everything" step ' + 'in the paint pattern considered incorrect.\n'; + } + } while (call.moveNext()); + } + + bool _runPredicate(Symbol methodName, List arguments) { + try { + return predicate(methodName, arguments); + } on String catch (s) { + throw 'It painted something that the predicate passed to an "everything" step ' + 'in the paint pattern considered incorrect:\n $s\n '; + } + } + + @override + String toString() => 'an "everything" step'; +} + +class _FunctionPaintPredicate extends _PaintPredicate { + _FunctionPaintPredicate(this.symbol, this.arguments); + + final Symbol symbol; + + final List arguments; + + @override + void match(Iterator call) { + checkMethod(call, symbol); + if (call.current.invocation.positionalArguments.length != arguments.length) { + throw 'It called ${_symbolName(symbol)} with ${call.current.invocation.positionalArguments.length} arguments; expected ${arguments.length}.'; + } + for (int index = 0; index < arguments.length; index += 1) { + final dynamic actualArgument = call.current.invocation.positionalArguments[index]; + final dynamic desiredArgument = arguments[index]; + + if (desiredArgument is Matcher) { + expect(actualArgument, desiredArgument); + } else if (desiredArgument != null && desiredArgument != actualArgument) { + throw 'It called ${_symbolName(symbol)} with argument $index having value ${_valueName(actualArgument)} when ${_valueName(desiredArgument)} was expected.'; + } + } + call.moveNext(); + } + + @override + String toString() { + final List adjectives = [ + for (int index = 0; index < arguments.length; index += 1) + arguments[index] != null ? _valueName(arguments[index]) : '...', + ]; + return '${_symbolName(symbol)}(${adjectives.join(", ")})'; + } +} + +class _SaveRestorePairPaintPredicate extends _PaintPredicate { + @override + void match(Iterator call) { + checkMethod(call, #save); + int depth = 1; + while (depth > 0) { + if (!call.moveNext()) { + throw 'It did not have a matching restore() for the save() that was found where $this was expected.'; + } + if (call.current.invocation.isMethod) { + if (call.current.invocation.memberName == #save) { + depth += 1; + } else if (call.current.invocation.memberName == #restore) { + depth -= 1; + } + } + } + call.moveNext(); + } + + @override + String toString() => 'a matching save/restore pair'; +} + +String _valueName(Object? value) { + if (value is double) { + return value.toStringAsFixed(1); + } + return value.toString(); +} + +// Workaround for https://github.com/dart-lang/sdk/issues/28372 +String _symbolName(Symbol symbol) { + // WARNING: Assumes a fixed format for Symbol.toString which is *not* + // guaranteed anywhere. + final String s = '$symbol'; + return s.substring(8, s.length - 2); +} diff --git a/test/recording_canvas.dart b/test/recording_canvas.dart new file mode 100644 index 00000000..abbce077 --- /dev/null +++ b/test/recording_canvas.dart @@ -0,0 +1,245 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/rendering.dart'; + +/// An [Invocation] and the [stack] trace that led to it. +/// +/// Used by [TestRecordingCanvas] to trace canvas calls. +class RecordedInvocation { + /// Create a record for an invocation list. + const RecordedInvocation(this.invocation, { required this.stack }); + + /// The method that was called and its arguments. + /// + /// The arguments preserve identity, but not value. Thus, if two invocations + /// were made with the same [Paint] object, but with that object configured + /// differently each time, then they will both have the same object as their + /// argument, and inspecting that object will return the object's current + /// values (mostly likely those passed to the second call). + final Invocation invocation; + + /// The stack trace at the time of the method call. + final StackTrace stack; + + @override + String toString() => _describeInvocation(invocation); + + /// Converts [stack] to a string using the [FlutterError.defaultStackFilter] logic. + String stackToString({ String indent = '' }) { + assert(indent != null); + return indent + FlutterError.defaultStackFilter( + stack.toString().trimRight().split('\n'), + ).join('\n$indent'); + } +} + +/// A [Canvas] for tests that records its method calls. +/// +/// This class can be used in conjunction with [TestRecordingPaintingContext] +/// to record the [Canvas] method calls made by a renderer. For example: +/// +/// ```dart +/// RenderBox box = tester.renderObject(find.text('ABC')); +/// TestRecordingCanvas canvas = TestRecordingCanvas(); +/// TestRecordingPaintingContext context = TestRecordingPaintingContext(canvas); +/// box.paint(context, Offset.zero); +/// // Now test the expected canvas.invocations. +/// ``` +/// +/// In some cases it may be useful to define a subclass that overrides the +/// [Canvas] methods the test is checking and squirrels away the parameters +/// that the test requires. +/// +/// For simple tests, consider using the [paints] matcher, which overlays a +/// pattern matching API over [TestRecordingCanvas]. +class TestRecordingCanvas implements Canvas { + /// All of the method calls on this canvas. + final List invocations = []; + + int _saveCount = 0; + + @override + int getSaveCount() => _saveCount; + + @override + void save() { + _saveCount += 1; + invocations.add(RecordedInvocation(_MethodCall(#save), stack: StackTrace.current)); + } + + @override + void saveLayer(Rect? bounds, Paint paint) { + _saveCount += 1; + invocations.add(RecordedInvocation(_MethodCall(#saveLayer, [bounds, paint]), stack: StackTrace.current)); + } + + @override + void restore() { + _saveCount -= 1; + assert(_saveCount >= 0); + invocations.add(RecordedInvocation(_MethodCall(#restore), stack: StackTrace.current)); + } + + @override + void noSuchMethod(Invocation invocation) { + invocations.add(RecordedInvocation(invocation, stack: StackTrace.current)); + } +} + +/// A [PaintingContext] for tests that use [TestRecordingCanvas]. +class TestRecordingPaintingContext extends ClipContext implements PaintingContext { + /// Creates a [PaintingContext] for tests that use [TestRecordingCanvas]. + TestRecordingPaintingContext(this.canvas); + + @override + final Canvas canvas; + + @override + void paintChild(RenderObject child, Offset offset) { + child.paint(this, offset); + } + + @override + ClipRectLayer? pushClipRect( + bool needsCompositing, + Offset offset, + Rect clipRect, + PaintingContextCallback painter, { + Clip clipBehavior = Clip.hardEdge, + ClipRectLayer? oldLayer, + }) { + clipRectAndPaint(clipRect.shift(offset), clipBehavior, clipRect.shift(offset), () => painter(this, offset)); + return null; + } + + @override + ClipRRectLayer? pushClipRRect( + bool needsCompositing, + Offset offset, + Rect bounds, + RRect clipRRect, + PaintingContextCallback painter, { + Clip clipBehavior = Clip.antiAlias, + ClipRRectLayer? oldLayer, + }) { + assert(clipBehavior != null); + clipRRectAndPaint(clipRRect.shift(offset), clipBehavior, bounds.shift(offset), () => painter(this, offset)); + return null; + } + + @override + ClipPathLayer? pushClipPath( + bool needsCompositing, + Offset offset, + Rect bounds, + Path clipPath, + PaintingContextCallback painter, { + Clip clipBehavior = Clip.antiAlias, + ClipPathLayer? oldLayer, + }) { + clipPathAndPaint(clipPath.shift(offset), clipBehavior, bounds.shift(offset), () => painter(this, offset)); + return null; + } + + @override + TransformLayer? pushTransform( + bool needsCompositing, + Offset offset, + Matrix4 transform, + PaintingContextCallback painter, { + TransformLayer? oldLayer, + }) { + canvas.save(); + canvas.transform(transform.storage); + painter(this, offset); + canvas.restore(); + return null; + } + + @override + OpacityLayer pushOpacity( + Offset offset, + int alpha, + PaintingContextCallback painter, { + OpacityLayer? oldLayer, + }) { + canvas.saveLayer(null, Paint()); // TODO(ianh): Expose the alpha somewhere. + painter(this, offset); + canvas.restore(); + return OpacityLayer(); + } + + @override + void pushLayer( + Layer childLayer, + PaintingContextCallback painter, + Offset offset, { + Rect? childPaintBounds, + }) { + painter(this, offset); + } + + @override + void noSuchMethod(Invocation invocation) { } +} + +class _MethodCall implements Invocation { + _MethodCall(this._name, [ this._arguments = const []]); + final Symbol _name; + final List _arguments; + @override + bool get isAccessor => false; + @override + bool get isGetter => false; + @override + bool get isMethod => true; + @override + bool get isSetter => false; + @override + Symbol get memberName => _name; + @override + Map get namedArguments => {}; + @override + List get positionalArguments => _arguments; + @override + List get typeArguments => const []; +} + +String _valueName(Object? value) { + if (value is double) { + return value.toStringAsFixed(1); + } + return value.toString(); +} + +// Workaround for https://github.com/dart-lang/sdk/issues/28372 +String _symbolName(Symbol symbol) { + // WARNING: Assumes a fixed format for Symbol.toString which is *not* + // guaranteed anywhere. + final String s = '$symbol'; + return s.substring(8, s.length - 2); +} + +// Workaround for https://github.com/dart-lang/sdk/issues/28373 +String _describeInvocation(Invocation call) { + final StringBuffer buffer = StringBuffer(); + buffer.write(_symbolName(call.memberName)); + if (call.isSetter) { + buffer.write(call.positionalArguments[0].toString()); + } else if (call.isMethod) { + buffer.write('('); + buffer.writeAll(call.positionalArguments.map(_valueName), ', '); + String separator = call.positionalArguments.isEmpty ? '' : ', '; + call.namedArguments.forEach((Symbol name, Object? value) { + buffer.write(separator); + buffer.write(_symbolName(name)); + buffer.write(': '); + buffer.write(_valueName(value)); + separator = ', '; + }); + buffer.write(')'); + } + return buffer.toString(); +} From a735e5a152f798f989cc856c031f26bd19969858 Mon Sep 17 00:00:00 2001 From: Alfred Schilken Date: Fri, 27 Jan 2023 11:32:41 +0100 Subject: [PATCH 06/11] fix warnings in copied sources mock_canvas.dart and recording_canvas.dart --- test/mock_canvas.dart | 2 +- test/recording_canvas.dart | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/test/mock_canvas.dart b/test/mock_canvas.dart index 57a63373..e652a895 100644 --- a/test/mock_canvas.dart +++ b/test/mock_canvas.dart @@ -498,7 +498,7 @@ class _PathMatcher extends Matcher { } class _MismatchedCall { - const _MismatchedCall(this.message, this.callIntroduction, this.call) : assert(call != null); + const _MismatchedCall(this.message, this.callIntroduction, this.call); final String message; final String callIntroduction; final RecordedInvocation call; diff --git a/test/recording_canvas.dart b/test/recording_canvas.dart index abbce077..76872c78 100644 --- a/test/recording_canvas.dart +++ b/test/recording_canvas.dart @@ -27,8 +27,7 @@ class RecordedInvocation { String toString() => _describeInvocation(invocation); /// Converts [stack] to a string using the [FlutterError.defaultStackFilter] logic. - String stackToString({ String indent = '' }) { - assert(indent != null); + String stackToString({String indent = ''}) { return indent + FlutterError.defaultStackFilter( stack.toString().trimRight().split('\n'), ).join('\n$indent'); @@ -124,7 +123,6 @@ class TestRecordingPaintingContext extends ClipContext implements PaintingContex Clip clipBehavior = Clip.antiAlias, ClipRRectLayer? oldLayer, }) { - assert(clipBehavior != null); clipRRectAndPaint(clipRRect.shift(offset), clipBehavior, bounds.shift(offset), () => painter(this, offset)); return null; } From 91014d3e3872c443b096cf3f785a504f3ab5abf5 Mon Sep 17 00:00:00 2001 From: Alfred Schilken Date: Sat, 28 Jan 2023 10:55:55 +0100 Subject: [PATCH 07/11] format new and changed files --- test/indicators/capacity_indicators_test.dart | 21 +- test/mock_canvas.dart | 681 +++++++++++++----- test/recording_canvas.dart | 37 +- 3 files changed, 533 insertions(+), 206 deletions(-) diff --git a/test/indicators/capacity_indicators_test.dart b/test/indicators/capacity_indicators_test.dart index 60d0ea1c..5f5eb33a 100644 --- a/test/indicators/capacity_indicators_test.dart +++ b/test/indicators/capacity_indicators_test.dart @@ -59,27 +59,27 @@ void main() { ); }); -testWidgets( + testWidgets( 'CapacityIndicator paints the correct number of segments', (WidgetTester tester) async { - await tester.pumpWidget( + await tester.pumpWidget( const Directionality( - textDirection: TextDirection.ltr, + textDirection: TextDirection.ltr, child: Center( - child: SizedBox( - width: 200.0, - child: CapacityIndicator( + child: SizedBox( + width: 200.0, + child: CapacityIndicator( value: 50, splits: 20, discrete: true, + ), ), ), ), - ), - ); + ); - expect( - find.byType(CapacityIndicator), + expect( + find.byType(CapacityIndicator), // each discrete segment is drawn 3 times, two times with fill, last time with stroke paintsExactlyCountTimes(#drawRRect, 20 * 3), ); @@ -167,7 +167,6 @@ testWidgets( ), ) ..translate(x: 20.0, y: 0.0) - ..rrect( rrect: RRect.fromLTRBR( 0.0, diff --git a/test/mock_canvas.dart b/test/mock_canvas.dart index e652a895..c86c7482 100644 --- a/test/mock_canvas.dart +++ b/test/mock_canvas.dart @@ -64,10 +64,12 @@ Matcher paintsExactlyCountTimes(Symbol methodName, int count) { /// ```dart /// if (methodName == #drawCircle) { ... } /// ``` -typedef PaintPatternPredicate = bool Function(Symbol methodName, List arguments); +typedef PaintPatternPredicate = bool Function( + Symbol methodName, List arguments); /// The signature of [RenderObject.paint] functions. -typedef _ContextPainterFunction = void Function(PaintingContext context, Offset offset); +typedef _ContextPainterFunction = void Function( + PaintingContext context, Offset offset); /// The signature of functions that paint directly on a canvas. typedef _CanvasPainterFunction = void Function(Canvas canvas); @@ -93,21 +95,21 @@ abstract class PaintPattern { /// each value in the matrix must match in the expected matrix. A deep /// matching [Matcher] such as [equals] can be used to test each value in the /// matrix with utilities such as [moreOrLessEquals]. - void transform({ dynamic matrix4 }); + void transform({dynamic matrix4}); /// Indicates that a translation transform is expected next. /// /// Calls are skipped until a call to [Canvas.translate] is found. The call's /// arguments are compared to those provided here. If any fail to match, or if /// no call to [Canvas.translate] is found, then the matcher fails. - void translate({ double? x, double? y }); + void translate({double? x, double? y}); /// Indicates that a scale transform is expected next. /// /// Calls are skipped until a call to [Canvas.scale] is found. The call's /// arguments are compared to those provided here. If any fail to match, or if /// no call to [Canvas.scale] is found, then the matcher fails. - void scale({ double? x, double? y }); + void scale({double? x, double? y}); /// Indicates that a rotate transform is expected next. /// @@ -115,7 +117,7 @@ abstract class PaintPattern { /// argument is provided here, the call's argument is compared to it. If that /// fails to match, or if no call to [Canvas.rotate] is found, then the /// matcher fails. - void rotate({ double? angle }); + void rotate({double? angle}); /// Indicates that a save is expected next. /// @@ -163,7 +165,7 @@ abstract class PaintPattern { /// /// Any calls made between the last matched call (if any) and the /// [Canvas.clipRect] call are ignored. - void clipRect({ Rect? rect }); + void clipRect({Rect? rect}); /// Indicates that a path clip is expected next. /// @@ -175,7 +177,7 @@ abstract class PaintPattern { /// /// Any calls made between the last matched call (if any) and the /// [Canvas.clipPath] call are ignored. - void clipPath({ Matcher? pathMatcher }); + void clipPath({Matcher? pathMatcher}); /// Indicates that a rectangle is expected next. /// @@ -193,7 +195,12 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void rect({ Rect? rect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + void rect( + {Rect? rect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}); /// Indicates that a rounded rectangle clip is expected next. /// @@ -205,7 +212,7 @@ abstract class PaintPattern { /// /// Any calls made between the last matched call (if any) and the /// [Canvas.clipRRect] call are ignored. - void clipRRect({ RRect? rrect }); + void clipRRect({RRect? rrect}); /// Indicates that a rounded rectangle is expected next. /// @@ -223,7 +230,12 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void rrect({ RRect? rrect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + void rrect( + {RRect? rrect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}); /// Indicates that a rounded rectangle outline is expected next. /// @@ -241,7 +253,13 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void drrect({ RRect? outer, RRect? inner, Color? color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }); + void drrect( + {RRect? outer, + RRect? inner, + Color? color, + double strokeWidth, + bool hasMaskFilter, + PaintingStyle style}); /// Indicates that a circle is expected next. /// @@ -259,7 +277,14 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void circle({ double? x, double? y, double? radius, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + void circle( + {double? x, + double? y, + double? radius, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}); /// Indicates that a path is expected next. /// @@ -282,7 +307,13 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void path({ Iterable? includes, Iterable? excludes, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + void path( + {Iterable? includes, + Iterable? excludes, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}); /// Indicates that a line is expected next. /// @@ -300,7 +331,13 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void line({ Offset? p1, Offset? p2, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + void line( + {Offset? p1, + Offset? p2, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}); /// Indicates that an arc is expected next. /// @@ -318,7 +355,11 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void arc({ Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + void arc( + {Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}); /// Indicates that a paragraph is expected next. /// @@ -334,7 +375,7 @@ abstract class PaintPattern { /// offset. /// /// If no call to [Canvas.drawParagraph] was made, then this results in failure. - void paragraph({ ui.Paragraph? paragraph, dynamic offset }); + void paragraph({ui.Paragraph? paragraph, dynamic offset}); /// Indicates that a shadow is expected next. /// @@ -355,7 +396,12 @@ abstract class PaintPattern { /// /// Any calls made between the last matched call (if any) and the /// [Canvas.drawShadow] call are ignored. - void shadow({ Iterable? includes, Iterable? excludes, Color? color, double? elevation, bool? transparentOccluder }); + void shadow( + {Iterable? includes, + Iterable? excludes, + Color? color, + double? elevation, + bool? transparentOccluder}); /// Indicates that an image is expected next. /// @@ -373,7 +419,14 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void image({ ui.Image? image, double? x, double? y, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + void image( + {ui.Image? image, + double? x, + double? y, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}); /// Indicates that an image subsection is expected next. /// @@ -391,7 +444,14 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void drawImageRect({ ui.Image? image, Rect? source, Rect? destination, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }); + void drawImageRect( + {ui.Image? image, + Rect? source, + Rect? destination, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}); /// Provides a custom matcher. /// @@ -470,7 +530,8 @@ class _PathMatcher extends Matcher { if (errors.isEmpty) { return true; } - matchState[this] = 'Not all the given points were inside or outside the path as expected:\n ${errors.join("\n ")}'; + matchState[this] = + 'Not all the given points were inside or outside the path as expected:\n ${errors.join("\n ")}'; return false; } @@ -483,7 +544,9 @@ class _PathMatcher extends Matcher { } return '$count particular points'; } - return description.add('A Path that contains ${points(includes)} but does not contain ${points(excludes)}.'); + + return description.add( + 'A Path that contains ${points(includes)} but does not contain ${points(excludes)}.'); } @override @@ -531,13 +594,15 @@ abstract class _TestRecordingCanvasMatcher extends Matcher { @override bool matches(Object? object, Map matchState) { final TestRecordingCanvas canvas = TestRecordingCanvas(); - final TestRecordingPaintingContext context = TestRecordingPaintingContext(canvas); + final TestRecordingPaintingContext context = + TestRecordingPaintingContext(canvas); final StringBuffer description = StringBuffer(); String prefixMessage = 'unexpectedly failed.'; bool result = false; try { if (!_evaluatePainter(object, canvas, context)) { - matchState[this] = 'was not one of the supported objects for the "paints" matcher.'; + matchState[this] = + 'was not one of the supported objects for the "paints" matcher.'; return false; } result = _evaluatePredicates(canvas.invocations, description); @@ -562,7 +627,8 @@ abstract class _TestRecordingCanvasMatcher extends Matcher { return result; } - bool _evaluatePredicates(Iterable calls, StringBuffer description); + bool _evaluatePredicates( + Iterable calls, StringBuffer description); @override Description describeMismatch( @@ -575,43 +641,51 @@ abstract class _TestRecordingCanvasMatcher extends Matcher { } } -class _TestRecordingCanvasPaintsCountMatcher extends _TestRecordingCanvasMatcher { +class _TestRecordingCanvasPaintsCountMatcher + extends _TestRecordingCanvasMatcher { _TestRecordingCanvasPaintsCountMatcher(Symbol methodName, int count) - : _methodName = methodName, - _count = count; + : _methodName = methodName, + _count = count; final Symbol _methodName; final int _count; @override Description describe(Description description) { - return description.add('Object or closure painting $_methodName exactly $_count times'); + return description + .add('Object or closure painting $_methodName exactly $_count times'); } @override - bool _evaluatePredicates(Iterable calls, StringBuffer description) { + bool _evaluatePredicates( + Iterable calls, StringBuffer description) { int count = 0; for (final RecordedInvocation call in calls) { - if (call.invocation.isMethod && call.invocation.memberName == _methodName) { + if (call.invocation.isMethod && + call.invocation.memberName == _methodName) { count++; } } if (count != _count) { - description.write('It painted $_methodName $count times instead of $_count times.'); + description.write( + 'It painted $_methodName $count times instead of $_count times.'); } return count == _count; } } -class _TestRecordingCanvasPaintsNothingMatcher extends _TestRecordingCanvasMatcher { +class _TestRecordingCanvasPaintsNothingMatcher + extends _TestRecordingCanvasMatcher { @override Description describe(Description description) { return description.add('An object or closure that paints nothing.'); } @override - bool _evaluatePredicates(Iterable calls, StringBuffer description) { - final Iterable paintingCalls = _filterCanvasCalls(calls); + bool _evaluatePredicates( + Iterable calls, StringBuffer description) { + final Iterable paintingCalls = + _filterCanvasCalls(calls); if (paintingCalls.isEmpty) { return true; } @@ -622,15 +696,17 @@ class _TestRecordingCanvasPaintsNothingMatcher extends _TestRecordingCanvasMatch return false; } - static const List _nonPaintingOperations = [ + static const List _nonPaintingOperations = [ #save, #restore, ]; // Filters out canvas calls that are not painting anything. - static Iterable _filterCanvasCalls(Iterable canvasCalls) { - return canvasCalls.where((RecordedInvocation canvasCall) => - !_nonPaintingOperations.contains(canvasCall.invocation.memberName), + static Iterable _filterCanvasCalls( + Iterable canvasCalls) { + return canvasCalls.where( + (RecordedInvocation canvasCall) => + !_nonPaintingOperations.contains(canvasCall.invocation.memberName), ); } } @@ -639,13 +715,15 @@ class _TestRecordingCanvasPaintsAssertionMatcher extends Matcher { @override bool matches(Object? object, Map matchState) { final TestRecordingCanvas canvas = TestRecordingCanvas(); - final TestRecordingPaintingContext context = TestRecordingPaintingContext(canvas); + final TestRecordingPaintingContext context = + TestRecordingPaintingContext(canvas); final StringBuffer description = StringBuffer(); String prefixMessage = 'unexpectedly failed.'; bool result = false; try { if (!_evaluatePainter(object, canvas, context)) { - matchState[this] = 'was not one of the supported objects for the "paints" matcher.'; + matchState[this] = + 'was not one of the supported objects for the "paints" matcher.'; return false; } prefixMessage = 'did not assert.'; @@ -671,7 +749,8 @@ class _TestRecordingCanvasPaintsAssertionMatcher extends Matcher { @override Description describe(Description description) { - return description.add('An object or closure that asserts when it tries to paint.'); + return description + .add('An object or closure that asserts when it tries to paint.'); } @override @@ -685,26 +764,27 @@ class _TestRecordingCanvasPaintsAssertionMatcher extends Matcher { } } -class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher implements PaintPattern { +class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher + implements PaintPattern { final List<_PaintPredicate> _predicates = <_PaintPredicate>[]; @override - void transform({ dynamic matrix4 }) { + void transform({dynamic matrix4}) { _predicates.add(_FunctionPaintPredicate(#transform, [matrix4])); } @override - void translate({ double? x, double? y }) { + void translate({double? x, double? y}) { _predicates.add(_FunctionPaintPredicate(#translate, [x, y])); } @override - void scale({ double? x, double? y }) { + void scale({double? x, double? y}) { _predicates.add(_FunctionPaintPredicate(#scale, [x, y])); } @override - void rotate({ double? angle }) { + void rotate({double? angle}) { _predicates.add(_FunctionPaintPredicate(#rotate, [angle])); } @@ -724,73 +804,190 @@ class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher imp } @override - void clipRect({ Rect? rect }) { + void clipRect({Rect? rect}) { _predicates.add(_FunctionPaintPredicate(#clipRect, [rect])); } @override - void clipPath({ Matcher? pathMatcher }) { + void clipPath({Matcher? pathMatcher}) { _predicates.add(_FunctionPaintPredicate(#clipPath, [pathMatcher])); } @override - void rect({ Rect? rect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { - _predicates.add(_RectPaintPredicate(rect: rect, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); + void rect( + {Rect? rect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) { + _predicates.add(_RectPaintPredicate( + rect: rect, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style)); } @override - void clipRRect({ RRect? rrect }) { + void clipRRect({RRect? rrect}) { _predicates.add(_FunctionPaintPredicate(#clipRRect, [rrect])); } @override - void rrect({ RRect? rrect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { - _predicates.add(_RRectPaintPredicate(rrect: rrect, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); - } - - @override - void drrect({ RRect? outer, RRect? inner, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { - _predicates.add(_DRRectPaintPredicate(outer: outer, inner: inner, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); - } - - @override - void circle({ double? x, double? y, double? radius, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { - _predicates.add(_CirclePaintPredicate(x: x, y: y, radius: radius, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); - } - - @override - void path({ Iterable? includes, Iterable? excludes, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { - _predicates.add(_PathPaintPredicate(includes: includes, excludes: excludes, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); - } - - @override - void line({ Offset? p1, Offset? p2, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { - _predicates.add(_LinePaintPredicate(p1: p1, p2: p2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); - } - - @override - void arc({ Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { - _predicates.add(_ArcPaintPredicate(color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); - } - - @override - void paragraph({ ui.Paragraph? paragraph, dynamic offset }) { - _predicates.add(_FunctionPaintPredicate(#drawParagraph, [paragraph, offset])); - } - - @override - void shadow({ Iterable? includes, Iterable? excludes, Color? color, double? elevation, bool? transparentOccluder }) { - _predicates.add(_ShadowPredicate(includes: includes, excludes: excludes, color: color, elevation: elevation, transparentOccluder: transparentOccluder)); - } - - @override - void image({ ui.Image? image, double? x, double? y, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { - _predicates.add(_DrawImagePaintPredicate(image: image, x: x, y: y, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); - } - - @override - void drawImageRect({ ui.Image? image, Rect? source, Rect? destination, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) { - _predicates.add(_DrawImageRectPaintPredicate(image: image, source: source, destination: destination, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style)); + void rrect( + {RRect? rrect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) { + _predicates.add(_RRectPaintPredicate( + rrect: rrect, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style)); + } + + @override + void drrect( + {RRect? outer, + RRect? inner, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) { + _predicates.add(_DRRectPaintPredicate( + outer: outer, + inner: inner, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style)); + } + + @override + void circle( + {double? x, + double? y, + double? radius, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) { + _predicates.add(_CirclePaintPredicate( + x: x, + y: y, + radius: radius, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style)); + } + + @override + void path( + {Iterable? includes, + Iterable? excludes, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) { + _predicates.add(_PathPaintPredicate( + includes: includes, + excludes: excludes, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style)); + } + + @override + void line( + {Offset? p1, + Offset? p2, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) { + _predicates.add(_LinePaintPredicate( + p1: p1, + p2: p2, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style)); + } + + @override + void arc( + {Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) { + _predicates.add(_ArcPaintPredicate( + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style)); + } + + @override + void paragraph({ui.Paragraph? paragraph, dynamic offset}) { + _predicates.add( + _FunctionPaintPredicate(#drawParagraph, [paragraph, offset])); + } + + @override + void shadow( + {Iterable? includes, + Iterable? excludes, + Color? color, + double? elevation, + bool? transparentOccluder}) { + _predicates.add(_ShadowPredicate( + includes: includes, + excludes: excludes, + color: color, + elevation: elevation, + transparentOccluder: transparentOccluder)); + } + + @override + void image( + {ui.Image? image, + double? x, + double? y, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) { + _predicates.add(_DrawImagePaintPredicate( + image: image, + x: x, + y: y, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style)); + } + + @override + void drawImageRect( + {ui.Image? image, + Rect? source, + Rect? destination, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) { + _predicates.add(_DrawImageRectPaintPredicate( + image: image, + source: source, + destination: destination, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style)); } @override @@ -810,13 +1007,17 @@ class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher imp } description.add('Object or closure painting:\n'); return description.addAll( - '', '\n', '', - _predicates.map((_PaintPredicate predicate) => predicate.toString()), + '', + '\n', + '', + _predicates + .map((_PaintPredicate predicate) => predicate.toString()), ); } @override - bool _evaluatePredicates(Iterable calls, StringBuffer description) { + bool _evaluatePredicates( + Iterable calls, StringBuffer description) { if (calls.isEmpty) { description.writeln('It painted nothing.'); return false; @@ -843,7 +1044,8 @@ class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher imp } on String catch (s) { description.writeln(s); try { - description.write('The stack of the offending call was:\n${call.current.stackToString(indent: " ")}\n'); + description.write( + 'The stack of the offending call was:\n${call.current.stackToString(indent: " ")}\n'); } on TypeError catch (_) { // All calls have been evaluated } @@ -860,15 +1062,16 @@ abstract class _PaintPredicate { void checkMethod(Iterator call, Symbol symbol) { int others = 0; final RecordedInvocation firstCall = call.current; - while (!call.current.invocation.isMethod || call.current.invocation.memberName != symbol) { + while (!call.current.invocation.isMethod || + call.current.invocation.memberName != symbol) { others += 1; if (!call.moveNext()) { throw _MismatchedCall( - 'It called $others other method${ others == 1 ? "" : "s" } on the canvas, ' - 'the first of which was $firstCall, but did not ' - 'call ${_symbolName(symbol)}() at the time where $this was expected.', + 'It called $others other method${others == 1 ? "" : "s"} on the canvas, ' + 'the first of which was $firstCall, but did not ' + 'call ${_symbolName(symbol)}() at the time where $this was expected.', 'The first method that was called when the call to ${_symbolName(symbol)}() ' - 'was expected, $firstCall, was called with the following stack:', + 'was expected, $firstCall, was called with the following stack:', firstCall, ); } @@ -907,7 +1110,8 @@ abstract class _DrawCommandPaintPredicate extends _PaintPredicate { @override void match(Iterator call) { checkMethod(call, symbol); - final int actualArgumentCount = call.current.invocation.positionalArguments.length; + final int actualArgumentCount = + call.current.invocation.positionalArguments.length; if (actualArgumentCount != argumentCount) { throw 'It called $methodName with $actualArgumentCount argument${actualArgumentCount == 1 ? "" : "s"}; expected $argumentCount.'; } @@ -925,7 +1129,8 @@ abstract class _DrawCommandPaintPredicate extends _PaintPredicate { if (strokeWidth != null && paintArgument.strokeWidth != strokeWidth) { throw 'It called $methodName with a paint whose strokeWidth, ${paintArgument.strokeWidth}, was not exactly the expected strokeWidth ($strokeWidth).'; } - if (hasMaskFilter != null && (paintArgument.maskFilter != null) != hasMaskFilter) { + if (hasMaskFilter != null && + (paintArgument.maskFilter != null) != hasMaskFilter) { if (hasMaskFilter!) { throw 'It called $methodName with a paint that did not have a mask filter, despite expecting one.'; } else { @@ -975,7 +1180,7 @@ class _OneParameterPaintPredicate extends _DrawCommandPaintPredicate { required double? strokeWidth, required bool? hasMaskFilter, required PaintingStyle? style, - }) : super( + }) : super( symbol, name, 2, @@ -1020,7 +1225,7 @@ class _TwoParameterPaintPredicate extends _DrawCommandPaintPredicate { required double? strokeWidth, required bool? hasMaskFilter, required PaintingStyle? style, - }) : super( + }) : super( symbol, name, 3, @@ -1069,28 +1274,40 @@ class _TwoParameterPaintPredicate extends _DrawCommandPaintPredicate { } class _RectPaintPredicate extends _OneParameterPaintPredicate { - _RectPaintPredicate({ Rect? rect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawRect, - 'a rectangle', - expected: rect, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _RectPaintPredicate( + {Rect? rect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) + : super( + #drawRect, + 'a rectangle', + expected: rect, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); } class _RRectPaintPredicate extends _DrawCommandPaintPredicate { - _RRectPaintPredicate({ this.rrect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawRRect, - 'a rounded rectangle', - 2, - 1, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _RRectPaintPredicate( + {this.rrect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) + : super( + #drawRRect, + 'a rounded rectangle', + 2, + 1, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final RRect? rrect; @@ -1100,18 +1317,18 @@ class _RRectPaintPredicate extends _DrawCommandPaintPredicate { const double eps = .0001; final RRect actual = arguments[0] as RRect; if (rrect != null && - ((actual.left - rrect!.left).abs() > eps || - (actual.right - rrect!.right).abs() > eps || - (actual.top - rrect!.top).abs() > eps || - (actual.bottom - rrect!.bottom).abs() > eps || - (actual.blRadiusX - rrect!.blRadiusX).abs() > eps || - (actual.blRadiusY - rrect!.blRadiusY).abs() > eps || - (actual.brRadiusX - rrect!.brRadiusX).abs() > eps || - (actual.brRadiusY - rrect!.brRadiusY).abs() > eps || - (actual.tlRadiusX - rrect!.tlRadiusX).abs() > eps || - (actual.tlRadiusY - rrect!.tlRadiusY).abs() > eps || - (actual.trRadiusX - rrect!.trRadiusX).abs() > eps || - (actual.trRadiusY - rrect!.trRadiusY).abs() > eps)) { + ((actual.left - rrect!.left).abs() > eps || + (actual.right - rrect!.right).abs() > eps || + (actual.top - rrect!.top).abs() > eps || + (actual.bottom - rrect!.bottom).abs() > eps || + (actual.blRadiusX - rrect!.blRadiusX).abs() > eps || + (actual.blRadiusY - rrect!.blRadiusY).abs() > eps || + (actual.brRadiusX - rrect!.brRadiusX).abs() > eps || + (actual.brRadiusY - rrect!.brRadiusY).abs() > eps || + (actual.tlRadiusX - rrect!.tlRadiusX).abs() > eps || + (actual.tlRadiusY - rrect!.tlRadiusY).abs() > eps || + (actual.trRadiusX - rrect!.trRadiusX).abs() > eps || + (actual.trRadiusY - rrect!.trRadiusY).abs() > eps)) { throw 'It called $methodName with RRect, $actual, which was not exactly the expected RRect ($rrect).'; } } @@ -1126,22 +1343,44 @@ class _RRectPaintPredicate extends _DrawCommandPaintPredicate { } class _DRRectPaintPredicate extends _TwoParameterPaintPredicate { - _DRRectPaintPredicate({ RRect? inner, RRect? outer, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawDRRect, - 'a rounded rectangle outline', - expected1: outer, - expected2: inner, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _DRRectPaintPredicate( + {RRect? inner, + RRect? outer, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) + : super( + #drawDRRect, + 'a rounded rectangle outline', + expected1: outer, + expected2: inner, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); } class _CirclePaintPredicate extends _DrawCommandPaintPredicate { - _CirclePaintPredicate({ this.x, this.y, this.radius, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawCircle, 'a circle', 3, 2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, - ); + _CirclePaintPredicate( + {this.x, + this.y, + this.radius, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) + : super( + #drawCircle, + 'a circle', + 3, + 2, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final double? x; final double? y; @@ -1190,9 +1429,23 @@ class _CirclePaintPredicate extends _DrawCommandPaintPredicate { } class _PathPaintPredicate extends _DrawCommandPaintPredicate { - _PathPaintPredicate({ this.includes, this.excludes, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawPath, 'a path', 2, 1, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, - ); + _PathPaintPredicate( + {this.includes, + this.excludes, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) + : super( + #drawPath, + 'a path', + 2, + 1, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final Iterable? includes; final Iterable? excludes; @@ -1232,9 +1485,23 @@ class _PathPaintPredicate extends _DrawCommandPaintPredicate { // TODO(ianh): add arguments to test the length, angle, that kind of thing class _LinePaintPredicate extends _DrawCommandPaintPredicate { - _LinePaintPredicate({ this.p1, this.p2, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawLine, 'a line', 3, 2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, - ); + _LinePaintPredicate( + {this.p1, + this.p2, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) + : super( + #drawLine, + 'a line', + 3, + 2, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final Offset? p1; final Offset? p2; @@ -1268,13 +1535,30 @@ class _LinePaintPredicate extends _DrawCommandPaintPredicate { } class _ArcPaintPredicate extends _DrawCommandPaintPredicate { - _ArcPaintPredicate({ Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawArc, 'an arc', 5, 4, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, - ); + _ArcPaintPredicate( + {Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) + : super( + #drawArc, + 'an arc', + 5, + 4, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); } class _ShadowPredicate extends _PaintPredicate { - _ShadowPredicate({ this.includes, this.excludes, this.color, this.elevation, this.transparentOccluder }); + _ShadowPredicate( + {this.includes, + this.excludes, + this.color, + this.elevation, + this.transparentOccluder}); final Iterable? includes; final Iterable? excludes; @@ -1314,7 +1598,8 @@ class _ShadowPredicate extends _PaintPredicate { throw 'It called $methodName with an elevation, $actualElevation, which was not exactly the expected value ($elevation).'; } final bool actualTransparentOccluder = arguments[3] as bool; - if (transparentOccluder != null && actualTransparentOccluder != transparentOccluder) { + if (transparentOccluder != null && + actualTransparentOccluder != transparentOccluder) { throw 'It called $methodName with a transparentOccluder value, $actualTransparentOccluder, which was not exactly the expected value ($transparentOccluder).'; } } @@ -1359,9 +1644,24 @@ class _ShadowPredicate extends _PaintPredicate { } class _DrawImagePaintPredicate extends _DrawCommandPaintPredicate { - _DrawImagePaintPredicate({ this.image, this.x, this.y, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawImage, 'an image', 3, 2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, - ); + _DrawImagePaintPredicate( + {this.image, + this.x, + this.y, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) + : super( + #drawImage, + 'an image', + 3, + 2, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final ui.Image? image; final double? x; @@ -1410,9 +1710,24 @@ class _DrawImagePaintPredicate extends _DrawCommandPaintPredicate { } class _DrawImageRectPaintPredicate extends _DrawCommandPaintPredicate { - _DrawImageRectPaintPredicate({ this.image, this.source, this.destination, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawImageRect, 'an image', 4, 3, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, - ); + _DrawImageRectPaintPredicate( + {this.image, + this.source, + this.destination, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style}) + : super( + #drawImageRect, + 'an image', + 4, + 3, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final ui.Image? image; final Rect? source; @@ -1462,14 +1777,15 @@ class _SomethingPaintPredicate extends _PaintPredicate { do { if (testedAllCalls) { throw 'It painted methods that the predicate passed to a "something" step, ' - 'in the paint pattern, none of which were considered correct.'; + 'in the paint pattern, none of which were considered correct.'; } currentCall = call.current; if (!currentCall.invocation.isMethod) { throw 'It called $currentCall, which was not a method, when the paint pattern expected a method call'; } testedAllCalls = !call.moveNext(); - } while (!_runPredicate(currentCall.invocation.memberName, currentCall.invocation.positionalArguments)); + } while (!_runPredicate(currentCall.invocation.memberName, + currentCall.invocation.positionalArguments)); } bool _runPredicate(Symbol methodName, List arguments) { @@ -1477,7 +1793,7 @@ class _SomethingPaintPredicate extends _PaintPredicate { return predicate(methodName, arguments); } on String catch (s) { throw 'It painted something that the predicate passed to a "something" step ' - 'in the paint pattern considered incorrect:\n $s\n '; + 'in the paint pattern considered incorrect:\n $s\n '; } } @@ -1497,9 +1813,10 @@ class _EverythingPaintPredicate extends _PaintPredicate { if (!currentCall.invocation.isMethod) { throw 'It called $currentCall, which was not a method, when the paint pattern expected a method call'; } - if (!_runPredicate(currentCall.invocation.memberName, currentCall.invocation.positionalArguments)) { + if (!_runPredicate(currentCall.invocation.memberName, + currentCall.invocation.positionalArguments)) { throw 'It painted something that the predicate passed to an "everything" step ' - 'in the paint pattern considered incorrect.\n'; + 'in the paint pattern considered incorrect.\n'; } } while (call.moveNext()); } @@ -1509,7 +1826,7 @@ class _EverythingPaintPredicate extends _PaintPredicate { return predicate(methodName, arguments); } on String catch (s) { throw 'It painted something that the predicate passed to an "everything" step ' - 'in the paint pattern considered incorrect:\n $s\n '; + 'in the paint pattern considered incorrect:\n $s\n '; } } @@ -1527,11 +1844,13 @@ class _FunctionPaintPredicate extends _PaintPredicate { @override void match(Iterator call) { checkMethod(call, symbol); - if (call.current.invocation.positionalArguments.length != arguments.length) { + if (call.current.invocation.positionalArguments.length != + arguments.length) { throw 'It called ${_symbolName(symbol)} with ${call.current.invocation.positionalArguments.length} arguments; expected ${arguments.length}.'; } for (int index = 0; index < arguments.length; index += 1) { - final dynamic actualArgument = call.current.invocation.positionalArguments[index]; + final dynamic actualArgument = + call.current.invocation.positionalArguments[index]; final dynamic desiredArgument = arguments[index]; if (desiredArgument is Matcher) { diff --git a/test/recording_canvas.dart b/test/recording_canvas.dart index 76872c78..d2bd2f33 100644 --- a/test/recording_canvas.dart +++ b/test/recording_canvas.dart @@ -9,7 +9,7 @@ import 'package:flutter/rendering.dart'; /// Used by [TestRecordingCanvas] to trace canvas calls. class RecordedInvocation { /// Create a record for an invocation list. - const RecordedInvocation(this.invocation, { required this.stack }); + const RecordedInvocation(this.invocation, {required this.stack}); /// The method that was called and its arguments. /// @@ -28,9 +28,10 @@ class RecordedInvocation { /// Converts [stack] to a string using the [FlutterError.defaultStackFilter] logic. String stackToString({String indent = ''}) { - return indent + FlutterError.defaultStackFilter( - stack.toString().trimRight().split('\n'), - ).join('\n$indent'); + return indent + + FlutterError.defaultStackFilter( + stack.toString().trimRight().split('\n'), + ).join('\n$indent'); } } @@ -65,20 +66,24 @@ class TestRecordingCanvas implements Canvas { @override void save() { _saveCount += 1; - invocations.add(RecordedInvocation(_MethodCall(#save), stack: StackTrace.current)); + invocations + .add(RecordedInvocation(_MethodCall(#save), stack: StackTrace.current)); } @override void saveLayer(Rect? bounds, Paint paint) { _saveCount += 1; - invocations.add(RecordedInvocation(_MethodCall(#saveLayer, [bounds, paint]), stack: StackTrace.current)); + invocations.add(RecordedInvocation( + _MethodCall(#saveLayer, [bounds, paint]), + stack: StackTrace.current)); } @override void restore() { _saveCount -= 1; assert(_saveCount >= 0); - invocations.add(RecordedInvocation(_MethodCall(#restore), stack: StackTrace.current)); + invocations.add( + RecordedInvocation(_MethodCall(#restore), stack: StackTrace.current)); } @override @@ -88,7 +93,8 @@ class TestRecordingCanvas implements Canvas { } /// A [PaintingContext] for tests that use [TestRecordingCanvas]. -class TestRecordingPaintingContext extends ClipContext implements PaintingContext { +class TestRecordingPaintingContext extends ClipContext + implements PaintingContext { /// Creates a [PaintingContext] for tests that use [TestRecordingCanvas]. TestRecordingPaintingContext(this.canvas); @@ -109,7 +115,8 @@ class TestRecordingPaintingContext extends ClipContext implements PaintingContex Clip clipBehavior = Clip.hardEdge, ClipRectLayer? oldLayer, }) { - clipRectAndPaint(clipRect.shift(offset), clipBehavior, clipRect.shift(offset), () => painter(this, offset)); + clipRectAndPaint(clipRect.shift(offset), clipBehavior, + clipRect.shift(offset), () => painter(this, offset)); return null; } @@ -123,7 +130,8 @@ class TestRecordingPaintingContext extends ClipContext implements PaintingContex Clip clipBehavior = Clip.antiAlias, ClipRRectLayer? oldLayer, }) { - clipRRectAndPaint(clipRRect.shift(offset), clipBehavior, bounds.shift(offset), () => painter(this, offset)); + clipRRectAndPaint(clipRRect.shift(offset), clipBehavior, + bounds.shift(offset), () => painter(this, offset)); return null; } @@ -137,7 +145,8 @@ class TestRecordingPaintingContext extends ClipContext implements PaintingContex Clip clipBehavior = Clip.antiAlias, ClipPathLayer? oldLayer, }) { - clipPathAndPaint(clipPath.shift(offset), clipBehavior, bounds.shift(offset), () => painter(this, offset)); + clipPathAndPaint(clipPath.shift(offset), clipBehavior, bounds.shift(offset), + () => painter(this, offset)); return null; } @@ -180,11 +189,11 @@ class TestRecordingPaintingContext extends ClipContext implements PaintingContex } @override - void noSuchMethod(Invocation invocation) { } + void noSuchMethod(Invocation invocation) {} } class _MethodCall implements Invocation { - _MethodCall(this._name, [ this._arguments = const []]); + _MethodCall(this._name, [this._arguments = const []]); final Symbol _name; final List _arguments; @override @@ -202,7 +211,7 @@ class _MethodCall implements Invocation { @override List get positionalArguments => _arguments; @override - List get typeArguments => const []; + List get typeArguments => const []; } String _valueName(Object? value) { From d114f8716058928105cc98c0ea0bad345f2ca754 Mon Sep 17 00:00:00 2001 From: Alfred Schilken Date: Sat, 11 Feb 2023 10:59:49 +0100 Subject: [PATCH 08/11] Update CHANGELOG.md Co-authored-by: Reuben Turner --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b25e487..da9c5875 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ Other changes * Update `MacosScrollBar.thumbVisibility` with the latest change introduced in Flutter 3.7 * Update `README.md` to address issues [#325](https://github.com/GroovinChip/macos_ui/issues/325) & [#332](https://github.com/GroovinChip/macos_ui/issues/332) -* Fixed a bug where `CapacityIndicator` did only work correctly for splits = 10 +* Fixed a bug where `CapacityIndicator` only worked correctly for splits = 10 ## [1.7.6] From 6f948c13a2f6bd073ad9d42bbd12301f52acd444 Mon Sep 17 00:00:00 2001 From: Alfred Schilken Date: Sat, 11 Feb 2023 11:14:26 +0100 Subject: [PATCH 09/11] format indicators_page.dart, run flutter pub get to update lock files --- example/lib/pages/indicators_page.dart | 2 +- example/pubspec.lock | 98 +++++---- pubspec.lock | 263 +++++++++++++++++-------- 3 files changed, 247 insertions(+), 116 deletions(-) diff --git a/example/lib/pages/indicators_page.dart b/example/lib/pages/indicators_page.dart index 317e3a0c..e5923d2d 100644 --- a/example/lib/pages/indicators_page.dart +++ b/example/lib/pages/indicators_page.dart @@ -41,7 +41,7 @@ class _IndicatorsPageState extends State { CapacityIndicator( value: sliderValue, onChanged: (v) => setState(() => sliderValue = v), - splits: 20, + splits: 20, discrete: true, ), const SizedBox(height: 20), diff --git a/example/pubspec.lock b/example/pubspec.lock index 2e43425c..dfe71d4c 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,49 +5,56 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted version: "1.2.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" flutter: @@ -59,7 +66,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted version: "2.0.1" flutter_test: @@ -67,11 +75,20 @@ packages: description: flutter source: sdk version: "0.0.0" + js: + dependency: transitive + description: + name: js + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" + source: hosted + version: "0.6.5" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" source: hosted version: "2.0.1" macos_ui: @@ -85,42 +102,48 @@ packages: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted version: "1.8.0" nested: dependency: transitive description: name: nested - url: "https://pub.dartlang.org" + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" source: hosted version: "1.0.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted version: "1.8.2" provider: dependency: "direct main" description: name: provider - url: "https://pub.dartlang.org" + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" source: hosted version: "6.0.5" sky_engine: @@ -132,51 +155,58 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.4.16" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" sdks: - dart: ">=2.17.0 <3.0.0" + dart: ">=2.18.0 <4.0.0" flutter: ">=1.20.0" diff --git a/pubspec.lock b/pubspec.lock index 0315814a..0682b11c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,126 +5,144 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + sha256: d976d24314f193899a3079b14fe336215a63a3b1e1c3743eabba8f83e049e9a9 + url: "https://pub.dev" source: hosted - version: "47.0.0" + version: "49.0.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + sha256: "40ba2c6d2ab41a66476f8f1f099da6be0795c1b47221f5e2c5f8ad6048cdffae" + url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "5.1.0" analyzer_plugin: dependency: transitive description: name: analyzer_plugin - url: "https://pub.dartlang.org" + sha256: c1d5f167683de03d5ab6c3b53fc9aeefc5d59476e7810ba7bbddff50c6f4392d + url: "https://pub.dev" source: hosted - version: "0.10.0" + version: "0.11.2" ansicolor: dependency: transitive description: name: ansicolor - url: "https://pub.dartlang.org" + sha256: "607f8fa9786f392043f169898923e6c59b4518242b68b8862eb8a8b7d9c30b4a" + url: "https://pub.dev" source: hosted version: "2.0.1" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611" + url: "https://pub.dev" source: hosted version: "2.3.2" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted version: "1.2.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" source: hosted version: "3.1.1" coverage: dependency: transitive description: name: coverage - url: "https://pub.dartlang.org" + sha256: "961c4aebd27917269b1896382c7cb1b1ba81629ba669ba09c27a7e5710ec9040" + url: "https://pub.dev" source: hosted version: "1.6.2" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" source: hosted version: "3.0.2" csslib: dependency: transitive description: name: csslib - url: "https://pub.dartlang.org" + sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 + url: "https://pub.dev" source: hosted version: "0.17.2" dart_code_metrics: dependency: "direct dev" description: name: dart_code_metrics - url: "https://pub.dartlang.org" + sha256: "219607f5abbf4c0d254ca39ee009f9ff28df91c40aef26718fde15af6b7a6c24" + url: "https://pub.dev" source: hosted - version: "4.19.2" + version: "4.21.3" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" + url: "https://pub.dev" source: hosted version: "2.2.4" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" source: hosted version: "6.1.4" flutter: @@ -136,7 +154,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted version: "2.0.1" flutter_test: @@ -148,168 +167,232 @@ packages: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "3.2.0" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + url: "https://pub.dev" source: hosted version: "2.1.1" html: dependency: transitive description: name: html - url: "https://pub.dartlang.org" + sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 + url: "https://pub.dev" source: hosted version: "0.15.1" + http: + dependency: transitive + description: + name: http + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" + source: hosted + version: "0.13.5" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" source: hosted version: "4.0.2" io: dependency: transitive description: name: io - url: "https://pub.dartlang.org" + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" source: hosted version: "1.0.4" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted version: "0.6.5" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 + url: "https://pub.dev" + source: hosted + version: "4.8.0" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" source: hosted version: "2.0.1" logging: dependency: transitive description: name: logging - url: "https://pub.dartlang.org" + sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" + url: "https://pub.dev" source: hosted version: "1.1.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted version: "1.8.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" source: hosted version: "1.0.4" mocktail: dependency: "direct dev" description: name: mocktail - url: "https://pub.dartlang.org" + sha256: "80a996cd9a69284b3dc521ce185ffe9150cde69767c2d3a0720147d93c0cef53" + url: "https://pub.dev" source: hosted version: "0.3.0" node_preamble: dependency: transitive description: name: node_preamble - url: "https://pub.dartlang.org" + sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d" + url: "https://pub.dev" source: hosted version: "2.0.1" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" source: hosted version: "2.1.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted version: "1.8.2" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + url: "https://pub.dev" source: hosted version: "5.1.0" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" source: hosted version: "1.5.1" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dartlang.org" + sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + url: "https://pub.dev" source: hosted version: "2.1.3" + pub_updater: + dependency: transitive + description: + name: pub_updater + sha256: "42890302ab2672adf567dc2b20e55b4ecc29d7e19c63b6b98143ab68dd717d3a" + url: "https://pub.dev" + source: hosted + version: "0.2.4" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + url: "https://pub.dev" source: hosted version: "1.4.0" shelf_packages_handler: dependency: transitive description: name: shelf_packages_handler - url: "https://pub.dartlang.org" + sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306 + url: "https://pub.dev" source: hosted version: "3.0.1" shelf_static: dependency: transitive description: name: shelf_static - url: "https://pub.dartlang.org" + sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c + url: "https://pub.dev" source: hosted version: "1.1.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + url: "https://pub.dev" source: hosted version: "1.0.3" sky_engine: @@ -321,128 +404,146 @@ packages: dependency: transitive description: name: source_map_stack_trace - url: "https://pub.dartlang.org" + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" source: hosted version: "2.1.1" source_maps: dependency: transitive description: name: source_maps - url: "https://pub.dartlang.org" + sha256: "490098075234dcedb83c5d949b4c93dad5e6b7702748de000be2b57b8e6b2427" + url: "https://pub.dev" source: hosted version: "0.10.11" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test: dependency: transitive description: name: test - url: "https://pub.dartlang.org" + sha256: a5fcd2d25eeadbb6589e80198a47d6a464ba3e2049da473943b8af9797900c2d + url: "https://pub.dev" source: hosted - version: "1.21.4" + version: "1.22.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.4.16" test_core: dependency: transitive description: name: test_core - url: "https://pub.dartlang.org" + sha256: "0ef9755ec6d746951ba0aabe62f874b707690b5ede0fecc818b138fcc9b14888" + url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.4.20" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" source: hosted version: "1.3.1" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" vm_service: dependency: transitive description: name: vm_service - url: "https://pub.dartlang.org" + sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 + url: "https://pub.dev" source: hosted version: "9.4.0" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + url: "https://pub.dev" source: hosted version: "1.0.2" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b + url: "https://pub.dev" source: hosted version: "2.3.0" webkit_inspection_protocol: dependency: transitive description: name: webkit_inspection_protocol - url: "https://pub.dartlang.org" + sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + url: "https://pub.dev" source: hosted version: "1.2.0" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" + url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.2.2" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + url: "https://pub.dev" source: hosted version: "3.1.1" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=2.18.0 <4.0.0" flutter: ">=1.20.0" From fbb990deb3ce7c1cbbc3d902d01b0d4f0771a5fa Mon Sep 17 00:00:00 2001 From: Alfred Schilken Date: Sat, 11 Feb 2023 11:21:32 +0100 Subject: [PATCH 10/11] set dart < 3.0.0 --- example/pubspec.lock | 2 +- pubspec.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index dfe71d4c..45cafbfa 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -208,5 +208,5 @@ packages: source: hosted version: "2.1.4" sdks: - dart: ">=2.18.0 <4.0.0" + dart: ">=2.18.0 <3.0.0" flutter: ">=1.20.0" diff --git a/pubspec.lock b/pubspec.lock index 0682b11c..eb16ba9a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -545,5 +545,5 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=2.18.0 <4.0.0" + dart: ">=2.18.0 <3.0.0" flutter: ">=1.20.0" From d2275f700ea9cb8d84170a523c4b7bc8ff0928fb Mon Sep 17 00:00:00 2001 From: Alfred Schilken Date: Sat, 11 Feb 2023 11:24:20 +0100 Subject: [PATCH 11/11] revert change of spec checksums in Podfile.lock --- example/macos/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index d0136fe3..90ae1621 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -14,7 +14,7 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/macos_ui/macos SPEC CHECKSUMS: - FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811 + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 macos_ui: 125c911559d646194386d84c017ad6819122e2db PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7