Unverified Commit 2ac7536e authored by flutteractionsbot's avatar flutteractionsbot Committed by GitHub

[CP-stable]Enhance ColorScheme.fromSeed with a new `variant` parameter (#148916)

This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/wiki/Flutter-Cherrypick-Process#automatically-creates-a-cherry-pick-request)
Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request.

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

https://github.com/flutter/flutter/issues/148359

### Changelog Description:
Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/wiki/Hotfix-Documentation-Best-Practices) for examples

Provide an option in `ColorScheme.fromSeed` method to respect the seed color even if the seed color is very bright.

### Impact Description:
What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch)

The updated algorithm in `ColorScheme.fromSeed` creates a darker version of `ColorScheme`. This may result in apps looking different from their original color theme.

### Workaround:
Is there a workaround for this issue?

Manually construct a desired `ColorScheme` instead of using `ColorScheme.fromSeed`, or use the deprecated `Scheme` class in [MCU package](https://github.com/material-foundation/material-color-utilities/blob/main/dart/lib/scheme/scheme.dart) to build the `ColorScheme`

### Risk:
What is the risk level of this cherry-pick?

This cherry-pick does not break the current implementation but only provides an option if users want the `ColorScheme` built by `ColorScheme.fromSeed` respect the seed color.

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
What are the steps to validate that this fix works?

With `dynamicSchemeVariant: DynamicSchemeVariant.fidelity`, the color scheme constructed by `ColorScheme.fromSeed()` respects the seed color.
parent d8e72c6d
...@@ -19,95 +19,93 @@ class ColorSchemeExample extends StatefulWidget { ...@@ -19,95 +19,93 @@ class ColorSchemeExample extends StatefulWidget {
class _ColorSchemeExampleState extends State<ColorSchemeExample> { class _ColorSchemeExampleState extends State<ColorSchemeExample> {
Color selectedColor = ColorSeed.baseColor.color; Color selectedColor = ColorSeed.baseColor.color;
Brightness selectedBrightness = Brightness.light;
static const List<DynamicSchemeVariant> schemeVariants = DynamicSchemeVariant.values;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final Color? colorSeed = selectedColor == ColorSeed.baseColor.color ? null : selectedColor;
final ThemeData lightTheme = ThemeData(
colorSchemeSeed: colorSeed,
brightness: Brightness.light,
);
final ThemeData darkTheme = ThemeData(
colorSchemeSeed: colorSeed,
brightness: Brightness.dark,
);
Widget schemeLabel(String brightness) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Text(
brightness,
style: const TextStyle(fontWeight: FontWeight.bold),
),
);
}
Widget schemeView(ThemeData theme) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: ColorSchemeView(colorScheme: theme.colorScheme),
);
}
return MaterialApp( return MaterialApp(
theme: ThemeData(colorSchemeSeed: selectedColor), debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: selectedColor,
brightness: selectedBrightness,
)
),
home: Builder( home: Builder(
builder: (BuildContext context) => Scaffold( builder: (BuildContext context) => Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('ColorScheme'), title: const Text('ColorScheme'),
leading: MenuAnchor( actions: <Widget>[
builder: (BuildContext context, MenuController controller, Widget? widget) { Row(
return IconButton( children: <Widget>[
icon: Icon(Icons.circle, color: selectedColor), const Text('Color Seed'),
onPressed: () { MenuAnchor(
setState(() { builder: (BuildContext context, MenuController controller, Widget? widget) {
if (!controller.isOpen) { return IconButton(
controller.open(); icon: Icon(Icons.circle, color: selectedColor),
} onPressed: () {
}); setState(() {
}, if (!controller.isOpen) {
); controller.open();
}, }
menuChildren: List<Widget>.generate(ColorSeed.values.length, (int index) { });
final Color itemColor = ColorSeed.values[index].color; },
return MenuItemButton( );
leadingIcon: selectedColor == ColorSeed.values[index].color },
? Icon(Icons.circle, color: itemColor) menuChildren: List<Widget>.generate(ColorSeed.values.length, (int index) {
: Icon(Icons.circle_outlined, color: itemColor), final Color itemColor = ColorSeed.values[index].color;
onPressed: () { return MenuItemButton(
setState(() { leadingIcon: selectedColor == ColorSeed.values[index].color
selectedColor = itemColor; ? Icon(Icons.circle, color: itemColor)
}); : Icon(Icons.circle_outlined, color: itemColor),
}, onPressed: () {
child: Text(ColorSeed.values[index].label), setState(() {
); selectedColor = itemColor;
}), });
), },
child: Text(ColorSeed.values[index].label),
);
}),
),
],
),
],
), ),
body: SingleChildScrollView( body: SingleChildScrollView(
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 5), padding: const EdgeInsets.only(top: 5),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Row( Padding(
children: <Widget>[ padding: const EdgeInsets.symmetric(horizontal: 24.0),
Expanded( child: Row(
child: Column( children: <Widget>[
children: <Widget>[ const Text('Brightness'),
schemeLabel('Light ColorScheme'), const SizedBox(width: 10),
schemeView(lightTheme), Switch(
], value: selectedBrightness == Brightness.light,
), onChanged: (bool value) {
), setState(() {
Expanded( selectedBrightness = value ? Brightness.light : Brightness.dark;
child: Column( });
children: <Widget>[ },
schemeLabel('Dark ColorScheme'),
schemeView(darkTheme),
],
), ),
), ],
], ),
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List<Widget>.generate(schemeVariants.length, (int index) {
return ColorSchemeVariantColumn(
selectedColor: selectedColor,
brightness: selectedBrightness,
schemeVariant: schemeVariants[index],
);
}).toList(),
),
), ),
], ],
), ),
...@@ -119,6 +117,47 @@ class _ColorSchemeExampleState extends State<ColorSchemeExample> { ...@@ -119,6 +117,47 @@ class _ColorSchemeExampleState extends State<ColorSchemeExample> {
} }
} }
class ColorSchemeVariantColumn extends StatelessWidget {
const ColorSchemeVariantColumn({
super.key,
this.schemeVariant = DynamicSchemeVariant.tonalSpot,
this.brightness = Brightness.light,
required this.selectedColor,
});
final DynamicSchemeVariant schemeVariant;
final Brightness brightness;
final Color selectedColor;
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: const BoxConstraints.tightFor(width: 250),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Text(
schemeVariant.name == 'tonalSpot' ? '${schemeVariant.name} (Default)' : schemeVariant.name,
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: ColorSchemeView(
colorScheme: ColorScheme.fromSeed(
seedColor: selectedColor,
brightness: brightness,
dynamicSchemeVariant: schemeVariant,
),
),
),
],
)
);
}
}
class ColorSchemeView extends StatelessWidget { class ColorSchemeView extends StatelessWidget {
const ColorSchemeView({super.key, required this.colorScheme}); const ColorSchemeView({super.key, required this.colorScheme});
...@@ -301,7 +340,10 @@ enum ColorSeed { ...@@ -301,7 +340,10 @@ enum ColorSeed {
yellow('Yellow', Colors.yellow), yellow('Yellow', Colors.yellow),
orange('Orange', Colors.orange), orange('Orange', Colors.orange),
deepOrange('Deep Orange', Colors.deepOrange), deepOrange('Deep Orange', Colors.deepOrange),
pink('Pink', Colors.pink); pink('Pink', Colors.pink),
brightBlue('Bright Blue', Color(0xFF0000FF)),
brightGreen('Bright Green', Color(0xFF00FF00)),
brightRed('Bright Red', Color(0xFFFF0000));
const ColorSeed(this.label, this.color); const ColorSeed(this.label, this.color);
final String label; final String label;
......
...@@ -11,10 +11,9 @@ void main() { ...@@ -11,10 +11,9 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
const example.ColorSchemeExample(), const example.ColorSchemeExample(),
); );
expect(find.text('Light ColorScheme'), findsOneWidget); expect(find.text('tonalSpot (Default)'), findsOneWidget);
expect(find.text('Dark ColorScheme'), findsOneWidget);
expect(find.byType(example.ColorChip), findsNWidgets(86)); expect(find.byType(example.ColorChip), findsNWidgets(43 * 9));
}); });
testWidgets('Change color seed', (WidgetTester tester) async { testWidgets('Change color seed', (WidgetTester tester) async {
...@@ -30,7 +29,7 @@ void main() { ...@@ -30,7 +29,7 @@ void main() {
) )
); );
} }
expect(coloredBox().color, const Color(0xFF6750A4)); expect(coloredBox().color, const Color(0xff65558f));
await tester.tap(find.byType(MenuAnchor)); await tester.tap(find.byType(MenuAnchor));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await tester.tap(find.widgetWithText(MenuItemButton, 'Yellow')); await tester.tap(find.widgetWithText(MenuItemButton, 'Yellow'));
......
...@@ -8,10 +8,58 @@ import 'dart:ui' as ui; ...@@ -8,10 +8,58 @@ import 'dart:ui' as ui;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:material_color_utilities/material_color_utilities.dart'; import 'package:material_color_utilities/material_color_utilities.dart';
import 'package:material_color_utilities/scheme/scheme_fruit_salad.dart';
import 'package:material_color_utilities/scheme/scheme_rainbow.dart';
import 'colors.dart'; import 'colors.dart';
import 'theme_data.dart'; import 'theme_data.dart';
/// The algorithm used to construct a [ColorScheme] in [ColorScheme.fromSeed].
///
/// The `tonalSpot` variant builds default Material scheme colors. These colors are
/// mapped to light or dark tones to achieve visually accessible color
/// pairings with sufficient contrast between foreground and background elements.
///
/// In some cases, the tones can prevent colors from appearing as intended,
/// such as when a color is too light to offer enough contrast for accessibility.
/// Color fidelity (`DynamicSchemeVariant.fidelity`) is a feature that adjusts
/// tones in these cases to produce the intended visual results without harming
/// visual contrast.
enum DynamicSchemeVariant {
/// Default for Material theme colors. Builds pastel palettes with a low chroma.
tonalSpot,
/// The resulting color palettes match seed color, even if the seed color
/// is very bright (high chroma).
fidelity,
/// All colors are grayscale, no chroma.
monochrome,
/// Close to grayscale, a hint of chroma.
neutral,
/// Pastel colors, high chroma palettes. The primary palette's chroma is at
/// maximum. Use `fidelity` instead if tokens should alter their tone to match
/// the palette vibrancy.
vibrant,
/// Pastel colors, medium chroma palettes. The primary palette's hue is
/// different from the seed color, for variety.
expressive,
/// Almost identical to `fidelity`. Tokens and palettes match the seed color.
/// [ColorScheme.primaryContainer] is the seed color, adjusted to ensure
/// contrast with surfaces. The tertiary palette is analogue of the seed color.
content,
/// A playful theme - the seed color's hue does not appear in the theme.
rainbow,
/// A playful theme - the seed color's hue does not appear in the theme.
fruitSalad,
}
/// {@template flutter.material.color_scheme.ColorScheme} /// {@template flutter.material.color_scheme.ColorScheme}
/// A set of 45 colors based on the /// A set of 45 colors based on the
/// [Material spec](https://m3.material.io/styles/color/the-color-system/color-roles) /// [Material spec](https://m3.material.io/styles/color/the-color-system/color-roles)
...@@ -215,20 +263,35 @@ class ColorScheme with Diagnosticable { ...@@ -215,20 +263,35 @@ class ColorScheme with Diagnosticable {
/// Generate a [ColorScheme] derived from the given `seedColor`. /// Generate a [ColorScheme] derived from the given `seedColor`.
/// ///
/// Using the seedColor as a starting point, a set of tonal palettes are /// Using the `seedColor` as a starting point, a set of tonal palettes are
/// constructed. These tonal palettes are based on the Material 3 Color /// constructed. By default, the tonal palettes are based on the Material 3
/// system and provide all the needed colors for a [ColorScheme]. These /// Color system and provide all of the [ColorScheme] colors. These colors are
/// colors are designed to work well together and meet contrast /// designed to work well together and meet contrast requirements for
/// requirements for accessibility. /// accessibility.
/// ///
/// If any of the optional color parameters are non-null they will be /// If any of the optional color parameters are non-null they will be
/// used in place of the generated colors for that field in the resulting /// used in place of the generated colors for that field in the resulting
/// color scheme. This allows apps to override specific colors for their /// color scheme. This allows apps to override specific colors for their
/// needs. /// needs.
/// ///
/// Given the nature of the algorithm, the seedColor may not wind up as /// Given the nature of the algorithm, the `seedColor` may not wind up as
/// one of the ColorScheme colors. /// one of the ColorScheme colors.
/// ///
/// The `dynamicSchemeVariant` parameter creates different types of
/// [DynamicScheme]s, which are used to generate different styles of [ColorScheme]s.
/// By default, `dynamicSchemeVariant` is set to `tonalSpot`. A [ColorScheme]
/// constructed by `dynamicSchemeVariant.tonalSpot` has pastel palettes and
/// won't be too "colorful" even if the `seedColor` has a high chroma value.
/// If the resulting color scheme is too dark, consider setting `dynamicSchemeVariant`
/// to [DynamicSchemeVariant.fidelity], whose palettes match the seed color.
///
/// {@tool dartpad}
/// This sample shows how to use [ColorScheme.fromSeed] to create dynamic
/// color schemes with different [DynamicSchemeVariant]s.
///
/// ** See code in examples/api/lib/material/color_scheme/color_scheme.0.dart **
/// {@end-tool}
///
/// See also: /// See also:
/// ///
/// * <https://m3.material.io/styles/color/the-color-system/color-roles>, the /// * <https://m3.material.io/styles/color/the-color-system/color-roles>, the
...@@ -238,6 +301,7 @@ class ColorScheme with Diagnosticable { ...@@ -238,6 +301,7 @@ class ColorScheme with Diagnosticable {
factory ColorScheme.fromSeed({ factory ColorScheme.fromSeed({
required Color seedColor, required Color seedColor,
Brightness brightness = Brightness.light, Brightness brightness = Brightness.light,
DynamicSchemeVariant dynamicSchemeVariant = DynamicSchemeVariant.tonalSpot,
Color? primary, Color? primary,
Color? onPrimary, Color? onPrimary,
Color? primaryContainer, Color? primaryContainer,
...@@ -300,13 +364,7 @@ class ColorScheme with Diagnosticable { ...@@ -300,13 +364,7 @@ class ColorScheme with Diagnosticable {
) )
Color? surfaceVariant, Color? surfaceVariant,
}) { }) {
final SchemeTonalSpot scheme; final DynamicScheme scheme = _buildDynamicScheme(brightness, seedColor, dynamicSchemeVariant);
switch (brightness) {
case Brightness.light:
scheme = SchemeTonalSpot(sourceColorHct: Hct.fromInt(seedColor.value), isDark: false, contrastLevel: 0.0);
case Brightness.dark:
scheme = SchemeTonalSpot(sourceColorHct: Hct.fromInt(seedColor.value), isDark: true, contrastLevel: 0.0);
}
return ColorScheme( return ColorScheme(
primary: primary ?? Color(MaterialDynamicColors.primary.getArgb(scheme)), primary: primary ?? Color(MaterialDynamicColors.primary.getArgb(scheme)),
...@@ -1615,6 +1673,7 @@ class ColorScheme with Diagnosticable { ...@@ -1615,6 +1673,7 @@ class ColorScheme with Diagnosticable {
static Future<ColorScheme> fromImageProvider({ static Future<ColorScheme> fromImageProvider({
required ImageProvider provider, required ImageProvider provider,
Brightness brightness = Brightness.light, Brightness brightness = Brightness.light,
DynamicSchemeVariant dynamicSchemeVariant = DynamicSchemeVariant.tonalSpot,
Color? primary, Color? primary,
Color? onPrimary, Color? onPrimary,
Color? primaryContainer, Color? primaryContainer,
...@@ -1688,13 +1747,7 @@ class ColorScheme with Diagnosticable { ...@@ -1688,13 +1747,7 @@ class ColorScheme with Diagnosticable {
final List<int> scoredResults = Score.score(colorToCount, desired: 1); final List<int> scoredResults = Score.score(colorToCount, desired: 1);
final ui.Color baseColor = Color(scoredResults.first); final ui.Color baseColor = Color(scoredResults.first);
final SchemeTonalSpot scheme; final DynamicScheme scheme = _buildDynamicScheme(brightness, baseColor, dynamicSchemeVariant);
switch (brightness) {
case Brightness.light:
scheme = SchemeTonalSpot(sourceColorHct: Hct.fromInt(baseColor.value), isDark: false, contrastLevel: 0.0);
case Brightness.dark:
scheme = SchemeTonalSpot(sourceColorHct: Hct.fromInt(baseColor.value), isDark: true, contrastLevel: 0.0);
}
return ColorScheme( return ColorScheme(
primary: primary ?? Color(MaterialDynamicColors.primary.getArgb(scheme)), primary: primary ?? Color(MaterialDynamicColors.primary.getArgb(scheme)),
...@@ -1830,4 +1883,20 @@ class ColorScheme with Diagnosticable { ...@@ -1830,4 +1883,20 @@ class ColorScheme with Diagnosticable {
final int b = abgr & onlyBMask; final int b = abgr & onlyBMask;
return (abgr & exceptRMask & exceptBMask) | (b << 16) | r; return (abgr & exceptRMask & exceptBMask) | (b << 16) | r;
} }
static DynamicScheme _buildDynamicScheme(Brightness brightness, Color seedColor, DynamicSchemeVariant schemeVariant) {
final bool isDark = brightness == Brightness.dark;
final Hct sourceColor = Hct.fromInt(seedColor.value);
return switch (schemeVariant) {
DynamicSchemeVariant.tonalSpot => SchemeTonalSpot(sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0),
DynamicSchemeVariant.fidelity => SchemeFidelity(sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0),
DynamicSchemeVariant.content => SchemeContent(sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0),
DynamicSchemeVariant.monochrome => SchemeMonochrome(sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0),
DynamicSchemeVariant.neutral => SchemeNeutral(sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0),
DynamicSchemeVariant.vibrant => SchemeVibrant(sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0),
DynamicSchemeVariant.expressive => SchemeExpressive(sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0),
DynamicSchemeVariant.rainbow => SchemeRainbow(sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0),
DynamicSchemeVariant.fruitSalad => SchemeFruitSalad(sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0),
};
}
} }
...@@ -2,10 +2,13 @@ ...@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:material_color_utilities/material_color_utilities.dart';
import 'package:material_color_utilities/scheme/scheme_fruit_salad.dart';
import 'package:material_color_utilities/scheme/scheme_rainbow.dart';
import '../image_data.dart'; import '../image_data.dart';
...@@ -684,4 +687,143 @@ void main() { ...@@ -684,4 +687,143 @@ void main() {
}, },
skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 skip: isBrowser, // https://github.com/flutter/flutter/issues/44115
); );
testWidgets('Color values in ColorScheme.fromSeed with different variants matches values in DynamicScheme', (WidgetTester tester) async {
const Color seedColor = Colors.orange;
final Hct sourceColor = Hct.fromInt(seedColor.value);
for (final DynamicSchemeVariant schemeVariant in DynamicSchemeVariant.values) {
final DynamicScheme dynamicScheme = switch (schemeVariant) {
DynamicSchemeVariant.tonalSpot => SchemeTonalSpot(sourceColorHct: sourceColor, isDark: false, contrastLevel: 0.0),
DynamicSchemeVariant.fidelity => SchemeFidelity(sourceColorHct: sourceColor, isDark: false, contrastLevel: 0.0),
DynamicSchemeVariant.content => SchemeContent(sourceColorHct: sourceColor, isDark: false, contrastLevel: 0.0),
DynamicSchemeVariant.monochrome => SchemeMonochrome(sourceColorHct: sourceColor, isDark: false, contrastLevel: 0.0),
DynamicSchemeVariant.neutral => SchemeNeutral(sourceColorHct: sourceColor, isDark: false, contrastLevel: 0.0),
DynamicSchemeVariant.vibrant => SchemeVibrant(sourceColorHct: sourceColor, isDark: false, contrastLevel: 0.0),
DynamicSchemeVariant.expressive => SchemeExpressive(sourceColorHct: sourceColor, isDark: false, contrastLevel: 0.0),
DynamicSchemeVariant.rainbow => SchemeRainbow(sourceColorHct: sourceColor, isDark: false, contrastLevel: 0.0),
DynamicSchemeVariant.fruitSalad => SchemeFruitSalad(sourceColorHct: sourceColor, isDark: false, contrastLevel: 0.0),
};
final ColorScheme colorScheme = ColorScheme.fromSeed(
seedColor: seedColor,
dynamicSchemeVariant: schemeVariant,
);
expect(colorScheme.primary.value, MaterialDynamicColors.primary.getArgb(dynamicScheme));
expect(colorScheme.onPrimary.value, MaterialDynamicColors.onPrimary.getArgb(dynamicScheme));
expect(colorScheme.primaryContainer.value, MaterialDynamicColors.primaryContainer.getArgb(dynamicScheme));
expect(colorScheme.onPrimaryContainer.value, MaterialDynamicColors.onPrimaryContainer.getArgb(dynamicScheme));
expect(colorScheme.primaryFixed.value, MaterialDynamicColors.primaryFixed.getArgb(dynamicScheme));
expect(colorScheme.primaryFixedDim.value, MaterialDynamicColors.primaryFixedDim.getArgb(dynamicScheme));
expect(colorScheme.onPrimaryFixed.value, MaterialDynamicColors.onPrimaryFixed.getArgb(dynamicScheme));
expect(colorScheme.onPrimaryFixedVariant.value, MaterialDynamicColors.onPrimaryFixedVariant.getArgb(dynamicScheme));
expect(colorScheme.secondary.value, MaterialDynamicColors.secondary.getArgb(dynamicScheme));
expect(colorScheme.onSecondary.value, MaterialDynamicColors.onSecondary.getArgb(dynamicScheme));
expect(colorScheme.secondaryContainer.value, MaterialDynamicColors.secondaryContainer.getArgb(dynamicScheme));
expect(colorScheme.onSecondaryContainer.value, MaterialDynamicColors.onSecondaryContainer.getArgb(dynamicScheme));
expect(colorScheme.secondaryFixed.value, MaterialDynamicColors.secondaryFixed.getArgb(dynamicScheme));
expect(colorScheme.secondaryFixedDim.value, MaterialDynamicColors.secondaryFixedDim.getArgb(dynamicScheme));
expect(colorScheme.onSecondaryFixed.value, MaterialDynamicColors.onSecondaryFixed.getArgb(dynamicScheme));
expect(colorScheme.onSecondaryFixedVariant.value, MaterialDynamicColors.onSecondaryFixedVariant.getArgb(dynamicScheme));
expect(colorScheme.tertiary.value, MaterialDynamicColors.tertiary.getArgb(dynamicScheme));
expect(colorScheme.onTertiary.value, MaterialDynamicColors.onTertiary.getArgb(dynamicScheme));
expect(colorScheme.tertiaryContainer.value, MaterialDynamicColors.tertiaryContainer.getArgb(dynamicScheme));
expect(colorScheme.onTertiaryContainer.value, MaterialDynamicColors.onTertiaryContainer.getArgb(dynamicScheme));
expect(colorScheme.tertiaryFixed.value, MaterialDynamicColors.tertiaryFixed.getArgb(dynamicScheme));
expect(colorScheme.tertiaryFixedDim.value, MaterialDynamicColors.tertiaryFixedDim.getArgb(dynamicScheme));
expect(colorScheme.onTertiaryFixed.value, MaterialDynamicColors.onTertiaryFixed.getArgb(dynamicScheme));
expect(colorScheme.onTertiaryFixedVariant.value, MaterialDynamicColors.onTertiaryFixedVariant.getArgb(dynamicScheme));
expect(colorScheme.error.value, MaterialDynamicColors.error.getArgb(dynamicScheme));
expect(colorScheme.onError.value, MaterialDynamicColors.onError.getArgb(dynamicScheme));
expect(colorScheme.errorContainer.value, MaterialDynamicColors.errorContainer.getArgb(dynamicScheme));
expect(colorScheme.onErrorContainer.value, MaterialDynamicColors.onErrorContainer.getArgb(dynamicScheme));
expect(colorScheme.background.value, MaterialDynamicColors.background.getArgb(dynamicScheme));
expect(colorScheme.onBackground.value, MaterialDynamicColors.onBackground.getArgb(dynamicScheme));
expect(colorScheme.surface.value, MaterialDynamicColors.surface.getArgb(dynamicScheme));
expect(colorScheme.surfaceDim.value, MaterialDynamicColors.surfaceDim.getArgb(dynamicScheme));
expect(colorScheme.surfaceBright.value, MaterialDynamicColors.surfaceBright.getArgb(dynamicScheme));
expect(colorScheme.surfaceContainerLowest.value, MaterialDynamicColors.surfaceContainerLowest.getArgb(dynamicScheme));
expect(colorScheme.surfaceContainerLow.value, MaterialDynamicColors.surfaceContainerLow.getArgb(dynamicScheme));
expect(colorScheme.surfaceContainer.value, MaterialDynamicColors.surfaceContainer.getArgb(dynamicScheme));
expect(colorScheme.surfaceContainerHigh.value, MaterialDynamicColors.surfaceContainerHigh.getArgb(dynamicScheme));
expect(colorScheme.surfaceContainerHighest.value, MaterialDynamicColors.surfaceContainerHighest.getArgb(dynamicScheme));
expect(colorScheme.onSurface.value, MaterialDynamicColors.onSurface.getArgb(dynamicScheme));
expect(colorScheme.surfaceVariant.value, MaterialDynamicColors.surfaceVariant.getArgb(dynamicScheme));
expect(colorScheme.onSurfaceVariant.value, MaterialDynamicColors.onSurfaceVariant.getArgb(dynamicScheme));
expect(colorScheme.outline.value, MaterialDynamicColors.outline.getArgb(dynamicScheme));
expect(colorScheme.outlineVariant.value, MaterialDynamicColors.outlineVariant.getArgb(dynamicScheme));
expect(colorScheme.shadow.value, MaterialDynamicColors.shadow.getArgb(dynamicScheme));
expect(colorScheme.scrim.value, MaterialDynamicColors.scrim.getArgb(dynamicScheme));
expect(colorScheme.inverseSurface.value, MaterialDynamicColors.inverseSurface.getArgb(dynamicScheme));
expect(colorScheme.onInverseSurface.value, MaterialDynamicColors.inverseOnSurface.getArgb(dynamicScheme));
expect(colorScheme.inversePrimary.value, MaterialDynamicColors.inversePrimary.getArgb(dynamicScheme));
}
});
testWidgets('ColorScheme.fromSeed with different variants spot checks', (WidgetTester tester) async {
// Default (Variant.tonalSpot).
await _testFilledButtonColor(tester, ColorScheme.fromSeed(seedColor: const Color(0xFF000000)), const Color(0xFF8C4A60));
await _testFilledButtonColor(tester, ColorScheme.fromSeed(seedColor: const Color(0xFF00FF00)), const Color(0xFF406836));
await _testFilledButtonColor(tester, ColorScheme.fromSeed(seedColor: const Color(0xFF6559F5)), const Color(0xFF5B5891));
await _testFilledButtonColor(tester, ColorScheme.fromSeed(seedColor: const Color(0xFFFFFFFF)), const Color(0xFF006874));
// Variant.fidelity.
await _testFilledButtonColor(
tester,
ColorScheme.fromSeed(
seedColor: const Color(0xFF000000),
dynamicSchemeVariant: DynamicSchemeVariant.fidelity
),
const Color(0xFF000000)
);
await _testFilledButtonColor(
tester,
ColorScheme.fromSeed(
seedColor: const Color(0xFF00FF00),
dynamicSchemeVariant: DynamicSchemeVariant.fidelity
),
const Color(0xFF026E00)
);
await _testFilledButtonColor(
tester,
ColorScheme.fromSeed(
seedColor: const Color(0xFF6559F5),
dynamicSchemeVariant: DynamicSchemeVariant.fidelity
),
const Color(0xFF3F2CD0)
);
await _testFilledButtonColor(
tester,
ColorScheme.fromSeed(
seedColor: const Color(0xFFFFFFFF),
dynamicSchemeVariant: DynamicSchemeVariant.fidelity
),
const Color(0xFF5D5F5F)
);
});
}
Future<void> _testFilledButtonColor(WidgetTester tester, ColorScheme scheme, Color expectation) async {
final GlobalKey key = GlobalKey();
await tester.pumpWidget(Container()); // reset
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
colorScheme: scheme,
),
home: FilledButton(
key: key,
onPressed: () {},
child: const SizedBox.square(dimension: 200),
),
),
);
final Finder buttonMaterial = find.descendant(
of: find.byType(FilledButton),
matching: find.byType(Material),
);
final Material material = tester.widget<Material>(buttonMaterial);
expect(material.color, expectation);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment