1. 01 Feb, 2024 22 commits
    • David Martos's avatar
      Fix gen_defaults test randomness (#142743) · d242d136
      David Martos authored
      This PR improves the gen_defaults tests to not be tied to a particular order of execution.
      Since there is a global class that holds the state of the used/not used tokens, we need to clear this logger before each test.
      
      Fixes https://github.com/flutter/flutter/issues/142716
      
      cc @zanderso @QuncCccccc 
      
      *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
      d242d136
    • auto-submit[bot]'s avatar
      Reverts "Added ButtonStyle.foregroundBuilder and ButtonStyle.backgroundBuilder" (#142748) · 07ca92a6
      auto-submit[bot] authored
      Reverts flutter/flutter#141818
      Initiated by: XilaiZhang
      This change reverts the following previous change:
      Original Description:
      Fixes https://github.com/flutter/flutter/issues/139456, https://github.com/flutter/flutter/issues/130335, https://github.com/flutter/flutter/issues/89563.
      
      Two new properties have been added to ButtonStyle to make it possible to insert arbitrary state-dependent widgets in a button's background or foreground. These properties can be specified for an individual button, using the style parameter, or for all buttons using a button theme's style parameter.
      
      The new ButtonStyle properties are `backgroundBuilder` and `foregroundBuilder` and their (function) types are:
      
      ```dart
      typedef ButtonLayerBuilder = Widget Function(
        BuildContext context,
        Set<MaterialState> states,
        Widget? child
      );
      ```
      
      The new builder functions are called whenever the button is built and the `states` parameter communicates the pressed/hovered/etc state fo the button.
      
      ## `backgroundBuilder`
      
      Creates a widget that becomes the child of the button's Material and whose child is the rest of the button, including the button's `child` parameter.  By default the returned widget is clipped to the Material's ButtonStyle.shape.
      
      The `backgroundBuilder` can be used to add a gradient to the button's background. Here's an example that creates a yellow/orange gradient background:
      
      ![opaque-gradient-bg](https://github.com/flutter/flutter/assets/1377460/80df8368-e7cf-49ef-aee7-2776a573644c)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            return DecoratedBox(
              decoration: BoxDecoration(
                gradient: LinearGradient(colors: [Colors.orange, Colors.yellow]),
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      Because the background widget becomes the child of the button's Material, if it's opaque (as it is in this case) then it obscures the overlay highlights which are painted on the button's Material. To ensure that the highlights show through one can decorate the background with an `Ink` widget.  This version also overrides the overlay color to be (shades of) red, because that makes the highlights look a little nicer with the yellow/orange background.
      
      ![ink-gradient-bg](https://github.com/flutter/flutter/assets/1377460/68a49733-f30e-44a1-a948-dc8cc95e1716)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          overlayColor: Colors.red,
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            return Ink(
              decoration: BoxDecoration(
                gradient: LinearGradient(colors: [Colors.orange, Colors.yellow]),
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      Now the button's overlay highlights are painted on the Ink widget. An Ink widget isn't needed if the background is sufficiently translucent. This version of the example creates a translucent backround widget. 
      
      ![translucent-graident-bg](https://github.com/flutter/flutter/assets/1377460/3b016e1f-200a-4d07-8111-e20d29f18014)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          overlayColor: Colors.red,
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            return DecoratedBox(
              decoration: BoxDecoration(
                gradient: LinearGradient(colors: [
                  Colors.orange.withOpacity(0.5),
                  Colors.yellow.withOpacity(0.5),
                ]),
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      One can also decorate the background with an image. In this example, the button's background is an burlap texture image. The foreground color has been changed to black to make the button's text a little clearer relative to the mottled brown backround.
      
      ![burlap-bg](https://github.com/flutter/flutter/assets/1377460/f2f61ab1-10d9-43a4-bd63-beecdce33b45)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          foregroundColor: Colors.black,
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            return Ink(
              decoration: BoxDecoration(
                image: DecorationImage(
                  image: NetworkImage(burlapUrl),
                  fit: BoxFit.cover,
                ),
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      The background widget can depend on the `states` parameter. In this example the blue/orange gradient flips horizontally when the button is hovered/pressed.
      
      ![gradient-flip](https://github.com/flutter/flutter/assets/1377460/c6c6fe26-ae47-445b-b82d-4605d9583bd8)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            final Color color1 = Colors.blue.withOpacity(0.5);
            final Color color2 = Colors.orange.withOpacity(0.5);
            return DecoratedBox(
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  colors: switch (states.contains(MaterialState.hovered)) {
                    true => <Color>[color1, color2],
                    false => <Color>[color2, color1],
                  },
                ),
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      The preceeding examples have not included a BoxDecoration border because ButtonStyle already supports `ButtonStyle.shape` and `ButtonStyle.side` parameters that can be uesd to define state-dependent borders. Borders defined with the ButtonStyle side parameter match the button's shape. To add a border that changes color when the button is hovered or pressed, one must specify the side property using `copyWith`, since there's no `styleFrom` shorthand for this case.
      
      ![border-gradient-bg](https://github.com/flutter/flutter/assets/1377460/63cffcd3-0dcf-4eb1-aed5-d14adf1e57f6)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          foregroundColor: Colors.indigo,
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            final Color color1 = Colors.blue.withOpacity(0.5);
            final Color color2 = Colors.orange.withOpacity(0.5);
            return DecoratedBox(
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  colors: switch (states.contains(MaterialState.hovered)) {
                    true => <Color>[color1, color2],
                    false => <Color>[color2, color1],
                  },
                ),
              ),
              child: child,
            );
          },
        ).copyWith(
          side: MaterialStateProperty.resolveWith<BorderSide?>((Set<MaterialState> states) {
            if (states.contains(MaterialState.hovered)) {
              return BorderSide(width: 3, color: Colors.yellow);
            }
            return null; // defer to the default
          }),
        ),
        child: Text('Text Button'),
      )
      ```
      
      Although all of the examples have created a ButtonStyle locally and only applied it to one button, they could have configured the `ThemeData.textButtonTheme` instead and applied the style to all TextButtons. And, of course, all of this works for all of the ButtonStyleButton classes, not just TextButton.
      
      ## `foregroundBuilder`
      
      Creates a Widget that contains the button's child parameter. The returned widget is clipped by the button's [ButtonStyle.shape] inset by the button's [ButtonStyle.padding] and aligned by the button's [ButtonStyle.alignment].
      
      The `foregroundBuilder` can be used to wrap the button's child, e.g. with a border or a `ShaderMask` or as a state-dependent substitute for the child.
      
      This example adds a border that's just applied to the child. The border only appears when the button is hovered/pressed.
      
      ![border-fg](https://github.com/flutter/flutter/assets/1377460/687a3245-fe68-4983-a04e-5fcc77f8aa21)
      
      ```dart
      ElevatedButton(
        onPressed: () {},
        style: ElevatedButton.styleFrom(
          foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            final ColorScheme colorScheme = Theme.of(context).colorScheme;
            return DecoratedBox(
              decoration: BoxDecoration(
                border: states.contains(MaterialState.hovered)
                  ? Border(bottom: BorderSide(color: colorScheme.primary))
                  : Border(), // essentially "no border"
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      The foregroundBuilder can be used with `ShaderMask` to change the way the button's child is rendered. In this example the ShaderMask's gradient causes the button's child to fade out on top.
      
      ![shader_mask_fg](https://github.com/flutter/flutter/assets/1377460/54010f24-e65d-4551-ae58-712135df3d8d)
      
      ```dart
      ElevatedButton(
        onPressed: () { },
        style: ElevatedButton.styleFrom(
          foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            final ColorScheme colorScheme = Theme.of(context).colorScheme;
            return ShaderMask(
              shaderCallback: (Rect bounds) {
                return LinearGradient(
                  begin: Alignment.bottomCenter,
                  end: Alignment.topCenter,
                  colors: <Color>[
                    colorScheme.primary,
                    colorScheme.primaryContainer,
                  ],
                ).createShader(bounds);
              },
              blendMode: BlendMode.srcATop,
              child: child,
            );
          },
        ),
        child:  const Text('Elevated Button'),
      )
      ```
      
      A commonly requested configuration for butttons has the developer provide images, one for pressed/hovered/normal state. You can use the foregroundBuilder to create a button that fades between a normal image and another image when the button is pressed. In this case the foregroundBuilder doesn't use the child it's passed, even though we've provided the required TextButton child parameter.
      
      ![image-button](https://github.com/flutter/flutter/assets/1377460/f5b1a22f-43ce-4be3-8e70-06de4c958380)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            final String url = states.contains(MaterialState.pressed) ? smiley2Url : smiley1Url;
            return AnimatedContainer(
              width: 100,
              height: 100,
              duration: Duration(milliseconds: 300),
              decoration: BoxDecoration(
                image: DecorationImage(
                  image: NetworkImage(url),
                  fit: BoxFit.contain,
                ),
              ),
            );
          },
        ),
        child: Text('No Child'),
      )
      ```
      
      In this example the button's default overlay appears when the button is hovered and pressed. Another image can be used to indicate the hovered state and the default overlay can be defeated by specifying `Colors.transparent` for the `overlayColor`:
      
      ![image-per-state](https://github.com/flutter/flutter/assets/1377460/7ab9da2f-f661-4374-b395-c2e0c7c4cf13)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          overlayColor: Colors.transparent,
          foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            String url = states.contains(MaterialState.hovered) ? smiley3Url : smiley1Url;
            if (states.contains(MaterialState.pressed)) {
              url = smiley2Url;
            }
            return AnimatedContainer(
              width: 100,
              height: 100,
              duration: Duration(milliseconds: 300),
              decoration: BoxDecoration(
                image: DecorationImage(
                  image: NetworkImage(url),
                  fit: BoxFit.contain,
                ),
              ),
            );
          },
        ),
        child: Text('No Child'),
      )
      ```
      07ca92a6
    • engine-flutter-autoroll's avatar
      Roll Flutter Engine from 39415c3eed42 to 9beb7e82e081 (5 revisions) (#142745) · bf735d70
      engine-flutter-autoroll authored
      https://github.com/flutter/engine/compare/39415c3eed42...9beb7e82e081
      
      2024-02-01 30870216+gaaclarke@users.noreply.github.com [Impeller] new blur: round downsample to power of two (flutter/engine#50245)
      2024-02-01 john@johnmccutchan.com Provide a more helpful error message in the case of UnsatisfiedLinkError (flutter/engine#50247)
      2024-02-01 jonahwilliams@google.com Update expected golden number. (flutter/engine#50249)
      2024-02-01 jonahwilliams@google.com [Impeller] remove drawPicture from Aiks Canvas. (flutter/engine#50242)
      2024-02-01 737941+loic-sharma@users.noreply.github.com Reland "[Windows] Introduce egl::Surface and egl::WindowSurface" (flutter/engine#50148)
      
      If this roll has caused a breakage, revert this CL and stop the roller
      using the controls here:
      https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
      Please CC matanl@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
      is aware of the problem.
      
      To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose
      
      To report a problem with the AutoRoller itself, please file a bug:
      https://issues.skia.org/issues/new?component=1389291&template=1850622
      
      Documentation for the AutoRoller is here:
      https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
      bf735d70
    • Jenn Magder's avatar
    • Polina Cherkasova's avatar
      Fix leaks in tests. (#142677) · fdf05c90
      Polina Cherkasova authored
      fdf05c90
    • engine-flutter-autoroll's avatar
      Roll Flutter Engine from 8c43332c6ffc to 39415c3eed42 (1 revision) (#142740) · e91f530b
      engine-flutter-autoroll authored
      https://github.com/flutter/engine/compare/8c43332c6ffc...39415c3eed42
      
      2024-02-01 30870216+gaaclarke@users.noreply.github.com [Impeller] added an assert that goldens are generated (flutter/engine#50222)
      
      If this roll has caused a breakage, revert this CL and stop the roller
      using the controls here:
      https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
      Please CC matanl@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
      is aware of the problem.
      
      To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose
      
      To report a problem with the AutoRoller itself, please file a bug:
      https://issues.skia.org/issues/new?component=1389291&template=1850622
      
      Documentation for the AutoRoller is here:
      https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
      e91f530b
    • Jenn Magder's avatar
    • Jenn Magder's avatar
      Remove outdated arm64_armv7 check (#142737) · 89d46db7
      Jenn Magder authored
      CI is running Xcode 15, remove outdated arm64_armv7 framework checks.
      89d46db7
    • Simone Stasi's avatar
      fix CupertinoTabView's Android back button handling with PopScope (#141604) · cd6ed395
      Simone Stasi authored
      This PR fixes CupertinoTabView's handling of Android back button with PopScope and nested navigators by calling `NavigatorState.maybePop` instead of `NavigatorState.pop`, so that the Navigator pops only when it should.
      
      Fix #139050
      cd6ed395
    • engine-flutter-autoroll's avatar
      Roll Flutter Engine from 68943afd62d1 to 8c43332c6ffc (8 revisions) (#142726) · 5f9bd7f0
      engine-flutter-autoroll authored
      https://github.com/flutter/engine/compare/68943afd62d1...8c43332c6ffc
      
      2024-02-01 zanderso@users.noreply.github.com Moves impeller/golden_tests_harvester to tools/golden_tests_harvester (flutter/engine#50211)
      2024-02-01 skia-flutter-autoroll@skia.org Roll Skia from 2386d5077ec5 to cdf214adfb4d (2 revisions) (flutter/engine#50239)
      2024-02-01 skia-flutter-autoroll@skia.org Roll Skia from 20578fecfc37 to 2386d5077ec5 (2 revisions) (flutter/engine#50238)
      2024-02-01 skia-flutter-autoroll@skia.org Roll Skia from 756276a133b1 to 20578fecfc37 (1 revision) (flutter/engine#50236)
      2024-02-01 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from nymRxHV9Shod7cyLe... to kvEXgoydRYnW3UvX2... (flutter/engine#50235)
      2024-02-01 bdero@google.com [Impeller] Assign incremental clip depth to all entities. (flutter/engine#49828)
      2024-02-01 skia-flutter-autoroll@skia.org Roll Skia from 505d22d0ecdc to 756276a133b1 (3 revisions) (flutter/engine#50232)
      2024-02-01 skia-flutter-autoroll@skia.org Roll Skia from bcbc172f74da to 505d22d0ecdc (1 revision) (flutter/engine#50230)
      
      Also rolling transitive DEPS:
        fuchsia/sdk/core/linux-amd64 from nymRxHV9Shod to kvEXgoydRYnW
      
      If this roll has caused a breakage, revert this CL and stop the roller
      using the controls here:
      https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
      Please CC matanl@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
      is aware of the problem.
      
      To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose
      
      To report a problem with the AutoRoller itself, please file a bug:
      https://issues.skia.org/issues/new?component=1389291&template=1850622
      
      Documentation for the AutoRoller is here:
      https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
      5f9bd7f0
    • Christopher Fujino's avatar
    • Zachary Anderson's avatar
    • Zachary Anderson's avatar
    • engine-flutter-autoroll's avatar
      Roll Flutter Engine from f4fbabf1eb9f to 68943afd62d1 (9 revisions) (#142690) · e02e2079
      engine-flutter-autoroll authored
      https://github.com/flutter/engine/compare/f4fbabf1eb9f...68943afd62d1
      
      2024-02-01 jason-simmons@users.noreply.github.com [Impeller] Clear the GPUTracerVK in_frame flag when ending a frame even if the tracer is disabled (flutter/engine#50228)
      2024-02-01 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Remove migration flag and unused header files" (flutter/engine#50229)
      2024-02-01 jonahwilliams@google.com [Impeller] size vk swapchain to window size. (flutter/engine#50205)
      2024-02-01 robert.ancell@canonical.com Remove string field from FlKeyEvent (flutter/engine#50189)
      2024-02-01 skia-flutter-autoroll@skia.org Roll Skia from 19e5e8f089b2 to bcbc172f74da (2 revisions) (flutter/engine#50226)
      2024-02-01 matanlurey@users.noreply.github.com Ignore CRLF endings when determining the names of header guards. (flutter/engine#50227)
      2024-02-01 jonahwilliams@google.com [Impeller] make GPU tracing off by default. (flutter/engine#50215)
      2024-02-01 dkwingsmt@users.noreply.github.com Multiview: Add view ID to _render and remove render rule skipping (flutter/engine#50220)
      2024-02-01 31859944+LongCatIsLooong@users.noreply.github.com Remove migration flag and unused header files (flutter/engine#50216)
      
      If this roll has caused a breakage, revert this CL and stop the roller
      using the controls here:
      https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
      Please CC matanl@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
      is aware of the problem.
      
      To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose
      
      To report a problem with the AutoRoller itself, please file a bug:
      https://issues.skia.org/issues/new?component=1389291&template=1850622
      
      Documentation for the AutoRoller is here:
      https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
      e02e2079
    • Qun Cheng's avatar
      Introduce tone-based surfaces and accent color add-ons - Part 1 (#142654) · 4d61823c
      Qun Cheng authored
      This PR is to add 19 new `ColorScheme` roles following the Material Design 3 specs. This PR doesn't apply the new colors to `ThemeData`  or any widgets.
      
      This PR is created to split the big change in #138521, once this is merged, another PR that contains the rest of the changes(apply new color roles to widgets and deprecate 3 more colors) will follow.
      
      **Tone-based surface colors** (7 colors): 
      * surfaceBright
      * surfaceDim
      * surfaceContainer
      * surfaceContainerLowest
      * surfaceContainerLow
      * surfaceContainerHigh
      * surfaceContainerHighest
      
      **Accent color add-ons** (12 colors):
      * primary/secondary/tertiary-Fixed
      * primary/secondary/tertiary-FixedDim
      * onPrimary/onSecondary/onTertiary-Fixed
      * onPrimary/onSecondary/onTertiary-FixedVariant
      
      Please checkout this [design doc](https://docs.google.com/document/d/1ODqivpM_6c490T4j5XIiWCDKo5YqHy78YEFqDm4S8h4/edit?usp=sharing) for more information:)
      4d61823c
    • Andrew Kolos's avatar
      31116770
    • engine-flutter-autoroll's avatar
      Roll Flutter Engine from c4247c5e31ba to f4fbabf1eb9f (1 revision) (#142675) · bdf2a748
      engine-flutter-autoroll authored
      https://github.com/flutter/engine/compare/c4247c5e31ba...f4fbabf1eb9f
      
      2024-01-31 chinmaygarde@google.com [Impeller] Implement framebuffer-fetch via subpasses in Vulkan without extensions. (flutter/engine#50154)
      
      If this roll has caused a breakage, revert this CL and stop the roller
      using the controls here:
      https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
      Please CC matanl@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
      is aware of the problem.
      
      To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose
      
      To report a problem with the AutoRoller itself, please file a bug:
      https://issues.skia.org/issues/new?component=1389291&template=1850622
      
      Documentation for the AutoRoller is here:
      https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
      bdf2a748
    • engine-flutter-autoroll's avatar
      Roll Flutter Engine from c83617eee093 to c4247c5e31ba (3 revisions) (#142662) · 9b46df72
      engine-flutter-autoroll authored
      https://github.com/flutter/engine/compare/c83617eee093...c4247c5e31ba
      
      2024-01-31 amyles@google.com Make screen reader announcement append a non-breaking space every other message. (flutter/engine#50151)
      2024-01-31 skia-flutter-autoroll@skia.org Roll Skia from 0ad5b2a9cebd to 19e5e8f089b2 (3 revisions) (flutter/engine#50214)
      2024-01-31 1961493+harryterkelsen@users.noreply.github.com [CanvasKit] Only render one frame at a time. (flutter/engine#50055)
      
      If this roll has caused a breakage, revert this CL and stop the roller
      using the controls here:
      https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
      Please CC matanl@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
      is aware of the problem.
      
      To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose
      
      To report a problem with the AutoRoller itself, please file a bug:
      https://issues.skia.org/issues/new?component=1389291&template=1850622
      
      Documentation for the AutoRoller is here:
      https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
      9b46df72
    • Jonah Williams's avatar
      [Impeller] opt vulkan tests into GPU tracing. (#142649) · 7208d3b7
      Jonah Williams authored
      We're going to disable GPU tracing by default. Opt our benchmarks back in so that we have continuity.
      7208d3b7
    • Greg Spencer's avatar
      Convert button `.icon` and `.tonalIcon` constructors to take nullable icons. (#142644) · 2652b9a3
      Greg Spencer authored
      ## Description
      
      This changes the factory constructors for `TextButton.icon`, `ElevatedButton.icon`, `FilledButton.icon`, and `FilledButton.tonalIcon` to take nullable icons. If the icon is null, then the "regular" version of the button is created.
      
      ## Tests
       - Added tests for all four constructors.
      2652b9a3
    • David Martos's avatar
      Fix token usages on Regular Chip and Action Chip (#141701) · b34ee073
      David Martos authored
      The regular chip and the action chip templates were referencing non existent M3 design tokens.
      
      Fixes https://github.com/flutter/flutter/issues/141288
      
      The `ActionChip` doesn't have any visual difference. Even though the template and file changes, the default `labelStyle` color already uses `onSurface`.
      For the reviewer, I've changed the `action_chip_test` to expect a color from the colorScheme so that it is more explicit that the color might not be the same as the labelLarge default in the global textTheme, even if for this case the color is the same.
      
      The regular `Chip` does have visual differences, in particular, the label and trailing icon colors, which were not following the specification. In order to fix this, the regular chip now is based from the `filter-chip` spec as described in the linked issue.
      
      ## Before
      
      ![image](https://github.com/flutter/flutter/assets/22084723/d602ef42-625a-4b5c-b63b-c46cb2070d80)
      
      ## After
      
      ![image](https://github.com/flutter/flutter/assets/22084723/dddb754f-fd29-4c4c-96cc-e7f508219f12)
      b34ee073
    • Hans Muller's avatar
      Added ButtonStyle.foregroundBuilder and ButtonStyle.backgroundBuilder (#141818) · ff6c8f5d
      Hans Muller authored
      Fixes https://github.com/flutter/flutter/issues/139456, https://github.com/flutter/flutter/issues/130335, https://github.com/flutter/flutter/issues/89563.
      
      Two new properties have been added to ButtonStyle to make it possible to insert arbitrary state-dependent widgets in a button's background or foreground. These properties can be specified for an individual button, using the style parameter, or for all buttons using a button theme's style parameter.
      
      The new ButtonStyle properties are `backgroundBuilder` and `foregroundBuilder` and their (function) types are:
      
      ```dart
      typedef ButtonLayerBuilder = Widget Function(
        BuildContext context,
        Set<MaterialState> states,
        Widget? child
      );
      ```
      
      The new builder functions are called whenever the button is built and the `states` parameter communicates the pressed/hovered/etc state fo the button.
      
      ## `backgroundBuilder`
      
      Creates a widget that becomes the child of the button's Material and whose child is the rest of the button, including the button's `child` parameter.  By default the returned widget is clipped to the Material's ButtonStyle.shape.
      
      The `backgroundBuilder` can be used to add a gradient to the button's background. Here's an example that creates a yellow/orange gradient background:
      
      ![opaque-gradient-bg](https://github.com/flutter/flutter/assets/1377460/80df8368-e7cf-49ef-aee7-2776a573644c)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            return DecoratedBox(
              decoration: BoxDecoration(
                gradient: LinearGradient(colors: [Colors.orange, Colors.yellow]),
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      Because the background widget becomes the child of the button's Material, if it's opaque (as it is in this case) then it obscures the overlay highlights which are painted on the button's Material. To ensure that the highlights show through one can decorate the background with an `Ink` widget.  This version also overrides the overlay color to be (shades of) red, because that makes the highlights look a little nicer with the yellow/orange background.
      
      ![ink-gradient-bg](https://github.com/flutter/flutter/assets/1377460/68a49733-f30e-44a1-a948-dc8cc95e1716)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          overlayColor: Colors.red,
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            return Ink(
              decoration: BoxDecoration(
                gradient: LinearGradient(colors: [Colors.orange, Colors.yellow]),
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      Now the button's overlay highlights are painted on the Ink widget. An Ink widget isn't needed if the background is sufficiently translucent. This version of the example creates a translucent backround widget. 
      
      ![translucent-graident-bg](https://github.com/flutter/flutter/assets/1377460/3b016e1f-200a-4d07-8111-e20d29f18014)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          overlayColor: Colors.red,
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            return DecoratedBox(
              decoration: BoxDecoration(
                gradient: LinearGradient(colors: [
                  Colors.orange.withOpacity(0.5),
                  Colors.yellow.withOpacity(0.5),
                ]),
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      One can also decorate the background with an image. In this example, the button's background is an burlap texture image. The foreground color has been changed to black to make the button's text a little clearer relative to the mottled brown backround.
      
      ![burlap-bg](https://github.com/flutter/flutter/assets/1377460/f2f61ab1-10d9-43a4-bd63-beecdce33b45)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          foregroundColor: Colors.black,
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            return Ink(
              decoration: BoxDecoration(
                image: DecorationImage(
                  image: NetworkImage(burlapUrl),
                  fit: BoxFit.cover,
                ),
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      The background widget can depend on the `states` parameter. In this example the blue/orange gradient flips horizontally when the button is hovered/pressed.
      
      ![gradient-flip](https://github.com/flutter/flutter/assets/1377460/c6c6fe26-ae47-445b-b82d-4605d9583bd8)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            final Color color1 = Colors.blue.withOpacity(0.5);
            final Color color2 = Colors.orange.withOpacity(0.5);
            return DecoratedBox(
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  colors: switch (states.contains(MaterialState.hovered)) {
                    true => <Color>[color1, color2],
                    false => <Color>[color2, color1],
                  },
                ),
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      The preceeding examples have not included a BoxDecoration border because ButtonStyle already supports `ButtonStyle.shape` and `ButtonStyle.side` parameters that can be uesd to define state-dependent borders. Borders defined with the ButtonStyle side parameter match the button's shape. To add a border that changes color when the button is hovered or pressed, one must specify the side property using `copyWith`, since there's no `styleFrom` shorthand for this case.
      
      ![border-gradient-bg](https://github.com/flutter/flutter/assets/1377460/63cffcd3-0dcf-4eb1-aed5-d14adf1e57f6)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          foregroundColor: Colors.indigo,
          backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            final Color color1 = Colors.blue.withOpacity(0.5);
            final Color color2 = Colors.orange.withOpacity(0.5);
            return DecoratedBox(
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  colors: switch (states.contains(MaterialState.hovered)) {
                    true => <Color>[color1, color2],
                    false => <Color>[color2, color1],
                  },
                ),
              ),
              child: child,
            );
          },
        ).copyWith(
          side: MaterialStateProperty.resolveWith<BorderSide?>((Set<MaterialState> states) {
            if (states.contains(MaterialState.hovered)) {
              return BorderSide(width: 3, color: Colors.yellow);
            }
            return null; // defer to the default
          }),
        ),
        child: Text('Text Button'),
      )
      ```
      
      Although all of the examples have created a ButtonStyle locally and only applied it to one button, they could have configured the `ThemeData.textButtonTheme` instead and applied the style to all TextButtons. And, of course, all of this works for all of the ButtonStyleButton classes, not just TextButton.
      
      ## `foregroundBuilder`
      
      Creates a Widget that contains the button's child parameter. The returned widget is clipped by the button's [ButtonStyle.shape] inset by the button's [ButtonStyle.padding] and aligned by the button's [ButtonStyle.alignment].
      
      The `foregroundBuilder` can be used to wrap the button's child, e.g. with a border or a `ShaderMask` or as a state-dependent substitute for the child.
      
      This example adds a border that's just applied to the child. The border only appears when the button is hovered/pressed.
      
      ![border-fg](https://github.com/flutter/flutter/assets/1377460/687a3245-fe68-4983-a04e-5fcc77f8aa21)
      
      ```dart
      ElevatedButton(
        onPressed: () {},
        style: ElevatedButton.styleFrom(
          foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            final ColorScheme colorScheme = Theme.of(context).colorScheme;
            return DecoratedBox(
              decoration: BoxDecoration(
                border: states.contains(MaterialState.hovered)
                  ? Border(bottom: BorderSide(color: colorScheme.primary))
                  : Border(), // essentially "no border"
              ),
              child: child,
            );
          },
        ),
        child: Text('Text Button'),
      )
      ```
      
      The foregroundBuilder can be used with `ShaderMask` to change the way the button's child is rendered. In this example the ShaderMask's gradient causes the button's child to fade out on top.
      
      ![shader_mask_fg](https://github.com/flutter/flutter/assets/1377460/54010f24-e65d-4551-ae58-712135df3d8d)
      
      ```dart
      ElevatedButton(
        onPressed: () { },
        style: ElevatedButton.styleFrom(
          foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            final ColorScheme colorScheme = Theme.of(context).colorScheme;
            return ShaderMask(
              shaderCallback: (Rect bounds) {
                return LinearGradient(
                  begin: Alignment.bottomCenter,
                  end: Alignment.topCenter,
                  colors: <Color>[
                    colorScheme.primary,
                    colorScheme.primaryContainer,
                  ],
                ).createShader(bounds);
              },
              blendMode: BlendMode.srcATop,
              child: child,
            );
          },
        ),
        child:  const Text('Elevated Button'),
      )
      ```
      
      A commonly requested configuration for butttons has the developer provide images, one for pressed/hovered/normal state. You can use the foregroundBuilder to create a button that fades between a normal image and another image when the button is pressed. In this case the foregroundBuilder doesn't use the child it's passed, even though we've provided the required TextButton child parameter.
      
      ![image-button](https://github.com/flutter/flutter/assets/1377460/f5b1a22f-43ce-4be3-8e70-06de4c958380)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            final String url = states.contains(MaterialState.pressed) ? smiley2Url : smiley1Url;
            return AnimatedContainer(
              width: 100,
              height: 100,
              duration: Duration(milliseconds: 300),
              decoration: BoxDecoration(
                image: DecorationImage(
                  image: NetworkImage(url),
                  fit: BoxFit.contain,
                ),
              ),
            );
          },
        ),
        child: Text('No Child'),
      )
      ```
      
      In this example the button's default overlay appears when the button is hovered and pressed. Another image can be used to indicate the hovered state and the default overlay can be defeated by specifying `Colors.transparent` for the `overlayColor`:
      
      ![image-per-state](https://github.com/flutter/flutter/assets/1377460/7ab9da2f-f661-4374-b395-c2e0c7c4cf13)
      
      ```dart
      TextButton(
        onPressed: () {},
        style: TextButton.styleFrom(
          overlayColor: Colors.transparent,
          foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
            String url = states.contains(MaterialState.hovered) ? smiley3Url : smiley1Url;
            if (states.contains(MaterialState.pressed)) {
              url = smiley2Url;
            }
            return AnimatedContainer(
              width: 100,
              height: 100,
              duration: Duration(milliseconds: 300),
              decoration: BoxDecoration(
                image: DecorationImage(
                  image: NetworkImage(url),
                  fit: BoxFit.contain,
                ),
              ),
            );
          },
        ),
        child: Text('No Child'),
      )
      ```
      ff6c8f5d
  2. 31 Jan, 2024 18 commits