mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Enhance ColorScheme.fromSeed with a new variant
parameter (#144805)
Fixes #144649 This PR is to add an enhancement for `ColorScheme.fromSeed()`. When we input a brighter color with a high chroma and we want the resulting `ColorScheme` respects the source color, we can achieve this by setting ```dart ColorScheme.fromSeed( seedColor: sourceColor, variant: Variant.fidelity, ... ) ``` Here is a demo for `ColorScheme` constructed by all 9 variants:  
This commit is contained in:
parent
a46ed4ee07
commit
950ec1c405
@ -19,43 +19,28 @@ 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>[
|
||||||
|
Row(
|
||||||
|
children: <Widget>[
|
||||||
|
const Text('Color Seed'),
|
||||||
|
MenuAnchor(
|
||||||
builder: (BuildContext context, MenuController controller, Widget? widget) {
|
builder: (BuildContext context, MenuController controller, Widget? widget) {
|
||||||
return IconButton(
|
return IconButton(
|
||||||
icon: Icon(Icons.circle, color: selectedColor),
|
icon: Icon(Icons.circle, color: selectedColor),
|
||||||
@ -83,38 +68,92 @@ class _ColorSchemeExampleState extends State<ColorSchemeExample> {
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
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(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||||
|
child: Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
const Text('Brightness'),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Switch(
|
||||||
|
value: selectedBrightness == Brightness.light,
|
||||||
|
onChanged: (bool value) {
|
||||||
|
setState(() {
|
||||||
|
selectedBrightness = value ? Brightness.light : Brightness.dark;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Row(
|
||||||
|
children: List<Widget>.generate(schemeVariants.length, (int index) {
|
||||||
|
return ColorSchemeVariantColumn(
|
||||||
|
selectedColor: selectedColor,
|
||||||
|
brightness: selectedBrightness,
|
||||||
|
schemeVariant: schemeVariants[index],
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
schemeLabel('Light ColorScheme'),
|
Padding(
|
||||||
schemeView(lightTheme),
|
padding: const EdgeInsets.symmetric(vertical: 15),
|
||||||
],
|
child: Text(
|
||||||
|
schemeVariant.name == 'tonalSpot' ? '${schemeVariant.name} (Default)' : schemeVariant.name,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Padding(
|
||||||
child: Column(
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
children: <Widget>[
|
child: ColorSchemeView(
|
||||||
schemeLabel('Dark ColorScheme'),
|
colorScheme: ColorScheme.fromSeed(
|
||||||
schemeView(darkTheme),
|
seedColor: selectedColor,
|
||||||
],
|
brightness: brightness,
|
||||||
|
dynamicSchemeVariant: schemeVariant,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
)
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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() {
|
|||||||
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() {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
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'));
|
||||||
|
@ -12,6 +12,52 @@ import 'package:material_color_utilities/material_color_utilities.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 +261,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 +299,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 +362,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 +1671,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 +1745,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 +1881,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,11 @@
|
|||||||
// 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 '../image_data.dart';
|
import '../image_data.dart';
|
||||||
|
|
||||||
@ -684,4 +685,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(0xFF4C3CDB)
|
||||||
|
);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user