From 21f03ca800840bdcada886c05b22182a9493764a Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Mon, 29 Jan 2024 21:57:48 -0300 Subject: [PATCH 1/8] Create StyledImage --- lib/mix.dart | 1 + lib/src/attributes/scalars/scalar_util.dart | 35 +++++++ lib/src/specs/image/image_attribute.dart | 28 +++++- lib/src/specs/image/image_spec.dart | 43 +++++++- lib/src/specs/image/image_util.dart | 25 +++++ lib/src/specs/image/image_widget.dart | 94 ++++++++++++++++++ pubspec.yaml | 3 + .../src/specs/image/image_attribute_test.dart | 14 ++- test/src/specs/image/image_spec_test.dart | 37 ++++++- test/src/specs/image/image_widget_test.dart | 68 +++++++++++++ test_resources/logo.png | Bin 0 -> 14240 bytes 11 files changed, 337 insertions(+), 11 deletions(-) create mode 100644 lib/src/specs/image/image_widget.dart create mode 100644 test/src/specs/image/image_widget_test.dart create mode 100644 test_resources/logo.png diff --git a/lib/mix.dart b/lib/mix.dart index 0db6fc50e..fe133a4ba 100644 --- a/lib/mix.dart +++ b/lib/mix.dart @@ -57,6 +57,7 @@ export 'src/specs/icon/icon_widget.dart'; export 'src/specs/image/image_attribute.dart'; export 'src/specs/image/image_spec.dart'; export 'src/specs/image/image_util.dart'; +export 'src/specs/image/image_widget.dart'; export 'src/specs/stack/stack_attribute.dart'; export 'src/specs/stack/stack_spec.dart'; export 'src/specs/stack/stack_util.dart'; diff --git a/lib/src/attributes/scalars/scalar_util.dart b/lib/src/attributes/scalars/scalar_util.dart index 57a121ef9..c385903a9 100644 --- a/lib/src/attributes/scalars/scalar_util.dart +++ b/lib/src/attributes/scalars/scalar_util.dart @@ -782,3 +782,38 @@ class TextAlignUtility T start() => _builder(TextAlign.start); T end() => _builder(TextAlign.end); } + +class RectUtility extends ScalarUtility { + const RectUtility(super.builder); + T largest() => _builder(Rect.largest); + T zero() => _builder(Rect.zero); + + T fromCenter({ + required Offset center, + required double width, + required double height, + }) => + _builder(Rect.fromCenter(center: center, width: width, height: height)); + + T fromLTRB(double left, double top, double right, double bottom) => + _builder(Rect.fromLTRB(left, top, right, bottom)); + + T fromLTWH(double left, double top, double width, double height) => + _builder(Rect.fromLTWH(left, top, width, height)); + + T fromCircle({required Offset center, required double radius}) => + _builder(Rect.fromCircle(center: center, radius: radius)); + + T fromPoints({required Offset a, required Offset b}) => + _builder(Rect.fromPoints(a, b)); +} + +class FilterQualityUtility + extends ScalarUtility { + const FilterQualityUtility(super.builder); + + T none() => _builder(FilterQuality.none); + T low() => _builder(FilterQuality.low); + T medium() => _builder(FilterQuality.medium); + T high() => _builder(FilterQuality.high); +} diff --git a/lib/src/specs/image/image_attribute.dart b/lib/src/specs/image/image_attribute.dart index d4d5bb26f..14bcaf1b9 100644 --- a/lib/src/specs/image/image_attribute.dart +++ b/lib/src/specs/image/image_attribute.dart @@ -11,13 +11,21 @@ class ImageSpecAttribute extends SpecAttribute { final ColorDto? color; final ImageRepeat? repeat; final BoxFit? fit; + final AlignmentGeometry? alignment; + final Rect? centerSlice; + final FilterQuality? filterQuality; + final BlendMode? colorBlendMode; const ImageSpecAttribute({ + this.centerSlice, this.width, this.height, this.color, this.repeat, this.fit, + this.alignment, + this.colorBlendMode, + this.filterQuality, }); @override @@ -28,6 +36,10 @@ class ImageSpecAttribute extends SpecAttribute { color: color?.resolve(mix), repeat: repeat, fit: fit, + alignment: alignment, + centerSlice: centerSlice, + filterQuality: filterQuality, + colorBlendMode: colorBlendMode, ); } @@ -41,9 +53,23 @@ class ImageSpecAttribute extends SpecAttribute { color: other.color ?? color, repeat: other.repeat ?? repeat, fit: other.fit ?? fit, + alignment: other.alignment ?? alignment, + centerSlice: other.centerSlice ?? centerSlice, + filterQuality: other.filterQuality ?? filterQuality, + colorBlendMode: other.colorBlendMode ?? colorBlendMode, ); } @override - get props => [width, height, color, repeat, fit]; + get props => [ + width, + height, + color, + repeat, + fit, + centerSlice, + alignment, + filterQuality, + colorBlendMode, + ]; } diff --git a/lib/src/specs/image/image_spec.dart b/lib/src/specs/image/image_spec.dart index d1534a72f..8e3c2078f 100644 --- a/lib/src/specs/image/image_spec.dart +++ b/lib/src/specs/image/image_spec.dart @@ -13,6 +13,10 @@ class ImageSpec extends Spec { final Color? color; final ImageRepeat? repeat; final BoxFit? fit; + final AlignmentGeometry? alignment; + final Rect? centerSlice; + final FilterQuality? filterQuality; + final BlendMode? colorBlendMode; const ImageSpec({ required this.width, @@ -20,6 +24,10 @@ class ImageSpec extends Spec { required this.color, required this.repeat, required this.fit, + required this.alignment, + required this.centerSlice, + required this.filterQuality, + required this.colorBlendMode, }); const ImageSpec.empty() @@ -27,12 +35,15 @@ class ImageSpec extends Spec { height = null, color = null, repeat = null, + alignment = null, + centerSlice = null, + filterQuality = FilterQuality.none, + colorBlendMode = BlendMode.clear, fit = null; - static ImageSpec resolve(MixData mix) { - final recipe = mix.attributeOf()?.resolve(mix); - - return recipe ?? const ImageSpecAttribute().resolve(mix); + static ImageSpec of(MixData mix) { + return mix.attributeOf()?.resolve(mix) ?? + const ImageSpec.empty(); } @override @@ -43,6 +54,10 @@ class ImageSpec extends Spec { color: Color.lerp(color, other?.color, t), repeat: t < 0.5 ? repeat : other?.repeat, fit: t < 0.5 ? fit : other?.fit, + centerSlice: Rect.lerp(centerSlice, other?.centerSlice, t), + filterQuality: t < 0.5 ? filterQuality : other?.filterQuality, + colorBlendMode: t < 0.5 ? colorBlendMode : other?.colorBlendMode, + alignment: AlignmentGeometry.lerp(alignment, other?.alignment, t), ); } @@ -54,6 +69,10 @@ class ImageSpec extends Spec { Color? color, ImageRepeat? repeat, BoxFit? fit, + AlignmentGeometry? alignment, + Rect? centerSlice, + FilterQuality? filterQuality, + BlendMode? colorBlendMode, }) { return ImageSpec( width: width ?? this.width, @@ -61,9 +80,23 @@ class ImageSpec extends Spec { color: color ?? this.color, repeat: repeat ?? this.repeat, fit: fit ?? this.fit, + centerSlice: centerSlice ?? this.centerSlice, + alignment: alignment ?? this.alignment, + filterQuality: filterQuality ?? this.filterQuality, + colorBlendMode: colorBlendMode ?? this.colorBlendMode, ); } @override - get props => [width, height, color, repeat, fit]; + get props => [ + width, + height, + color, + repeat, + fit, + centerSlice, + alignment, + filterQuality, + colorBlendMode, + ]; } diff --git a/lib/src/specs/image/image_util.dart b/lib/src/specs/image/image_util.dart index e804265a5..739c02f82 100644 --- a/lib/src/specs/image/image_util.dart +++ b/lib/src/specs/image/image_util.dart @@ -16,6 +16,10 @@ class ImageUtility extends SpecUtility { ColorDto? color, ImageRepeat? repeat, BoxFit? fit, + AlignmentGeometry? alignment, + Rect? centerSlice, + BlendMode? blendMode, + FilterQuality? filterQuality, }) { return ImageSpecAttribute( width: width, @@ -23,6 +27,10 @@ class ImageUtility extends SpecUtility { color: color, repeat: repeat, fit: fit, + alignment: alignment, + centerSlice: centerSlice, + colorBlendMode: blendMode, + filterQuality: filterQuality, ); } @@ -45,4 +53,21 @@ class ImageUtility extends SpecUtility { DoubleUtility get height { return DoubleUtility((height) => _only(height: height)); } + + AlignmentUtility get alignment { + return AlignmentUtility((alignment) => _only(alignment: alignment)); + } + + RectUtility get centerSlice { + return RectUtility((rect) => _only(centerSlice: rect)); + } + + FilterQualityUtility get filterQuality { + return FilterQualityUtility( + (filterQuality) => _only(filterQuality: filterQuality)); + } + + BlendModeUtility get blendMode { + return BlendModeUtility((blendMode) => _only(blendMode: blendMode)); + } } diff --git a/lib/src/specs/image/image_widget.dart b/lib/src/specs/image/image_widget.dart new file mode 100644 index 000000000..761d185c4 --- /dev/null +++ b/lib/src/specs/image/image_widget.dart @@ -0,0 +1,94 @@ +import 'package:flutter/material.dart'; + +import '../../core/styled_widget.dart'; +import '../../factory/mix_provider.dart'; +import '../../factory/mix_provider_data.dart'; +import '../../utils/helper_util.dart'; +import 'image_spec.dart'; + +class StyledImage extends StyledWidget { + final ImageProvider image; + final ImageFrameBuilder? frameBuilder; + final ImageLoadingBuilder? loadingBuilder; + final ImageErrorWidgetBuilder? errorBuilder; + final String? semanticLabel; + final bool excludeFromSemantics; + + const StyledImage({ + super.key, + super.style, + this.frameBuilder, + this.loadingBuilder, + this.errorBuilder, + this.semanticLabel, + this.excludeFromSemantics = false, + required this.image, + }); + + @override + Widget build(BuildContext context) { + return withMix(context, (mix) { + return MixedImage( + image: image, + errorBuilder: errorBuilder, + excludeFromSemantics: excludeFromSemantics, + frameBuilder: frameBuilder, + loadingBuilder: loadingBuilder, + semanticLabel: semanticLabel, + ); + }); + } +} + +class MixedImage extends StatelessWidget { + const MixedImage({ + super.key, + this.decoratorOrder = const [], + this.mix, + required this.image, + this.frameBuilder, + this.loadingBuilder, + this.errorBuilder, + this.semanticLabel, + this.excludeFromSemantics = false, + }); + + final MixData? mix; + final ImageProvider image; + final ImageFrameBuilder? frameBuilder; + final ImageLoadingBuilder? loadingBuilder; + final ImageErrorWidgetBuilder? errorBuilder; + final String? semanticLabel; + final bool excludeFromSemantics; + final List decoratorOrder; + + @override + Widget build(BuildContext context) { + final mix = this.mix ?? MixProvider.of(context); + final spec = ImageSpec.of(mix); + + final current = Image( + image: image, + frameBuilder: frameBuilder, + loadingBuilder: loadingBuilder, + errorBuilder: errorBuilder, + semanticLabel: semanticLabel, + excludeFromSemantics: excludeFromSemantics, + width: spec.width, + height: spec.height, + color: spec.color, + repeat: spec.repeat ?? ImageRepeat.noRepeat, + fit: spec.fit, + alignment: spec.alignment ?? Alignment.center, + centerSlice: spec.centerSlice, + filterQuality: spec.filterQuality ?? FilterQuality.none, + colorBlendMode: spec.colorBlendMode ?? BlendMode.clear, + ); + + return shouldApplyDecorators( + mix: mix, + orderOfDecorators: decoratorOrder, + child: current, + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 6a6c328cf..06f9a05e1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,3 +22,6 @@ dev_dependencies: mockito: ^5.4.2 meta: ^1.9.1 +flutter: + assets: + - test_resources/ diff --git a/test/src/specs/image/image_attribute_test.dart b/test/src/specs/image/image_attribute_test.dart index 7c83aafc0..7cd4fbdcc 100644 --- a/test/src/specs/image/image_attribute_test.dart +++ b/test/src/specs/image/image_attribute_test.dart @@ -52,18 +52,26 @@ void main() { const attribute = ImageSpecAttribute( width: 100, height: 200, - color: ColorDto(Colors.red), + color: ColorDto(Colors.black), repeat: ImageRepeat.repeat, fit: BoxFit.cover, + alignment: Alignment.bottomCenter, + centerSlice: Rect.zero, + filterQuality: FilterQuality.low, + colorBlendMode: BlendMode.srcOver, ); final props = attribute.props; - expect(props.length, 5); + expect(props.length, 9); expect(props[0], 100); expect(props[1], 200); - expect(props[2], const ColorDto(Colors.red)); + expect(props[2], const ColorDto(Colors.black)); expect(props[3], ImageRepeat.repeat); expect(props[4], BoxFit.cover); + expect(props[5], Rect.zero); + expect(props[6], Alignment.bottomCenter); + expect(props[7], FilterQuality.low); + expect(props[8], BlendMode.srcOver); }); }); } diff --git a/test/src/specs/image/image_spec_test.dart b/test/src/specs/image/image_spec_test.dart index 61300fd92..41a6cd681 100644 --- a/test/src/specs/image/image_spec_test.dart +++ b/test/src/specs/image/image_spec_test.dart @@ -9,7 +9,7 @@ import '../../../helpers/testing_utils.dart'; void main() { group('ImageSpec', () { test('resolve returns correct recipe', () { - final recipe = ImageSpec.resolve(EmptyMixData); + final recipe = ImageSpec.of(EmptyMixData); expect(recipe.width, null); expect(recipe.height, null); @@ -25,6 +25,10 @@ void main() { color: Colors.red, repeat: ImageRepeat.repeat, fit: BoxFit.cover, + alignment: Alignment.bottomCenter, + centerSlice: Rect.zero, + filterQuality: FilterQuality.low, + colorBlendMode: BlendMode.srcOver, ); const spec2 = ImageSpec( width: 150, @@ -32,6 +36,10 @@ void main() { color: Colors.blue, repeat: ImageRepeat.noRepeat, fit: BoxFit.fill, + alignment: Alignment.bottomCenter, + centerSlice: Rect.fromLTRB(0, 0, 0, 0), + filterQuality: FilterQuality.high, + colorBlendMode: BlendMode.colorBurn, ); final lerpSpec = spec1.lerp(spec2, 0.5); @@ -40,6 +48,10 @@ void main() { expect(lerpSpec.color, Color.lerp(Colors.red, Colors.blue, 0.5)); expect(lerpSpec.repeat, ImageRepeat.noRepeat); expect(lerpSpec.fit, BoxFit.fill); + expect(lerpSpec.alignment, Alignment.bottomCenter); + expect(lerpSpec.centerSlice, const Rect.fromLTRB(0, 0, 0, 0)); + expect(lerpSpec.filterQuality, FilterQuality.high); + expect(lerpSpec.colorBlendMode, BlendMode.colorBurn); }); test('copyWith returns correct ImageSpec', () { @@ -49,6 +61,10 @@ void main() { color: Colors.red, repeat: ImageRepeat.repeat, fit: BoxFit.cover, + alignment: Alignment.bottomCenter, + centerSlice: Rect.fromLTRB(0, 0, 0, 0), + filterQuality: FilterQuality.low, + colorBlendMode: BlendMode.srcOver, ); final copiedSpec = spec.copyWith( width: 150, @@ -56,6 +72,10 @@ void main() { color: Colors.blue, repeat: ImageRepeat.noRepeat, fit: BoxFit.fill, + alignment: Alignment.topCenter, + centerSlice: Rect.zero, + filterQuality: FilterQuality.none, + colorBlendMode: BlendMode.clear, ); expect(copiedSpec.width, 150); @@ -63,6 +83,10 @@ void main() { expect(copiedSpec.color, Colors.blue); expect(copiedSpec.repeat, ImageRepeat.noRepeat); expect(copiedSpec.fit, BoxFit.fill); + expect(copiedSpec.alignment, Alignment.topCenter); + expect(copiedSpec.centerSlice, Rect.zero); + expect(copiedSpec.filterQuality, FilterQuality.none); + expect(copiedSpec.colorBlendMode, BlendMode.clear); }); test('props returns correct list of properties', () { @@ -72,15 +96,24 @@ void main() { color: Colors.red, repeat: ImageRepeat.repeat, fit: BoxFit.cover, + alignment: Alignment.bottomCenter, + centerSlice: Rect.zero, + filterQuality: FilterQuality.low, + colorBlendMode: BlendMode.srcOver, ); + final props = spec.props; - expect(props.length, 5); + expect(props.length, 9); expect(props[0], 100); expect(props[1], 200); expect(props[2], Colors.red); expect(props[3], ImageRepeat.repeat); expect(props[4], BoxFit.cover); + expect(props[5], Rect.zero); + expect(props[6], Alignment.bottomCenter); + expect(props[7], FilterQuality.low); + expect(props[8], BlendMode.srcOver); }); }); } diff --git a/test/src/specs/image/image_widget_test.dart b/test/src/specs/image/image_widget_test.dart new file mode 100644 index 000000000..8cffd883e --- /dev/null +++ b/test/src/specs/image/image_widget_test.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +void main() { + group('StyledImage', () { + testWidgets('receive all the attributes', (WidgetTester tester) async { + TestWidgetsFlutterBinding.ensureInitialized(); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: StyledImage( + style: Style( + image.width(152), + image.height(152), + image.color.black(), + image.repeat.repeat(), + image.fit.fill(), + image.centerSlice.fromLTRB(1, 2, 3, 4), + image.alignment.bottomLeft(), + image.filterQuality.high(), + image.blendMode.colorDodge(), + ), + image: const AssetImage('test_resources/logo.png'), + ), + ), + ), + ); + + final imageWidget = tester.element(find.byType(Image)).widget as Image; + + expect(imageWidget.width, 152); + expect(imageWidget.height, 152); + expect(imageWidget.color, Colors.black); + expect(imageWidget.repeat, ImageRepeat.repeat); + expect(imageWidget.fit, BoxFit.fill); + expect(imageWidget.centerSlice, const Rect.fromLTRB(1, 2, 3, 4)); + expect(imageWidget.alignment, Alignment.bottomLeft); + expect(imageWidget.filterQuality, FilterQuality.high); + expect(imageWidget.colorBlendMode, BlendMode.colorDodge); + }); + + testWidgets('can receive a decorator', (WidgetTester tester) async { + TestWidgetsFlutterBinding.ensureInitialized(); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: StyledImage( + style: Style( + image.width(152), + image.height(152), + opacity(0.5), + ), + image: const AssetImage('test_resources/logo.png'), + ), + ), + ), + ); + + final opacityWidget = + tester.element(find.byType(Opacity)).widget as Opacity; + + expect(opacityWidget.opacity, 0.5); + }); + }); +} diff --git a/test_resources/logo.png b/test_resources/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..157e9adf9a2471c3b6f1becbb2314889e07b91b2 GIT binary patch literal 14240 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 Date: Mon, 29 Jan 2024 22:31:27 -0300 Subject: [PATCH 2/8] create documentation --- website/pages/docs/widgets/icon.mdx | 2 +- website/pages/docs/widgets/image.mdx | 107 ++++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 5 deletions(-) diff --git a/website/pages/docs/widgets/icon.mdx b/website/pages/docs/widgets/icon.mdx index 5646800b0..3a67f1b51 100644 --- a/website/pages/docs/widgets/icon.mdx +++ b/website/pages/docs/widgets/icon.mdx @@ -18,7 +18,7 @@ StyledIcon( ## Inheritance -The **StyledIcon** widget has the `inherit` flag set to `true` by default. This means that the style attributes will be inherited from its closest `Mix` ancestor in the widget tree. +The **StyledIcon** widget has the `inherit` flag set to `true` by default. This means that the style attributes will be inherited from its closest `Style` ancestor in the widget tree. ```dart Box( diff --git a/website/pages/docs/widgets/image.mdx b/website/pages/docs/widgets/image.mdx index c52d49cfa..e1d4dde5a 100644 --- a/website/pages/docs/widgets/image.mdx +++ b/website/pages/docs/widgets/image.mdx @@ -6,8 +6,107 @@ import { Callout } from "nextra-theme-docs"; # StyleImage - - The StyledImage is in progress, if you would like to keep up to date with the progress. - +A wrapped `Image` widget that can be easily themed and styled using Mix style attributes. This simplifies the process of applying consistent and reusable styling across `Image` widgets. + +## Usage + +To use `StyledImage`, you need to pass the `ImageProvider` and apply the style using the `Style` class. + +```dart +StyledImage( + image: const AssetImage('assets/image.jpg'), + style: Style( + image.width(152), + image.height(152), + image.fit.fill(), + image.alignment.bottomLeft(), + image.blendMode.colorDodge(), + ), +), +``` + +## Inheritance + +The **StyledImage** widget has the `inherit` flag set to `true` by default. This means that the style attributes will be inherited from its closest `Style` ancestor in the widget tree. + +```dart +Box( + Style( + image.height(30), + image.color.blue(), + ), + child: StyledImage(image: const AssetImage('some_image.jpg')), +); +``` + +In the this example, the `StyledImage` widget will inherit the image height and color from the `Box` widget. However, remember that decorators attributes cannot be inherited. + +## Utilities + +The `image` constant alias is an instance of `ImageUtility`, which facilitates the construction of `ImageSpec` attributes. These attributes are used to style and manage properties of image widgets. + +#### **color** + +Change the color of the image: + +```dart +// Apply a color to the image +image.color.red(); +``` + +#### **width** +Specifies the width of the image. + +```dart +image.width(100); +``` + +#### **height** +Specifies the height of the image. + +```dart +image.height(100); +``` + +#### **repeat** +Determines how the image should be repeated over the space of the widget. + +```dart +image.repeat.repeat(); +``` + +#### **fit** +Defines how the image should be inscribed into the space allocated during layout. + +```dart +image.fit.cover(); +``` + +#### **alignment** +Specifies the alignment of the image within its bounds. + +```dart +image.alignment.center(); +``` + +#### **centerSlice** +Slices the image for nine-patch effects. + +```dart +image.centerSlice.fromLTWH(10, 10, 20, 20); +``` + +#### **blendMode** +Specifies the blending mode applied to the image's color and the underlying widget's color. + +```dart +image.blendMode.multiply(); +``` + +#### **filterQuality** +Determines the quality of the filtering operations applied to the image. + +```dart +image.filterQuality.high(); +``` -please follow the StyledImage issue. \ No newline at end of file From fd257dcd38993cde2e4ebb2282ec4ef5d4d667da Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Mon, 29 Jan 2024 22:37:55 -0300 Subject: [PATCH 3/8] support to inherit --- lib/src/specs/image/image_widget.dart | 1 + test/src/specs/image/image_widget_test.dart | 28 ++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/lib/src/specs/image/image_widget.dart b/lib/src/specs/image/image_widget.dart index 761d185c4..49bbcd96c 100644 --- a/lib/src/specs/image/image_widget.dart +++ b/lib/src/specs/image/image_widget.dart @@ -17,6 +17,7 @@ class StyledImage extends StyledWidget { const StyledImage({ super.key, super.style, + super.inherit = true, this.frameBuilder, this.loadingBuilder, this.errorBuilder, diff --git a/test/src/specs/image/image_widget_test.dart b/test/src/specs/image/image_widget_test.dart index 8cffd883e..22bbfd755 100644 --- a/test/src/specs/image/image_widget_test.dart +++ b/test/src/specs/image/image_widget_test.dart @@ -4,9 +4,9 @@ import 'package:mix/mix.dart'; void main() { group('StyledImage', () { - testWidgets('receive all the attributes', (WidgetTester tester) async { - TestWidgetsFlutterBinding.ensureInitialized(); + TestWidgetsFlutterBinding.ensureInitialized(); + testWidgets('receive all the attributes', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -42,8 +42,6 @@ void main() { }); testWidgets('can receive a decorator', (WidgetTester tester) async { - TestWidgetsFlutterBinding.ensureInitialized(); - await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -64,5 +62,27 @@ void main() { expect(opacityWidget.opacity, 0.5); }); + + testWidgets('can inherit style from the parent StyledWidget', + (WidgetTester tester) async { + await tester.pumpWidget( + Box( + style: Style( + image.width(152), + image.height(152), + image.color.black(), + ), + child: const StyledImage( + image: AssetImage('test_resources/logo.png'), + ), + ), + ); + + final imageWidget = tester.element(find.byType(Image)).widget as Image; + + expect(imageWidget.width, 152); + expect(imageWidget.height, 152); + expect(imageWidget.color, Colors.black); + }); }); } From 4abb5fca27a9e3dc448d14d99d0c2c1f7e296f76 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:15:07 -0300 Subject: [PATCH 4/8] solve comment about lerp --- lib/src/specs/image/image_spec.dart | 11 ++++++----- pubspec.lock | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/src/specs/image/image_spec.dart b/lib/src/specs/image/image_spec.dart index 8e3c2078f..eddadf80a 100644 --- a/lib/src/specs/image/image_spec.dart +++ b/lib/src/specs/image/image_spec.dart @@ -5,6 +5,7 @@ import 'package:flutter/widgets.dart'; import '../../core/attribute.dart'; import '../../factory/mix_provider_data.dart'; +import '../../helpers/lerp_helpers.dart'; import 'image_attribute.dart'; @immutable @@ -52,11 +53,11 @@ class ImageSpec extends Spec { width: lerpDouble(width, other?.width, t), height: lerpDouble(height, other?.height, t), color: Color.lerp(color, other?.color, t), - repeat: t < 0.5 ? repeat : other?.repeat, - fit: t < 0.5 ? fit : other?.fit, - centerSlice: Rect.lerp(centerSlice, other?.centerSlice, t), - filterQuality: t < 0.5 ? filterQuality : other?.filterQuality, - colorBlendMode: t < 0.5 ? colorBlendMode : other?.colorBlendMode, + centerSlice: lerpSnap(centerSlice, other?.centerSlice, t), + repeat: lerpSnap(repeat, other?.repeat, t), + fit: lerpSnap(fit, other?.fit, t), + filterQuality: lerpSnap(filterQuality, other?.filterQuality, t), + colorBlendMode: lerpSnap(colorBlendMode, other?.colorBlendMode, t), alignment: AlignmentGeometry.lerp(alignment, other?.alignment, t), ); } diff --git a/pubspec.lock b/pubspec.lock index 5196db178..857e63c88 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -529,4 +529,4 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0 <4.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" From 747fa1baf5c5f957eaded2e4326739bde3e5b424 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:29:29 -0300 Subject: [PATCH 5/8] solve comments --- test/src/specs/image/image_attribute_test.dart | 1 - test/src/specs/image/image_widget_test.dart | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/src/specs/image/image_attribute_test.dart b/test/src/specs/image/image_attribute_test.dart index 7cd4fbdcc..2626f5f52 100644 --- a/test/src/specs/image/image_attribute_test.dart +++ b/test/src/specs/image/image_attribute_test.dart @@ -62,7 +62,6 @@ void main() { ); final props = attribute.props; - expect(props.length, 9); expect(props[0], 100); expect(props[1], 200); expect(props[2], const ColorDto(Colors.black)); diff --git a/test/src/specs/image/image_widget_test.dart b/test/src/specs/image/image_widget_test.dart index 22bbfd755..b672477b1 100644 --- a/test/src/specs/image/image_widget_test.dart +++ b/test/src/specs/image/image_widget_test.dart @@ -15,7 +15,7 @@ void main() { image.width(152), image.height(152), image.color.black(), - image.repeat.repeat(), + image.imageRepeat.repeat(), image.fit.fill(), image.centerSlice.fromLTRB(1, 2, 3, 4), image.alignment.bottomLeft(), From e2824e927b01dc9c29b36554990935ab98c53e64 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:36:20 -0300 Subject: [PATCH 6/8] Update image_util.dart --- lib/src/specs/image/image_util.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/specs/image/image_util.dart b/lib/src/specs/image/image_util.dart index 739c02f82..3f0939236 100644 --- a/lib/src/specs/image/image_util.dart +++ b/lib/src/specs/image/image_util.dart @@ -38,7 +38,7 @@ class ImageUtility extends SpecUtility { return ColorUtility((color) => _only(color: color)); } - ImageRepeatUtility get repeat { + ImageRepeatUtility get imageRepeat { return ImageRepeatUtility((repeat) => _only(repeat: repeat)); } From 9b570ccd257c08d6639f26501fffdb9ccd65f18a Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Wed, 31 Jan 2024 15:48:35 -0300 Subject: [PATCH 7/8] add a call method in ImageRepeatUtility --- lib/src/attributes/scalars/scalar_util.dart | 6 ++++-- lib/src/specs/image/image_util.dart | 2 +- test/src/specs/image/image_widget_test.dart | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/src/attributes/scalars/scalar_util.dart b/lib/src/attributes/scalars/scalar_util.dart index c385903a9..a1e7c896a 100644 --- a/lib/src/attributes/scalars/scalar_util.dart +++ b/lib/src/attributes/scalars/scalar_util.dart @@ -443,10 +443,12 @@ class FontFamilyUtility /// ``` /// See [ImageRepeat] for more information. class ImageRepeatUtility - extends ScalarUtility { + extends MixUtility { const ImageRepeatUtility(super.builder); + + T call() => builder(ImageRepeat.repeat); + T noRepeat() => builder(ImageRepeat.noRepeat); - T repeat() => builder(ImageRepeat.repeat); T repeatX() => builder(ImageRepeat.repeatX); T repeatY() => builder(ImageRepeat.repeatY); } diff --git a/lib/src/specs/image/image_util.dart b/lib/src/specs/image/image_util.dart index 3f0939236..739c02f82 100644 --- a/lib/src/specs/image/image_util.dart +++ b/lib/src/specs/image/image_util.dart @@ -38,7 +38,7 @@ class ImageUtility extends SpecUtility { return ColorUtility((color) => _only(color: color)); } - ImageRepeatUtility get imageRepeat { + ImageRepeatUtility get repeat { return ImageRepeatUtility((repeat) => _only(repeat: repeat)); } diff --git a/test/src/specs/image/image_widget_test.dart b/test/src/specs/image/image_widget_test.dart index b672477b1..b6394c036 100644 --- a/test/src/specs/image/image_widget_test.dart +++ b/test/src/specs/image/image_widget_test.dart @@ -15,7 +15,7 @@ void main() { image.width(152), image.height(152), image.color.black(), - image.imageRepeat.repeat(), + image.repeat(), image.fit.fill(), image.centerSlice.fromLTRB(1, 2, 3, 4), image.alignment.bottomLeft(), From 1dd0a179bf18bd0c8645006a34d1f7667c2d6827 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Wed, 31 Jan 2024 15:49:50 -0300 Subject: [PATCH 8/8] Update scalar_util_test.dart --- test/src/attributes/scalars/scalar_util_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/attributes/scalars/scalar_util_test.dart b/test/src/attributes/scalars/scalar_util_test.dart index 2f8638347..030bdb04e 100644 --- a/test/src/attributes/scalars/scalar_util_test.dart +++ b/test/src/attributes/scalars/scalar_util_test.dart @@ -162,11 +162,11 @@ void main() { const utility = ImageRepeatUtility(UtilityTestAttribute.new); test('Properties are initialized correctly', () { expect(utility.noRepeat().value, isA()); - expect(utility.repeat().value, isA()); + expect(utility().value, isA()); expect(utility.repeatX().value, isA()); expect(utility.repeatY().value, isA()); expect(utility.noRepeat().value, ImageRepeat.noRepeat); - expect(utility.repeat().value, ImageRepeat.repeat); + expect(utility().value, ImageRepeat.repeat); expect(utility.repeatX().value, ImageRepeat.repeatX); expect(utility.repeatY().value, ImageRepeat.repeatY); });