mirror of
https://github.com/flutter/flutter
synced 2024-10-04 07:19:46 +00:00
API to generate a ColorScheme from a single seed color. (#93463)
This commit is contained in:
parent
818f5caf38
commit
8630315aad
|
@ -4,19 +4,51 @@
|
|||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:material_color_utilities/material_color_utilities.dart';
|
||||
|
||||
import 'colors.dart';
|
||||
import 'theme_data.dart';
|
||||
|
||||
/// A set of colors based on the
|
||||
/// A set of 25 colors based on the
|
||||
/// [Material spec](https://m3.material.io/styles/color/the-color-system/color-roles)
|
||||
/// that can be used to configure the color properties of most components.
|
||||
///
|
||||
/// The [Theme] has a color scheme, [ThemeData.colorScheme], which is constructed
|
||||
/// with [ColorScheme.fromSwatch].
|
||||
/// The main accent color groups in the scheme are [primary], [secondary],
|
||||
/// and [tertiary].
|
||||
///
|
||||
/// * Primary colors are used for key components across the UI, such as the FAB,
|
||||
/// prominent buttons, and active states.
|
||||
///
|
||||
/// * Secondary colors are used for less prominent components in the UI, such as
|
||||
/// filter chips, while expanding the opportunity for color expression.
|
||||
///
|
||||
/// * Tertiary colors are used for contrasting accents that can be used to
|
||||
/// balance primary and secondary colors or bring heightened attention to
|
||||
/// an element, such as an input field. The tertiary colors are left
|
||||
/// for makers to use at their discretion and are intended to support
|
||||
/// broader color expression in products.
|
||||
///
|
||||
/// The remaining colors of the scheme are comprised of neutral colors used for
|
||||
/// backgrounds and surfaces, as well as specific colors for errors, dividers
|
||||
/// and shadows.
|
||||
///
|
||||
/// Many of the colors have matching 'on' colors, which are used for drawing
|
||||
/// content on top of the matching color. For example, if something is using
|
||||
/// [primary] for a background color, [onPrimary] would be used to paint text
|
||||
/// and icons on top of it. For this reason, the 'on' colors should have a
|
||||
/// contrast ratio with their matching colors of at least 4.5:1 in order to
|
||||
/// be readable.
|
||||
///
|
||||
/// The [Theme] has a color scheme, [ThemeData.colorScheme], which can either be
|
||||
/// passed in as a parameter to the constructor or by using 'brightness' and
|
||||
/// 'colorSchemeSeed' parameters (which are used to generate a scheme with
|
||||
/// [ColorScheme.fromSeed]).
|
||||
@immutable
|
||||
class ColorScheme with Diagnosticable {
|
||||
/// Create a ColorScheme instance.
|
||||
/// Create a ColorScheme instance from the given colors.
|
||||
///
|
||||
/// [ColorScheme.fromSeed] can be used as a simpler way to create a full
|
||||
/// color scheme derived from a single seed color.
|
||||
///
|
||||
/// For the color parameters that are nullable, it is still recommended
|
||||
/// that applications provide values for them. They are only nullable due
|
||||
|
@ -24,9 +56,25 @@ class ColorScheme with Diagnosticable {
|
|||
///
|
||||
/// If a color is not provided, the closest fallback color from the given
|
||||
/// colors will be used for it (e.g. [primaryContainer] will default
|
||||
/// to [primary]). Material 3 makes use of these colors for many component
|
||||
/// defaults, so for the best results the application should supply colors
|
||||
/// for all the parameters.
|
||||
/// to [primary]). Material Design 3 makes use of these colors for many
|
||||
/// component defaults, so for the best results the application should
|
||||
/// supply colors for all the parameters. An easy way to ensure this is to
|
||||
/// use [ColorScheme.fromSeed] to generate a full set of colors.
|
||||
///
|
||||
/// During the migration to Material Design 3, if an app's
|
||||
/// [ThemeData.useMaterial3] is false, then components will only
|
||||
/// use the following colors for defaults:
|
||||
///
|
||||
/// * [primary]
|
||||
/// * [onPrimary]
|
||||
/// * [secondary]
|
||||
/// * [onSecondary]
|
||||
/// * [error]
|
||||
/// * [onError]
|
||||
/// * [background]
|
||||
/// * [onBackground]
|
||||
/// * [surface]
|
||||
/// * [onSurface]
|
||||
const ColorScheme({
|
||||
required this.brightness,
|
||||
required this.primary,
|
||||
|
@ -97,6 +145,127 @@ class ColorScheme with Diagnosticable {
|
|||
_primaryVariant = primaryVariant,
|
||||
_secondaryVariant = secondaryVariant;
|
||||
|
||||
/// Generate a [ColorScheme] derived from the given `seedColor`.
|
||||
///
|
||||
/// Using the seedColor as a starting point, a set of tonal palettes are
|
||||
/// constructed. These tonal palettes are based on the Material 3 Color
|
||||
/// system and provide all the needed colors for a [ColorScheme]. These
|
||||
/// colors are designed to work well together and meet contrast
|
||||
/// requirements for accessibility.
|
||||
///
|
||||
/// 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
|
||||
/// color scheme. This allows apps to override specific colors for their
|
||||
/// needs.
|
||||
///
|
||||
/// Given the nature of the algorithm, the seedColor may not wind up as
|
||||
/// one of the ColorScheme colors.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * <https://m3.material.io/styles/color/the-color-system/color-roles>, the
|
||||
/// Material 3 Color system specification.
|
||||
/// * <https://pub.dev/packages/material_color_utilities>, the package
|
||||
/// used to generate the tonal palettes needed for the scheme.
|
||||
factory ColorScheme.fromSeed({
|
||||
required Color seedColor,
|
||||
Brightness brightness = Brightness.light,
|
||||
Color? primary,
|
||||
Color? onPrimary,
|
||||
Color? primaryContainer,
|
||||
Color? onPrimaryContainer,
|
||||
Color? secondary,
|
||||
Color? onSecondary,
|
||||
Color? secondaryContainer,
|
||||
Color? onSecondaryContainer,
|
||||
Color? tertiary,
|
||||
Color? onTertiary,
|
||||
Color? tertiaryContainer,
|
||||
Color? onTertiaryContainer,
|
||||
Color? error,
|
||||
Color? onError,
|
||||
Color? errorContainer,
|
||||
Color? onErrorContainer,
|
||||
Color? outline,
|
||||
Color? background,
|
||||
Color? onBackground,
|
||||
Color? surface,
|
||||
Color? onSurface,
|
||||
Color? surfaceVariant,
|
||||
Color? onSurfaceVariant,
|
||||
Color? inverseSurface,
|
||||
Color? onInverseSurface,
|
||||
Color? inversePrimary,
|
||||
Color? shadow,
|
||||
}) {
|
||||
final CorePalette palette = CorePalette.of(seedColor.value);
|
||||
switch (brightness) {
|
||||
case Brightness.light:
|
||||
return ColorScheme(
|
||||
primary: primary ?? Color(palette.primary.get(40)),
|
||||
onPrimary: onPrimary ?? Color(palette.primary.get(100)),
|
||||
primaryContainer: primaryContainer ?? Color(palette.primary.get(90)),
|
||||
onPrimaryContainer: onPrimaryContainer ?? Color(palette.primary.get(10)),
|
||||
secondary: secondary ?? Color(palette.secondary.get(40)),
|
||||
onSecondary: onSecondary ?? Color(palette.secondary.get(100)),
|
||||
secondaryContainer: secondaryContainer ?? Color(palette.secondary.get(90)),
|
||||
onSecondaryContainer: onSecondaryContainer ?? Color(palette.secondary.get(10)),
|
||||
tertiary: tertiary ?? Color(palette.tertiary.get(40)),
|
||||
onTertiary: onTertiary ?? Color(palette.tertiary.get(100)),
|
||||
tertiaryContainer: tertiaryContainer ?? Color(palette.tertiary.get(90)),
|
||||
onTertiaryContainer: onTertiaryContainer ?? Color(palette.tertiary.get(10)),
|
||||
error: error ?? Color(palette.error.get(40)),
|
||||
onError: onError ?? Color(palette.error.get(100)),
|
||||
errorContainer: errorContainer ?? Color(palette.error.get(90)),
|
||||
onErrorContainer: onErrorContainer ?? Color(palette.error.get(10)),
|
||||
outline: outline ?? Color(palette.neutralVariant.get(50)),
|
||||
background: background ?? Color(palette.neutral.get(90)),
|
||||
onBackground: onBackground ?? Color(palette.neutral.get(10)),
|
||||
surface: surface ?? Color(palette.neutral.get(99)),
|
||||
onSurface: onSurface ?? Color(palette.neutral.get(0)),
|
||||
surfaceVariant: surfaceVariant ?? Color(palette.neutralVariant.get(90)),
|
||||
onSurfaceVariant: onSurfaceVariant ?? Color(palette.neutralVariant.get(30)),
|
||||
inverseSurface: inverseSurface ?? Color(palette.neutral.get(20)),
|
||||
onInverseSurface: onInverseSurface ?? Color(palette.neutral.get(95)),
|
||||
inversePrimary: inversePrimary ?? Color(palette.primary.get(80)),
|
||||
shadow: shadow ?? Color(palette.neutral.get(0)),
|
||||
brightness: brightness,
|
||||
);
|
||||
|
||||
case Brightness.dark:
|
||||
return ColorScheme(
|
||||
primary: primary ?? Color(palette.primary.get(80)),
|
||||
onPrimary: onPrimary ?? Color(palette.primary.get(20)),
|
||||
primaryContainer: primaryContainer ?? Color(palette.primary.get(70)),
|
||||
onPrimaryContainer: onPrimaryContainer ?? Color(palette.primary.get(10)),
|
||||
secondary: secondary ?? Color(palette.secondary.get(80)),
|
||||
onSecondary: onSecondary ?? Color(palette.secondary.get(20)),
|
||||
secondaryContainer: secondaryContainer ?? Color(palette.secondary.get(70)),
|
||||
onSecondaryContainer: onSecondaryContainer ?? Color(palette.secondary.get(10)),
|
||||
tertiary: tertiary ?? Color(palette.tertiary.get(80)),
|
||||
onTertiary: onTertiary ?? Color(palette.tertiary.get(20)),
|
||||
tertiaryContainer: tertiaryContainer ?? Color(palette.tertiary.get(70)),
|
||||
onTertiaryContainer: onTertiaryContainer ?? Color(palette.tertiary.get(10)),
|
||||
error: error ?? Color(palette.error.get(80)),
|
||||
onError: onError ?? Color(palette.error.get(20)),
|
||||
errorContainer: errorContainer ?? Color(palette.error.get(70)),
|
||||
onErrorContainer: onErrorContainer ?? Color(palette.error.get(10)),
|
||||
outline: outline ?? Color(palette.neutralVariant.get(60)),
|
||||
background: background ?? Color(palette.neutral.get(10)),
|
||||
onBackground: onBackground ?? Color(palette.neutral.get(90)),
|
||||
surface: surface ?? Color(palette.neutral.get(10)),
|
||||
onSurface: onSurface ?? Color(palette.neutral.get(100)),
|
||||
surfaceVariant: surfaceVariant ?? Color(palette.neutralVariant.get(30)),
|
||||
onSurfaceVariant: onSurfaceVariant ?? Color(palette.neutralVariant.get(80)),
|
||||
inverseSurface: inverseSurface ?? Color(palette.neutral.get(90)),
|
||||
onInverseSurface: onInverseSurface ?? Color(palette.neutral.get(20)),
|
||||
inversePrimary: inversePrimary ?? Color(palette.primary.get(40)),
|
||||
shadow: shadow ?? Color(palette.neutral.get(0)),
|
||||
brightness: brightness,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a ColorScheme based on a purple primary color that matches the
|
||||
/// [baseline Material color scheme](https://material.io/design/color/the-color-system.html#color-theme-creation).
|
||||
const ColorScheme.light({
|
||||
|
|
|
@ -200,13 +200,30 @@ enum MaterialTapTargetSize {
|
|||
class ThemeData with Diagnosticable {
|
||||
/// Create a [ThemeData] that's used to configure a [Theme].
|
||||
///
|
||||
/// Typically, only the [brightness], [primaryColor], or [primarySwatch] are
|
||||
/// specified. That pair of values are used to construct the [colorScheme].
|
||||
///
|
||||
/// The [colorScheme] and [textTheme] are used by the Material components to
|
||||
/// compute default values for visual properties. The API documentation for
|
||||
/// each component widget explains exactly how the defaults are computed.
|
||||
///
|
||||
/// When providing a [ColorScheme], apps can either provide one directly
|
||||
/// with the [colorScheme] parameter, or have one generated for them by
|
||||
/// using the [colorSchemeSeed] and [brightness] parameters. A generated
|
||||
/// color scheme will be based on the tones of [colorSchemeSeed] and all of
|
||||
/// its contrasting color will meet accessibility guidelines for readability.
|
||||
/// (See [ColorScheme.fromSeed] for more details.)
|
||||
///
|
||||
/// If the app wants to customize a generated color scheme, it can use
|
||||
/// [ColorScheme.fromSeed] directly and then [ColorScheme.copyWith] on the
|
||||
/// result to override any colors that need to be replaced. The result of
|
||||
/// this can be used as the [colorScheme] directly.
|
||||
///
|
||||
/// For historical reasons, instead of using a [colorSchemeSeed] or
|
||||
/// [colorScheme], you can provide either a [primaryColor] or [primarySwatch]
|
||||
/// to construct the [colorScheme], but the results will not be as complete
|
||||
/// as when using generation from a seed color.
|
||||
///
|
||||
/// If [colorSchemeSeed] is non-null then [colorScheme], [primaryColor] and
|
||||
/// [primarySwatch] must all be null.
|
||||
///
|
||||
/// The [textTheme] [TextStyle] colors are black if the color scheme's
|
||||
/// brightness is [Brightness.light], and white for [Brightness.dark].
|
||||
///
|
||||
|
@ -219,6 +236,7 @@ class ThemeData with Diagnosticable {
|
|||
/// * [ThemeData.from], which creates a ThemeData from a [ColorScheme].
|
||||
/// * [ThemeData.light], which creates a light blue theme.
|
||||
/// * [ThemeData.dark], which creates dark theme with a teal secondary [ColorScheme] color.
|
||||
/// * [ColorScheme.fromSeed], which is used to create a [ColorScheme] from a seed color.
|
||||
factory ThemeData({
|
||||
// GENERAL CONFIGURATION
|
||||
AndroidOverscrollIndicator? androidOverscrollIndicator,
|
||||
|
@ -234,9 +252,10 @@ class ThemeData with Diagnosticable {
|
|||
bool? useMaterial3,
|
||||
// COLOR
|
||||
// [colorScheme] is the preferred way to configure colors. The other color
|
||||
// properties (as well as brightness, primaryColorBrightness, and primarySwatch)
|
||||
// properties (as well as primaryColorBrightness, and primarySwatch)
|
||||
// will gradually be phased out, see https://github.com/flutter/flutter/issues/91772.
|
||||
ColorScheme? colorScheme,
|
||||
Color? colorSchemeSeed,
|
||||
Brightness? brightness,
|
||||
MaterialColor? primarySwatch,
|
||||
Color? primaryColor,
|
||||
|
@ -368,7 +387,6 @@ class ThemeData with Diagnosticable {
|
|||
Brightness? primaryColorBrightness,
|
||||
}) {
|
||||
// GENERAL CONFIGURATION
|
||||
applyElevationOverlayColor ??= false;
|
||||
cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault();
|
||||
inputDecorationTheme ??= const InputDecorationTheme();
|
||||
platform ??= defaultTargetPlatform;
|
||||
|
@ -392,8 +410,35 @@ class ThemeData with Diagnosticable {
|
|||
|
||||
// COLOR
|
||||
assert(colorScheme?.brightness == null || brightness == null || colorScheme!.brightness == brightness);
|
||||
assert(colorSchemeSeed == null || colorScheme == null);
|
||||
assert(colorSchemeSeed == null || primarySwatch == null);
|
||||
assert(colorSchemeSeed == null || primaryColor == null);
|
||||
final Brightness _brightness = brightness ?? colorScheme?.brightness ?? Brightness.light;
|
||||
final bool isDark = _brightness == Brightness.dark;
|
||||
if (colorSchemeSeed != null) {
|
||||
colorScheme = ColorScheme.fromSeed(seedColor: colorSchemeSeed, brightness: _brightness);
|
||||
|
||||
// For surfaces that use primary color in light themes and surface color in dark
|
||||
final Color primarySurfaceColor = isDark ? colorScheme.surface : colorScheme.primary;
|
||||
final Color onPrimarySurfaceColor = isDark ? colorScheme.onSurface : colorScheme.onPrimary;
|
||||
|
||||
// Default some of the color settings to values from the color scheme
|
||||
primaryColor = primarySurfaceColor;
|
||||
primaryColorBrightness = ThemeData.estimateBrightnessForColor(primarySurfaceColor);
|
||||
canvasColor ??= colorScheme.background;
|
||||
accentColor ??= colorScheme.secondary;
|
||||
accentColorBrightness ??= ThemeData.estimateBrightnessForColor(colorScheme.secondary);
|
||||
scaffoldBackgroundColor ??= colorScheme.background;
|
||||
bottomAppBarColor ??= colorScheme.surface;
|
||||
cardColor ??= colorScheme.surface;
|
||||
dividerColor ??= colorScheme.outline;
|
||||
backgroundColor ??= colorScheme.background;
|
||||
dialogBackgroundColor ??= colorScheme.background;
|
||||
indicatorColor ??= onPrimarySurfaceColor;
|
||||
errorColor ??= colorScheme.error;
|
||||
applyElevationOverlayColor ??= isDark;
|
||||
}
|
||||
applyElevationOverlayColor ??= false;
|
||||
primarySwatch ??= Colors.blue;
|
||||
primaryColor ??= isDark ? Colors.grey[900]! : primarySwatch;
|
||||
final Brightness _primaryColorBrightness = estimateBrightnessForColor(primaryColor);
|
||||
|
|
|
@ -161,4 +161,139 @@ void main() {
|
|||
expect(scheme.primaryVariant, const Color(0xffbe9eff));
|
||||
expect(scheme.secondaryVariant, const Color(0xff66fff9));
|
||||
});
|
||||
|
||||
test('can generate a light scheme from a seed color', () {
|
||||
final ColorScheme scheme = ColorScheme.fromSeed(seedColor: Colors.blue);
|
||||
expect(scheme.primary, const Color(0xff0061a6));
|
||||
expect(scheme.onPrimary, const Color(0xffffffff));
|
||||
expect(scheme.primaryContainer, const Color(0xffd0e4ff));
|
||||
expect(scheme.onPrimaryContainer, const Color(0xff001d36));
|
||||
expect(scheme.secondary, const Color(0xff535f70));
|
||||
expect(scheme.onSecondary, const Color(0xffffffff));
|
||||
expect(scheme.secondaryContainer, const Color(0xffd6e3f7));
|
||||
expect(scheme.onSecondaryContainer, const Color(0xff101c2b));
|
||||
expect(scheme.tertiary, const Color(0xff6b5778));
|
||||
expect(scheme.onTertiary, const Color(0xffffffff));
|
||||
expect(scheme.tertiaryContainer, const Color(0xfff3daff));
|
||||
expect(scheme.onTertiaryContainer, const Color(0xff251432));
|
||||
expect(scheme.error, const Color(0xffba1b1b));
|
||||
expect(scheme.onError, const Color(0xffffffff));
|
||||
expect(scheme.errorContainer, const Color(0xffffdad4));
|
||||
expect(scheme.onErrorContainer, const Color(0xff410001));
|
||||
expect(scheme.outline, const Color(0xff73777f));
|
||||
expect(scheme.background, const Color(0xffe2e2e6));
|
||||
expect(scheme.onBackground, const Color(0xff1b1b1b));
|
||||
expect(scheme.surface, const Color(0xfffdfcff));
|
||||
expect(scheme.onSurface, const Color(0xff000000));
|
||||
expect(scheme.surfaceVariant, const Color(0xffdfe2eb));
|
||||
expect(scheme.onSurfaceVariant, const Color(0xff42474e));
|
||||
expect(scheme.inverseSurface, const Color(0xff2f3033));
|
||||
expect(scheme.onInverseSurface, const Color(0xfff1f0f4));
|
||||
expect(scheme.inversePrimary, const Color(0xff9ccaff));
|
||||
expect(scheme.shadow, const Color(0xff000000));
|
||||
expect(scheme.brightness, Brightness.light);
|
||||
});
|
||||
|
||||
test('can generate a dark scheme from a seed color', () {
|
||||
final ColorScheme scheme = ColorScheme.fromSeed(seedColor: Colors.blue, brightness: Brightness.dark);
|
||||
expect(scheme.primary, const Color(0xff9ccaff));
|
||||
expect(scheme.onPrimary, const Color(0xff00325a));
|
||||
expect(scheme.primaryContainer, const Color(0xff60b0ff));
|
||||
expect(scheme.onPrimaryContainer, const Color(0xff001d36));
|
||||
expect(scheme.secondary, const Color(0xffbbc8db));
|
||||
expect(scheme.onSecondary, const Color(0xff253140));
|
||||
expect(scheme.secondaryContainer, const Color(0xff9facbf));
|
||||
expect(scheme.onSecondaryContainer, const Color(0xff101c2b));
|
||||
expect(scheme.tertiary, const Color(0xffd6bee4));
|
||||
expect(scheme.onTertiary, const Color(0xff3b2948));
|
||||
expect(scheme.tertiaryContainer, const Color(0xffbba3c9));
|
||||
expect(scheme.onTertiaryContainer, const Color(0xff251432));
|
||||
expect(scheme.error, const Color(0xffffb4a9));
|
||||
expect(scheme.onError, const Color(0xff680003));
|
||||
expect(scheme.errorContainer, const Color(0xffff897a));
|
||||
expect(scheme.onErrorContainer, const Color(0xff410001));
|
||||
expect(scheme.outline, const Color(0xff8d9199));
|
||||
expect(scheme.background, const Color(0xff1b1b1b));
|
||||
expect(scheme.onBackground, const Color(0xffe2e2e6));
|
||||
expect(scheme.surface, const Color(0xff1b1b1b));
|
||||
expect(scheme.onSurface, const Color(0xffffffff));
|
||||
expect(scheme.surfaceVariant, const Color(0xff42474e));
|
||||
expect(scheme.onSurfaceVariant, const Color(0xffc3c7d0));
|
||||
expect(scheme.inverseSurface, const Color(0xffe2e2e6));
|
||||
expect(scheme.onInverseSurface, const Color(0xff2f3033));
|
||||
expect(scheme.inversePrimary, const Color(0xff0061a6));
|
||||
expect(scheme.shadow, const Color(0xff000000));
|
||||
expect(scheme.brightness, Brightness.dark);
|
||||
});
|
||||
|
||||
test('can override specific colors in a generated scheme', () {
|
||||
final ColorScheme baseScheme = ColorScheme.fromSeed(seedColor: Colors.blue);
|
||||
const Color primaryOverride = Color(0xffabcdef);
|
||||
final ColorScheme scheme = ColorScheme.fromSeed(
|
||||
seedColor: Colors.blue,
|
||||
primary: primaryOverride,
|
||||
);
|
||||
expect(scheme.primary, primaryOverride);
|
||||
// The rest should be the same.
|
||||
expect(scheme.onPrimary, baseScheme.onPrimary);
|
||||
expect(scheme.primaryContainer, baseScheme.primaryContainer);
|
||||
expect(scheme.onPrimaryContainer, baseScheme.onPrimaryContainer);
|
||||
expect(scheme.secondary, baseScheme.secondary);
|
||||
expect(scheme.onSecondary, baseScheme.onSecondary);
|
||||
expect(scheme.secondaryContainer, baseScheme.secondaryContainer);
|
||||
expect(scheme.onSecondaryContainer, baseScheme.onSecondaryContainer);
|
||||
expect(scheme.tertiary, baseScheme.tertiary);
|
||||
expect(scheme.onTertiary, baseScheme.onTertiary);
|
||||
expect(scheme.tertiaryContainer, baseScheme.tertiaryContainer);
|
||||
expect(scheme.onTertiaryContainer, baseScheme.onTertiaryContainer);
|
||||
expect(scheme.error, baseScheme.error);
|
||||
expect(scheme.onError, baseScheme.onError);
|
||||
expect(scheme.errorContainer, baseScheme.errorContainer);
|
||||
expect(scheme.onErrorContainer, baseScheme.onErrorContainer);
|
||||
expect(scheme.outline, baseScheme.outline);
|
||||
expect(scheme.background, baseScheme.background);
|
||||
expect(scheme.onBackground, baseScheme.onBackground);
|
||||
expect(scheme.surface, baseScheme.surface);
|
||||
expect(scheme.onSurface, baseScheme.onSurface);
|
||||
expect(scheme.surfaceVariant, baseScheme.surfaceVariant);
|
||||
expect(scheme.onSurfaceVariant, baseScheme.onSurfaceVariant);
|
||||
expect(scheme.inverseSurface, baseScheme.inverseSurface);
|
||||
expect(scheme.onInverseSurface, baseScheme.onInverseSurface);
|
||||
expect(scheme.inversePrimary, baseScheme.inversePrimary);
|
||||
expect(scheme.shadow, baseScheme.shadow);
|
||||
expect(scheme.brightness, baseScheme.brightness);
|
||||
});
|
||||
|
||||
testWidgets('generated scheme "on" colors meet a11y contrast guidelines', (WidgetTester tester) async {
|
||||
final ColorScheme colors = ColorScheme.fromSeed(seedColor: Colors.teal);
|
||||
|
||||
Widget label(String text, Color textColor, Color background) {
|
||||
return Container(
|
||||
color: background,
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Text(text, style: TextStyle(color: textColor)),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData.from(colorScheme: colors),
|
||||
home: Scaffold(
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
label('primary', colors.onPrimary, colors.primary),
|
||||
label('secondary', colors.onSecondary, colors.secondary),
|
||||
label('tertiary', colors.onTertiary, colors.tertiary),
|
||||
label('error', colors.onError, colors.error),
|
||||
label('background', colors.onBackground, colors.background),
|
||||
label('surface', colors.onSurface, colors.surface),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
||||
},
|
||||
skip: isBrowser, // https://github.com/flutter/flutter/issues/44115
|
||||
);
|
||||
}
|
||||
|
|
|
@ -130,6 +130,111 @@ void main() {
|
|||
expect(const TextSelectionThemeData(cursorColor: Colors.red).cursorColor, Colors.red);
|
||||
});
|
||||
|
||||
test('If colorSchemeSeed is used colorScheme, primaryColor and primarySwatch should not be.', () {
|
||||
expect(() => ThemeData(colorSchemeSeed: Colors.blue, colorScheme: const ColorScheme.light()), throwsAssertionError);
|
||||
expect(() => ThemeData(colorSchemeSeed: Colors.blue, primaryColor: Colors.green), throwsAssertionError);
|
||||
expect(() => ThemeData(colorSchemeSeed: Colors.blue, primarySwatch: Colors.green), throwsAssertionError);
|
||||
});
|
||||
|
||||
test('ThemeData can generate a light colorScheme from colorSchemeSeed', () {
|
||||
final ThemeData theme = ThemeData(colorSchemeSeed: Colors.blue);
|
||||
|
||||
expect(theme.colorScheme.primary, const Color(0xff0061a6));
|
||||
expect(theme.colorScheme.onPrimary, const Color(0xffffffff));
|
||||
expect(theme.colorScheme.primaryContainer, const Color(0xffd0e4ff));
|
||||
expect(theme.colorScheme.onPrimaryContainer, const Color(0xff001d36));
|
||||
expect(theme.colorScheme.secondary, const Color(0xff535f70));
|
||||
expect(theme.colorScheme.onSecondary, const Color(0xffffffff));
|
||||
expect(theme.colorScheme.secondaryContainer, const Color(0xffd6e3f7));
|
||||
expect(theme.colorScheme.onSecondaryContainer, const Color(0xff101c2b));
|
||||
expect(theme.colorScheme.tertiary, const Color(0xff6b5778));
|
||||
expect(theme.colorScheme.onTertiary, const Color(0xffffffff));
|
||||
expect(theme.colorScheme.tertiaryContainer, const Color(0xfff3daff));
|
||||
expect(theme.colorScheme.onTertiaryContainer, const Color(0xff251432));
|
||||
expect(theme.colorScheme.error, const Color(0xffba1b1b));
|
||||
expect(theme.colorScheme.onError, const Color(0xffffffff));
|
||||
expect(theme.colorScheme.errorContainer, const Color(0xffffdad4));
|
||||
expect(theme.colorScheme.onErrorContainer, const Color(0xff410001));
|
||||
expect(theme.colorScheme.outline, const Color(0xff73777f));
|
||||
expect(theme.colorScheme.background, const Color(0xffe2e2e6));
|
||||
expect(theme.colorScheme.onBackground, const Color(0xff1b1b1b));
|
||||
expect(theme.colorScheme.surface, const Color(0xfffdfcff));
|
||||
expect(theme.colorScheme.onSurface, const Color(0xff000000));
|
||||
expect(theme.colorScheme.surfaceVariant, const Color(0xffdfe2eb));
|
||||
expect(theme.colorScheme.onSurfaceVariant, const Color(0xff42474e));
|
||||
expect(theme.colorScheme.inverseSurface, const Color(0xff2f3033));
|
||||
expect(theme.colorScheme.onInverseSurface, const Color(0xfff1f0f4));
|
||||
expect(theme.colorScheme.inversePrimary, const Color(0xff9ccaff));
|
||||
expect(theme.colorScheme.shadow, const Color(0xff000000));
|
||||
expect(theme.colorScheme.brightness, Brightness.light);
|
||||
|
||||
expect(theme.primaryColor, theme.colorScheme.primary);
|
||||
expect(theme.primaryColorBrightness, Brightness.dark);
|
||||
expect(theme.canvasColor, theme.colorScheme.background);
|
||||
expect(theme.accentColor, theme.colorScheme.secondary);
|
||||
expect(theme.accentColorBrightness, Brightness.dark);
|
||||
expect(theme.scaffoldBackgroundColor, theme.colorScheme.background);
|
||||
expect(theme.bottomAppBarColor, theme.colorScheme.surface);
|
||||
expect(theme.cardColor, theme.colorScheme.surface);
|
||||
expect(theme.dividerColor, theme.colorScheme.outline);
|
||||
expect(theme.backgroundColor, theme.colorScheme.background);
|
||||
expect(theme.dialogBackgroundColor, theme.colorScheme.background);
|
||||
expect(theme.indicatorColor, theme.colorScheme.onPrimary);
|
||||
expect(theme.errorColor, theme.colorScheme.error);
|
||||
expect(theme.applyElevationOverlayColor, false);
|
||||
});
|
||||
|
||||
test('ThemeData can generate a dark colorScheme from colorSchemeSeed', () {
|
||||
final ThemeData theme = ThemeData(
|
||||
colorSchemeSeed: Colors.blue,
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
|
||||
expect(theme.colorScheme.primary, const Color(0xff9ccaff));
|
||||
expect(theme.colorScheme.onPrimary, const Color(0xff00325a));
|
||||
expect(theme.colorScheme.primaryContainer, const Color(0xff60b0ff));
|
||||
expect(theme.colorScheme.onPrimaryContainer, const Color(0xff001d36));
|
||||
expect(theme.colorScheme.secondary, const Color(0xffbbc8db));
|
||||
expect(theme.colorScheme.onSecondary, const Color(0xff253140));
|
||||
expect(theme.colorScheme.secondaryContainer, const Color(0xff9facbf));
|
||||
expect(theme.colorScheme.onSecondaryContainer, const Color(0xff101c2b));
|
||||
expect(theme.colorScheme.tertiary, const Color(0xffd6bee4));
|
||||
expect(theme.colorScheme.onTertiary, const Color(0xff3b2948));
|
||||
expect(theme.colorScheme.tertiaryContainer, const Color(0xffbba3c9));
|
||||
expect(theme.colorScheme.onTertiaryContainer, const Color(0xff251432));
|
||||
expect(theme.colorScheme.error, const Color(0xffffb4a9));
|
||||
expect(theme.colorScheme.onError, const Color(0xff680003));
|
||||
expect(theme.colorScheme.errorContainer, const Color(0xffff897a));
|
||||
expect(theme.colorScheme.onErrorContainer, const Color(0xff410001));
|
||||
expect(theme.colorScheme.outline, const Color(0xff8d9199));
|
||||
expect(theme.colorScheme.background, const Color(0xff1b1b1b));
|
||||
expect(theme.colorScheme.onBackground, const Color(0xffe2e2e6));
|
||||
expect(theme.colorScheme.surface, const Color(0xff1b1b1b));
|
||||
expect(theme.colorScheme.onSurface, const Color(0xffffffff));
|
||||
expect(theme.colorScheme.surfaceVariant, const Color(0xff42474e));
|
||||
expect(theme.colorScheme.onSurfaceVariant, const Color(0xffc3c7d0));
|
||||
expect(theme.colorScheme.inverseSurface, const Color(0xffe2e2e6));
|
||||
expect(theme.colorScheme.onInverseSurface, const Color(0xff2f3033));
|
||||
expect(theme.colorScheme.inversePrimary, const Color(0xff0061a6));
|
||||
expect(theme.colorScheme.shadow, const Color(0xff000000));
|
||||
expect(theme.colorScheme.brightness, Brightness.dark);
|
||||
|
||||
expect(theme.primaryColor, theme.colorScheme.surface);
|
||||
expect(theme.primaryColorBrightness, Brightness.dark);
|
||||
expect(theme.canvasColor, theme.colorScheme.background);
|
||||
expect(theme.accentColor, theme.colorScheme.secondary);
|
||||
expect(theme.accentColorBrightness, Brightness.light);
|
||||
expect(theme.scaffoldBackgroundColor, theme.colorScheme.background);
|
||||
expect(theme.bottomAppBarColor, theme.colorScheme.surface);
|
||||
expect(theme.cardColor, theme.colorScheme.surface);
|
||||
expect(theme.dividerColor, theme.colorScheme.outline);
|
||||
expect(theme.backgroundColor, theme.colorScheme.background);
|
||||
expect(theme.dialogBackgroundColor, theme.colorScheme.background);
|
||||
expect(theme.indicatorColor, theme.colorScheme.onSurface);
|
||||
expect(theme.errorColor, theme.colorScheme.error);
|
||||
expect(theme.applyElevationOverlayColor, true);
|
||||
});
|
||||
|
||||
testWidgets('ThemeData.from a light color scheme sets appropriate values', (WidgetTester tester) async {
|
||||
const ColorScheme lightColors = ColorScheme.light();
|
||||
final ThemeData theme = ThemeData.from(colorScheme: lightColors);
|
||||
|
|
Loading…
Reference in a new issue