diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 0000000..3cb9a9b --- /dev/null +++ b/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "beta" +} \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9591980..0fd3672 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -39,7 +39,7 @@ jobs: - name: Install Flutter and Dart SDK uses: subosito/flutter-action@v2 with: - channel: 'stable' + channel: 'beta' - name: "Show Dart SDK version" run: dart --version - name: "Show Flutter SDK version" @@ -66,14 +66,14 @@ jobs: - name: "EXAMPLE START BUILD - Flutter clean before build" run: flutter clean && cd example && flutter clean - name: "EXAMPLE WEB release build" - run: cd example && flutter build web --web-renderer canvaskit --base-href "/flexseedscheme/demo-v1/" --release -t lib/main.dart + run: cd example && flutter build web --web-renderer canvaskit --base-href "/flexseedscheme/demo-v2/" --release -t lib/main.dart - name: "EXAMPLE DEPLOY to GitHub Pages repository, published on commit." uses: dmnemec/copy_file_to_another_repo_action@v1.0.4 env: API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }} with: source_file: 'example/build/web/.' - destination_folder: 'flexseedscheme/demo-v1' + destination_folder: 'flexseedscheme/demo-v2' destination_repo: 'rydmike/rydmike.github.io' user_email: 'm.rydstrom@gmail.com' user_name: 'rydmike' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dacb88c..a6d4776 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,7 +31,7 @@ jobs: - name: "Install Flutter and Dart SDK" uses: subosito/flutter-action@v2 with: - channel: "stable" + channel: "beta" - name: "Show Dart SDK version" run: dart --version - name: "Show Flutter SDK version" diff --git a/CHANGELOG.md b/CHANGELOG.md index e688c30..4ff173d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,36 @@ All notable changes to the **FlexSeedScheme** (FSS) package are documented here. +## 2.0.0-dev.1 + +**May 13, 2024** + +This release adds support for the revised Material-3 `ColorScheme` released in Flutter version 3.22. + +* **CHANGE** + * Bring the internal Material Color Utilities (MCU) library version to parity with its latest package release 0.11.1. Flutter SDK stable 3.22 still uses MCU 0.8.0, but the Flutter master channel is using MCU 0.11.1. + * The `FlexPaletteType.extended` tones got two new tones added, tone 2, and 24. It now has 27 tones. + + +* **NEW** + * Support revised Material-3 `ColorScheme` with the new colors primaryFixed, primaryFixedDim, onPrimaryFixed, onPrimaryFixedVariant, secondaryFixed, secondaryFixedDim, onSecondaryFixed, onSecondaryFixedVariant, tertiaryFixed, tertiaryFixedDim, onTertiaryFixed, onTertiaryFixedVariant, surfaceDim, surfaceBright, surfaceContainerLowest, surfaceContainerLow, surfaceContainer, surfaceContainerHigh and surfaceContainerHighest. + + * New optional way to specify used seeding algorithm in `SeedColorScheme.fromSeeds` by providing new enum value `FlexSchemeVariant` to its `variant` property. + + * In addition to supporting selection of previously built-in `FlexTones`, the `variant` property also supports using Flutter SDK scheme variants `tonalSpot`, `monochrome`, `neutral`, `vibrant`, `expressive`, `content`,`rainbow` and `fruitSalad` in property `variant` in `SeedColorScheme.fromSeeds`. In Flutter 3.22 only the default `tonalSpot` is available, but with FSS you can use any of the other variants as well already in Flutter 3.22. The other variants are not yet available in Flutter 3.22, but they are available in the `ColorScheme` API in the master channel and will be available in Flutter `ColorScheme.fromSeed` as well, in the next stable release after 3.22. With FSS you can use them already starting from Flutter 3.22.0. + + +* **BREAKING** + * The Material-3 `ColorScheme` colors `background`, `onBackground` and `surfaceVariant` have been deprecated since they are also deprecated in Flutter 3.22. + * These **deprecated** colors are still supported in `SeedColorScheme.fromSeeds` and `FlexTones`, but will be removed in a future release. They are replaced by `surface` and newer colors like `surfaceDim`, `surfaceBright` and `surfaceContainerLowest` in the new Material-3 `ColorScheme` in Flutter 3.22. + * The fact that these deprecated colors are still referenced in the package will reduce its **pub.dev** score with 10 points, but it is kept for now to maintain compatibility with Flutter 3.22 that also still provides values for the deprecated colors. This package needs to provide the same values to be fully compatible. The `ColorScheme` colors `background`, `onBackground` and `surfaceVariant` may only be fully removed when they have been removed from the Flutter SDK stable channel. They may, if they can be removed without breaking any styles, be removed in a future release of this package, even if they are still available in the Flutter SDK stable channel. + + +* **BREAKING STYLES** + + * All built-in `FlexTones` now use the `paletteType` extended via `FlexPaletteType.extended` as default for additional tone fidelity. This is needed for compatibility with Flutter 3.22 and its revised `ColorScheme`. + * The default tones for the built-in `FlexTones` have been adjusted to match the new Material-3 `ColorScheme` in Flutter 3.22. The new tones and default styles are marginally different but also better than in previous Flutter versions. If you need the result and style used in Flutter 3.19 and earlier, you can use the `FlexTones.material3Legacy` as `tones` in `SeedColorScheme.fromSeeds` to get the result `FlexTones.material` produced in FSS before version 2.0.0 and that was default in Flutter in version 3.19 and earlier. + ## 1.5.0 **April 3, 2024** diff --git a/README.md b/README.md index a19e518..64d5875 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,16 @@ [![Pub Version](https://img.shields.io/pub/v/flex_seed_scheme?label=flex_seed_scheme&labelColor=333940&logo=dart)](https://pub.dev/packages/flex_seed_scheme) [![codecov](https://codecov.io/gh/rydmike/flex_seed_scheme/branch/master/graph/badge.svg?token=YFNVrvWAXw)](https://codecov.io/gh/rydmike/flex_seed_scheme) [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -# FlexSeedScheme +# FlexSeedScheme (FSS) A more flexible and powerful version of Flutter's ColorScheme.fromSeed. Use this package like `ColorScheme.fromSeed` with the following additional capabilities: -* Use separate key colors to generate seed-based tonal palettes for primary and optionally - secondary, tertiary as well as error, neutral and neutral variant colors in `ColorScheme`. -* Change the chroma limits and values used in the Material-3 default strategy for tonal palette - generation in the new Google HCT (Hue-Chroma-Tone) color space. -* Change which tones in the generated core tonal palettes are used by which `ColorScheme` color. - Changes are limited to the tones from correct core palette for each `ColorScheme` color, but - any tone from it can be used. Going up or down one tone is often usable, in some cases even two. -* When using the default tonal palette `FlexPaletteType.common` two additional tones, 5 and 98 - are available. They can be used to offer more fidelity at the dark and - light end of the tonal palettes, and can be mapped to `ColorScheme` colors - when using custom tone mapping. Tone 98 was previously also available in the web-based - [Material-3 Theme Builder](https://m3.material.io/theme-builder#/custom), but is no longer so, - and is also not included in the [Material-3 design guide](https://m3.material.io/styles/color/the-color-system/key-colors-tones). The guide explicitly mentions thirteen - tones and excludes tone 98. With **FlexSeedScheme** you can use **fifteen** tones, including 98 and 5. -* For even more tones use `FlexPaletteType.extened` that gives access to all the new tones that - are used in the revised Material design 3 for surfaces and fixed main color. These are not yet - supported by the standard `ColorScheme` in Flutter 3.10, but are expected to arrive in later versions. +* Use separate key colors to generate seed-based tonal palettes for primary and optionally secondary, tertiary as well as error, neutral and neutral variant colors in `ColorScheme`. +* Change the chroma limits and values used in the Material-3 default strategy for tonal palette generation in the new Google HCT (Hue-Chroma-Tone) color space. +* Get access to new Material-3 design `ColorScheme` variants like `fidelity` and `monochrome` that do not yet exist in Flutter SDK (Flutter 3.22), but will arrive in later versions. +* Change which tones in the generated core tonal palettes are used by which `ColorScheme` color. Changes are limited to the tones from correct core palette for each `ColorScheme` color, but any tone from it can be used. Going up or down one tone is often usable, in some cases even two. +* For more tones use `FlexPaletteType.extended`, that gives access to all the new tones that are used in revised Material-3 design for surfaces and fixed main color. These new tones are used and supported by the standard `ColorScheme` in Flutter 3.22 and later. It is recommended to use `FlexPaletteType.extended` if creating new custom FlexTones. In the package version 2.0.0 and later, `FlexPaletteType.extended` is the default palette type. The older palette type `FlexPaletteType.common` is still available for backwards compatibility, but should be avoided. ## Background @@ -132,7 +120,7 @@ bottom: palettes The color tones in the above palettes are then mapped to `ColorScheme` colors. Mapping is -different for light and dark theme mode in order to create a color scheme with suitable contrast. +different for light and dark theme mode to create a color scheme with suitable contrast. With the example `FlexTones.vivid` setup used in `tones`, the light `ColorScheme` is mapped as shown below: @@ -147,6 +135,28 @@ color and tone 90 to `primaryContainer`. In dark mode they get tones 80 and 20. are repeated for secondary, tertiary, error colors and all the surface and background colors. It is this mapping that `FlexTones` gives you control over. +### Variants + +If you want to access the `ColorScheme` variants that Flutter SDK will provide in a future version, most likely in the next stable version after Flutter 3.22, then use `SeedColorScheme.fromSeeds` with the `variant` property of enum type `FlexSchemeVariant`. + +If the variant `FlexSchemeVariant` style is one that is also provided by Flutter SDK, it has `FlexSchemeVariant` property `isFlutterScheme` set to true. In that case, all other key colors except `primaryKey` are ignored. This is because the Flutter SDK `ColorScheme` variant system only supports one seed color. The `FlexSchemeVariant` also include the predefined `FlexTone` based variants. You can use the `variant` option as a way to select `ColorScheme` seed generation variant that is based on both new (coming) Flutter SDK options and the FlexSeedScheme predefined FlexTones `tones` based seed generation options. + +```dart + // Make a light ColorScheme from a seeds using variant style fidelity. + // This is a variant that is not yet available in Flutter SDK, but will be after 3.22.x stable. + final ColorScheme schemeLight = SeedColorScheme.fromSeeds( + brightness: Brightness.light, + primaryKey: primarySeedColor, + variant: FlexSchemeVariant.fidelity, + ); + // Make a dark ColorScheme from a seeds using variant style fidelity. + final ColorScheme schemeDark = SeedColorScheme.fromSeeds( + brightness: Brightness.dark, + primaryKey: primarySeedColor, + variant: FlexSchemeVariant.fidelity, + ); +``` + ## Define ThemeData In your `MaterialApp` you then define your light and dark mode themes using the seed @@ -225,7 +235,8 @@ color values is appropriate. In the above example, we used a predefined tone mapping and chroma setup `ColorScheme` generation strategy called `FlexTones.vivid`. There are currently **eleven** predefined configurations available: -* `FlexTones.material`, default and same as Flutter SDK M3 setup. +* `FlexTones.material`, default and same as Flutter SDK M3 setup in Flutter 3.22.0 and later. +* `FlexTones.material3Legacy`, same as Flutter SDK M3 default setup in Flutter before 3.22.0. * `FlexTones.soft`, softer and earthier tones than M3 FlexTones.material. * `FlexTones.vivid`, more vivid colors, uses chroma as defined by each given key color. * `FlexTones.vividSurfaces`, like `vivid`, but with more color tint in surfaces and backgrounds. @@ -276,19 +287,17 @@ const FlexTones myDarkTones = FlexTones.dark( ## Extended Palette -By using `paletteType` with value `FlexPaletteType.extended`, you can create seed generated `ColorScheme`s that use and access new color tones that exists in the late 2022 revised `ColorScheme` for surface colors and even more colors for **fixed** and **fixedDim** main colors that are coming to Material-3 design, potentially during later half of 2023. - -The `ColorScheme` colors that use these new tones are not yet available in Flutter 3.10 or earlier. The new colors may not even arrive in the next stable version after 3.10. For more information and the latest updates, see [Material-3 color-roles](https://m3.material.io/styles/color/the-color-system/color-roles) specification. +By using `paletteType` with value `FlexPaletteType.extended`, you can create seed generated `ColorScheme`s that use and access new color tones that exists in the late 2022 revised `ColorScheme` for surface colors and even more colors for **fixed** and **fixedDim** main colors that arrived in the Material-3 design during later half of 2023. -The updated Material-3 color system adds tones `[4, 6, 12, 17, 22]`, they are used for new dark mode surfaces in revised Material-3 dark surface colors. Likewise, the added tones `[87, 92, 94, 96, 97]` are for light mode surfaces in the updated Material-3 color system. By default `paletteType` of `FlexTones.common` is used. It produces the classic M3 tones with its own two additions `[5]` and `[98]` resulting in the 15 tones `[0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 98, 99, 100]`. +The `ColorScheme` colors that use these new tones are now finally also available in Flutter 3.22 or later. For more information and the latest updates, see [Material-3 color-roles](https://m3.material.io/styles/color/the-color-system/color-roles) specification. -To enable support for the tones in the updated specification and also adding one more custom tone `[97]`, use `paletteType` with value `FlexPaletteType.extended`. The extended palette type produces 25 tones `[0, 4, 5, 6, 10, 12, 17, 20, 22, 30, 40, 50, 60, 70, 80, 87, 90, 92, 94, 95, 96, 97, 98, 99, 100]`. +The updated Material-3 color system adds tones `[4, 6, 12, 17, 22, 24]`, they are used for new dark mode surfaces in revised Material-3 dark surface colors. Likewise, the added tones `[87, 92, 94, 96, 98]` are for light mode surfaces in the updated Material-3 color system. By default `paletteType` of `FlexTones.extended` is now used to enable support for the tones in the updated specification and also adding three more custom tone `[2, 5, 97]`. The `paletteType` with value `FlexPaletteType.extended` is now default, it produces 27 tones `[0, 2, 4, 5, 6, 10, 12, 17, 20, 22, 24, 30, 40, 50, 60, 70, 80, 87, 90, 92, 94, 95, 96, 97, 98, 99, 100]`. -Flutter 3.10 and earlier do not yet use these new tones in its standard `ColorScheme`, but since they are in the Material-3 specification, they will arrive at some later point. +To use the older classic setup you can still use `FlexTones.common`. It produces the legacy M3 tones with its own two additions `[5]` and `[98]` resulting in 15 tones `[0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 98, 99, 100]`. Flutter versions before 3.22 do not yet use these new tones in its standard `ColorScheme`. -Traditionally and for backwards compatibility, when using type `FlexPaletteType.common` the chroma of high tones, meaning higher or equal to 90, are limited to maximum chroma of 40. This keeps the chromacity of tones 90 to 100 lower than or equal to 40. If the source seed color has higher chromacity than 40, there may be a sudden jump in chroma reduction at tone 90. This is the standard behavior for the original Material-3 tonal palette computation. The `FlexPaletteType.common` type is intended to be used when there is a need to follow the M3's original palette design. +For backwards compatibility, when using type `FlexPaletteType.common` the chroma of high tones, meaning higher or equal to 90, are limited to maximum chroma of 40. This keeps the chromacity of tones 90 to 100 lower than or equal to 40. If the source seed color has higher chromacity than 40, there may be a sudden jump in chroma reduction at tone 90. This is the standard behavior for the original Material-3 tonal palette computation. The `FlexPaletteType.common` type is intended to be used when there is a need to follow the M3's original palette design. -When using the `FlexPaletteType.extended` type tones, there are not only the new tones, but the chroma limit of tones >= 90 is also removed. This increases fidelity of higher tone when high chromacity is used. Of the pre-made `FlexTones` only `candyPop` and `chroma` use the new `FlexPaletteType.extended` tonal palette to produce their `ColorScheme`s. All other that were defined in `FlexSeedScheme` before `FlexPaletteType.extended` was introduced, continue to use `FlexTones.common` for backwards compatibility. +When using the `FlexPaletteType.extended` type tones, there are not only new tones, but the chroma limit of tones >= 90 is also removed. This increases fidelity of higher tone when high chromacity is used. ## Accessibility @@ -351,6 +360,10 @@ Another way to modify `FlexTones` configurations for contrast and accessibility, If we remove the Material-3 guide used color system's colored contrasting colors, we can improve color accessibility and contrast on any `FlexTones` configuration. +> [!NOTE] +> If you use the `variant` property to the seed generated `ColorScheme` you cannot +> use the below presented `tones` modifiers, as they are modifiers used only on the input `FlexTones` configurations provided in `tones`. In the package example app you can find a demonstration of how to instead use `tones` as input for `FlexTones` based variants and `variant` being effective only when using variants that are Flutter SDK based. + We can do this with the `FlexTones` modifying methods `onMainsUseBW()`, for main on colors and with `onSurfacesUseBW()` for the surface on colors. These modifiers automatically make their corresponding contrasting colors black or white, depending on if the source color is light or dark. @@ -361,27 +374,26 @@ The main colors are: * `tertiary`, `tertiaryContainer` * `error`, `errorContainer` -So the on colors made black or white by `onMainsUseBW()` are: - +The on colors made black or white by `onMainsUseBW()` are: * `onPrimary`, `onPrimaryContainer` +* `onPrimaryFixed`, `onPrimaryFixedVariant` * `onSecondary`, `onSecondaryContainer` +* `onSecondaryFixed`, `onSecondaryFixedVariant` * `onTertiary`, `onTertiaryContainer` +* `onTertiaryFixed`, `onTertiaryFixedVariant` * `onError`, `onErrorContainer` -The surface colors are: -* `background` -* `surface` -* `surfaceVariant -* `inverseSurface` - -Hence, the on colors made black or white by `onSurfacesUseBW()` are: - -* `onBackground` +The surface on colors made black or white by `onSurfacesUseBW()` are: +* `onBackground` (deprecated) * `onSurface` * `onSurfaceVariant` * `onInverseSurface` +The surface colors made black by `surfacesUseBW()` are: +* `background` (deprecated in Flutter 3.22) +* `surface` + Here is a usage example, using both these modifiers. You cna use them individually too, and you don't have to use them in both light and dark mode. @@ -439,37 +451,24 @@ tones: FlexTones.material(Brightness.light) ); ``` -## [Example Application](https://rydmike.com/flexseedscheme/demo-v1) +## [Example Application](https://rydmike.com/flexseedscheme/demo-v2) The included example application uses above color seeding and custom tone mapping. You can also choose any of the built-in pre-configured tone mappings as used seeding strategy. When you select seeding strategy, basic info about is displayed. -You can try a web version of this example [**here**](https://rydmike.com/flexseedscheme/demo-v1). +You can try a web version of this example for version 2 of FSS [**here**](https://rydmike.com/flexseedscheme/demo-v2). The older demo for version 1 of FSS is still available [**here**](https://rydmike.com/flexseedscheme/demo-v1). -You can choose to use secondary and primary seed colors as additional keys to generate the color schemes. -You can also toggle keeping contrasting onColors black & white, or force background and surface -colors to be white in light mode and true black in dark mode. You can change the seed colors with -a color picker by tapping on the seed colors. You can also modify the default error seed color. +You can choose to use secondary and primary seed colors as additional keys to generate the color schemes. You can also toggle keeping contrasting onColors black & white, or force background and surface colors to be white in light mode and true black in dark mode. You can change the seed colors with a color picker by tapping on the seed colors. You can also modify the default error seed color. With the app we can compare results from `FlexSeedScheme.fromSeeds`, to using the single seed color based `ColorScheme.fromSeed` seed generated default Material-3 `ColorScheme` available in Flutter. -Both use the same key color as their primary seed color, but `ColorScheme.fromSeed` can only use it as -its single seed color, we cannot use hues from our secondary and tertiary key colors for the -seed produced tonal palettes, nor change how and its tones are mapped to the generated `ColorScheme`. - -With `ColorScheme.fromSeed` we can also not customize the colorfulness (chromacity) -of its seed generated secondary and tertiary colors. Like we can with `FlexSeedScheme.fromSeeds`, -demonstrated here by choosing different `FlexTones` configurations. The tonal palette tones to -`ColorScheme` color mappings can also not be modified, like we can do with `FlexSeedScheme.fromSeeds` -and its different mappings in each `FlexTones` seeding strategy. - -The seed generated tonal palettes are also displayed in the example application. You can toggle it -to show the default `FlexPaletteType.common` or the `FlexPaletteType.extended` version. -Only `FlexTones.candyPop` and `chroma`, as well as the custom mappings used in the example custom -`FlexTones` in the example app, use the extended tones. More schemes might use the extended tones later -when Flutter SDK also starts using them. +Both use the same key color as their primary seed color, but `ColorScheme.fromSeed` can only use it as its single seed color, we cannot use hues from our secondary and tertiary key colors for the seed produced tonal palettes, nor change how and its tones are mapped to the generated `ColorScheme`. + +With `ColorScheme.fromSeed` we can also not customize the colorfulness (chromacity) of its seed generated secondary and tertiary colors. Like we can with `FlexSeedScheme.fromSeeds`, demonstrated here by choosing different `FlexTones` configurations. The tonal palette tones to `ColorScheme` color mappings can also not be modified, like we can do with `FlexSeedScheme.fromSeeds` and its different mappings in each `FlexTones` seeding strategy. + +The seed generated tonal palettes are also displayed in the example application. You can toggle it to show the default `FlexPaletteType.common` or the `FlexPaletteType.extended` version. Only `FlexTones.candyPop` and `chroma`, as well as the custom mappings used in the example custom FlexTones` in the example app, use the extended tones. More schemes might use the extended tones later when Flutter SDK also starts using them. ## Scheme Generation Strategies diff --git a/example/lib/core/constants/app_data.dart b/example/lib/core/constants/app_data.dart index ff09d18..1611aad 100644 --- a/example/lib/core/constants/app_data.dart +++ b/example/lib/core/constants/app_data.dart @@ -25,16 +25,16 @@ class AppData { static const String packageName = 'FlexSeed\u{00AD}Scheme'; // Version of the WEB build, usually same as package, but it also has a // build numbers. - static const String versionMajor = '1'; - static const String versionMinor = '5'; - static const String versionPatch = '0'; + static const String versionMajor = '2'; + static const String versionMinor = '0'; + static const String versionPatch = '0-dev.1'; static const String versionBuild = '01'; static const String version = '$versionMajor.$versionMinor.$versionPatch ' 'Build-$versionBuild'; static const String packageVersion = '$versionMajor.$versionMinor.$versionPatch'; - static const String flutterVersion = '3.19.5 (canvaskit)'; - static const String copyright = '© 2022, 2023'; + static const String flutterVersion = '3.22.0 (canvaskit)'; + static const String copyright = '© 2022-2024'; static const String author = 'Mike Rydstrom'; static const String license = 'BSD 3-Clause License'; static final Uri packageUri = Uri( diff --git a/example/lib/core/views/app/color_name_value.dart b/example/lib/core/views/app/color_name_value.dart index c9918cf..221110f 100644 --- a/example/lib/core/views/app/color_name_value.dart +++ b/example/lib/core/views/app/color_name_value.dart @@ -264,12 +264,12 @@ class _ColorNameValueState extends State { inactiveThumbColor: Color.alphaBlend( widget.color.withAlpha(0xCC), widget.textColor), trackOutlineColor: theme.useMaterial3 - ? MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.selected)) { + ? WidgetStateProperty.resolveWith( + (Set states) { + if (states.contains(WidgetState.selected)) { return Colors.transparent; } - if (states.contains(MaterialState.disabled)) { + if (states.contains(WidgetState.disabled)) { return theme.colorScheme.onSurface.withAlpha(0x1F); } return widget.textColor.withAlpha(0x26); diff --git a/example/lib/core/views/app/copy_color_to_clipboard.dart b/example/lib/core/views/app/copy_color_to_clipboard.dart index 34e4152..8cc2ec6 100644 --- a/example/lib/core/views/app/copy_color_to_clipboard.dart +++ b/example/lib/core/views/app/copy_color_to_clipboard.dart @@ -7,12 +7,14 @@ import '../../utils/flex_color_extension.dart'; /// Copy the color value as a String to the Clipboard in Flutter Dart format. /// /// Notify with [SnackBar] that it was copied. -Future copyColorToClipboard(BuildContext context, Color color) async { +Future copyColorToClipboard(BuildContext context, Color color, + [String label = '']) async { final ClipboardData data = ClipboardData(text: '0x${color.hexAlpha}'); await Clipboard.setData(data); final String materialName = ColorTools.materialName(color); final String nameThatColor = ColorTools.nameThatColor(color); final String space = materialName == '' ? '' : ' '; + final String spaceLabel = label == '' ? '' : ' '; // Show a snack bar with the copy message. if (context.mounted) { final double? width = MediaQuery.of(context).size.width > 800 ? 700 : null; @@ -38,8 +40,8 @@ Future copyColorToClipboard(BuildContext context, Color color) async { const SizedBox(width: 8), Expanded( child: Text( - 'Copied color $nameThatColor $materialName${space}to ' - 'the clipboard', + 'Copied color $label$spaceLabel$nameThatColor ' + '$materialName${space}to the clipboard', ), ), ], diff --git a/example/lib/core/views/universal/color_scheme_view.dart b/example/lib/core/views/universal/color_scheme_view.dart new file mode 100644 index 0000000..782694f --- /dev/null +++ b/example/lib/core/views/universal/color_scheme_view.dart @@ -0,0 +1,474 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +import '../../utils/flex_color_extension.dart'; +import '../app/copy_color_to_clipboard.dart'; + +const Size _colorChipSize = Size(160, 50); +const Size _onChipSize = Size(160, 36); +const Size _equalFourChipSize = Size(160, 43); +const Size _equalThreeChipSize = Size(160, 57.333); + +/// A view that shows all the colors in a [ColorScheme]. +/// +/// It also allows copying the color values to the clipboard by tapping the +/// scheme color. +class ColorSchemeView extends StatelessWidget { + const ColorSchemeView({super.key, this.scheme}); + + final ColorScheme? scheme; + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final ColorScheme colorScheme = scheme ?? theme.colorScheme; + final bool useMaterial3 = theme.useMaterial3; + const double spacing = 6; + + // Grab the card border from the theme card shape + ShapeBorder? border = theme.cardTheme.shape; + // If we had one, copy in a border side to it. + if (border is RoundedRectangleBorder) { + border = border.copyWith( + side: BorderSide(color: colorScheme.outlineVariant), + ); + // If + } else { + // If border was null, make one matching Card default, but with border + // side, if it was not null, we leave it as it was. + border ??= RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(useMaterial3 ? 12 : 4)), + side: BorderSide(color: colorScheme.outlineVariant), + ); + } + + return Theme( + data: Theme.of(context).copyWith( + cardTheme: CardTheme.of(context).copyWith( + elevation: 0, + shape: border, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Text( + 'ColorScheme Colors', + style: theme.textTheme.titleMedium, + ), + ), + Wrap( + spacing: spacing, + runSpacing: spacing, + children: [ + ColorGroup(children: [ + ColorChip( + label: 'primary', + color: colorScheme.primary, + onColor: colorScheme.onPrimary, + size: _colorChipSize, + ), + ColorChip( + label: 'onPrimary', + color: colorScheme.onPrimary, + onColor: colorScheme.primary), + ColorChip( + label: 'primaryContainer', + color: colorScheme.primaryContainer, + onColor: colorScheme.onPrimaryContainer, + size: _colorChipSize, + ), + ColorChip( + label: 'onPrimaryContainer', + color: colorScheme.onPrimaryContainer, + onColor: colorScheme.primaryContainer, + ), + ]), + ColorGroup(children: [ + ColorChip( + label: 'primaryFixed', + color: colorScheme.primaryFixed, + onColor: colorScheme.onPrimaryFixed, + size: _colorChipSize, + ), + ColorChip( + label: 'onPrimaryFixed', + color: colorScheme.onPrimaryFixed, + onColor: colorScheme.primaryFixed), + ColorChip( + label: 'primaryFixedDim', + color: colorScheme.primaryFixedDim, + onColor: colorScheme.onPrimaryFixedVariant, + size: _colorChipSize, + ), + ColorChip( + label: 'onPrimaryFixedVariant', + color: colorScheme.onPrimaryFixedVariant, + onColor: colorScheme.primaryFixedDim, + ), + ]), + ColorGroup(children: [ + ColorChip( + label: 'secondary', + color: colorScheme.secondary, + onColor: colorScheme.onSecondary, + size: _colorChipSize, + ), + ColorChip( + label: 'onSecondary', + color: colorScheme.onSecondary, + onColor: colorScheme.secondary, + ), + ColorChip( + label: 'secondaryContainer', + color: colorScheme.secondaryContainer, + onColor: colorScheme.onSecondaryContainer, + size: _colorChipSize, + ), + ColorChip( + label: 'onSecondaryContainer', + color: colorScheme.onSecondaryContainer, + onColor: colorScheme.secondaryContainer, + ), + ]), + ColorGroup(children: [ + ColorChip( + label: 'secondaryFixed', + color: colorScheme.secondaryFixed, + onColor: colorScheme.onSecondaryFixed, + size: _colorChipSize, + ), + ColorChip( + label: 'onSecondaryFixed', + color: colorScheme.onSecondaryFixed, + onColor: colorScheme.secondaryFixed), + ColorChip( + label: 'secondaryFixedDim', + color: colorScheme.secondaryFixedDim, + onColor: colorScheme.onSecondaryFixedVariant, + size: _colorChipSize, + ), + ColorChip( + label: 'onSecondaryFixedVariant', + color: colorScheme.onSecondaryFixedVariant, + onColor: colorScheme.secondaryFixedDim, + ), + ]), + ColorGroup( + children: [ + ColorChip( + label: 'tertiary', + color: colorScheme.tertiary, + onColor: colorScheme.onTertiary, + size: _colorChipSize, + ), + ColorChip( + label: 'onTertiary', + color: colorScheme.onTertiary, + onColor: colorScheme.tertiary, + ), + ColorChip( + label: 'tertiaryContainer', + color: colorScheme.tertiaryContainer, + onColor: colorScheme.onTertiaryContainer, + size: _colorChipSize, + ), + ColorChip( + label: 'onTertiaryContainer', + color: colorScheme.onTertiaryContainer, + onColor: colorScheme.tertiaryContainer, + ), + ], + ), + ColorGroup(children: [ + ColorChip( + label: 'tertiaryFixed', + color: colorScheme.tertiaryFixed, + onColor: colorScheme.onTertiaryFixed, + size: _colorChipSize, + ), + ColorChip( + label: 'onTertiaryFixed', + color: colorScheme.onTertiaryFixed, + onColor: colorScheme.tertiaryFixed), + ColorChip( + label: 'tertiaryFixedDim', + color: colorScheme.tertiaryFixedDim, + onColor: colorScheme.onTertiaryFixedVariant, + size: _colorChipSize, + ), + ColorChip( + label: 'onTertiaryFixedVariant', + color: colorScheme.onTertiaryFixedVariant, + onColor: colorScheme.tertiaryFixedDim, + ), + ]), + ColorGroup( + children: [ + ColorChip( + label: 'error', + color: colorScheme.error, + onColor: colorScheme.onError, + size: _colorChipSize, + ), + ColorChip( + label: 'onError', + color: colorScheme.onError, + onColor: colorScheme.error, + ), + ColorChip( + label: 'errorContainer', + color: colorScheme.errorContainer, + onColor: colorScheme.onErrorContainer, + size: _colorChipSize, + ), + ColorChip( + label: 'onErrorContainer', + color: colorScheme.onErrorContainer, + onColor: colorScheme.errorContainer, + ), + ], + ), + ColorGroup( + children: [ + ColorChip( + label: 'surface', + color: colorScheme.surface, + onColor: colorScheme.onSurface, + size: _colorChipSize, + ), + ColorChip( + label: 'onSurface', + color: colorScheme.onSurface, + onColor: colorScheme.surface, + ), + ColorChip( + label: 'surfaceContainer', + color: colorScheme.surfaceContainer, + onColor: colorScheme.onSurfaceVariant, + size: _colorChipSize, + ), + ColorChip( + label: 'onSurfaceVariant', + color: colorScheme.onSurfaceVariant, + onColor: colorScheme.surfaceContainer, + ), + ], + ), + ColorGroup( + children: [ + ColorChip( + label: 'surfaceContainerLowest', + color: colorScheme.surfaceContainerLowest, + onColor: colorScheme.onSurface, + size: _equalFourChipSize, + ), + ColorChip( + label: 'surfaceContainerLow', + color: colorScheme.surfaceContainerLow, + onColor: colorScheme.onSurface, + size: _equalFourChipSize, + ), + ColorChip( + label: 'surfaceContainerHigh', + color: colorScheme.surfaceContainerHigh, + onColor: colorScheme.onSurface, + size: _equalFourChipSize, + ), + ColorChip( + label: 'surfaceContainerHighest', + color: colorScheme.surfaceContainerHighest, + onColor: colorScheme.onSurface, + size: _equalFourChipSize, + ), + ], + ), + ColorGroup( + children: [ + ColorChip( + label: 'surfaceDim', + color: colorScheme.surfaceDim, + onColor: colorScheme.onSurface, + size: _equalFourChipSize, + ), + ColorChip( + label: 'surfaceBright', + color: colorScheme.surfaceBright, + onColor: colorScheme.onSurface, + size: _equalFourChipSize, + ), + ColorChip( + label: 'inverseSurface', + color: colorScheme.inverseSurface, + onColor: colorScheme.onInverseSurface, + size: _equalFourChipSize, + ), + ColorChip( + label: 'onInverseSurface', + color: colorScheme.onInverseSurface, + onColor: colorScheme.inverseSurface, + size: _equalFourChipSize, + ), + ], + ), + ColorGroup( + children: [ + ColorChip( + label: 'outline', + color: colorScheme.outline, + onColor: colorScheme.surface, + size: _equalThreeChipSize, + ), + ColorChip( + label: 'outlineVariant', + color: colorScheme.outlineVariant, + size: _equalThreeChipSize, + ), + ColorChip( + label: 'scrim', + color: colorScheme.scrim, + size: _equalThreeChipSize, + ), + ], + ), + ColorGroup( + children: [ + ColorChip( + label: 'surfaceTint', + color: colorScheme.surfaceTint, + size: _equalThreeChipSize, + ), + ColorChip( + label: 'inversePrimary', + color: colorScheme.inversePrimary, + onColor: colorScheme.primary, + size: _equalThreeChipSize, + ), + ColorChip( + label: 'shadow', + color: colorScheme.shadow, + size: _equalThreeChipSize, + ), + ], + ), + // TODO(rydmike): Remove deprecated colors in Flutter 3.25. + // Show the deprecated colors. + ColorGroup( + children: [ + ColorChip( + label: 'background\n(deprecated)', + color: colorScheme.background, + onColor: colorScheme.onBackground, + size: _equalThreeChipSize, + ), + ColorChip( + label: 'onBackground\n(deprecated)', + color: colorScheme.onBackground, + onColor: colorScheme.background, + size: _equalThreeChipSize, + ), + ColorChip( + label: 'surfaceVariant\n(deprecated)', + color: colorScheme.surfaceVariant, + onColor: colorScheme.onSurfaceVariant, + size: _equalThreeChipSize, + ), + ], + ), + ], + ), + ], + ), + ); + } +} + +class ColorGroup extends StatelessWidget { + const ColorGroup({super.key, required this.children}); + + final List children; + + @override + Widget build(BuildContext context) { + return RepaintBoundary( + child: Card( + surfaceTintColor: Colors.transparent, + clipBehavior: Clip.antiAliasWithSaveLayer, + child: Column( + children: children, + ), + ), + ); + } +} + +class ColorChip extends StatelessWidget { + const ColorChip({ + super.key, + required this.color, + required this.label, + this.onColor, + this.size, + this.copyEnabled = true, + }); + + final Color color; + final Color? onColor; + final String label; + final Size? size; + final bool copyEnabled; + + static Color _contrastColor(Color color) { + final Brightness brightness = ThemeData.estimateBrightnessForColor(color); + switch (brightness) { + case Brightness.dark: + return Colors.white; + case Brightness.light: + return Colors.black; + } + } + + @override + Widget build(BuildContext context) { + final Color labelColor = onColor ?? _contrastColor(color); + final Size effectiveSize = size ?? _onChipSize; + + return SizedBox( + width: effectiveSize.width, + height: effectiveSize.height, + child: Tooltip( + waitDuration: const Duration(milliseconds: 700), + message: copyEnabled + ? 'Color #${color.hexCode}.' + '\nTap box to copy RGB value to Clipboard.' + : '', + child: ColoredBox( + color: color, + child: InkWell( + onTap: copyEnabled + ? () { + unawaited(copyColorToClipboard(context, color, label)); + } + : null, + child: Padding( + padding: const EdgeInsets.all(10), + child: Row( + children: [ + Expanded( + child: Text( + label, + style: TextStyle(color: labelColor, fontSize: 11), + ), + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/example/lib/core/views/universal/showcase_material.dart b/example/lib/core/views/universal/showcase_material.dart index 7480187..5b0f8f5 100644 --- a/example/lib/core/views/universal/showcase_material.dart +++ b/example/lib/core/views/universal/showcase_material.dart @@ -568,9 +568,9 @@ class _SwitchShowcaseState extends State { }, ), Switch( - thumbIcon: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.selected)) { + thumbIcon: WidgetStateProperty.resolveWith( + (Set states) { + if (states.contains(WidgetState.selected)) { return Icon(Icons.check, color: isLight ? colorScheme.primary : colorScheme.onPrimary); @@ -1927,7 +1927,7 @@ class _SearchBarShowcaseState extends State { return SearchBar( controller: controller, hintText: 'Search using SearchBar', - padding: const MaterialStatePropertyAll( + padding: const WidgetStatePropertyAll( EdgeInsets.symmetric(horizontal: 16.0)), onTap: () { controller.openView(); diff --git a/example/lib/home/views/pages/home_page.dart b/example/lib/home/views/pages/home_page.dart index a572e26..c1a7eab 100644 --- a/example/lib/home/views/pages/home_page.dart +++ b/example/lib/home/views/pages/home_page.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import '../../../about/views/about.dart'; import '../../../core/constants/app_data.dart'; +import '../../../core/views/universal/color_scheme_view.dart'; import '../../../core/views/universal/showcase_material.dart'; import '../../../theme/controllers/theme_controller.dart'; import '../widgets/flex_tones_popup_menu.dart'; -import '../widgets/show_color_scheme_colors.dart'; import '../widgets/show_input_colors.dart'; import '../widgets/show_tonal_palette.dart'; @@ -54,14 +54,16 @@ class HomePage extends StatelessWidget { body: ListView( children: [ FlexTonesPopupMenu( - title: 'Used FlexTones seed strategy:', - tone: controller.usedTone, + title: 'Selected scheme variant:', + variant: controller.usedVariant, onChanged: controller.setUsedTone, + contentPadding: + const EdgeInsetsDirectional.only(start: 16, end: 24), ), ListTile( - title: Text('${controller.usedTone.toneLabel}' - ' FlexTones uses:'), - subtitle: Text('${controller.usedTone.setup}\n'), + title: Text('${controller.usedVariant.variantName}' + ' scheme variant configuration info:'), + subtitle: Text('${controller.usedVariant.configDetails}\n'), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), @@ -71,57 +73,91 @@ class HomePage extends StatelessWidget { dense: true, title: Text('Primary key color is always used to seed the ' 'ColorScheme. Tap to change colors.')), + if (controller.usedVariant.isFlutterScheme) + const ListTile( + dense: true, + title: Text('Additional seed generation options are not ' + 'available when using Flutter SDK scheme variant styles. ' + 'Use a variant based on FlexTones for more options.'), + ) + else + const ListTile( + dense: true, + title: Text('Additional seed generation option are available ' + 'when using FlexTones based scheme variants.'), + ), const Divider(), SwitchListTile( dense: true, title: const Text('Use secondary key color to seed the ColorScheme'), - value: controller.useSecondaryKey, - onChanged: controller.setUseSecondaryKey, + value: controller.useSecondaryKey && + !controller.usedVariant.isFlutterScheme, + onChanged: controller.usedVariant.isFlutterScheme + ? null + : controller.setUseSecondaryKey, ), SwitchListTile( dense: true, title: const Text('Use tertiary key color to seed the ColorScheme'), - value: controller.useTertiaryKey, - onChanged: controller.setUseTertiaryKey, + value: controller.useTertiaryKey && + !controller.usedVariant.isFlutterScheme, + onChanged: controller.usedVariant.isFlutterScheme + ? null + : controller.setUseTertiaryKey, ), SwitchListTile( dense: true, title: const Text( 'Use custom error key color to seed the ColorScheme'), - value: controller.useErrorKey, - onChanged: controller.setUseErrorKey, + value: controller.useErrorKey && + !controller.usedVariant.isFlutterScheme, + onChanged: controller.usedVariant.isFlutterScheme + ? null + : controller.setUseErrorKey, ), const Divider(), SwitchListTile( dense: true, title: const Text( 'Keep main onColors in seeded ColorScheme black and white'), - value: controller.keepMainOnColorsBW, - onChanged: controller.setKeepMainOnColorsBW, + value: controller.keepMainOnColorsBW && + !controller.usedVariant.isFlutterScheme, + onChanged: controller.usedVariant.isFlutterScheme + ? null + : controller.setKeepMainOnColorsBW, ), SwitchListTile( dense: true, title: const Text( 'Keep surface onColors in seeded ColorScheme black and white'), - value: controller.keepSurfaceOnColorsBW, - onChanged: controller.setKeepSurfaceOnColorsBW, + value: controller.keepSurfaceOnColorsBW && + !controller.usedVariant.isFlutterScheme, + onChanged: controller.usedVariant.isFlutterScheme + ? null + : controller.setKeepSurfaceOnColorsBW, ), if (isLight) SwitchListTile( dense: true, title: const Text('Keep surface and background white in seeded ' 'light ColorScheme'), - value: controller.keepLightSurfaceColorsWhite, - onChanged: controller.setKeepLightSurfaceColorsWhite, + value: controller.keepLightSurfaceColorsWhite && + !controller.usedVariant.isFlutterScheme, + onChanged: controller.usedVariant.isFlutterScheme + ? null + : controller.setKeepLightSurfaceColorsWhite, ) else SwitchListTile( dense: true, title: const Text('Keep surface and background black in seeded ' 'dark ColorScheme'), - value: controller.keepDarkSurfaceColorsBlack, - onChanged: controller.setKeepDarkSurfaceColorsBlack, + value: controller.keepDarkSurfaceColorsBlack && + !controller.usedVariant.isFlutterScheme, + onChanged: controller.usedVariant.isFlutterScheme + ? null + : controller.setKeepDarkSurfaceColorsBlack, ), const Divider(), Padding( @@ -130,7 +166,7 @@ class HomePage extends StatelessWidget { ), const Padding( padding: EdgeInsets.symmetric(horizontal: 16), - child: ShowColorSchemeColors(), + child: ColorSchemeView(), ), const SizedBox(height: 16), const Divider(), diff --git a/example/lib/home/views/widgets/flex_tones_popup_menu.dart b/example/lib/home/views/widgets/flex_tones_popup_menu.dart index c9e2f51..bc36057 100644 --- a/example/lib/home/views/widgets/flex_tones_popup_menu.dart +++ b/example/lib/home/views/widgets/flex_tones_popup_menu.dart @@ -3,21 +3,20 @@ import 'package:flutter/material.dart'; import '../../../core/utils/flex_color_extension.dart'; import '../../../core/views/universal/color_scheme_box.dart'; -import '../../../theme/model/flex_tones_enum.dart'; /// Widget used to select used [FlexTones] with a popup menu. /// -/// Uses enhanced enum [FlexTonesEnum] to get data for the UI. +/// Uses enhanced enum [FlexSchemeVariant] to get data for the UI. class FlexTonesPopupMenu extends StatelessWidget { const FlexTonesPopupMenu({ super.key, - required this.tone, + required this.variant, this.onChanged, this.title = '', this.contentPadding, }); - final FlexTonesEnum tone; - final ValueChanged? onChanged; + final FlexSchemeVariant variant; + final ValueChanged? onChanged; final String title; final EdgeInsetsGeometry? contentPadding; // Defaults to 16. @@ -27,34 +26,44 @@ class FlexTonesPopupMenu extends StatelessWidget { final ColorScheme colorScheme = theme.colorScheme; final TextStyle txtStyle = theme.textTheme.labelLarge!; - return PopupMenuButton( + return PopupMenuButton( tooltip: '', padding: EdgeInsets.zero, - onSelected: (FlexTonesEnum tone) { - onChanged?.call(tone); + onSelected: (FlexSchemeVariant variant) { + onChanged?.call(variant); }, - itemBuilder: (BuildContext context) => >[ - for (final FlexTonesEnum tone in FlexTonesEnum.values) - PopupMenuItem( - value: tone, + itemBuilder: (BuildContext context) => >[ + for (final FlexSchemeVariant variant in FlexSchemeVariant.values) + PopupMenuItem( + value: variant, child: ListTile( dense: true, - leading: ColorSchemeBox( - optionIcon: tone.icon, - color: colorScheme.primary.darken(tone.shade), + leading: Badge( + label: variant.isFlutterScheme + ? const Text('MCU', style: TextStyle(fontSize: 8)) + : const Text('FSS', style: TextStyle(fontSize: 8)), + child: ColorSchemeBox( + optionIcon: variant.icon, + color: colorScheme.primary.darken(variant.shade), + ), ), - title: Text(tone.toneLabel, style: txtStyle), + title: Text(variant.variantName, style: txtStyle), ), ) ], child: ListTile( contentPadding: contentPadding ?? const EdgeInsets.symmetric(horizontal: 16), - title: Text('$title ${tone.toneLabel}'), - subtitle: Text(tone.describe), - trailing: ColorSchemeBox( - color: colorScheme.primary, - optionIcon: tone.icon, + title: Text('$title ${variant.variantName}'), + subtitle: Text(variant.description), + trailing: Badge( + label: variant.isFlutterScheme + ? const Text('MCU', style: TextStyle(fontSize: 8)) + : const Text('FSS', style: TextStyle(fontSize: 8)), + child: ColorSchemeBox( + color: colorScheme.primary, + optionIcon: variant.icon, + ), ), ), ); diff --git a/example/lib/home/views/widgets/show_color_scheme_colors.dart b/example/lib/home/views/widgets/show_color_scheme_colors.dart index c0dc607..5c15f88 100644 --- a/example/lib/home/views/widgets/show_color_scheme_colors.dart +++ b/example/lib/home/views/widgets/show_color_scheme_colors.dart @@ -156,16 +156,6 @@ class ShowColorSchemeColors extends StatelessWidget { color: colorScheme.onErrorContainer, textColor: colorScheme.errorContainer, ), - ColorCard( - label: 'Background', - color: colorScheme.background, - textColor: colorScheme.onBackground, - ), - ColorCard( - label: 'on\nBackground', - color: colorScheme.onBackground, - textColor: colorScheme.background, - ), ColorCard( label: 'Surface', color: colorScheme.surface, @@ -176,20 +166,10 @@ class ShowColorSchemeColors extends StatelessWidget { color: colorScheme.onSurface, textColor: colorScheme.surface, ), - ColorCard( - label: 'Surface\nVariant', - color: colorScheme.surfaceVariant, - textColor: colorScheme.onSurfaceVariant, - ), - ColorCard( - label: 'onSurface\nVariant', - color: colorScheme.onSurfaceVariant, - textColor: colorScheme.surfaceVariant, - ), ColorCard( label: 'Outline', color: colorScheme.outline, - textColor: colorScheme.background, + textColor: colorScheme.surface, ), ColorCard( label: 'Outline\nVariant', diff --git a/example/lib/home/views/widgets/show_input_colors.dart b/example/lib/home/views/widgets/show_input_colors.dart index 395fd6a..a9b2a31 100644 --- a/example/lib/home/views/widgets/show_input_colors.dart +++ b/example/lib/home/views/widgets/show_input_colors.dart @@ -45,7 +45,7 @@ class ShowInputColors extends StatelessWidget { final Color onTertiary = _onColor(tertiary); final Color error = controller.errorSeedColor; final Color onError = _onColor(error); - final Color background = colorScheme.background; + final Color surface = colorScheme.surface; // Grab the card border from the theme card shape ShapeBorder? border = theme.cardTheme.shape; @@ -142,8 +142,10 @@ class ShowInputColors extends StatelessWidget { elevation: 0, clipBehavior: Clip.hardEdge, child: Material( - color: - controller.useSecondaryKey ? secondary : background, + color: controller.useSecondaryKey && + !controller.usedVariant.isFlutterScheme + ? secondary + : surface, child: ColorPickerInkWellDialog( color: secondary, onChanged: controller.setSecondarySeedColor, @@ -154,15 +156,18 @@ class ShowInputColors extends StatelessWidget { controller.setSecondarySeedColor(secondary); } }, - enabled: controller.useSecondaryKey, + enabled: controller.useSecondaryKey && + !controller.usedVariant.isFlutterScheme, child: ColorNameValue( key: ValueKey('ipc secondary $secondary'), - color: controller.useSecondaryKey + color: controller.useSecondaryKey && + !controller.usedVariant.isFlutterScheme ? secondary - : background, - textColor: controller.useSecondaryKey + : surface, + textColor: controller.useSecondaryKey && + !controller.usedVariant.isFlutterScheme ? onSecondary - : background, + : surface, showInputColor: false, label: 'secondary', showMaterialName: true, @@ -184,10 +189,12 @@ class ShowInputColors extends StatelessWidget { elevation: 0, clipBehavior: Clip.hardEdge, child: Material( - color: controller.useTertiaryKey ? tertiary : background, + color: controller.useTertiaryKey && + !controller.usedVariant.isFlutterScheme + ? tertiary + : surface, child: ColorPickerInkWellDialog( - color: - controller.useTertiaryKey ? tertiary : background, + color: controller.useTertiaryKey ? tertiary : surface, onChanged: controller.setTertiarySeedColor, recentColors: controller.recentColors, onRecentColorsChanged: controller.setRecentColors, @@ -196,14 +203,18 @@ class ShowInputColors extends StatelessWidget { controller.setTertiarySeedColor(tertiary); } }, - enabled: controller.useTertiaryKey, + enabled: controller.useTertiaryKey && + !controller.usedVariant.isFlutterScheme, child: ColorNameValue( key: ValueKey('ipc tertiary $tertiary'), - color: - controller.useTertiaryKey ? tertiary : background, - textColor: controller.useTertiaryKey + color: controller.useTertiaryKey && + !controller.usedVariant.isFlutterScheme + ? tertiary + : surface, + textColor: controller.useTertiaryKey && + !controller.usedVariant.isFlutterScheme ? onTertiary - : background, + : surface, label: 'tertiary', showInputColor: false, showMaterialName: true, @@ -224,9 +235,12 @@ class ShowInputColors extends StatelessWidget { elevation: 0, clipBehavior: Clip.hardEdge, child: Material( - color: controller.useErrorKey ? error : background, + color: controller.useErrorKey && + !controller.usedVariant.isFlutterScheme + ? error + : surface, child: ColorPickerInkWellDialog( - color: controller.useErrorKey ? error : background, + color: controller.useErrorKey ? error : surface, onChanged: controller.setErrorSeedColor, recentColors: controller.recentColors, onRecentColorsChanged: controller.setRecentColors, @@ -235,12 +249,18 @@ class ShowInputColors extends StatelessWidget { controller.setErrorSeedColor(error); } }, - enabled: controller.useErrorKey, + enabled: controller.useErrorKey && + !controller.usedVariant.isFlutterScheme, child: ColorNameValue( key: ValueKey('ipc error $error'), - color: controller.useErrorKey ? error : background, - textColor: - controller.useErrorKey ? onError : background, + color: controller.useErrorKey && + !controller.usedVariant.isFlutterScheme + ? error + : surface, + textColor: controller.useErrorKey && + !controller.usedVariant.isFlutterScheme + ? onError + : surface, label: 'error', showInputColor: false, showMaterialName: true, diff --git a/example/lib/home/views/widgets/show_tonal_palette.dart b/example/lib/home/views/widgets/show_tonal_palette.dart index 7452278..cc23be5 100644 --- a/example/lib/home/views/widgets/show_tonal_palette.dart +++ b/example/lib/home/views/widgets/show_tonal_palette.dart @@ -18,32 +18,81 @@ class ShowTonalPalette extends StatelessWidget { final ThemeData theme = Theme.of(context); final Brightness brightness = theme.brightness; // Get the FlexTones setup - final FlexTones tones = controller.usedTone.tones(brightness); + final FlexTones tones = controller.usedVariant.tones(brightness); // Type of palette to show. final FlexPaletteType paletteType = controller.paletteType; - // Compute all the FlexCoreTonalPalette tones. - final FlexCorePalette palettes = FlexCorePalette.fromSeeds( - primary: controller.primarySeedColor.value, - // Pass in null if set to not use secondary or tertiary seed keys. - secondary: controller.useSecondaryKey - ? controller.secondarySeedColor.value - : null, - tertiary: - controller.useTertiaryKey ? controller.tertiarySeedColor.value : null, - error: controller.useErrorKey ? controller.errorSeedColor.value : null, - // Tone config details we get from active FlexTones. - primaryChroma: tones.primaryChroma, - primaryMinChroma: tones.primaryMinChroma, - secondaryChroma: tones.secondaryChroma, - secondaryMinChroma: tones.secondaryMinChroma, - tertiaryChroma: tones.tertiaryChroma, - tertiaryMinChroma: tones.tertiaryMinChroma, - tertiaryHueRotation: tones.tertiaryHueRotation, - neutralChroma: tones.neutralChroma, - neutralVariantChroma: tones.neutralVariantChroma, - paletteType: paletteType, - ); + // List of ints that we need to draw the tonal palettes. + List primaryTonals = []; + List secondaryTonals = []; + List tertiaryTonals = []; + List errorTonals = []; + List neutralTonals = []; + List neutralVariantTonals = []; + + // Are we using a Flutter SDK scheme? Otherwise use FlexTone. + if (controller.usedVariant.isFlutterScheme) { + // Get DynamicScheme tones if using Flutter SDK scheme. + final DynamicScheme dynamicScheme = SeedColorScheme.buildDynamicScheme( + brightness, controller.primarySeedColor, controller.usedVariant); + + // Assign the tonals for the schemes to the int lists using tone indexes + // from FlexTonalPalette based on used type. + switch (paletteType) { + case FlexPaletteType.common: + for (final int i in FlexTonalPalette.commonTones) { + primaryTonals.add(dynamicScheme.primaryPalette.get(i)); + secondaryTonals.add(dynamicScheme.secondaryPalette.get(i)); + tertiaryTonals.add(dynamicScheme.tertiaryPalette.get(i)); + errorTonals.add(dynamicScheme.errorPalette.get(i)); + neutralTonals.add(dynamicScheme.neutralPalette.get(i)); + neutralVariantTonals + .add(dynamicScheme.neutralVariantPalette.get(i)); + } + case FlexPaletteType.extended: + for (final int i in FlexTonalPalette.extendedTones) { + primaryTonals.add(dynamicScheme.primaryPalette.get(i)); + secondaryTonals.add(dynamicScheme.secondaryPalette.get(i)); + tertiaryTonals.add(dynamicScheme.tertiaryPalette.get(i)); + errorTonals.add(dynamicScheme.errorPalette.get(i)); + neutralTonals.add(dynamicScheme.neutralPalette.get(i)); + neutralVariantTonals + .add(dynamicScheme.neutralVariantPalette.get(i)); + } + } + } else { + // Get FlexCorePalette tones if using FlexTone + final FlexCorePalette palettes = FlexCorePalette.fromSeeds( + primary: controller.primarySeedColor.value, + // Pass in null if set to not use secondary or tertiary seed keys. + secondary: controller.useSecondaryKey + ? controller.secondarySeedColor.value + : null, + tertiary: controller.useTertiaryKey + ? controller.tertiarySeedColor.value + : null, + error: controller.useErrorKey ? controller.errorSeedColor.value : null, + // Tone config details we get from active FlexTones. + primaryChroma: tones.primaryChroma, + primaryMinChroma: tones.primaryMinChroma, + secondaryChroma: tones.secondaryChroma, + secondaryMinChroma: tones.secondaryMinChroma, + tertiaryChroma: tones.tertiaryChroma, + tertiaryMinChroma: tones.tertiaryMinChroma, + tertiaryHueRotation: tones.tertiaryHueRotation, + neutralChroma: tones.neutralChroma, + neutralVariantChroma: tones.neutralVariantChroma, + paletteType: paletteType, + ); + // Assign the tonals for the schemes to the int lists. + primaryTonals = palettes.primary.asList; + secondaryTonals = palettes.secondary.asList; + tertiaryTonals = palettes.tertiary.asList; + errorTonals = palettes.error.asList; + neutralTonals = palettes.neutral.asList; + neutralVariantTonals = palettes.neutralVariant.asList; + } + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -63,32 +112,32 @@ class ShowTonalPalette extends StatelessWidget { ), TonalPaletteColors( name: 'Primary', - tonalPalette: palettes.primary.asList, + tonalPalette: primaryTonals, paletteType: paletteType, ), TonalPaletteColors( name: 'Secondary', - tonalPalette: palettes.secondary.asList, + tonalPalette: secondaryTonals, paletteType: paletteType, ), TonalPaletteColors( name: 'Tertiary', - tonalPalette: palettes.tertiary.asList, + tonalPalette: tertiaryTonals, paletteType: paletteType, ), TonalPaletteColors( name: 'Error', - tonalPalette: palettes.error.asList, + tonalPalette: errorTonals, paletteType: paletteType, ), TonalPaletteColors( name: 'Neutral', - tonalPalette: palettes.neutral.asList, + tonalPalette: neutralTonals, paletteType: paletteType, ), TonalPaletteColors( name: 'Neutral variant', - tonalPalette: palettes.neutralVariant.asList, + tonalPalette: neutralVariantTonals, paletteType: paletteType, ), ], diff --git a/example/lib/theme/controllers/theme_controller.dart b/example/lib/theme/controllers/theme_controller.dart index 04289d1..a34fd2d 100644 --- a/example/lib/theme/controllers/theme_controller.dart +++ b/example/lib/theme/controllers/theme_controller.dart @@ -2,7 +2,6 @@ import 'package:flex_seed_scheme/flex_seed_scheme.dart'; import 'package:flutter/material.dart'; import '../../core/constants/app_colors.dart'; -import '../model/flex_tones_enum.dart'; /// A ChangeNotifier controller used to control inputs that configures the /// ColorScheme in ThemeData and ThemeMode. @@ -27,7 +26,7 @@ class ThemeController with ChangeNotifier { if (notify) notifyListeners(); } - FlexPaletteType _paletteType = FlexPaletteType.common; + FlexPaletteType _paletteType = FlexPaletteType.extended; FlexPaletteType get paletteType => _paletteType; void setPaletteType(FlexPaletteType? value, [bool notify = true]) { if (value == null) return; @@ -99,12 +98,12 @@ class ThemeController with ChangeNotifier { if (notify) notifyListeners(); } - FlexTonesEnum _usedTone = FlexTonesEnum.material; - FlexTonesEnum get usedTone => _usedTone; - void setUsedTone(FlexTonesEnum? value, [bool notify = true]) { + FlexSchemeVariant _usedVariant = FlexSchemeVariant.tonalSpot; + FlexSchemeVariant get usedVariant => _usedVariant; + void setUsedTone(FlexSchemeVariant? value, [bool notify = true]) { if (value == null) return; - if (value == _usedTone) return; - _usedTone = value; + if (value == _usedVariant) return; + _usedVariant = value; if (notify) notifyListeners(); } diff --git a/example/lib/theme/model/app_theme.dart b/example/lib/theme/model/app_theme.dart index 1e05bdf..6e53597 100644 --- a/example/lib/theme/model/app_theme.dart +++ b/example/lib/theme/model/app_theme.dart @@ -26,17 +26,22 @@ class AppTheme { tertiaryKey: controller.useTertiaryKey ? controller.tertiarySeedColor : null, errorKey: controller.useErrorKey ? controller.errorSeedColor : null, + variant: controller.usedVariant.isFlutterScheme + ? controller.usedVariant + : null, // Tone chroma config and tone mapping is optional. If you do not add it // you get a config matching Flutter's Material 3 ColorScheme.fromSeed. // // Use tone style and mapping, for light mode. // Make both main On and all On surfaces colors black and white if // opted in on that setting. - tones: controller.usedTone - .tones(Brightness.light) - .onMainsUseBW(controller.keepMainOnColorsBW) - .onSurfacesUseBW(controller.keepSurfaceOnColorsBW) - .surfacesUseBW(controller.keepLightSurfaceColorsWhite), + tones: controller.usedVariant.isFlutterScheme + ? null + : controller.usedVariant + .tones(Brightness.light) + .onMainsUseBW(controller.keepMainOnColorsBW) + .onSurfacesUseBW(controller.keepSurfaceOnColorsBW) + .surfacesUseBW(controller.keepLightSurfaceColorsWhite), ); // Light mode theme @@ -64,11 +69,16 @@ class AppTheme { controller.useSecondaryKey ? controller.secondarySeedColor : null, tertiaryKey: controller.useTertiaryKey ? controller.tertiarySeedColor : null, - tones: controller.usedTone - .tones(Brightness.dark) - .onMainsUseBW(controller.keepMainOnColorsBW) - .onSurfacesUseBW(controller.keepSurfaceOnColorsBW) - .surfacesUseBW(controller.keepDarkSurfaceColorsBlack), + variant: controller.usedVariant.isFlutterScheme + ? controller.usedVariant + : null, + tones: controller.usedVariant.isFlutterScheme + ? null + : controller.usedVariant + .tones(Brightness.dark) + .onMainsUseBW(controller.keepMainOnColorsBW) + .onSurfacesUseBW(controller.keepSurfaceOnColorsBW) + .surfacesUseBW(controller.keepDarkSurfaceColorsBlack), ); // Dark mode theme diff --git a/example/lib/theme/model/flex_tones_enum.dart b/example/lib/theme/model/flex_tones_enum.dart deleted file mode 100644 index 5faa9ec..0000000 --- a/example/lib/theme/model/flex_tones_enum.dart +++ /dev/null @@ -1,225 +0,0 @@ -import 'package:flex_seed_scheme/flex_seed_scheme.dart'; -import 'package:flutter/material.dart'; - -import 'custom_tones.dart'; - -/// Enum used to return and describes properties of used [FlexTones]. -/// -/// By using [tones] and a given [Brightness], it returns the corresponding -/// [FlexTones] made with same named constructor or even a custom option. -/// -/// Contains used icon for each tone and shade value to adjust used -/// color value on the icon, used by UI building. -/// -/// Also a small demonstration of how we can use Dart 2.17 enhanced enums. -enum FlexTonesEnum { - custom( - toneLabel: 'Custom', - describe: 'A custom mapping and chroma config made for this example.', - setup: 'Primary - Chroma from key color, but min 55, tone 30/70\n' - 'Secondary - Chroma from key color, but min 25\n' - 'Tertiary - Chroma from key color, but min 40\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 5 (L), 7 (D)\n' - 'Neutral variant - Chroma set to 10 (L), 14 (D)\n' - 'Tonal palette - Extended', - icon: Icons.texture_outlined, - shade: 1, - ), - material( - toneLabel: 'Material 3', - describe: 'Default Material 3 design tone map and chroma setup', - setup: 'Primary - Chroma from key color, but min 48\n' - 'Secondary - Chroma set to 16\n' - 'Tertiary - Chroma set to 24\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 4\n' - 'Neutral variant - Chroma set to 8\n' - 'Tonal palette - Common', - icon: Icons.blur_circular, - shade: -5, - ), - soft( - toneLabel: 'Soft', - describe: 'Softer and more earth like tones than Material 3 defaults', - setup: 'Primary - Chroma set to 30\n' - 'Secondary - Chroma set to 14\n' - 'Tertiary - Chroma set to 20\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 4\n' - 'Neutral variant - Chroma set to 8\n' - 'Tonal palette - Common', - icon: Icons.blur_on, - shade: 2, - ), - vivid( - toneLabel: 'Vivid', - describe: 'More Vivid colors than Material 3 defaults', - setup: 'Primary - Chroma from key color, but min 50\n' - 'Secondary - Chroma from key color\n' - 'Tertiary - Chroma from key color\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 4\n' - 'Neutral variant - Chroma set to 8\n' - 'Tonal palette - Common', - icon: Icons.tonality, - shade: 6, - ), - vividSurfaces( - toneLabel: 'Vivid surfaces', - describe: 'Like Vivid, but with more colorful containers, onColors and ' - 'surface tones. Creates alpha blend like effect without ' - 'any blend level', - setup: 'Primary - Chroma from key color, but min 50\n' - 'Secondary - Chroma from key color\n' - 'Tertiary - Chroma from key color\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 5\n' - 'Neutral variant - Chroma set to 10\n' - 'Tonal palette - Common', - icon: Icons.radio_button_checked, - shade: 10, - ), - highContrast( - toneLabel: 'High contrast', - describe: 'High contrast version, may be useful for accessibility', - setup: 'Primary - Chroma from key color, but min 65\n' - 'Secondary - Chroma from key color, but min 55\n' - 'Tertiary - Chroma from key color, but min 55\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 4\n' - 'Neutral variant - Chroma set to 8\n' - 'Tonal palette - Common', - icon: Icons.contrast, - shade: 14, - ), - ultraContrast( - toneLabel: 'Ultra contrast', - describe: 'Ultra high contrast version, useful for accessibility, ' - 'less colorful than high contrast, especially dark mode', - setup: 'Primary - Chroma from key color, but min 60\n' - 'Secondary - Chroma from key color, but min 70\n' - 'Tertiary - Chroma from key color, but min 65\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 3\n' - 'Neutral variant - Chroma set to 6\n' - 'Tonal palette - Common', - icon: Icons.lens, - shade: 20, - ), - jolly( - toneLabel: 'Jolly', - describe: 'Jolly color tones with more chroma and pop in them', - setup: 'Primary - Chroma from key color, but min 55\n' - 'Secondary - Chroma from key color, but min 40\n' - 'Tertiary - Chroma set to 40\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 6\n' - 'Neutral variant - Chroma set to 10\n' - 'Tonal palette - Common', - icon: Icons.sunny, - shade: 8, - ), - vividBackground( - toneLabel: 'Vivid background', - describe: 'Like Vivid surfaces, but with tone mapping for surface ' - 'and background swapped', - setup: 'Primary - Chroma from key color, but min 50\n' - 'Secondary - Chroma from key color\n' - 'Tertiary - Chroma from key color\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 5\n' - 'Neutral variant - Chroma set to 10\n' - 'Tonal palette - Common', - icon: Icons.panorama_wide_angle_select_rounded, - shade: 10, - ), - oneHue( - toneLabel: 'One hue', - describe: 'If only primary key color given, scheme uses only one hue', - setup: 'Primary - Chroma from key color, but min 55\n' - 'Secondary - Chroma set to 26\n' - 'Tertiary - Chroma set to 36, no Hue rotation\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 4\n' - 'Neutral variant - Chroma set to 8\n' - 'Tonal palette - Common', - icon: Icons.looks_one_rounded, - shade: 7, - ), - candyPop( - toneLabel: 'Candy pop', - describe: 'A high contrast color scheme, useful for accessible themes, ' - 'with colors that pop like candy. Keeps the background and surface ' - 'white in light mode, and only a slight tint in dark mode. Neutrals ' - 'have very low chroma.', - setup: 'Primary - Chroma from key color, but min 60\n' - 'Secondary - Chroma from key color, but min 44\n' - 'Tertiary - Chroma from key color, but min 50\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 2\n' - 'Neutral variant - Chroma set to 4\n' - 'Tonal palette - Extended', - icon: Icons.join_left_outlined, - shade: 9, - ), - chroma( - toneLabel: 'Chroma', - describe: - 'A color scheme that follows chroma of each used seed color. Useful ' - 'for manual control of pop or low chromacity. It uses low ' - 'surface tint and neutrals with medium chroma.', - setup: 'Primary - Chroma from key color, min 0\n' - 'Secondary - Chroma from key color, min 0\n' - 'Tertiary - Chroma from key color, min 0\n' - 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' - 'Neutral - Chroma set to 2 (L), 3 (D)\n' - 'Neutral variant - Chroma set to 4 (L), 6 (D)\n' - 'Tonal palette - Extended', - icon: Icons.lens_outlined, - shade: 3, - ); - - const FlexTonesEnum({ - required this.toneLabel, - required this.describe, - required this.setup, - required this.icon, - required this.shade, - }); - - final String toneLabel; - final String describe; - final String setup; - final IconData icon; - final int shade; - - FlexTones tones(Brightness brightness) { - switch (this) { - case FlexTonesEnum.custom: - return brightness == Brightness.light ? myLightTones : myDarkTones; - case FlexTonesEnum.material: - return FlexTones.material(brightness); - case FlexTonesEnum.soft: - return FlexTones.soft(brightness); - case FlexTonesEnum.vivid: - return FlexTones.vivid(brightness); - case FlexTonesEnum.vividSurfaces: - return FlexTones.vividSurfaces(brightness); - case FlexTonesEnum.highContrast: - return FlexTones.highContrast(brightness); - case FlexTonesEnum.ultraContrast: - return FlexTones.ultraContrast(brightness); - case FlexTonesEnum.jolly: - return FlexTones.jolly(brightness); - case FlexTonesEnum.vividBackground: - return FlexTones.vividBackground(brightness); - case FlexTonesEnum.oneHue: - return FlexTones.oneHue(brightness); - case FlexTonesEnum.candyPop: - return FlexTones.candyPop(brightness); - case FlexTonesEnum.chroma: - return FlexTones.chroma(brightness); - } - } -} diff --git a/example/pubspec.lock b/example/pubspec.lock index d2f2447..858c18c 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: "direct main" description: name: cupertino_icons - sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.6" + version: "1.0.8" fake_async: dependency: transitive description: @@ -71,7 +71,7 @@ packages: path: ".." relative: true source: path - version: "1.5.0" + version: "2.0.0-dev.1" flutter: dependency: "direct main" description: flutter @@ -91,26 +91,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.3" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" matcher: dependency: transitive description: @@ -131,10 +131,10 @@ packages: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.12.0" path: dependency: transitive description: @@ -200,26 +200,26 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.0" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e" + sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e" url: "https://pub.dev" source: hosted - version: "6.2.5" + version: "6.2.6" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 + sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.1" url_launcher_ios: dependency: transitive description: @@ -256,10 +256,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "3692a459204a33e04bc94f5fb91158faf4f2c8903281ddd82915adecdb1a901d" + sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.1" url_launcher_windows: dependency: transitive description: @@ -280,10 +280,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.1" web: dependency: transitive description: @@ -294,4 +294,4 @@ packages: version: "0.5.1" sdks: dart: ">=3.3.0 <4.0.0" - flutter: ">=3.19.0" + flutter: ">=3.22.0-0.3.pre" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e545815..743bbbd 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,10 +1,10 @@ name: flex_seed_scheme_example description: Example that demonstrate how to use the FlexSeedScheme package. -version: 1.5.0 +version: 2.0.0-dev.1 publish_to: 'none' environment: sdk: '>=3.0.0 <4.0.0' - flutter: '>=3.10.0' + flutter: '>=3.22.0-0.3.pre' dependencies: # Adds the Cupertino Icons font to your application. Used by the @@ -28,7 +28,7 @@ dependencies: # Used for launching a WEB URL, by Google flutter.dev. # https://pub.dev/packages/url_launcher - url_launcher: ^6.2.5 + url_launcher: ^6.2.6 dev_dependencies: flutter_test: @@ -39,4 +39,4 @@ flutter: dependency_overrides: flex_seed_scheme: - path: ../ \ No newline at end of file + path: ../ diff --git a/lib/flex_seed_scheme.dart b/lib/flex_seed_scheme.dart index e79b50a..ceb91ee 100644 --- a/lib/flex_seed_scheme.dart +++ b/lib/flex_seed_scheme.dart @@ -14,6 +14,10 @@ library flex_seed_scheme; /// [neutral], [neutralVariant] and [error]. export 'src/flex/flex_core_palette.dart'; +/// Enum used to select which scheme variant algorithm to use when creating +/// a color scheme. +export 'src/flex/flex_scheme_variant.dart'; + /// Extension on `ColorScheme` to give us `SeedColorScheme.fromSeeds`. export 'src/flex/flex_seed_scheme.dart' show SeedColorScheme; @@ -48,10 +52,18 @@ export 'src/flex/flex_tones.dart'; /// * Blend /// * Cam16 /// * CorePalette +/// * DynamicScheme /// * Hct /// * TonalPalette /// * ViewingConditions /// /// More APIs from MCU may be exported later if needed. export 'src/mcu/material_color_utilities.dart' - show Blend, Cam16, CorePalette, Hct, TonalPalette, ViewingConditions; + show + Blend, + Cam16, + CorePalette, + DynamicScheme, + Hct, + TonalPalette, + ViewingConditions; diff --git a/lib/src/flex/flex_core_palette.dart b/lib/src/flex/flex_core_palette.dart index 9a81391..d38f6f6 100644 --- a/lib/src/flex/flex_core_palette.dart +++ b/lib/src/flex/flex_core_palette.dart @@ -486,92 +486,185 @@ class FlexCorePalette { /// The default [FlexPaletteType.common] with 15 tones or the extended /// [FlexPaletteType.extended] with 24 tones. final FlexPaletteType paletteType = FlexPaletteType.common, + + /// If true, the CAM16 color space is used to define the HCT color, if + /// false simpler and faster HCT from int is used. + /// + /// Prior to version 2.0.0 of this package, the CAM16 color space was always + /// used. However, in Flutter 3.22 the HCT vanilla HCT.fromInt is used + /// for its seeded scheme colors.It is used here by the Material3 + /// style seeded color schemes as well, while the FSS ones continues to use + /// Cam16. + final bool useCam16 = true, }) { // Primary TonalPalette calculation. - // - // Key color is required, we can use it. - final Cam16 camPrimary = Cam16.fromInt(primary); + late final double primaryComputedChroma; + late final double primaryComputedHue; + if (useCam16) { + final Cam16 camPrimary = Cam16.fromInt(primary); + primaryComputedHue = camPrimary.hue; + primaryComputedChroma = camPrimary.chroma; + } else { + final Hct hctPrimary = Hct.fromInt(primary); + primaryComputedHue = hctPrimary.hue; + primaryComputedChroma = hctPrimary.chroma; + } + // final Cam16 camPrimary = Cam16.fromInt(primary); + // If a fixed chroma was given we use it instead of chroma in primary. - final double effectivePrimaryChroma = primaryChroma ?? camPrimary.chroma; + final double effectivePrimaryChroma = + primaryChroma ?? primaryComputedChroma; // We use the effectiveChroma, but only if it is over the min level. - final FlexTonalPalette tonalPrimary = FlexTonalPalette.of(camPrimary.hue, - math.max(primaryMinChroma ?? 48, effectivePrimaryChroma), paletteType); + final FlexTonalPalette tonalPrimary = FlexTonalPalette.of( + primaryComputedHue, + math.max(primaryMinChroma ?? 48, effectivePrimaryChroma), + paletteType); // Secondary TonalPalette calculation. // // Provided key color may be null, then we use primary as key color. - final Cam16 camSecondary = - secondary == null ? camPrimary : Cam16.fromInt(secondary); + late final double secondaryComputedChroma; + late final double secondaryComputedHue; + if (secondary == null) { + secondaryComputedHue = primaryComputedHue; + secondaryComputedChroma = primaryComputedChroma; + } else { + if (useCam16) { + final Cam16 camSecondary = Cam16.fromInt(secondary); + secondaryComputedHue = camSecondary.hue; + secondaryComputedChroma = camSecondary.chroma; + } else { + final Hct hctSecondary = Hct.fromInt(secondary); + secondaryComputedHue = hctSecondary.hue; + secondaryComputedChroma = hctSecondary.chroma; + } + } // If a fixed chroma value was given we use it instead. final double effectiveSecondaryChroma = - secondaryChroma ?? camSecondary.chroma; + secondaryChroma ?? secondaryComputedChroma; // We use the effectiveChroma, but only if it is over the min level. final FlexTonalPalette tonalSecondary = FlexTonalPalette.of( - camSecondary.hue, + secondaryComputedHue, math.max(secondaryMinChroma ?? 0, effectiveSecondaryChroma), paletteType); // Tertiary TonalPalette calculation. // // Provided key color may be null, then we use primary as key color. - final Cam16 camTertiary = - tertiary == null ? camPrimary : Cam16.fromInt(tertiary); + late final double tertiaryComputedChroma; + late final double tertiaryComputedHue; + if (tertiary == null) { + // If we had no tertiary keyColor, we won't use primary key's hue + // directly, we add 60 degrees to it, this is the M3 way to shift hue + // from a single key. + tertiaryComputedHue = MathUtils.sanitizeDegreesDouble( + primaryComputedHue + (tertiaryHueRotation ?? 60)); + tertiaryComputedChroma = primaryComputedChroma; + } else { + if (useCam16) { + final Cam16 camTertiary = Cam16.fromInt(tertiary); + tertiaryComputedHue = camTertiary.hue; + tertiaryComputedChroma = camTertiary.chroma; + } else { + final Hct hctTertiary = Hct.fromInt(tertiary); + tertiaryComputedHue = hctTertiary.hue; + tertiaryComputedChroma = hctTertiary.chroma; + } + } // If a fixed chroma value was given we use it instead. - final double effectiveTertiaryChroma = tertiaryChroma ?? camTertiary.chroma; - // If we had no tertiary keyColor, we won't use primary key's hue - // directly, we add 60 degrees to it, this is the M3 way to shift hue from a - // single key. - final double effectiveTertiaryHue = tertiary == null - ? camPrimary.hue + (tertiaryHueRotation ?? 60) - : camTertiary.hue; + final double effectiveTertiaryChroma = + tertiaryChroma ?? tertiaryComputedChroma; // We use the effective hue and the effectiveChroma, but chroma // only if it is over the min level. final FlexTonalPalette tonalTertiary = FlexTonalPalette.of( - effectiveTertiaryHue, + tertiaryComputedHue, math.max(tertiaryMinChroma ?? 0, effectiveTertiaryChroma), paletteType); // Neutral TonalPalette calculation. // // Provided key color may be null, then we use primary as key color. - final Cam16 camNeutral = - neutral == null ? camPrimary : Cam16.fromInt(neutral); + late final double neutralComputedChroma; + late final double neutralComputedHue; + if (neutral == null) { + neutralComputedHue = primaryComputedHue; + neutralComputedChroma = primaryComputedChroma; + } else { + if (useCam16) { + final Cam16 camNeutral = Cam16.fromInt(neutral); + neutralComputedHue = camNeutral.hue; + neutralComputedChroma = camNeutral.chroma; + } else { + final Hct hctNeutral = Hct.fromInt(neutral); + neutralComputedHue = hctNeutral.hue; + neutralComputedChroma = hctNeutral.chroma; + } + } // If a fixed chroma value was given we use it instead. - final double effectiveNeutralChroma = neutralChroma ?? camNeutral.chroma; + final double effectiveNeutralChroma = + neutralChroma ?? neutralComputedChroma; // We use the effectiveChroma, but only if it is over the min level. - final FlexTonalPalette tonalNeutral = FlexTonalPalette.of(camNeutral.hue, - math.max(neutralMinChroma ?? 0, effectiveNeutralChroma), paletteType); + final FlexTonalPalette tonalNeutral = FlexTonalPalette.of( + neutralComputedHue, + math.max(neutralMinChroma ?? 0, effectiveNeutralChroma), + paletteType); // NeutralVariant TonalPalette calculation. // // Provided key color may be null, then we use primary as key color. - final Cam16 camNeutralVariant = - neutralVariant == null ? camPrimary : Cam16.fromInt(neutralVariant); + late final double neutralVariantComputedChroma; + late final double neutralVariantComputedHue; + if (neutralVariant == null) { + neutralVariantComputedHue = primaryComputedHue; + neutralVariantComputedChroma = primaryComputedChroma; + } else { + if (useCam16) { + final Cam16 camNeutralVariant = Cam16.fromInt(neutralVariant); + neutralVariantComputedHue = camNeutralVariant.hue; + neutralVariantComputedChroma = camNeutralVariant.chroma; + } else { + final Hct hctNeutralVariant = Hct.fromInt(neutralVariant); + neutralVariantComputedHue = hctNeutralVariant.hue; + neutralVariantComputedChroma = hctNeutralVariant.chroma; + } + } // If a fixed chroma value was given we use it instead. final double effectiveNeutralVariantChroma = - neutralVariantChroma ?? camNeutralVariant.chroma; + neutralVariantChroma ?? neutralVariantComputedChroma; // We use the effectiveChroma, but only if it is over the min level. final FlexTonalPalette tonalNeutralVariant = FlexTonalPalette.of( - camNeutralVariant.hue, + neutralVariantComputedHue, math.max(neutralVariantMinChroma ?? 0, effectiveNeutralVariantChroma), paletteType); // Error TonalPalette calculation. // // Input error color maybe null, but if it is not we make a Cam16 from it. - final Cam16? camError = error == null ? null : Cam16.fromInt(error); - + late final double errorComputedChroma; + late final double errorComputedHue; + // If no error color was given, we use M3 default error color, hue 25 and + // chroma 84. + if (error == null) { + errorComputedHue = 25; + errorComputedChroma = 84; + } else { + // If an error color was given, we use its hue and chroma from Cam or Hct. + if (useCam16) { + final Cam16 camError = Cam16.fromInt(error); + errorComputedHue = camError.hue; + errorComputedChroma = camError.chroma; + } else { + final Hct hctError = Hct.fromInt(error); + errorComputedHue = hctError.hue; + errorComputedChroma = hctError.chroma; + } + } // If a fixed error chroma value was given we will use it instead as // effective chroma value, if not and if input error color was given, we use // its chroma, if one was not given we fall back to M3 default chroma 84. - final double effectiveErrorChroma = errorChroma ?? camError?.chroma ?? 84; - - // If an error color was given, we use its hue, if none was given we fall - // back to hue 25, the Material 3 default. - final double effectiveErrorHue = camError?.hue ?? 25; - + final double effectiveErrorChroma = errorChroma ?? errorComputedChroma; // We use the effectiveChroma, but only if it is over the min level. - final FlexTonalPalette tonalError = FlexTonalPalette.of(effectiveErrorHue, + final FlexTonalPalette tonalError = FlexTonalPalette.of(errorComputedHue, math.max(errorMinChroma ?? 0, effectiveErrorChroma), paletteType); return FlexCorePalette( diff --git a/lib/src/flex/flex_scheme_variant.dart b/lib/src/flex/flex_scheme_variant.dart new file mode 100644 index 0000000..807becb --- /dev/null +++ b/lib/src/flex/flex_scheme_variant.dart @@ -0,0 +1,610 @@ +import 'package:flutter/material.dart'; + +import 'flex_seed_scheme.dart'; +import 'flex_tones.dart'; + +/// Enum used to return and describes properties of the [FlexSchemeVariant] +/// variants to invoke different color scheme generation algorithms +/// in [SeedColorScheme.fromSeeds], when passed to its [FlexSchemeVariant] +/// property variant. +/// +/// [FlexSchemeVariant] values that use [isFlutterScheme] set to true, use the +/// Flutter SDK algorithm to construct a [ColorScheme] identical to +/// [ColorScheme.fromSeed], or more exactly will do in next stable after +/// Flutter 3.22.x +/// +/// The [tonalSpot] is the only variant available in Flutter 3.22 and it builds +/// the default Material-3 style 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. The [fidelity] variant is a feature that adjusts +/// tones in these cases to produce the intended visual results without harming +/// visual contrast. +/// +/// Variants that use [isFlutterScheme] set to false, use FlexSeedScheme's own +/// algorithm to construct a [ColorScheme] based on the provided seed colors. +/// These variants are mapped to built-in [FlexTones] configurations that can +/// be used to construct a [ColorScheme] with a more flexible algorithm than +/// the Flutter SDK's [ColorScheme.fromSeed]. A key feature is that all tonal +/// palettes can use their own seed color. +/// +/// By using [tones] function and a given [Brightness], it will returns the +/// corresponding [FlexTones] made with same named [FlexTones] constructor, for +/// cases where [isFlutterScheme] set to false. +/// +/// If you want to make use your own custom [FlexTones] configuration, do not +/// assign any value to `variant` in [SeedColorScheme.fromSeeds] and instead +/// provide your own custom [FlexTones] configuration to the [FlexTones] +/// property `tones` in [SeedColorScheme.fromSeeds]. +/// +/// This enum also contains labels for variant names, a short description and +/// configuration details, as well as an icon for each tone and shade value to +/// adjust used color value on the icon. These properties can optionally be +/// used when building UIs that present the different scheme variants. They +/// serve no other purpose. They can also be ignored and you can use the enum +/// values as input and use them to build your own UI for selecting and +/// describing the scheme variants. These values are used in the example app +/// and also in the `FlexColorScheme` package example app, like the +/// Themes Playground. +enum FlexSchemeVariant { + /// A Dynamic Color theme with low to medium colorfulness and a Tertiary + /// Tonal Palette]with a hue related to the source color. The default + /// Material You theme on Android 12 and 13. + /// + /// This is the default seed generation used by Flutter SDK starting from + /// Flutter 3.22. The tonal palette used before Flutter 3.22 was slightly + /// different and can be selected with [material3Legacy]. + /// + /// This modified palette uses chroma 36 on primary palette, previous one used + /// 48. It uses chroma 6 on neutral palette, where the previous one used 4. + tonalSpot( + variantName: 'Tonal spot', + description: 'Default for Material-3 theme colors. Results in pastel ' + 'palettes with low chroma.', + configDetails: 'Primary - Chroma from key color, but min 36\n' + 'Secondary - Chroma set to 16\n' + 'Tertiary - Chroma set to 24\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 6\n' + 'Neutral variant - Chroma set to 8\n' + 'Variant style: MaterialColorUtilities (MCU)', + icon: Icons.looks_3_outlined, + shade: -6, + isFlutterScheme: true, + ), + + /// A scheme that places the source color in Scheme primaryContainer. + /// + /// Primary Container is the source color, adjusted for color relativity. + /// It maintains constant appearance in light mode and dark mode. + /// This adds ~5 tone in light mode, and subtracts ~5 tone in dark mode. + /// + /// Tertiary Container is the complement to the source color, using + /// TemperatureCache. It also maintains constant appearance. + fidelity( + variantName: 'Fidelity', + description: 'The resulting color palettes match seed color, also when ' + 'the seed color is very bright and using high chroma.', + configDetails: 'Primary - Chroma from key color\n' + 'Secondary - Max of: chroma from key -32 or *0.5\n' + 'Tertiary - TemperatureCache complement\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma from key /8\n' + 'Neutral variant - Chroma from key /8 +4\n' + 'Variant style: Material Color Utilities (MCU)', + icon: Icons.grain_outlined, + shade: 0, + isFlutterScheme: true, + ), + + /// All colors are grayscale, no chroma. + monochrome( + variantName: 'Monochrome', + description: 'All colors are grayscale, with no chroma.', + configDetails: 'Primary - Chroma 0\n' + 'Secondary - Chroma 0\n' + 'Tertiary - Chroma 0\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma 0\n' + 'Neutral variant - Chroma 0\n' + 'Variant style: Material Color Utilities (MCU)', + icon: Icons.filter_b_and_w_outlined, + shade: 10, + isFlutterScheme: true, + ), + + /// A scheme that is near grayscale. + neutral( + variantName: 'Neutral', + description: 'Close to grayscale, but with a hint of chroma.', + configDetails: 'Primary - Chroma 12\n' + 'Secondary - Chroma 8\n' + 'Tertiary - Chroma 16\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma 2\n' + 'Neutral variant - Chroma 2\n' + 'Variant style: Material Color Utilities (MCU)', + icon: Icons.gradient_outlined, + shade: -10, + isFlutterScheme: true, + ), + + /// A scheme that maxes out colorfulness at each position in the + /// Primary TonalPalette. + /// + /// The primary palette's chroma is at maximum. Use `fidelity` instead if + /// tokens should alter their tone to match the palette vibrancy. + vibrant( + variantName: 'Vibrant', + description: 'Maxed out colorfulness at each position in the primary ' + 'palette', + configDetails: 'Primary - Chroma 200\n' + 'Secondary - Chroma 24\n' + 'Tertiary - Chroma 32\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma 10\n' + 'Neutral variant - Chroma 12\n' + 'Variant style: Material Color Utilities (MCU)', + icon: Icons.flare_outlined, + shade: 0, + isFlutterScheme: true, + ), + + /// A scheme that is intentionally detached from the input color. + /// The primary palette's hue is different from the seed color, for variety. + expressive( + variantName: 'Expressive', + description: 'Primary palette hue is intentionally different from the ' + 'seed color.', + configDetails: 'Primary - Hue+240, Chroma 40\n' + 'Secondary - Hue rotations, Chroma 24\n' + 'Tertiary - Hue rotations, Chroma 32\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Hue +15, Chroma 8\n' + 'Neutral variant - Hue +15, Chroma 12\n' + 'Variant style: Material Color Utilities (MCU)', + icon: Icons.shuffle_on_outlined, + shade: 0, + isFlutterScheme: true, + ), + + /// 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. + /// + /// Primary Container is the source color, adjusted for color relativity. + /// It maintains constant appearance in light mode and dark mode. + /// This adds ~5 tone in light mode, and subtracts ~5 tone in dark mode. + /// + /// Tertiary Container is an analogous color, specifically, the analog of a + /// color wheel divided into 6, and the precise analog is the one found by + /// increasing hue. It also maintains constant appearance. + content( + variantName: 'Content', + description: 'Tokens and palettes match the seed color. Good for image ' + 'color extracted seed color.', + configDetails: 'Primary - Chroma from key color\n' + 'Secondary - Max of: chroma from key -32 or *0.5\n' + 'Tertiary - TemperatureCache analogous last\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma from key /8\n' + 'Neutral variant - Chroma from key /8 +4\n' + 'Variant style: Material Color Utilities (MCU)', + icon: Icons.image_outlined, + shade: 0, + isFlutterScheme: true, + ), + + /// A playful theme - the seed color's hue does not appear in the theme. + rainbow( + variantName: 'Rainbow', + // TODO(rydmike): But it does, but this is what MCU and SDK says, so... + description: "A playful theme. The seed color's hue does not appear in " + 'the theme.', + configDetails: 'Primary - Chroma 48\n' + 'Secondary - Chroma 16\n' + 'Tertiary - Hue +60, Chroma 24\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma 0\n' + 'Neutral variant - Chroma 0\n' + 'Variant style: Material Color Utilities (MCU)', + icon: Icons.looks_outlined, + shade: 0, + isFlutterScheme: true, + ), + + /// A playful theme - the seed color's hue does not appear in the theme. + fruitSalad( + variantName: 'Fruit salad', + description: "A playful theme. The seed color's hue does not appear in " + 'the theme.', + configDetails: 'Primary - Hue -50, Chroma 12\n' + 'Secondary - Hue -50, Chroma 36\n' + 'Tertiary - Chroma 36\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma 10\n' + 'Neutral variant - Chroma 16\n' + 'Variant style: Material Color Utilities (MCU)', + icon: Icons.filter_vintage_outlined, + shade: 0, + isFlutterScheme: true, + ), + + /// A Material-3 standard tonal palette tones extraction using HCT + /// based chroma. + /// + /// This setup will when only one seed color is used, produce the same result + /// as Flutter SDK does when using [ColorScheme.fromSeed] in + /// Flutter version 3.22 and later. + /// + /// It should be noted that the Material-3 implementation in Flutter uses + /// DynamicSchemeVariant tonalSpot as default for the Material-3 design + /// seed generated ColorScheme. There might be some slight differences in + /// its results and using this selection in some edge cases, but none have + /// been observed in normal use cases. If an exact match is critical, use + /// [tonalSpot] as used in the Flutter SDK 3.22 and later. + /// + /// If you want to use multiple seed colors to generate a ColorScheme, you + /// will need to use [FlexTones] based configurations, the ones based on + /// Flutter SDK DynamicSchemeVariant and MCU do not provide that feature-set. + material( + variantName: 'Material-3', + description: 'Default Material 3 design tone map and chroma setup', + configDetails: 'Primary - Chroma from key color, but min 36\n' + 'Secondary - Chroma set to 16\n' + 'Tertiary - Chroma set to 24\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 6\n' + 'Neutral variant - Chroma set to 8\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.looks_3_outlined, + shade: -6, + isFlutterScheme: false, + ), + + /// A Material-3 standard tonal palette tones extraction using Cam16 + /// based chroma. + /// + /// This setup will when only one seed color is used, produce the same result + /// as Flutter SDK does when using [ColorScheme.fromSeed] in + /// Flutter version 3.19 and earlier. + /// + /// Prior to FlexSeedScheme 2.0.0, this was the default setup used by the + /// [FlexTones.material] configuration. However, [FlexTones.material] was in + /// FSS version 2.0.0 modified to match the new actual and revised Material-3 + /// configuration in Flutter 3.22 and later. This factory is provided if you + /// need and want to use the older Material-3 seed generation setup used in + /// Flutter 3.19 and earlier versions. + material3Legacy( + variantName: 'Material-3 Legacy', + description: 'Legacy Material 3 design tone map and chroma setup, used ' + 'before Flutter 3.22', + configDetails: 'Primary - Chroma from key color, but min 48\n' + 'Secondary - Chroma set to 16\n' + 'Tertiary - Chroma set to 24\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 4\n' + 'Neutral variant - Chroma set to 8\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.filter_3, + shade: -5, + isFlutterScheme: false, + ), + + /// Creates a tonal palette extraction setup that results in M3 like + /// ColorsSchemes with softer colors than Material-3 defaults. + /// + /// Primary chroma is 30, secondary 14 and tertiary 20. Tones are same as + /// in Material 3 default setup. + soft( + variantName: 'Soft', + description: 'Softer and more earth like tones than Material 3 defaults', + configDetails: 'Primary - Chroma set to 30\n' + 'Secondary - Chroma set to 14\n' + 'Tertiary - Chroma set to 20\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 4\n' + 'Neutral variant - Chroma set to 8\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.blur_on, + shade: 2, + isFlutterScheme: false, + ), + + /// A tonal palette extraction setup that results in M3 like + /// ColorsSchemes with more vivid colors. + /// + /// Primary tone is one tone darker than in Material 3 standard setup in light + /// mode. As in M3 default, primary uses its own chroma, but with a minimum + /// value of 50. Secondary and tertiary key colors use their own chroma + /// with no min limits, making the secondary and tertiary mid tones closer + /// to their used key colors. + vivid( + variantName: 'Vivid', + description: 'More Vivid colors than Material 3 defaults', + configDetails: 'Primary - Chroma from key color, but min 50\n' + 'Secondary - Chroma from key color\n' + 'Tertiary - Chroma from key color\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 4\n' + 'Neutral variant - Chroma set to 8\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.tonality, + shade: 6, + isFlutterScheme: false, + ), + + /// A tonal palette extraction setup that results in M3 like + /// ColorsSchemes with chroma like [FlexTones.vivid] on main colors, but + /// double chroma on neutrals and more color tinted surfaces and onColors. + /// + /// Primary tone is one tone darker than in Material 3 standard setup in light + /// mode. As in M3 default, primary uses its own chroma, but with a minimum + /// value of 50. Secondary and tertiary key colors use their own chroma + /// with no min limits, making the secondary and tertiary mid tones closer + /// to their used key colors. + /// Chroma for neutral is 8 and neutralVariant 16, doubled from M3 defaults. + /// + /// The tones are modified for more colorful container, onColors color tones + /// and for using higher tones on surfaces and backgrounds. This creates + /// an alpha blend like of effect of primary on surfaces, without using any + /// blend level in FlexColorScheme. You can apply alpha blends to this tones + /// setup too, but it is easy to overdo it with these surfaces and + /// backgrounds as starting points. + vividSurfaces( + variantName: 'Vivid surfaces', + description: 'Like Vivid, but with more colorful containers, onColors and ' + 'surface tones. Creates alpha blend like effect without ' + 'any blend level', + configDetails: 'Primary - Chroma from key color, but min 50\n' + 'Secondary - Chroma from key color\n' + 'Tertiary - Chroma from key color\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 5\n' + 'Neutral variant - Chroma set to 10\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.radio_button_checked, + shade: 10, + isFlutterScheme: false, + ), + + /// A tonal palette extraction setup that results in M3 like + /// ColorsSchemes with high contrast between color versus its on-color and + /// main color, versus its container color. + /// + /// Primary, Secondary and tertiary key colors use their own chroma, but + /// with minimum limit of 65 on primary and 55 on secondary and tertiary. + /// + /// Used tones are also modified from M3 defaults for increased contrast. + /// + /// This tonal configuration can be used to turn any M3 theme into one + /// that may be more accessibility since it offers increased contrast. + /// You could apply a variant of the active theme with this tonal map to + /// the high contrast theme data, thus providing increased contrast, but in + /// the spirit of the original theme. It may still be useful to also + /// provide purposefully designed optional extremely high contrast + /// themes as options for the high contrast accessibility themes. + highContrast( + variantName: 'High contrast', + description: 'High contrast version, may be useful for accessibility', + configDetails: 'Primary - Chroma from key color, but min 65\n' + 'Secondary - Chroma from key color, but min 55\n' + 'Tertiary - Chroma from key color, but min 55\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 4\n' + 'Neutral variant - Chroma set to 8\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.contrast, + shade: 14, + isFlutterScheme: false, + ), + + /// A tonal palette extraction setup that results in a very high + /// contrast version of selected ColorsSchemes. + ultraContrast( + variantName: 'Ultra contrast', + description: 'Ultra high contrast version, useful for accessibility, ' + 'less colorful than high contrast, especially dark mode', + configDetails: 'Primary - Chroma from key color, but min 60\n' + 'Secondary - Chroma from key color, but min 70\n' + 'Tertiary - Chroma from key color, but min 65\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 3\n' + 'Neutral variant - Chroma set to 6\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.lens, + shade: 20, + isFlutterScheme: false, + ), + + /// A tonal palette extraction setup that results in a more jolly + /// colorful ColorsSchemes. + jolly( + variantName: 'Jolly', + description: 'Jolly color tones with more chroma and pop in them', + configDetails: 'Primary - Chroma from key color, but min 55\n' + 'Secondary - Chroma from key color, but min 40\n' + 'Tertiary - Chroma set to 40\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 6\n' + 'Neutral variant - Chroma set to 10\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.sunny, + shade: 8, + isFlutterScheme: false, + ), + + /// A tonal palette extraction setup that results in M3 like + /// ColorsSchemes with chroma like [FlexTones.vividSurfaces], but + /// tone mapping surface and background are swapped. + vividBackground( + variantName: 'Vivid background', + description: 'Like Vivid surfaces, but with tone mapping for surface ' + 'and background swapped', + configDetails: 'Primary - Chroma from key color, but min 50\n' + 'Secondary - Chroma from key color\n' + 'Tertiary - Chroma from key color\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 5\n' + 'Neutral variant - Chroma set to 10\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.panorama_wide_angle_select_rounded, + shade: 10, + isFlutterScheme: false, + ), + + /// A Material-3 tonal palette tones extraction, but with no hue rotation + /// from primary if no ARGB key color is provided for tertiary palette. + /// + /// This setup will if only one seed color is used, produce a slightly more + /// chromatic color set than [FlexTones.material], since it does not rotate + /// hue from primary to get hue for tertiary, it will create a color + /// scheme using tonal palettes that are based on the same hue, but with + /// different chroma. In simple terms, all colors are shades of the provided + /// key color to seed the tonal palettes. We can get a nice one hue + /// toned theme with this configuration. + oneHue( + variantName: 'One hue', + description: 'If only primary key color given, scheme uses only one hue', + configDetails: 'Primary - Chroma from key color, but min 55\n' + 'Secondary - Chroma set to 26\n' + 'Tertiary - Chroma set to 36, no Hue rotation\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 4\n' + 'Neutral variant - Chroma set to 8\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.looks_one_rounded, + shade: 7, + isFlutterScheme: false, + ), + + /// A tonal palette setup that results in a high contrast colorful + /// candy pop like theme. + /// + /// It has white surface and background (tone 100) in light mode and + /// low chroma on neutrals (2 and 4). Dark mode uses dark + /// surface and background tone 6. + candyPop( + variantName: 'Candy pop', + description: 'A high contrast color scheme, useful for accessible themes, ' + 'with colors that pop like candy. Keeps the background and surface ' + 'white in light mode, and only a slight tint in dark mode. Neutrals ' + 'have very low chroma', + configDetails: 'Primary - Chroma from key color, but min 60\n' + 'Secondary - Chroma from key color, but min 44\n' + 'Tertiary - Chroma from key color, but min 50\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 2\n' + 'Neutral variant - Chroma set to 4\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.join_left_outlined, + shade: 9, + isFlutterScheme: false, + ), + + /// A tonal palette setup that result in a color scheme that follows chroma + /// of each used seed color. Useful for manual control of pop or low + /// chromacity. + /// + /// Uses low surface tint and neutrals with medium chroma. + /// Theme with background and surface tone 98, in light mode and very low + /// chroma in neutrals light mode (2 and 4) and moderate in dark mode + /// (3 and 6). Dark mode uses dark surface and background tone 6. + chroma( + variantName: 'Chroma', + description: + 'A color scheme that follows chroma of each used seed color. Useful ' + 'for manual control of pop or low chromacity. It uses low ' + 'surface tint and neutrals with medium chroma', + configDetails: 'Primary - Chroma from key color, min 0\n' + 'Secondary - Chroma from key color, min 0\n' + 'Tertiary - Chroma from key color, min 0\n' + 'Error - Chroma from key, unbound. Default Hue 25, Chroma 84\n' + 'Neutral - Chroma set to 2 (L), 3 (D)\n' + 'Neutral variant - Chroma set to 4 (L), 6 (D)\n' + 'Variant style: Flex Seed Scheme (FSS)', + icon: Icons.lens_outlined, + shade: 3, + isFlutterScheme: false, + ); + + /// The constructor for the [FlexSchemeVariant] enum. + const FlexSchemeVariant({ + required this.variantName, + required this.description, + required this.configDetails, + required this.icon, + required this.shade, + required this.isFlutterScheme, + }); + + /// Then name and label of the used Scheme variant. + final String variantName; + + /// A short description of the used Scheme variant. + final String description; + + /// A more detailed description of the used Scheme variant, including how it + /// is defined. + final String configDetails; + + /// The icon used to represent the Scheme variant. + final IconData icon; + + /// A shade value used to adjust the color of the icon. + final int shade; + + /// If true, this is a Flutter defined scheme, if false it is a custom scheme. + /// + /// This used to separate the two types of color schemes, those produced + /// via identical configuration to Flutter defined schemes, and those that + /// are custom and made by FlexColorScheme using a FlexTones configuration, + /// that offers capability to use multiple seed colors and more flexible + /// color scheme generation. + final bool isFlutterScheme; + + /// Returns a [FlexTones] instance based on the [FlexSchemeVariant] and + /// [Brightness] provided. + FlexTones tones(Brightness brightness) { + switch (this) { + case FlexSchemeVariant.tonalSpot: + case FlexSchemeVariant.fidelity: + case FlexSchemeVariant.monochrome: + case FlexSchemeVariant.neutral: + case FlexSchemeVariant.vibrant: + case FlexSchemeVariant.expressive: + case FlexSchemeVariant.content: + case FlexSchemeVariant.rainbow: + case FlexSchemeVariant.fruitSalad: + case FlexSchemeVariant.material: + return FlexTones.material(brightness); + case FlexSchemeVariant.material3Legacy: + return FlexTones.material3Legacy(brightness); + case FlexSchemeVariant.soft: + return FlexTones.soft(brightness); + case FlexSchemeVariant.vivid: + return FlexTones.vivid(brightness); + case FlexSchemeVariant.vividSurfaces: + return FlexTones.vividSurfaces(brightness); + case FlexSchemeVariant.highContrast: + return FlexTones.highContrast(brightness); + case FlexSchemeVariant.ultraContrast: + return FlexTones.ultraContrast(brightness); + case FlexSchemeVariant.jolly: + return FlexTones.jolly(brightness); + case FlexSchemeVariant.vividBackground: + return FlexTones.vividBackground(brightness); + case FlexSchemeVariant.oneHue: + return FlexTones.oneHue(brightness); + case FlexSchemeVariant.candyPop: + return FlexTones.candyPop(brightness); + case FlexSchemeVariant.chroma: + return FlexTones.chroma(brightness); + } + } +} diff --git a/lib/src/flex/flex_seed_scheme.dart b/lib/src/flex/flex_seed_scheme.dart index 3e2f86f..6b75313 100644 --- a/lib/src/flex/flex_seed_scheme.dart +++ b/lib/src/flex/flex_seed_scheme.dart @@ -1,7 +1,20 @@ import 'package:flutter/material.dart'; import 'package:meta/meta.dart' show internal; +import '../mcu/dynamiccolor/dynamic_scheme.dart'; +import '../mcu/dynamiccolor/material_dynamic_colors.dart'; +import '../mcu/hct/hct.dart'; +import '../mcu/scheme/scheme_content.dart'; +import '../mcu/scheme/scheme_expressive.dart'; +import '../mcu/scheme/scheme_fidelity.dart'; +import '../mcu/scheme/scheme_fruit_salad.dart'; +import '../mcu/scheme/scheme_monochrome.dart'; +import '../mcu/scheme/scheme_neutral.dart'; +import '../mcu/scheme/scheme_rainbow.dart'; +import '../mcu/scheme/scheme_tonal_spot.dart'; +import '../mcu/scheme/scheme_vibrant.dart'; import 'flex_core_palette.dart'; +import 'flex_scheme_variant.dart'; import 'flex_tones.dart'; // ignore_for_file: comment_references @@ -51,6 +64,21 @@ class FlexSeedScheme { /// A color that's clearly legible when drawn on [primaryContainer]. final int onPrimaryContainer; + /// A substitute for [primaryContainer] that's the same color for the dark + /// and light themes. + final int primaryFixed; + + /// A color used for elements needing more emphasis than [primaryFixed]. + final int primaryFixedDim; + + /// A color that is used for text and icons that exist on top of elements + /// having [primaryFixed] color. + final int onPrimaryFixed; + + /// A color that provides a lower-emphasis option for text and icons than + /// [onPrimaryFixed]. + final int onPrimaryFixedVariant; + /// An accent color used for less prominent components in the UI, such as /// filter chips, while expanding the opportunity for color expression. final int secondary; @@ -64,6 +92,21 @@ class FlexSeedScheme { /// A color that's clearly legible when drawn on [secondaryContainer]. final int onSecondaryContainer; + /// A substitute for [secondaryContainer] that's the same color for the dark + /// and light themes. + final int secondaryFixed; + + /// A color used for elements needing more emphasis than [secondaryFixed]. + final int secondaryFixedDim; + + /// A color that is used for text and icons that exist on top of elements + /// having [secondaryFixed] color. + final int onSecondaryFixed; + + /// A color that provides a lower-emphasis option for text and icons than + /// [onSecondaryFixed]. + final int onSecondaryFixedVariant; + /// A color used as a contrasting accent that can balance [primary] /// and [secondary] colors or bring heightened attention to an element, /// such as an input field. @@ -78,6 +121,21 @@ class FlexSeedScheme { /// A color that's clearly legible when drawn on [tertiaryContainer]. final int onTertiaryContainer; + /// A substitute for [tertiaryContainer] that's the same color for dark + /// and light themes. + final int tertiaryFixed; + + /// A color used for elements needing more emphasis than [tertiaryFixed]. + final int tertiaryFixedDim; + + /// A color that is used for text and icons that exist on top of elements + /// having [tertiaryFixed] color. + final int onTertiaryFixed; + + /// A color that provides a lower-emphasis option for text and icons than + /// [onTertiaryFixed]. + final int onTertiaryFixedVariant; + /// The color to use for input validation errors, e.g. for /// [InputDecoration.errorText]. final int error; @@ -91,22 +149,46 @@ class FlexSeedScheme { /// A color that's clearly legible when drawn on [errorContainer]. final int onErrorContainer; - /// A color that typically appears behind scrollable content. - final int background; - - /// A color that's clearly legible when drawn on [background]. - final int onBackground; - /// The background color for widgets like [Card]. final int surface; + /// A color that's always darkest in the dark or light theme. + final int surfaceDim; + + /// A color that's always the lightest in the dark or light theme. + final int surfaceBright; + + /// A surface container color with the lightest tone and the least emphasis + /// relative to the surface. + final int surfaceContainerLowest; + + /// A surface container color with a lighter tone that creates less emphasis + /// than [surfaceContainer] but more emphasis than [surfaceContainerLowest]. + final int surfaceContainerLow; + + /// A recommended color role for a distinct area within the surface. + /// + /// Surface container color roles are independent of elevation. They replace + /// the old opacity-based model which applied a tinted overlay on top of + /// surfaces based on their elevation. + /// + /// Surface container colors include [surfaceContainerLowest], + /// [surfaceContainerLow], [surfaceContainer], [surfaceContainerHigh] and + /// [surfaceContainerHighest]. + final int surfaceContainer; + + /// A surface container color with a darker tone. It is used to create more + /// emphasis than [surfaceContainer] but less emphasis than + /// [surfaceContainerHighest]. + final int surfaceContainerHigh; + + /// A surface container color with the darkest tone. It is used to create the + /// most emphasis against the surface. + final int surfaceContainerHighest; + /// A color that's clearly legible when drawn on [surface]. final int onSurface; - /// A color variant of [surface] that can be used for differentiation against - /// a component using [surface]. - final int surfaceVariant; - /// A color that's clearly legible when drawn on [surfaceVariant]. final int onSurfaceVariant; @@ -139,6 +221,19 @@ class FlexSeedScheme { /// elevation. final int surfaceTint; + /// A color that typically appears behind scrollable content. + @Deprecated('Use surface instead.') + final int background; + + /// A color that's clearly legible when drawn on [background]. + @Deprecated('Use onSurface instead.') + final int onBackground; + + /// A color variant of [surface] that can be used for differentiation against + /// a component using [surface]. + @Deprecated('Use surfaceContainerHighest instead.') + final int surfaceVariant; + /// Private constructor requiring all int color values. /// /// A [FlexSeedScheme] cannot be created externally. It is only used @@ -150,24 +245,45 @@ class FlexSeedScheme { required this.onPrimary, required this.primaryContainer, required this.onPrimaryContainer, + required this.primaryFixed, + required this.primaryFixedDim, + required this.onPrimaryFixed, + required this.onPrimaryFixedVariant, + // required this.secondary, required this.onSecondary, required this.secondaryContainer, required this.onSecondaryContainer, + required this.secondaryFixed, + required this.secondaryFixedDim, + required this.onSecondaryFixed, + required this.onSecondaryFixedVariant, + // required this.tertiary, required this.onTertiary, required this.tertiaryContainer, required this.onTertiaryContainer, + required this.tertiaryFixed, + required this.tertiaryFixedDim, + required this.onTertiaryFixed, + required this.onTertiaryFixedVariant, + // required this.error, required this.onError, required this.errorContainer, required this.onErrorContainer, - required this.background, - required this.onBackground, + // required this.surface, + required this.surfaceDim, + required this.surfaceBright, + required this.surfaceContainerLowest, + required this.surfaceContainerLow, + required this.surfaceContainer, + required this.surfaceContainerHigh, + required this.surfaceContainerHighest, required this.onSurface, - required this.surfaceVariant, required this.onSurfaceVariant, + // required this.outline, required this.outlineVariant, required this.shadow, @@ -176,6 +292,11 @@ class FlexSeedScheme { required this.onInverseSurface, required this.inversePrimary, required this.surfaceTint, + // + @Deprecated('Use surface instead.') required this.background, + @Deprecated('Use onSurface instead.') required this.onBackground, + @Deprecated('Use surfaceContainerHighest instead.') + required this.surfaceVariant, }); /// Factory that creates a [FlexSeedScheme] based on seed keys and FlexTones @@ -215,30 +336,56 @@ class FlexSeedScheme { neutralVariantChroma: tones.neutralVariantChroma, neutralVariantMinChroma: tones.neutralVariantMinChroma, paletteType: tones.paletteType, + useCam16: tones.useCam16, ); return FlexSeedScheme._( primary: core.primary.get(tones.primaryTone), onPrimary: core.primary.get(tones.onPrimaryTone), primaryContainer: core.primary.get(tones.primaryContainerTone), onPrimaryContainer: core.primary.get(tones.onPrimaryContainerTone), + primaryFixed: core.primary.get(tones.primaryFixedTone), + primaryFixedDim: core.primary.get(tones.primaryFixedDimTone), + onPrimaryFixed: core.primary.get(tones.onPrimaryFixedTone), + onPrimaryFixedVariant: core.primary.get(tones.onPrimaryFixedVariantTone), + // secondary: core.secondary.get(tones.secondaryTone), onSecondary: core.secondary.get(tones.onSecondaryTone), secondaryContainer: core.secondary.get(tones.secondaryContainerTone), onSecondaryContainer: core.secondary.get(tones.onSecondaryContainerTone), + secondaryFixed: core.secondary.get(tones.secondaryFixedTone), + secondaryFixedDim: core.secondary.get(tones.secondaryFixedDimTone), + onSecondaryFixed: core.secondary.get(tones.onSecondaryFixedTone), + onSecondaryFixedVariant: + core.secondary.get(tones.onSecondaryFixedVariantTone), + // tertiary: core.tertiary.get(tones.tertiaryTone), onTertiary: core.tertiary.get(tones.onTertiaryTone), tertiaryContainer: core.tertiary.get(tones.tertiaryContainerTone), onTertiaryContainer: core.tertiary.get(tones.onTertiaryContainerTone), + tertiaryFixed: core.tertiary.get(tones.tertiaryFixedTone), + tertiaryFixedDim: core.tertiary.get(tones.tertiaryFixedDimTone), + onTertiaryFixed: core.tertiary.get(tones.onTertiaryFixedTone), + onTertiaryFixedVariant: + core.tertiary.get(tones.onTertiaryFixedVariantTone), + // error: core.error.get(tones.errorTone), onError: core.error.get(tones.onErrorTone), errorContainer: core.error.get(tones.errorContainerTone), onErrorContainer: core.error.get(tones.onErrorContainerTone), - background: core.neutral.get(tones.backgroundTone), - onBackground: core.neutral.get(tones.onBackgroundTone), + // surface: core.neutral.get(tones.surfaceTone), + surfaceDim: core.neutral.get(tones.surfaceDimTone), + surfaceBright: core.neutral.get(tones.surfaceBrightTone), + surfaceContainerLowest: + core.neutral.get(tones.surfaceContainerLowestTone), + surfaceContainerLow: core.neutral.get(tones.surfaceContainerLowTone), + surfaceContainer: core.neutral.get(tones.surfaceContainerTone), + surfaceContainerHigh: core.neutral.get(tones.surfaceContainerHighTone), + surfaceContainerHighest: + core.neutral.get(tones.surfaceContainerHighestTone), onSurface: core.neutral.get(tones.onSurfaceTone), - surfaceVariant: core.neutralVariant.get(tones.surfaceVariantTone), onSurfaceVariant: core.neutralVariant.get(tones.onSurfaceVariantTone), + // outline: core.neutralVariant.get(tones.outlineTone), outlineVariant: core.neutralVariant.get(tones.outlineVariantTone), shadow: core.neutral.get(tones.shadowTone), @@ -247,6 +394,10 @@ class FlexSeedScheme { onInverseSurface: core.neutral.get(tones.onInverseSurfaceTone), inversePrimary: core.primary.get(tones.inversePrimaryTone), surfaceTint: core.primary.get(tones.surfaceTintTone), + // Deprecated colors + background: core.neutral.get(tones.backgroundTone), + onBackground: core.neutral.get(tones.onBackgroundTone), + surfaceVariant: core.neutralVariant.get(tones.surfaceVariantTone), ); } } @@ -353,10 +504,15 @@ extension SeedColorScheme on ColorScheme { /// color used as seed, ends up as the corresponding main color in the /// produced [ColorScheme] for the palette in question. In this case /// [neutralVariantKey] will typically not become your - /// [ColorScheme.surfaceVariant] color. It will only be of the same hue. + /// [ColorScheme] variant colors. It will only be of the same hue. /// If you used a color intended for light theme mode as - /// [neutralVariantKey], consider overriding [surfaceVariant] for the light - /// theme with the same color value as your [neutralVariantKey]. + /// [neutralVariantKey], consider overriding one of the variant theme colors + /// with the same color value as your [neutralVariantKey]. + /// + /// The variant palette is only used by the [ColorScheme] variant colors + /// [onSurfaceVariant], [outline] and [outlineVariant], the + /// main color that used it prior to Flutter 3.22 surfaceVariant has been + /// deprecated. Color? neutralVariantKey, /// Tonal palette chroma usage configuration and mapping to [ColorScheme]. @@ -372,8 +528,39 @@ extension SeedColorScheme on ColorScheme { /// different chroma limits and tonal mappings provide a custom [FlexTones], /// or use a predefined one like [FlexTones.jolly], [FlexTones.vivid] or /// [FlexTones.highContrast]. + /// + /// Starting with version 2.0.0 you can also use [variant] as an optional + /// way to select a predefined seed generation configuration, instead of + /// providing a [FlexTones] configuration. The [variant] API is also used + /// to provide access to the DynamicSchemeVariant that are available + /// in Flutter 3.23.0 and later. With FSS you can use them in Flutter 3.22 + /// already. FlexTones? tones, + /// An optional way to select the used algorithm for seeded [ColorScheme] + /// generation, can be used instead of a [FlexTones] provided in [tones]. + /// + /// If used and a non null value is given, any seed generation configuration + /// provided via [tones] is ignored and the [variant] is used to select + /// a predefined seed generation configuration. + /// + /// The [variant] selections includes all the Flutter SDK defined options + /// that will be available in the future in Flutter Stable after 3.22.x, + /// that are available in master channel now but did not land in Flutter + /// 3.22. Variant options that are identical to the Flutter SDK options + /// have [FlexSchemeVariant.value], [isFlutterScheme] set to true. These + /// enum options will not respect and use any other seed generation key + /// than the [primaryKey], as they only support using one seed color. + /// + /// The [FlexSchemeVariant] also includes quick selections for all the + /// predefined [FlexTones] configurations. However, with [variant] you can + /// only select one of the predefined configurations, and not make custom + /// configurations like you can with [FlexTones]. Additionally you can not + /// use the [FlexTones] modifiers [onMainsUseBW], [onSurfacesUseBW] and + /// [surfacesUseBW], since the only operate on the [FlexTones] + /// configurations passed in to [tones]. + FlexSchemeVariant? variant, + /// Override color for the seed generated [primary] color. /// /// You may want to assign the [primaryKey] to this color in light @@ -389,6 +576,18 @@ extension SeedColorScheme on ColorScheme { /// Override color for the seed generated [onPrimaryContainer] color. Color? onPrimaryContainer, + /// Override color for the seed generated [primaryFixed] color. + Color? primaryFixed, + + /// Override color for the seed generated [primaryFixedDim] color. + Color? primaryFixedDim, + + /// Override color for the seed generated [onPrimaryFixed] color. + Color? onPrimaryFixed, + + /// Override color for the seed generated [onPrimaryFixedVariant] color. + Color? onPrimaryFixedVariant, + /// Override color for the seed generated [secondary] color. /// /// You may sometimes want to assign the [secondaryKey] to this color in @@ -412,6 +611,18 @@ extension SeedColorScheme on ColorScheme { /// Override color for the seed generated [onSecondaryContainer] color. Color? onSecondaryContainer, + /// Override color for the seed generated [secondaryFixed] color. + Color? secondaryFixed, + + /// Override color for the seed generated [secondaryFixedDim] color. + Color? secondaryFixedDim, + + /// Override color for the seed generated [onSecondaryFixed] color. + Color? onSecondaryFixed, + + /// Override color for the seed generated [onSecondaryFixedVariant] color. + Color? onSecondaryFixedVariant, + /// Override color for the seed generated [tertiary] color. /// /// You may sometimes want to assign the [tertiaryKey] to this color in @@ -435,6 +646,18 @@ extension SeedColorScheme on ColorScheme { /// Override color for the seed generated [onTertiaryContainer] color. Color? onTertiaryContainer, + /// Override color for the seed generated [tertiaryFixed] color. + Color? tertiaryFixed, + + /// Override color for the seed generated [tertiaryFixedDim] color. + Color? tertiaryFixedDim, + + /// Override color for the seed generated [onTertiaryFixed] color. + Color? onTertiaryFixed, + + /// Override color for the seed generated [onTertiaryFixedVariant] color. + Color? onTertiaryFixedVariant, + /// Override color for the seed generated [error] color. Color? error, @@ -447,21 +670,33 @@ extension SeedColorScheme on ColorScheme { /// Override color for the seed generated [onErrorContainer] color. Color? onErrorContainer, - /// Override color for the seed generated [background] color. - Color? background, - - /// Override color for the seed generated [onBackground] color. - Color? onBackground, - /// Override color for the seed generated [surface] color. Color? surface, + /// Override color for the seed generated [surfaceDim] color. + Color? surfaceDim, + + /// Override color for the seed generated [surfaceBright] color. + Color? surfaceBright, + + /// Override color for the seed generated [surfaceContainerLowest] color. + Color? surfaceContainerLowest, + + /// Override color for the seed generated [surfaceContainerLow] color. + Color? surfaceContainerLow, + + /// Override color for the seed generated [surfaceContainer] color. + Color? surfaceContainer, + + /// Override color for the seed generated [surfaceContainerHigh] color. + Color? surfaceContainerHigh, + + /// Override color for the seed generated [surfaceContainerHighest] color. + Color? surfaceContainerHighest, + /// Override color for the seed generated [onSurface] color. Color? onSurface, - /// Override color for the seed generated [surfaceVariant] color. - Color? surfaceVariant, - /// Override color for the seed generated [onSurfaceVariant] color. Color? onSurfaceVariant, @@ -488,62 +723,254 @@ extension SeedColorScheme on ColorScheme { /// Override color for the seed generated [surfaceTint] color. Color? surfaceTint, + + /// Override color for the seed generated [background] color. + @Deprecated('Use surface instead.') Color? background, + + /// Override color for the seed generated [onBackground] color. + @Deprecated('Use onSurface instead.') Color? onBackground, + + /// Override color for the seed generated [surfaceVariant] color. + @Deprecated('Use surfaceContainerHighest instead.') Color? surfaceVariant, }) { - final FlexSeedScheme scheme = brightness == Brightness.light - ? FlexSeedScheme._tones( - primaryKey: primaryKey.value, - secondaryKey: secondaryKey?.value, - tertiaryKey: tertiaryKey?.value, - errorKey: errorKey?.value, - neutralKey: neutralKey?.value, - neutralVariantKey: neutralVariantKey?.value, - tones: tones ?? FlexTones.material(Brightness.light), - ) - : FlexSeedScheme._tones( - primaryKey: primaryKey.value, - secondaryKey: secondaryKey?.value, - tertiaryKey: tertiaryKey?.value, - errorKey: errorKey?.value, - neutralKey: neutralKey?.value, - neutralVariantKey: neutralVariantKey?.value, - tones: tones ?? FlexTones.material(Brightness.dark), - ); - return ColorScheme( - primary: primary ?? Color(scheme.primary), - onPrimary: onPrimary ?? Color(scheme.onPrimary), - primaryContainer: primaryContainer ?? Color(scheme.primaryContainer), - onPrimaryContainer: - onPrimaryContainer ?? Color(scheme.onPrimaryContainer), - secondary: secondary ?? Color(scheme.secondary), - onSecondary: onSecondary ?? Color(scheme.onSecondary), - secondaryContainer: - secondaryContainer ?? Color(scheme.secondaryContainer), - onSecondaryContainer: - onSecondaryContainer ?? Color(scheme.onSecondaryContainer), - tertiary: tertiary ?? Color(scheme.tertiary), - onTertiary: onTertiary ?? Color(scheme.onTertiary), - tertiaryContainer: tertiaryContainer ?? Color(scheme.tertiaryContainer), - onTertiaryContainer: - onTertiaryContainer ?? Color(scheme.onTertiaryContainer), - error: error ?? Color(scheme.error), - onError: onError ?? Color(scheme.onError), - errorContainer: errorContainer ?? Color(scheme.errorContainer), - onErrorContainer: onErrorContainer ?? Color(scheme.onErrorContainer), - background: background ?? Color(scheme.background), - onBackground: onBackground ?? Color(scheme.onBackground), - surface: surface ?? Color(scheme.surface), - onSurface: onSurface ?? Color(scheme.onSurface), - surfaceVariant: surfaceVariant ?? Color(scheme.surfaceVariant), - onSurfaceVariant: onSurfaceVariant ?? Color(scheme.onSurfaceVariant), - outline: outline ?? Color(scheme.outline), - outlineVariant: outlineVariant ?? Color(scheme.outlineVariant), - shadow: shadow ?? Color(scheme.shadow), - scrim: scrim ?? Color(scheme.scrim), - inverseSurface: inverseSurface ?? Color(scheme.inverseSurface), - onInverseSurface: onInverseSurface ?? Color(scheme.onInverseSurface), - inversePrimary: inversePrimary ?? Color(scheme.inversePrimary), - surfaceTint: surfaceTint ?? Color(scheme.primary), - brightness: brightness, - ); + // Assert that a none null value has not been assign to tones and variant + // at the same time, since they are mutually exclusive, both can be null. + assert(tones == null || variant == null, + 'Only one of tones or variant can be provided, not both.'); + + if (variant != null && variant.isFlutterScheme) { + final DynamicScheme scheme = + buildDynamicScheme(brightness, primaryKey, variant); + return ColorScheme( + primary: + primary ?? Color(MaterialDynamicColors.primary.getArgb(scheme)), + onPrimary: + onPrimary ?? Color(MaterialDynamicColors.onPrimary.getArgb(scheme)), + primaryContainer: primaryContainer ?? + Color(MaterialDynamicColors.primaryContainer.getArgb(scheme)), + onPrimaryContainer: onPrimaryContainer ?? + Color(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme)), + primaryFixed: primaryFixed ?? + Color(MaterialDynamicColors.primaryFixed.getArgb(scheme)), + primaryFixedDim: primaryFixedDim ?? + Color(MaterialDynamicColors.primaryFixedDim.getArgb(scheme)), + onPrimaryFixed: onPrimaryFixed ?? + Color(MaterialDynamicColors.onPrimaryFixed.getArgb(scheme)), + onPrimaryFixedVariant: onPrimaryFixedVariant ?? + Color(MaterialDynamicColors.onPrimaryFixedVariant.getArgb(scheme)), + secondary: + secondary ?? Color(MaterialDynamicColors.secondary.getArgb(scheme)), + onSecondary: onSecondary ?? + Color(MaterialDynamicColors.onSecondary.getArgb(scheme)), + secondaryContainer: secondaryContainer ?? + Color(MaterialDynamicColors.secondaryContainer.getArgb(scheme)), + onSecondaryContainer: onSecondaryContainer ?? + Color(MaterialDynamicColors.onSecondaryContainer.getArgb(scheme)), + secondaryFixed: secondaryFixed ?? + Color(MaterialDynamicColors.secondaryFixed.getArgb(scheme)), + secondaryFixedDim: secondaryFixedDim ?? + Color(MaterialDynamicColors.secondaryFixedDim.getArgb(scheme)), + onSecondaryFixed: onSecondaryFixed ?? + Color(MaterialDynamicColors.onSecondaryFixed.getArgb(scheme)), + onSecondaryFixedVariant: onSecondaryFixedVariant ?? + Color( + MaterialDynamicColors.onSecondaryFixedVariant.getArgb(scheme)), + tertiary: + tertiary ?? Color(MaterialDynamicColors.tertiary.getArgb(scheme)), + onTertiary: onTertiary ?? + Color(MaterialDynamicColors.onTertiary.getArgb(scheme)), + tertiaryContainer: tertiaryContainer ?? + Color(MaterialDynamicColors.tertiaryContainer.getArgb(scheme)), + onTertiaryContainer: onTertiaryContainer ?? + Color(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme)), + tertiaryFixed: tertiaryFixed ?? + Color(MaterialDynamicColors.tertiaryFixed.getArgb(scheme)), + tertiaryFixedDim: tertiaryFixedDim ?? + Color(MaterialDynamicColors.tertiaryFixedDim.getArgb(scheme)), + onTertiaryFixed: onTertiaryFixed ?? + Color(MaterialDynamicColors.onTertiaryFixed.getArgb(scheme)), + onTertiaryFixedVariant: onTertiaryFixedVariant ?? + Color(MaterialDynamicColors.onTertiaryFixedVariant.getArgb(scheme)), + error: error ?? Color(MaterialDynamicColors.error.getArgb(scheme)), + onError: + onError ?? Color(MaterialDynamicColors.onError.getArgb(scheme)), + errorContainer: errorContainer ?? + Color(MaterialDynamicColors.errorContainer.getArgb(scheme)), + onErrorContainer: onErrorContainer ?? + Color(MaterialDynamicColors.onErrorContainer.getArgb(scheme)), + outline: + outline ?? Color(MaterialDynamicColors.outline.getArgb(scheme)), + outlineVariant: outlineVariant ?? + Color(MaterialDynamicColors.outlineVariant.getArgb(scheme)), + surface: + surface ?? Color(MaterialDynamicColors.surface.getArgb(scheme)), + surfaceDim: surfaceDim ?? + Color(MaterialDynamicColors.surfaceDim.getArgb(scheme)), + surfaceBright: surfaceBright ?? + Color(MaterialDynamicColors.surfaceBright.getArgb(scheme)), + surfaceContainerLowest: surfaceContainerLowest ?? + Color(MaterialDynamicColors.surfaceContainerLowest.getArgb(scheme)), + surfaceContainerLow: surfaceContainerLow ?? + Color(MaterialDynamicColors.surfaceContainerLow.getArgb(scheme)), + surfaceContainer: surfaceContainer ?? + Color(MaterialDynamicColors.surfaceContainer.getArgb(scheme)), + surfaceContainerHigh: surfaceContainerHigh ?? + Color(MaterialDynamicColors.surfaceContainerHigh.getArgb(scheme)), + surfaceContainerHighest: surfaceContainerHighest ?? + Color( + MaterialDynamicColors.surfaceContainerHighest.getArgb(scheme)), + onSurface: + onSurface ?? Color(MaterialDynamicColors.onSurface.getArgb(scheme)), + onSurfaceVariant: onSurfaceVariant ?? + Color(MaterialDynamicColors.onSurfaceVariant.getArgb(scheme)), + inverseSurface: inverseSurface ?? + Color(MaterialDynamicColors.inverseSurface.getArgb(scheme)), + onInverseSurface: onInverseSurface ?? + Color(MaterialDynamicColors.inverseOnSurface.getArgb(scheme)), + inversePrimary: inversePrimary ?? + Color(MaterialDynamicColors.inversePrimary.getArgb(scheme)), + shadow: shadow ?? Color(MaterialDynamicColors.shadow.getArgb(scheme)), + scrim: scrim ?? Color(MaterialDynamicColors.scrim.getArgb(scheme)), + surfaceTint: + surfaceTint ?? Color(MaterialDynamicColors.primary.getArgb(scheme)), + brightness: brightness, + // DEPRECATED (newest deprecations at the bottom) + background: background ?? + Color(MaterialDynamicColors.background.getArgb(scheme)), + onBackground: onBackground ?? + Color(MaterialDynamicColors.onBackground.getArgb(scheme)), + surfaceVariant: surfaceVariant ?? + Color(MaterialDynamicColors.surfaceVariant.getArgb(scheme)), + ); + } else { + FlexTones? variantTones; + // If a variant is selected, use its tones. + if (variant != null) { + variantTones = variant.tones(brightness); + } + final FlexSeedScheme scheme = FlexSeedScheme._tones( + primaryKey: primaryKey.value, + secondaryKey: secondaryKey?.value, + tertiaryKey: tertiaryKey?.value, + errorKey: errorKey?.value, + neutralKey: neutralKey?.value, + neutralVariantKey: neutralVariantKey?.value, + tones: tones ?? variantTones ?? FlexTones.material(brightness), + ); + + return ColorScheme( + primary: primary ?? Color(scheme.primary), + onPrimary: onPrimary ?? Color(scheme.onPrimary), + primaryContainer: primaryContainer ?? Color(scheme.primaryContainer), + onPrimaryContainer: + onPrimaryContainer ?? Color(scheme.onPrimaryContainer), + primaryFixed: primaryFixed ?? Color(scheme.primaryFixed), + primaryFixedDim: primaryFixedDim ?? Color(scheme.primaryFixedDim), + onPrimaryFixed: onPrimaryFixed ?? Color(scheme.onPrimaryFixed), + onPrimaryFixedVariant: + onPrimaryFixedVariant ?? Color(scheme.onPrimaryFixedVariant), + // + secondary: secondary ?? Color(scheme.secondary), + onSecondary: onSecondary ?? Color(scheme.onSecondary), + secondaryContainer: + secondaryContainer ?? Color(scheme.secondaryContainer), + onSecondaryContainer: + onSecondaryContainer ?? Color(scheme.onSecondaryContainer), + secondaryFixed: secondaryFixed ?? Color(scheme.secondaryFixed), + secondaryFixedDim: secondaryFixedDim ?? Color(scheme.secondaryFixedDim), + onSecondaryFixed: onSecondaryFixed ?? Color(scheme.onSecondaryFixed), + onSecondaryFixedVariant: + onSecondaryFixedVariant ?? Color(scheme.onSecondaryFixedVariant), + // + tertiary: tertiary ?? Color(scheme.tertiary), + onTertiary: onTertiary ?? Color(scheme.onTertiary), + tertiaryContainer: tertiaryContainer ?? Color(scheme.tertiaryContainer), + onTertiaryContainer: + onTertiaryContainer ?? Color(scheme.onTertiaryContainer), + tertiaryFixed: tertiaryFixed ?? Color(scheme.tertiaryFixed), + tertiaryFixedDim: tertiaryFixedDim ?? Color(scheme.tertiaryFixedDim), + onTertiaryFixed: onTertiaryFixed ?? Color(scheme.onTertiaryFixed), + onTertiaryFixedVariant: + onTertiaryFixedVariant ?? Color(scheme.onTertiaryFixedVariant), + // + error: error ?? Color(scheme.error), + onError: onError ?? Color(scheme.onError), + errorContainer: errorContainer ?? Color(scheme.errorContainer), + onErrorContainer: onErrorContainer ?? Color(scheme.onErrorContainer), + // + surface: surface ?? Color(scheme.surface), + surfaceDim: surfaceDim ?? Color(scheme.surfaceDim), + surfaceBright: surfaceBright ?? Color(scheme.surfaceBright), + surfaceContainerLowest: + surfaceContainerLowest ?? Color(scheme.surfaceContainerLowest), + surfaceContainerLow: + surfaceContainerLow ?? Color(scheme.surfaceContainerLow), + surfaceContainer: surfaceContainer ?? Color(scheme.surfaceContainer), + surfaceContainerHigh: + surfaceContainerHigh ?? Color(scheme.surfaceContainerHigh), + surfaceContainerHighest: + surfaceContainerHighest ?? Color(scheme.surfaceContainerHighest), + onSurface: onSurface ?? Color(scheme.onSurface), + onSurfaceVariant: onSurfaceVariant ?? Color(scheme.onSurfaceVariant), + // + outline: outline ?? Color(scheme.outline), + outlineVariant: outlineVariant ?? Color(scheme.outlineVariant), + shadow: shadow ?? Color(scheme.shadow), + scrim: scrim ?? Color(scheme.scrim), + inverseSurface: inverseSurface ?? Color(scheme.inverseSurface), + onInverseSurface: onInverseSurface ?? Color(scheme.onInverseSurface), + inversePrimary: inversePrimary ?? Color(scheme.inversePrimary), + surfaceTint: surfaceTint ?? Color(scheme.primary), + // Deprecated colors + background: background ?? Color(scheme.background), + onBackground: onBackground ?? Color(scheme.onBackground), + surfaceVariant: surfaceVariant ?? Color(scheme.surfaceVariant), + // + brightness: brightness, + ); + } + } + + /// Build one of the Flutter SDK defined DynamicScheme variants. + /// + /// If used with a FlexTones based [FlexSchemeVariant] variant it returns + /// tonalSpot, the default Material-3 SDK style. + static DynamicScheme buildDynamicScheme( + Brightness brightness, Color seedColor, FlexSchemeVariant variant) { + final bool isDark = brightness == Brightness.dark; + final Hct sourceColor = Hct.fromInt(seedColor.value); + return switch (variant) { + FlexSchemeVariant.material || + FlexSchemeVariant.material3Legacy || + FlexSchemeVariant.soft || + FlexSchemeVariant.vivid || + FlexSchemeVariant.vividSurfaces || + FlexSchemeVariant.highContrast || + FlexSchemeVariant.ultraContrast || + FlexSchemeVariant.jolly || + FlexSchemeVariant.vividBackground || + FlexSchemeVariant.oneHue || + FlexSchemeVariant.candyPop || + FlexSchemeVariant.chroma || + FlexSchemeVariant.tonalSpot => + SchemeTonalSpot( + sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0), + FlexSchemeVariant.fidelity => SchemeFidelity( + sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0), + FlexSchemeVariant.content => SchemeContent( + sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0), + FlexSchemeVariant.monochrome => SchemeMonochrome( + sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0), + FlexSchemeVariant.neutral => SchemeNeutral( + sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0), + FlexSchemeVariant.vibrant => SchemeVibrant( + sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0), + FlexSchemeVariant.expressive => SchemeExpressive( + sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0), + FlexSchemeVariant.rainbow => SchemeRainbow( + sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0), + FlexSchemeVariant.fruitSalad => SchemeFruitSalad( + sourceColorHct: sourceColor, isDark: isDark, contrastLevel: 0.0), + }; } } diff --git a/lib/src/flex/flex_tonal_palette.dart b/lib/src/flex/flex_tonal_palette.dart index dbd063e..b26d479 100644 --- a/lib/src/flex/flex_tonal_palette.dart +++ b/lib/src/flex/flex_tonal_palette.dart @@ -1,9 +1,21 @@ -import 'dart:math' as math; +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. import 'package:collection/collection.dart' show ListEquality; -import 'package:meta/meta.dart' show immutable; +import 'package:meta/meta.dart'; -import '../mcu/material_color_utilities.dart'; +import '../mcu/hct/hct.dart'; // ignore_for_file: comment_references @@ -47,35 +59,15 @@ enum FlexPaletteType { /// A convenience class for retrieving colors that are constant in hue and /// chroma, but vary in tone. /// -/// This is a modification of package material_color_utilities [TonalPalette] -/// made to also include the tones 98 and tone 5. This gives additional fidelity -/// and expression possibilities when using tones close to black and white. -/// /// This class can be instantiated in two ways: -/// /// 1. [of] From hue and chroma. (preferred) -/// 2. [fromList] From a fixed-size [FlexTonalPalette.commonSize] or -/// [FlexTonalPalette.extendedSize] list of int representing ARBG colors, -/// depending on if [FlexPaletteType.common] paletteType -/// [FlexPaletteType.extended]. Correctness (constant hue and chroma) of -/// the input is not enforced. [get] will only return the input colors, -/// corresponding to [commonTones] or [extendedTones]. +/// 2. [fromList] From a fixed-size ([FlexTonalPalette.commonSize]) list of ints +/// representing ARBG colors. Correctness (constant hue and chroma) of the input +/// is not enforced. [get] will only return the input colors, corresponding to +/// [commonTones]. This also initializes the key color to black. @immutable class FlexTonalPalette { - // If modifying commonTones length, update commonSize to equal - // commonTones.length. There is both a test and assert that fails if not done. - - /// Commonly-used tone values in a [FlexTonalPalette]. - /// - /// Contains custom tones 5 and 98, in addition to the 13 tones included - /// in the Material 3 guide tonal palette. The tone 98 used to exist in the - /// [Web Material Theme Builder app](https://m3.material.io/theme-builder#/custom), - /// but no longer does. It never existed in Flutter or - /// [Material Color Utilities package](https://pub.dev/packages/material_color_utilities). - /// Tone 5 is custom addition used in e.g. in [FlexTones.ultraContrast]. - /// - /// Tone 98 provides optional tonal fidelity in the light and white end of the - /// palette and tone 5 a more dark tone in the black end of the palette. + /// Commonly-used tone values. static const List commonTones = [ 0, 5, @@ -101,7 +93,7 @@ class FlexTonalPalette { /// /// In original implementation package material_color_utilities this is /// defined as well, presumably for improved efficiency, there it is set to - /// [TonalPalette.commonTones.length]. Here we instead manually set it + /// [FlexTonalPalette.commonTones.length]. Here we instead manually set it /// to compile time const of same const list length. /// /// Flutter SDK [TonalPalette] has 13 common tones and [FlexTonalPalette] 15. @@ -109,29 +101,22 @@ class FlexTonalPalette { /// Extended one values in a [FlexTonalPalette]. /// - /// Contains custom tones 5 and 98, in addition to the 13 tones included - /// in the Material 3 guide tonal palette. The tone 98 used to exist in the - /// [Web Material Theme Builder app](https://m3.material.io/theme-builder#/custom), - /// but no longer does. It never existed in Flutter or - /// [Material Color Utilities package](https://pub.dev/packages/material_color_utilities). - /// Tone 5 is custom addition used in e.g. in [FlexTones.ultraContrast]. + /// Contains custom tones 2, 5 and 97 in addition to the 13 tones included + /// in the Material 3 guide tonal palette. /// - /// The added tones 4, 6, 12, 17, 22 are for new dark mode surfaces in - /// revised Material 3 dark surface colors. Likewise added tones - /// 97, 96, 94, 92, 87 are for light mode surfaces in the updated Material 3 + /// The added tones 4, 6, 12, 17, 22 and 24 are for new dark mode surfaces + /// in revised Material 3 dark surface colors. Likewise added tones + /// 98, 96, 94, 92, 87 are for light mode surfaces in the updated Material 3 /// color system. For more information, see: /// https://m3.material.io/styles/color/the-color-system/color-roles /// The additional tones in the Material 3 specification appeared during later - /// pert of first half of 2023. - /// - /// Tones 5, 97, and 98 are not in old or new M3 spec, but FlexSeedScheme - /// includes them to enable even more fidelity in dark and even more so in - /// the light tones. + /// part of first half of 2023. /// - /// Tone 98 provides optional tonal fidelity in the light and white end of the - /// palette and tone 5 a more dark tone in the black end of the palette. + /// Tones 2, 5, and 97 are not in old or new M3 spec, but FlexSeedScheme + /// includes them to enable even more fidelity in dark and light tones. static const List extendedTones = [ 0, + 2, 4, 5, 6, @@ -140,6 +125,7 @@ class FlexTonalPalette { 17, 20, 22, + 24, 30, 40, 50, @@ -165,33 +151,58 @@ class FlexTonalPalette { /// /// In original implementation package material_color_utilities this is /// defined as well, presumably for improved efficiency, but there it is set - /// to [TonalPalette.commonTones.length]. Here we instead manually set it + /// to [FlexTonalPalette.commonTones.length]. Here we instead manually set it /// to compile time const of same const list length. /// - /// Flutter SDK [TonalPalette] has 13 tones, [FlexTonalPalette] extended 25. - static const int extendedSize = 25; + /// Flutter SDK [TonalPalette] has 13 tones, [FlexTonalPalette] extended 27. + static const int extendedSize = 27; - final double? _hue; - final double? _chroma; + /// The hue of the palette. + final double hue; + + /// The chroma of the palette. + final double chroma; + + /// The used palette type. final FlexPaletteType _paletteType; + + /// The key color of the palette. + final Hct keyColor; + + /// A cache containing keys-value pairs where: + /// - keys are integers that represent tones, and + /// - values are colors in ARGB format. final Map _cache; + final bool _isFromCache; + + FlexTonalPalette._fromHct( + Hct hct, [ + FlexPaletteType paletteType = FlexPaletteType.common, + ]) : _cache = {}, + _paletteType = paletteType, + hue = hct.hue, + chroma = hct.chroma, + keyColor = hct, + _isFromCache = false; FlexTonalPalette._fromHueAndChroma( - double hue, - double chroma, [ + this.hue, + this.chroma, [ FlexPaletteType paletteType = FlexPaletteType.common, ]) : _cache = {}, - _hue = hue, - _chroma = chroma, - _paletteType = paletteType; + _paletteType = paletteType, + keyColor = createKeyColor(hue, chroma), + _isFromCache = false; - const FlexTonalPalette._fromCache( - Map cache, [ + FlexTonalPalette._fromCache( + Map cache, + this.hue, + this.chroma, [ FlexPaletteType paletteType = FlexPaletteType.common, ]) : _cache = cache, - _hue = null, - _chroma = null, - _paletteType = paletteType; + _paletteType = paletteType, + keyColor = createKeyColor(hue, chroma), + _isFromCache = true; /// Create colors using [hue] and [chroma]. static FlexTonalPalette of( @@ -202,6 +213,14 @@ class FlexTonalPalette { return FlexTonalPalette._fromHueAndChroma(hue, chroma, paletteType); } + /// Create a Tonal Palette from hue and chroma of [hct]. + static FlexTonalPalette fromHct( + Hct hct, [ + FlexPaletteType paletteType = FlexPaletteType.common, + ]) { + return FlexTonalPalette._fromHct(hct, paletteType); + } + /// Create colors from a fixed-size list of ARGB color ints. /// /// Inverse of [FlexTonalPalette.asList]. @@ -216,8 +235,7 @@ class FlexTonalPalette { paletteType == FlexPaletteType.extended), 'Length must be $commonSize when using FlexPaletteType.common OR ' 'length must be $extendedSize when using FlexPaletteType.extended.'); - Map cache; - cache = {}; + final Map cache = {}; switch (paletteType) { case FlexPaletteType.common: commonTones.asMap().forEach( @@ -226,7 +244,66 @@ class FlexTonalPalette { extendedTones.asMap().forEach( (int index, int toneValue) => cache[toneValue] = colors[index]); } - return FlexTonalPalette._fromCache(cache, paletteType); + + // Approximately deduces the original hue and chroma that generated this + // list of colors. + // Uses the hue and chroma of the provided color with the highest chroma. + double bestHue = 0.0; + double bestChroma = 0.0; + for (final int argb in colors) { + final Hct hct = Hct.fromInt(argb); + + // If the color is too close to white, its chroma may have been + // affected by a known issue, so we ignore it. + // https://github.com/material-foundation/material-color-utilities/issues/140 + if (hct.tone > 98.0) continue; + + if (hct.chroma > bestChroma) { + bestHue = hct.hue; + bestChroma = hct.chroma; + } + } + return FlexTonalPalette._fromCache(cache, bestHue, bestChroma, paletteType); + } + + /// Creates a key color from a [hue] and a [chroma]. + /// The key color is the first tone, starting from T50, matching the + /// given hue and chroma. Key color [Hct]. + static Hct createKeyColor(double hue, double chroma) { + const double startTone = 50.0; + Hct smallestDeltaHct = Hct.from(hue, chroma, startTone); + double smallestDelta = (smallestDeltaHct.chroma - chroma).abs(); + // Starting from T50, check T+/-delta to see if they match the requested + // chroma. + // + // Starts from T50 because T50 has the most chroma available, on + // average. Thus it is most likely to have a direct answer and minimize + // iteration. + for (double delta = 1.0; delta < 50.0; delta += 1.0) { + // Termination condition rounding instead of minimizing delta to avoid + // case where requested chroma is 16.51, and the closest chroma is 16.49. + // Error is minimized, but when rounded and displayed, requested chroma + // is 17, key color's chroma is 16. + if (chroma.round() == smallestDeltaHct.chroma.round()) { + return smallestDeltaHct; + } + + final Hct hctAdd = Hct.from(hue, chroma, startTone + delta); + final double hctAddDelta = (hctAdd.chroma - chroma).abs(); + if (hctAddDelta < smallestDelta) { + smallestDelta = hctAddDelta; + smallestDeltaHct = hctAdd; + } + + final Hct hctSubtract = Hct.from(hue, chroma, startTone - delta); + final double hctSubtractDelta = (hctSubtract.chroma - chroma).abs(); + if (hctSubtractDelta < smallestDelta) { + smallestDelta = hctSubtractDelta; + smallestDeltaHct = hctSubtract; + } + } + + return smallestDeltaHct; } /// Returns a fixed-size list of ARGB color ints for common tone values. @@ -236,50 +313,46 @@ class FlexTonalPalette { ? commonTones.map(get).toList() : extendedTones.map(get).toList(); - /// Returns the ARGB representation of an HCT color. + /// Returns the ARGB representation of an HCT color at the given [tone]. /// - /// If the class was instantiated from [_hue] and [_chroma], will return the - /// color with corresponding [tone]. - /// If the class was instantiated from a fixed-size list of color ints, [tone] - /// must be in [commonTones] if palette type is [FlexPaletteType.common] and - /// in [extendedTones] if palette type is [FlexPaletteType.extended]. + /// If the palette is constructed from a list of colors + /// (i.e. using [fromList]), the color provided at construction is returned + /// if possible; otherwise the result is generated from the deduced + /// [hue] and [chroma]. + /// + /// If the palette is constructed from a hue and chroma (i.e. using [of] or + /// [fromHct]), the result is generated from the given [hue] and [chroma]. int get(int tone) { - if (_hue == null || _chroma == null) { - if (!_cache.containsKey(tone)) { - throw ArgumentError.value( - tone, - 'tone', - 'When a FlexTonalPalette is created with fromList using ' - '$_paletteType, tone must be one of ' - // ignore: lines_longer_than_80_chars - '${_paletteType == FlexPaletteType.common ? commonTones : extendedTones}.', - ); - } else { - return _cache[tone]!; - } - } - - // If we are using `common` tonal palette type and the tone is larger or - // equal to 90, allow maximum chroma value of 90, in other cases - // use the actual chroma value. - final double chroma = - (tone >= 90.0) && _paletteType == FlexPaletteType.common - ? math.min(_chroma!, 40.0) - : _chroma!; return _cache.putIfAbsent( - tone, () => Hct.from(_hue!, chroma, tone.toDouble()).toInt()); + tone, + () => Hct.from(hue, chroma, tone.toDouble()).toInt(), + ); + } + + /// Returns the HCT color at the given [tone]. + /// + /// If the palette is constructed from a list of colors + /// (i.e. using [fromList]), the color provided at construction is returned + /// if possible; otherwise the result is generated from the deduced + /// [hue] and [chroma]. + /// + /// If the palette is constructed from a hue and chroma (i.e. using [of] or + /// [fromHct]), the result is generated from the given [hue] and [chroma]. + Hct getHct(double tone) { + if (_cache.containsKey(tone)) { + return Hct.fromInt(_cache[tone]!); + } else { + return Hct.from(hue, chroma, tone); + } } @override bool operator ==(Object other) { if (other is FlexTonalPalette) { - if (_hue != null && - _chroma != null && - other._hue != null && - other._chroma != null) { + if (!_isFromCache && !other._isFromCache) { // Both created with .of or .fromHct - return _hue == other._hue && - _chroma == other._chroma && + return hue == other.hue && + chroma == other.chroma && _paletteType == other._paletteType; } else { return const ListEquality().equals(asList, other.asList); @@ -290,8 +363,8 @@ class FlexTonalPalette { @override int get hashCode { - if (_hue != null && _chroma != null) { - return Object.hash(_hue, _chroma, _paletteType); + if (!_isFromCache) { + return Object.hash(hue, chroma, _paletteType); } else { return Object.hashAll(asList); } @@ -299,10 +372,10 @@ class FlexTonalPalette { @override String toString() { - if (_hue != null && _chroma != null) { - return 'FlexTonalPalette.of($_hue, $_chroma, $_paletteType)'; + if (!_isFromCache) { + return 'FlexTonalPalette.of($hue, $chroma, $_paletteType)'; } else { - return 'FlexTonalPalette.fromList($_cache, $_paletteType)'; + return 'FlexTonalPalette.fromList($asList, $_paletteType)'; } } } diff --git a/lib/src/flex/flex_tones.dart b/lib/src/flex/flex_tones.dart index c80a945..3b49d47 100644 --- a/lib/src/flex/flex_tones.dart +++ b/lib/src/flex/flex_tones.dart @@ -14,7 +14,10 @@ import '../../flex_seed_scheme.dart'; /// usage and limits with [SeedColorScheme.fromSeeds], you can pass in one of /// the predefined configs below, to its [tones] property: /// -/// * [FlexTones.material], default and same as Flutter SDK M3 setup. +/// * [FlexTones.material], default and same as Flutter SDK M3 setup used in +/// Flutter 3.22 and later. +/// * [FlexTones.material3Legacy], the same as Flutter SDK M3 setup used in +/// Flutter 3.19 and earlier. /// * [FlexTones.soft], softer and earthier tones than M3 [FlexTones.material]. /// * [FlexTones.vivid], more vivid colors, uses chroma from all key colors. /// * [FlexTones.vividSurfaces], like [vivid], but with more colors in surfaces. @@ -31,14 +34,17 @@ import '../../flex_seed_scheme.dart'; /// thus create a color scheme that uses only one hue. /// * [FlexTones.candyPop] for a high contrast, candy popping theme. It has /// tone 100, which is white surface and background in light mode and very -/// dark tone 6, dark mode. This [FlexTones] the [paletteType] extended via -/// [FlexPaletteType.extended], for additional tone fidelity. +/// dark tone 6, dark mode. /// * [FlexTones.chroma] for a theme where the chroma in each seed color is used /// as is with any min limitation. Chroma in passed in color can even be zero, /// producing a greyscale tonal palette as the palette. It has /// tone 100, which is white surface and background in light mode and very -/// dark tone 6, dark mode. This [FlexTones] the [paletteType] extended via -/// [FlexPaletteType.extended], for additional tone fidelity. +/// dark tone 6, dark mode. +/// +/// * In version 2.0.0 and later all built-in [FlexTones] use the [paletteType] +/// extended via [FlexPaletteType.extended], for additional tone fidelity. +/// This is needed for compatibility with Flutter 3.22 and its revised +/// [ColorScheme]. /// /// You can also easily create custom configurations by using the /// [FlexTones.light] and [FlexTones.dark] factories that have defaults that @@ -77,24 +83,45 @@ class FlexTones with Diagnosticable { required this.onPrimaryTone, required this.primaryContainerTone, required this.onPrimaryContainerTone, + required this.primaryFixedTone, + required this.primaryFixedDimTone, + required this.onPrimaryFixedTone, + required this.onPrimaryFixedVariantTone, + // required this.secondaryTone, required this.onSecondaryTone, required this.secondaryContainerTone, required this.onSecondaryContainerTone, + required this.secondaryFixedTone, + required this.secondaryFixedDimTone, + required this.onSecondaryFixedTone, + required this.onSecondaryFixedVariantTone, + // required this.tertiaryTone, required this.onTertiaryTone, required this.tertiaryContainerTone, required this.onTertiaryContainerTone, + required this.tertiaryFixedTone, + required this.tertiaryFixedDimTone, + required this.onTertiaryFixedTone, + required this.onTertiaryFixedVariantTone, + // required this.errorTone, required this.onErrorTone, required this.errorContainerTone, required this.onErrorContainerTone, - required this.backgroundTone, - required this.onBackgroundTone, + // required this.surfaceTone, + required this.surfaceDimTone, + required this.surfaceBrightTone, + required this.surfaceContainerLowestTone, + required this.surfaceContainerLowTone, + required this.surfaceContainerTone, + required this.surfaceContainerHighTone, + required this.surfaceContainerHighestTone, required this.onSurfaceTone, - required this.surfaceVariantTone, required this.onSurfaceVariantTone, + // required this.outlineTone, required this.outlineVariantTone, required this.shadowTone, @@ -103,6 +130,12 @@ class FlexTones with Diagnosticable { required this.onInverseSurfaceTone, required this.inversePrimaryTone, required this.surfaceTintTone, + // Deprecated color tones + @Deprecated('Use surfaceTone instead.') required this.backgroundTone, + @Deprecated('Use onSurfaceTone instead.') required this.onBackgroundTone, + @Deprecated('Use surfaceContainerHighestTone instead.') + required this.surfaceVariantTone, + // this.primaryChroma, this.primaryMinChroma, this.secondaryChroma, @@ -116,10 +149,11 @@ class FlexTones with Diagnosticable { this.neutralMinChroma, this.neutralVariantChroma, this.neutralVariantMinChroma, - this.paletteType = FlexPaletteType.common, + this.paletteType = FlexPaletteType.extended, + this.useCam16 = true, }); - /// Create an M3 standard light tonal palette tones extraction setup. + /// Create an M3 light theme mode tonal palette tones extraction setup. /// /// This setup is almost identical to the default that you get if only /// one seed color is used, as you get with Flutter when it uses @@ -127,14 +161,14 @@ class FlexTones with Diagnosticable { /// that it does not lock the chroma values for primary, secondary and /// tertiary to a specific chroma value, but uses actual chroma of specified /// key color, as long as it is over the minimum value. - /// The minimum values match the Material 3 defaults. + /// The minimum values match the Material-3 defaults. /// - /// To get the an exact matching setup as used by Material 3 + /// To get the an exact matching setup as used by Material-3 /// [ColorScheme.fromSeed] use the [FlexTones.material] factory as the /// [FlexTones] configuration. /// /// The default chroma limits for neutral and neutral variant key colors are - /// set to 4 and 8 as in Material 3 design. You can create a + /// set to 6 and 8 as in Material-3 design. You can create a /// [FlexTones.light] where you set [neutralChroma] and [neutralVariantChroma] /// to use the effective chroma values in their seed key values as the actual /// chroma value for the neutral and neutral tonal palette generation. @@ -150,34 +184,61 @@ class FlexTones with Diagnosticable { this.onPrimaryTone = 100, this.primaryContainerTone = 90, this.onPrimaryContainerTone = 10, + this.primaryFixedTone = 90, + this.primaryFixedDimTone = 80, + this.onPrimaryFixedTone = 10, + this.onPrimaryFixedVariantTone = 30, + + // this.secondaryTone = 40, this.onSecondaryTone = 100, this.secondaryContainerTone = 90, this.onSecondaryContainerTone = 10, + this.secondaryFixedTone = 90, + this.secondaryFixedDimTone = 80, + this.onSecondaryFixedTone = 10, + this.onSecondaryFixedVariantTone = 30, + // this.tertiaryTone = 40, this.onTertiaryTone = 100, this.tertiaryContainerTone = 90, this.onTertiaryContainerTone = 10, + this.tertiaryFixedTone = 90, + this.tertiaryFixedDimTone = 80, + this.onTertiaryFixedTone = 10, + this.onTertiaryFixedVariantTone = 30, + // this.errorTone = 40, this.onErrorTone = 100, this.errorContainerTone = 90, this.onErrorContainerTone = 10, // - this.backgroundTone = 99, - this.onBackgroundTone = 10, - this.surfaceTone = 99, + this.surfaceTone = 98, + this.surfaceDimTone = 87, + this.surfaceBrightTone = 98, + this.surfaceContainerLowestTone = 100, + this.surfaceContainerLowTone = 96, + this.surfaceContainerTone = 94, + this.surfaceContainerHighTone = 92, + this.surfaceContainerHighestTone = 90, this.onSurfaceTone = 10, - this.surfaceVariantTone = 90, this.onSurfaceVariantTone = 30, - this.outlineTone = 50, - this.outlineVariantTone = 80, - this.shadowTone = 0, - this.scrimTone = 0, + // this.inverseSurfaceTone = 20, this.onInverseSurfaceTone = 95, this.inversePrimaryTone = 80, this.surfaceTintTone = 40, // + this.outlineTone = 50, + this.outlineVariantTone = 80, + this.shadowTone = 0, + this.scrimTone = 0, + // Deprecated tones + @Deprecated('Use surfaceTone instead.') this.backgroundTone = 98, + @Deprecated('Use onSurfaceTone instead.') this.onBackgroundTone = 10, + @Deprecated('Use surfaceContainerHighestTone instead.') + this.surfaceVariantTone = 90, + // this.primaryChroma, this.primaryMinChroma, this.secondaryChroma, @@ -187,11 +248,12 @@ class FlexTones with Diagnosticable { this.tertiaryHueRotation, this.errorChroma, this.errorMinChroma, - this.neutralChroma = 4, + this.neutralChroma = 6, this.neutralMinChroma, this.neutralVariantChroma = 8, this.neutralVariantMinChroma, - this.paletteType = FlexPaletteType.common, + this.paletteType = FlexPaletteType.extended, + this.useCam16 = true, }); /// Create a M3 standard dark tonal palette tones extraction setup. @@ -225,34 +287,60 @@ class FlexTones with Diagnosticable { this.onPrimaryTone = 20, this.primaryContainerTone = 30, this.onPrimaryContainerTone = 90, + this.primaryFixedTone = 90, + this.primaryFixedDimTone = 80, + this.onPrimaryFixedTone = 10, + this.onPrimaryFixedVariantTone = 30, + // this.secondaryTone = 80, this.onSecondaryTone = 20, this.secondaryContainerTone = 30, this.onSecondaryContainerTone = 90, + this.secondaryFixedTone = 90, + this.secondaryFixedDimTone = 80, + this.onSecondaryFixedTone = 10, + this.onSecondaryFixedVariantTone = 30, + // this.tertiaryTone = 80, this.onTertiaryTone = 20, this.tertiaryContainerTone = 30, this.onTertiaryContainerTone = 90, + this.tertiaryFixedTone = 90, + this.tertiaryFixedDimTone = 80, + this.onTertiaryFixedTone = 10, + this.onTertiaryFixedVariantTone = 30, + // this.errorTone = 80, this.onErrorTone = 20, this.errorContainerTone = 30, - this.onErrorContainerTone = 80, + this.onErrorContainerTone = 90, // - this.backgroundTone = 10, - this.onBackgroundTone = 90, - this.surfaceTone = 10, + this.surfaceTone = 6, + this.surfaceDimTone = 6, + this.surfaceBrightTone = 24, + this.surfaceContainerLowestTone = 4, + this.surfaceContainerLowTone = 10, + this.surfaceContainerTone = 12, + this.surfaceContainerHighTone = 17, + this.surfaceContainerHighestTone = 22, this.onSurfaceTone = 90, - this.surfaceVariantTone = 30, this.onSurfaceVariantTone = 80, - this.outlineTone = 60, - this.outlineVariantTone = 30, - this.shadowTone = 0, - this.scrimTone = 0, + // this.inverseSurfaceTone = 90, this.onInverseSurfaceTone = 20, this.inversePrimaryTone = 40, this.surfaceTintTone = 80, // + this.outlineTone = 60, + this.outlineVariantTone = 30, + this.shadowTone = 0, + this.scrimTone = 0, + // Deprecated tones + @Deprecated('Use surfaceTone instead.') this.backgroundTone = 6, + @Deprecated('Use onSurfaceTone instead.') this.onBackgroundTone = 90, + @Deprecated('Use surfaceContainerHighestTone instead.') + this.surfaceVariantTone = 30, + // this.primaryChroma, this.primaryMinChroma, this.secondaryChroma, @@ -262,32 +350,86 @@ class FlexTones with Diagnosticable { this.tertiaryHueRotation, this.errorChroma, this.errorMinChroma, - this.neutralChroma = 4, + this.neutralChroma = 6, this.neutralMinChroma, this.neutralVariantChroma = 8, this.neutralVariantMinChroma, - this.paletteType = FlexPaletteType.common, + this.paletteType = FlexPaletteType.extended, + this.useCam16 = true, }); - /// Create a M3 standard tonal palette tones extraction and CAM16 - /// chroma setup. + /// Create a Material-3 standard tonal palette tones extraction using HCT + /// based chroma. /// /// This setup will if only one seed color is used, produce the same result - /// with [FlexColorPalette] as [Scheme.light] or [Scheme.dark] depending on - /// used [brightness], does when Flutter SDK uses [ColorPalette.of]. + /// as Flutter SDK does when using [ColorScheme.fromSeed] in + /// Flutter version 3.22 and later. + /// + /// Prior to Flutter 3.22 the [paletteType] was [FlexPaletteType.common] + /// and the [useCam16] was true, primaryChroma was 48 (now 36) and neutral + /// chroma 8 (now 6). These changed value match the new Material-3 defaults + /// in Flutter 3.22 and later. + /// + /// It should be noted that the Material-3 implementation in Flutter uses + /// DynamicSchemeVariant tonalSpot as default for the Material-3 design + /// seed generated ColorScheme. There might be some slight differences in + /// its results and using this selection in some edge cases, but none have + /// been observed in normal use cases. If an exact match is critical, use + /// [tonalSpot] as used in the Flutter SDK 3.22 and later. + /// + /// If you want to use multiple seed colors to generate a ColorScheme, you + /// will need to use [FlexTones] based configurations, the ones based on + /// Flutter SDK DynamicSchemeVariant and MCU do not provide that feature-set. factory FlexTones.material(Brightness brightness) => brightness == Brightness.light ? const FlexTones.light( + primaryChroma: 36, + primaryMinChroma: 0, secondaryChroma: 16, tertiaryChroma: 24, + useCam16: false, ) : const FlexTones.dark( + primaryChroma: 36, + primaryMinChroma: 0, + secondaryChroma: 16, + tertiaryChroma: 24, + useCam16: false, + ); + + /// Create a Material-3 standard tonal palette tones extraction using Cam16 + /// based chroma. + /// + /// This setup will when only one seed color is used, produce the same result + /// as Flutter SDK does when using [ColorScheme.fromSeed] in + /// Flutter version 3.19 and earlier. + /// + /// Prior to FlexSeedScheme 2.0.0, this was the default setup used by the + /// [FlexTones.material] configuration. However, [FlexTones.material] was in + /// FSS version 2.0.0 modified to match the new actual and revised Material-3 + /// configuration in Flutter 3.22 and later. This factory is provided if you + /// need and want to use the older Material-3 seed generation setup used in + /// Flutter 3.19 and earlier versions. + factory FlexTones.material3Legacy(Brightness brightness) => + brightness == Brightness.light + ? const FlexTones.light( + primaryChroma: 48, + primaryMinChroma: 0, + secondaryChroma: 16, + tertiaryChroma: 24, + ) + : const FlexTones.dark( + surfaceTone: 8, + backgroundTone: 8, + onErrorContainerTone: 90, + primaryChroma: 48, + primaryMinChroma: 0, secondaryChroma: 16, tertiaryChroma: 24, ); /// Creates a tonal palette extraction setup that results in M3 like - /// ColorsSchemes with softer colors than Material 3 defaults. + /// ColorsSchemes with softer colors than Material-3 defaults. /// /// Primary chroma is 30, secondary 14 and tertiary 20. Tones are same as /// in Material 3 default setup. @@ -439,6 +581,8 @@ class FlexTones with Diagnosticable { tertiaryContainerTone: 95, errorContainerTone: 95, surfaceTintTone: 30, + surfaceTone: 99, + backgroundTone: 99, // primaryMinChroma: 65, secondaryMinChroma: 55, @@ -454,6 +598,12 @@ class FlexTones with Diagnosticable { tertiaryContainerTone: 20, errorContainerTone: 20, onErrorContainerTone: 90, + backgroundTone: 4, + onBackgroundTone: 96, + surfaceTone: 4, + onSurfaceTone: 96, + surfaceContainerLowestTone: 0, + surfaceContainerLowTone: 6, // primaryMinChroma: 65, secondaryMinChroma: 55, @@ -474,10 +624,14 @@ class FlexTones with Diagnosticable { errorContainerTone: 95, onErrorContainerTone: 5, // + surfaceTone: 100, + backgroundTone: 100, + surfaceContainerLowTone: 98, + surfaceContainerTone: 96, onBackgroundTone: 0, onSurfaceTone: 0, - surfaceVariantTone: 95, - onSurfaceVariantTone: 10, + surfaceVariantTone: 96, + onSurfaceVariantTone: 6, onInverseSurfaceTone: 99, inversePrimaryTone: 90, outlineTone: 40, @@ -492,20 +646,22 @@ class FlexTones with Diagnosticable { ) : const FlexTones.dark( primaryTone: 90, - onPrimaryTone: 5, + onPrimaryTone: 2, onPrimaryContainerTone: 98, secondaryTone: 95, - onSecondaryTone: 5, + onSecondaryTone: 2, onSecondaryContainerTone: 98, tertiaryTone: 95, - onTertiaryTone: 5, + onTertiaryTone: 2, onTertiaryContainerTone: 98, - onErrorTone: 5, + onErrorTone: 2, onErrorContainerTone: 98, // - backgroundTone: 5, + backgroundTone: 2, onBackgroundTone: 99, - surfaceTone: 5, + surfaceTone: 2, + surfaceContainerLowestTone: 0, + surfaceContainerLowTone: 6, onSurfaceTone: 99, surfaceVariantTone: 20, onSurfaceVariantTone: 95, @@ -556,8 +712,9 @@ class FlexTones with Diagnosticable { neutralVariantChroma: 10, ); - /// Create a M3 tonal palette tones extraction, but with no hue rotation - /// from primary if no ARGB key color is provided for tertiary palette. + /// Create a Material-3 tonal palette tones extraction, but with no hue + /// rotation from primary if no ARGB key color is provided for tertiary + /// palette. /// /// This setup will if only one seed color is used, produce a slightly more /// chromatic color set than [FlexTones.material], since it does not rotate @@ -595,9 +752,6 @@ class FlexTones with Diagnosticable { /// It has white surface and background (tone 100) in light mode and /// low chroma on neutrals (2 and 4). Dark mode uses dark /// surface and background tone 6. - /// - /// The [FlexPaletteType.extended] is used as palette type for more - /// fidelity in high tones and for more tones options. factory FlexTones.candyPop(Brightness brightness) => brightness == Brightness.light ? const FlexTones.light( @@ -628,7 +782,6 @@ class FlexTones with Diagnosticable { tertiaryMinChroma: 50, neutralChroma: 2, neutralVariantChroma: 4, - paletteType: FlexPaletteType.extended, ) : const FlexTones.dark( primaryTone: 80, @@ -661,16 +814,16 @@ class FlexTones with Diagnosticable { tertiaryMinChroma: 50, neutralChroma: 2, neutralVariantChroma: 4, - paletteType: FlexPaletteType.extended, ); - /// Creates a tonal palette setup that results in a high contrast colorful - /// theme with background and surface tone 98, in light mode and very low + /// Creates a tonal palette setup that result in a color scheme that follows + /// chroma of each used seed color. Useful for manual control of pop or low + /// chromacity. + /// + /// Uses low surface tint and neutrals with medium chroma. + /// Theme with background and surface tone 98, in light mode and very low /// chroma in neutrals light mode (2 and 4) and moderate in dark mode /// (3 and 6). Dark mode uses dark surface and background tone 6. - /// - /// The [FlexPaletteType.extended] is used as palette type for more - /// fidelity in high tones and for more tones options. factory FlexTones.chroma(Brightness brightness) => brightness == Brightness.light ? const FlexTones.light( @@ -684,10 +837,10 @@ class FlexTones with Diagnosticable { tertiaryContainerTone: 95, onTertiaryContainerTone: 6, // - backgroundTone: 98, - onBackgroundTone: 6, - surfaceTone: 98, - onSurfaceTone: 6, + backgroundTone: 99, + onBackgroundTone: 4, + surfaceTone: 99, + onSurfaceTone: 4, surfaceVariantTone: 92, onSurfaceVariantTone: 10, onInverseSurfaceTone: 98, @@ -701,7 +854,6 @@ class FlexTones with Diagnosticable { tertiaryMinChroma: 0, neutralChroma: 2, neutralVariantChroma: 4, - paletteType: FlexPaletteType.extended, ) : const FlexTones.dark( primaryTone: 80, @@ -718,9 +870,11 @@ class FlexTones with Diagnosticable { onErrorTone: 6, onErrorContainerTone: 95, // - backgroundTone: 6, + backgroundTone: 4, onBackgroundTone: 95, - surfaceTone: 6, + surfaceTone: 4, + surfaceContainerLowestTone: 2, + surfaceContainerLowTone: 6, onSurfaceTone: 95, surfaceVariantTone: 20, onSurfaceVariantTone: 90, @@ -734,7 +888,6 @@ class FlexTones with Diagnosticable { tertiaryMinChroma: 0, neutralChroma: 3, neutralVariantChroma: 6, - paletteType: FlexPaletteType.extended, ); /// Returns a new [FlexTones] instance where on colors tones for all main on @@ -742,9 +895,12 @@ class FlexTones with Diagnosticable { /// what is appropriate contrast for its color pair. /// /// This will make the seeded on colors for [onPrimary], [onPrimaryContainer], - /// [onSecondary], [onSecondaryContainer], [onTertiary], - /// [onTertiaryContainer], [onError] and [onErrorContainer] pure black or - /// white, depending on need contrast, instead of tinted black and white. + /// [onPrimaryFixed], [onPrimaryFixedVariant], [onSecondary], + /// [onSecondaryContainer], [onSecondaryFixed], [onSecondaryFixedVariant], + /// [onTertiary], [onTertiaryContainer], [onTertiaryFixed], + /// [onTertiaryFixedVariant] as well as [onError] and [onErrorContainer] pure + /// black or white, depending on need contrast, instead of the its chroma + /// tinted black and white versions. /// /// This is a modifier, using copyWith, that can be used to change any /// existing or pre-made [FlexTones] config to not have any color tint in @@ -760,10 +916,16 @@ class FlexTones with Diagnosticable { return copyWith( onPrimaryTone: primaryTone <= 60 ? 100 : 0, onPrimaryContainerTone: primaryContainerTone <= 60 ? 100 : 0, + onPrimaryFixedTone: primaryFixedTone <= 60 ? 100 : 0, + onPrimaryFixedVariantTone: primaryFixedDimTone <= 60 ? 100 : 0, onSecondaryTone: secondaryTone <= 60 ? 100 : 0, onSecondaryContainerTone: secondaryContainerTone <= 60 ? 100 : 0, + onSecondaryFixedTone: secondaryFixedTone <= 60 ? 100 : 0, + onSecondaryFixedVariantTone: secondaryFixedDimTone <= 60 ? 100 : 0, onTertiaryTone: tertiaryTone <= 60 ? 100 : 0, onTertiaryContainerTone: tertiaryContainerTone <= 60 ? 100 : 0, + onTertiaryFixedTone: tertiaryFixedTone <= 60 ? 100 : 0, + onTertiaryFixedVariantTone: tertiaryFixedDimTone <= 60 ? 100 : 0, onErrorTone: errorTone <= 60 ? 100 : 0, onErrorContainerTone: errorContainerTone <= 60 ? 100 : 0, ); @@ -833,6 +995,21 @@ class FlexTones with Diagnosticable { /// [FlexTonalPalette]. final int onPrimaryContainerTone; + /// Tone used for [ColorScheme.primaryFixed] from primary [FlexTonalPalette]. + final int primaryFixedTone; + + /// Tone used for [ColorScheme.primaryFixedDim] from primary + /// [FlexTonalPalette]. + final int primaryFixedDimTone; + + /// Tone used for [ColorScheme.onPrimaryFixed] from primary + /// [FlexTonalPalette]. + final int onPrimaryFixedTone; + + /// Tone used for [ColorScheme.onPrimaryFixedVariant] from primary + /// [FlexTonalPalette]. + final int onPrimaryFixedVariantTone; + /// Tone used for [ColorScheme.secondary] from secondary [FlexTonalPalette]. final int secondaryTone; @@ -847,6 +1024,22 @@ class FlexTones with Diagnosticable { /// [FlexTonalPalette]. final int onSecondaryContainerTone; + /// Tone used for [ColorScheme.secondaryFixed] from secondary + /// [FlexTonalPalette]. + final int secondaryFixedTone; + + /// Tone used for [ColorScheme.secondaryFixedDim] from secondary + /// [FlexTonalPalette]. + final int secondaryFixedDimTone; + + /// Tone used for [ColorScheme.secondaryFixed] from secondary + /// [FlexTonalPalette]. + final int onSecondaryFixedTone; + + /// Tone used for [ColorScheme.onSecondaryFixedVariant] from secondary + /// [FlexTonalPalette]. + final int onSecondaryFixedVariantTone; + /// Tone used for [ColorScheme.tertiary] from tertiary [FlexTonalPalette]. final int tertiaryTone; @@ -861,6 +1054,22 @@ class FlexTones with Diagnosticable { /// [FlexTonalPalette]. final int onTertiaryContainerTone; + /// Tone used for [ColorScheme.tertiaryFixed] from tertiary + /// [FlexTonalPalette]. + final int tertiaryFixedTone; + + /// Tone used for [ColorScheme.tertiaryFixedDim] from tertiary + /// [FlexTonalPalette]. + final int tertiaryFixedDimTone; + + /// Tone used for [ColorScheme.onTertiaryFixed] from tertiary + /// [FlexTonalPalette]. + final int onTertiaryFixedTone; + + /// Tone used for [ColorScheme.onTertiaryFixedVariant] from tertiary + /// [FlexTonalPalette]. + final int onTertiaryFixedVariantTone; + /// Tone used for [ColorScheme.error] from error [FlexTonalPalette]. final int errorTone; @@ -874,21 +1083,37 @@ class FlexTones with Diagnosticable { /// [FlexTonalPalette]. final int onErrorContainerTone; - /// Tone used for [ColorScheme.background] from neutral [FlexTonalPalette]. - final int backgroundTone; - - /// Tone used for [ColorScheme.onBackground] from neutral [FlexTonalPalette]. - final int onBackgroundTone; - /// Tone used for [ColorScheme.surface] from neutral [FlexTonalPalette]. final int surfaceTone; - /// Tone used for [ColorScheme.onSurface] from neutral [FlexTonalPalette]. - final int onSurfaceTone; + /// Tone used for [ColorScheme.surfaceDim] from neutral [FlexTonalPalette]. + final int surfaceDimTone; + + /// Tone used for [ColorScheme.surfaceBright] from neutral [FlexTonalPalette]. + final int surfaceBrightTone; - /// Tone used for [ColorScheme.surfaceVariant] from neutralVariant + /// Tone used for [ColorScheme.surfaceContainerLowest] from neutral /// [FlexTonalPalette]. - final int surfaceVariantTone; + final int surfaceContainerLowestTone; + + /// Tone used for [ColorScheme.surfaceContainerLow] from neutral + /// [FlexTonalPalette]. + final int surfaceContainerLowTone; + + /// Tone used for [ColorScheme.surfaceContainer] from neutral + /// [FlexTonalPalette]. + final int surfaceContainerTone; + + /// Tone used for [ColorScheme.surfaceContainerHigh] from neutral + /// [FlexTonalPalette]. + final int surfaceContainerHighTone; + + /// Tone used for [ColorScheme.surfaceContainerHighest] from neutral + /// [FlexTonalPalette]. + final int surfaceContainerHighestTone; + + /// Tone used for [ColorScheme.onSurface] from neutral [FlexTonalPalette]. + final int onSurfaceTone; /// Tone used for [ColorScheme.onSurfaceVariant] from neutralVariant /// [FlexTonalPalette]. @@ -923,6 +1148,21 @@ class FlexTones with Diagnosticable { /// Tone used for [ColorScheme.surfaceTint] from primary [FlexTonalPalette]. final int surfaceTintTone; + // Deprecated colors. + + /// Tone used for ColorScheme background from neutral [FlexTonalPalette]. + @Deprecated('Use surfaceTone instead.') + final int backgroundTone; + + /// Tone used for ColorScheme onBackground from neutral [FlexTonalPalette]. + @Deprecated('Use onSurfaceTone instead.') + final int onBackgroundTone; + + /// Tone used for ColorScheme surfaceVariant from neutralVariant + /// [FlexTonalPalette]. + @Deprecated('Use surfaceContainerHighestTone instead.') + final int surfaceVariantTone; + /// Cam16 chroma value to use for primary colors [FlexTonalPalette] /// generation. /// @@ -1099,48 +1339,85 @@ class FlexTones with Diagnosticable { /// Defines what [FlexPaletteType] this [FlexTones] uses. /// - /// The default is [FlexPaletteType.common] with 15 tones or optionally use - /// the extended [FlexPaletteType.extended] with 24 tones. + /// The default is [FlexPaletteType.extended] with 26 tones or optionally use + /// the legacy [FlexPaletteType.common] with 15 tones. /// /// To make color schemes with new Material3 mappings for light and dark /// surface colors, using the extended tone set is needed. /// - /// In Flutter 3.10 and earlier the new [ColorScheme] surface colors that - /// need the new tones are not yet available. + /// In Flutter 3.19 and earlier the [ColorScheme] surface colors that + /// need the new tones are not yet available. In Flutter 3.22 and later the + /// new surface colors are available and the new tones are used. Due to this + /// the [FlexPaletteType.extended] is now the new default. The + /// [FlexPaletteType.common] may even be considered deprecated in the future, + /// but is kept around for backwards code compatibility for a while. /// - /// The added tones 4, 6, 12, 17, 22 are for new dark mode surfaces in + /// The added tones 4, 6, 12, 17, 22, 24 are for new dark mode surfaces in /// revised Material 3 dark surface colors. Likewise added tones /// 96, 94, 92, 87 are for light mode surfaces in the updated Material 3 /// color system. For more information, see: /// https://m3.material.io/styles/color/the-color-system/color-roles /// The additional tones in the Material 3 specification appeared during later - /// pert of first half of 2023. + /// part of first half of 2023, and in Flutter 3.22. final FlexPaletteType paletteType; + /// If true, the CAM16 color space is used to define the HCT color, if + /// false simpler and faster HCT from int is used. + /// + /// Prior to version 2.0.0 of this package, the CAM16 color space was always + /// used. However, in Flutter 3.22 the HCT vanilla HCT.fromInt is used + /// for its seeded scheme colors.It is used here by the Material3 + /// style seeded color schemes as well, while the FSS ones continues to use + /// Cam16. + /// + /// Defaults to true. + final bool useCam16; + /// Copy the object with one or more provided properties changed. FlexTones copyWith({ int? primaryTone, int? onPrimaryTone, int? primaryContainerTone, int? onPrimaryContainerTone, + int? primaryFixedTone, + int? primaryFixedDimTone, + int? onPrimaryFixedTone, + int? onPrimaryFixedVariantTone, + // int? secondaryTone, int? onSecondaryTone, int? secondaryContainerTone, int? onSecondaryContainerTone, + int? secondaryFixedTone, + int? secondaryFixedDimTone, + int? onSecondaryFixedTone, + int? onSecondaryFixedVariantTone, + // int? tertiaryTone, int? onTertiaryTone, int? tertiaryContainerTone, int? onTertiaryContainerTone, + int? tertiaryFixedTone, + int? tertiaryFixedDimTone, + int? onTertiaryFixedTone, + int? onTertiaryFixedVariantTone, + // int? errorTone, int? onErrorTone, int? errorContainerTone, int? onErrorContainerTone, - int? backgroundTone, - int? onBackgroundTone, + // int? surfaceTone, + int? surfaceDimTone, + int? surfaceBrightTone, + int? surfaceContainerLowestTone, + int? surfaceContainerLowTone, + int? surfaceContainerTone, + int? surfaceContainerHighTone, + int? surfaceContainerHighestTone, int? onSurfaceTone, - int? surfaceVariantTone, int? onSurfaceVariantTone, + // int? outlineTone, int? outlineVariantTone, int? shadowTone, @@ -1149,6 +1426,11 @@ class FlexTones with Diagnosticable { int? onInverseSurfaceTone, int? inversePrimaryTone, int? surfaceTintTone, + // Deprecated color tones. + int? backgroundTone, + int? onBackgroundTone, + int? surfaceVariantTone, + // double? primaryChroma, double? primaryMinChroma, double? secondaryChroma, @@ -1170,28 +1452,57 @@ class FlexTones with Diagnosticable { primaryContainerTone: primaryContainerTone ?? this.primaryContainerTone, onPrimaryContainerTone: onPrimaryContainerTone ?? this.onPrimaryContainerTone, + primaryFixedTone: primaryFixedTone ?? this.primaryFixedTone, + primaryFixedDimTone: primaryFixedDimTone ?? this.primaryFixedDimTone, + onPrimaryFixedTone: onPrimaryFixedTone ?? this.onPrimaryFixedTone, + onPrimaryFixedVariantTone: + onPrimaryFixedVariantTone ?? this.onPrimaryFixedVariantTone, + // secondaryTone: secondaryTone ?? this.secondaryTone, onSecondaryTone: onSecondaryTone ?? this.onSecondaryTone, secondaryContainerTone: secondaryContainerTone ?? this.secondaryContainerTone, onSecondaryContainerTone: onSecondaryContainerTone ?? this.onSecondaryContainerTone, + secondaryFixedTone: secondaryFixedTone ?? this.secondaryFixedTone, + secondaryFixedDimTone: + secondaryFixedDimTone ?? this.secondaryFixedDimTone, + onSecondaryFixedTone: onSecondaryFixedTone ?? this.onSecondaryFixedTone, + onSecondaryFixedVariantTone: + onSecondaryFixedVariantTone ?? this.onSecondaryFixedVariantTone, + // tertiaryTone: tertiaryTone ?? this.tertiaryTone, onTertiaryTone: onTertiaryTone ?? this.onTertiaryTone, tertiaryContainerTone: tertiaryContainerTone ?? this.tertiaryContainerTone, onTertiaryContainerTone: onTertiaryContainerTone ?? this.onTertiaryContainerTone, + tertiaryFixedTone: tertiaryFixedTone ?? this.tertiaryFixedTone, + tertiaryFixedDimTone: tertiaryFixedDimTone ?? this.tertiaryFixedDimTone, + onTertiaryFixedTone: onTertiaryFixedTone ?? this.onTertiaryFixedTone, + onTertiaryFixedVariantTone: + onTertiaryFixedVariantTone ?? this.onTertiaryFixedVariantTone, + // errorTone: errorTone ?? this.errorTone, onErrorTone: onErrorTone ?? this.onErrorTone, errorContainerTone: errorContainerTone ?? this.errorContainerTone, onErrorContainerTone: onErrorContainerTone ?? this.onErrorContainerTone, - backgroundTone: backgroundTone ?? this.backgroundTone, - onBackgroundTone: onBackgroundTone ?? this.onBackgroundTone, + // surfaceTone: surfaceTone ?? this.surfaceTone, + surfaceDimTone: surfaceDimTone ?? this.surfaceDimTone, + surfaceBrightTone: surfaceBrightTone ?? this.surfaceBrightTone, + surfaceContainerLowestTone: + surfaceContainerLowestTone ?? this.surfaceContainerLowestTone, + surfaceContainerLowTone: + surfaceContainerLowTone ?? this.surfaceContainerLowTone, + surfaceContainerTone: surfaceContainerTone ?? this.surfaceContainerTone, + surfaceContainerHighTone: + surfaceContainerHighTone ?? this.surfaceContainerHighTone, + surfaceContainerHighestTone: + surfaceContainerHighestTone ?? this.surfaceContainerHighestTone, onSurfaceTone: onSurfaceTone ?? this.onSurfaceTone, - surfaceVariantTone: surfaceVariantTone ?? this.surfaceVariantTone, onSurfaceVariantTone: onSurfaceVariantTone ?? this.onSurfaceVariantTone, + // outlineTone: outlineTone ?? this.outlineTone, outlineVariantTone: outlineVariantTone ?? this.outlineVariantTone, shadowTone: shadowTone ?? this.shadowTone, @@ -1200,6 +1511,11 @@ class FlexTones with Diagnosticable { onInverseSurfaceTone: onInverseSurfaceTone ?? this.onInverseSurfaceTone, inversePrimaryTone: inversePrimaryTone ?? this.inversePrimaryTone, surfaceTintTone: surfaceTintTone ?? this.surfaceTintTone, + // Deprecated color tones. + backgroundTone: backgroundTone ?? this.backgroundTone, + onBackgroundTone: onBackgroundTone ?? this.onBackgroundTone, + surfaceVariantTone: surfaceVariantTone ?? this.surfaceVariantTone, + // primaryChroma: primaryChroma ?? this.primaryChroma, primaryMinChroma: primaryMinChroma ?? this.primaryMinChroma, secondaryChroma: secondaryChroma ?? this.secondaryChroma, @@ -1228,24 +1544,45 @@ class FlexTones with Diagnosticable { other.onPrimaryTone == onPrimaryTone && other.primaryContainerTone == primaryContainerTone && other.onPrimaryContainerTone == onPrimaryContainerTone && + other.primaryFixedTone == primaryFixedTone && + other.primaryFixedDimTone == primaryFixedDimTone && + other.onPrimaryFixedTone == onPrimaryFixedTone && + other.onPrimaryFixedVariantTone == onPrimaryFixedVariantTone && + // other.secondaryTone == secondaryTone && other.onSecondaryTone == onSecondaryTone && other.secondaryContainerTone == secondaryContainerTone && other.onSecondaryContainerTone == onSecondaryContainerTone && + other.secondaryFixedTone == secondaryFixedTone && + other.secondaryFixedDimTone == secondaryFixedDimTone && + other.onSecondaryFixedTone == onSecondaryFixedTone && + other.onSecondaryFixedVariantTone == onSecondaryFixedVariantTone && + // other.tertiaryTone == tertiaryTone && other.onTertiaryTone == onTertiaryTone && other.tertiaryContainerTone == tertiaryContainerTone && other.onTertiaryContainerTone == onTertiaryContainerTone && + other.tertiaryFixedTone == tertiaryFixedTone && + other.tertiaryFixedDimTone == tertiaryFixedDimTone && + other.onTertiaryFixedTone == onTertiaryFixedTone && + other.onTertiaryFixedVariantTone == onTertiaryFixedVariantTone && + // other.errorTone == errorTone && other.onErrorTone == onErrorTone && other.errorContainerTone == errorContainerTone && other.onErrorContainerTone == onErrorContainerTone && - other.backgroundTone == backgroundTone && - other.onBackgroundTone == onBackgroundTone && + // other.surfaceTone == surfaceTone && + other.surfaceDimTone == surfaceDimTone && + other.surfaceBrightTone == surfaceBrightTone && + other.surfaceContainerLowestTone == surfaceContainerLowestTone && + other.surfaceContainerLowTone == surfaceContainerLowTone && + other.surfaceContainerTone == surfaceContainerTone && + other.surfaceContainerHighTone == surfaceContainerHighTone && + other.surfaceContainerHighestTone == surfaceContainerHighestTone && other.onSurfaceTone == onSurfaceTone && - other.surfaceVariantTone == surfaceVariantTone && other.onSurfaceVariantTone == onSurfaceVariantTone && + // other.outlineTone == outlineTone && other.outlineVariantTone == outlineVariantTone && other.shadowTone == shadowTone && @@ -1254,6 +1591,11 @@ class FlexTones with Diagnosticable { other.onInverseSurfaceTone == onInverseSurfaceTone && other.inversePrimaryTone == inversePrimaryTone && other.surfaceTintTone == surfaceTintTone && + // Deprecated color tones. + other.backgroundTone == backgroundTone && + other.onBackgroundTone == onBackgroundTone && + other.surfaceVariantTone == surfaceVariantTone && + // other.primaryChroma == primaryChroma && other.primaryMinChroma == primaryMinChroma && other.secondaryChroma == secondaryChroma && @@ -1277,24 +1619,45 @@ class FlexTones with Diagnosticable { onPrimaryTone, primaryContainerTone, onPrimaryContainerTone, + primaryFixedTone, + primaryFixedDimTone, + onPrimaryFixedTone, + onPrimaryFixedVariantTone, + // secondaryTone, onSecondaryTone, secondaryContainerTone, onSecondaryContainerTone, + secondaryFixedTone, + secondaryFixedDimTone, + onSecondaryFixedTone, + onSecondaryFixedVariantTone, + // tertiaryTone, onTertiaryTone, tertiaryContainerTone, onTertiaryContainerTone, + tertiaryFixedTone, + tertiaryFixedDimTone, + onTertiaryFixedTone, + onTertiaryFixedVariantTone, + // errorTone, onErrorTone, errorContainerTone, onErrorContainerTone, - backgroundTone, - onBackgroundTone, + // surfaceTone, + surfaceDimTone, + surfaceBrightTone, + surfaceContainerLowestTone, + surfaceContainerLowTone, + surfaceContainerTone, + surfaceContainerHighTone, + surfaceContainerHighestTone, onSurfaceTone, - surfaceVariantTone, onSurfaceVariantTone, + // outlineTone, outlineVariantTone, shadowTone, @@ -1303,6 +1666,11 @@ class FlexTones with Diagnosticable { onInverseSurfaceTone, inversePrimaryTone, surfaceTintTone, + // Deprecated color tones. + backgroundTone, + onBackgroundTone, + surfaceVariantTone, + // primaryChroma, primaryMinChroma, secondaryChroma, @@ -1329,6 +1697,15 @@ class FlexTones with Diagnosticable { DiagnosticsProperty('primaryContainerTone', primaryContainerTone)); properties.add(DiagnosticsProperty( 'onPrimaryContainerTone', onPrimaryContainerTone)); + properties + .add(DiagnosticsProperty('primaryFixedTone', primaryFixedTone)); + properties.add( + DiagnosticsProperty('primaryFixedDimTone', primaryFixedDimTone)); + properties.add( + DiagnosticsProperty('onPrimaryFixedTone', onPrimaryFixedTone)); + properties.add(DiagnosticsProperty( + 'onPrimaryFixedVariantTone', onPrimaryFixedVariantTone)); + // properties.add(DiagnosticsProperty('secondaryTone', secondaryTone)); properties .add(DiagnosticsProperty('onSecondaryTone', onSecondaryTone)); @@ -1336,26 +1713,55 @@ class FlexTones with Diagnosticable { 'secondaryContainerTone', secondaryContainerTone)); properties.add(DiagnosticsProperty( 'onSecondaryContainerTone', onSecondaryContainerTone)); + properties.add( + DiagnosticsProperty('secondaryFixedTone', secondaryFixedTone)); + properties.add(DiagnosticsProperty( + 'secondaryFixedDimTone', secondaryFixedDimTone)); + properties.add( + DiagnosticsProperty('onSecondaryFixedTone', onSecondaryFixedTone)); + properties.add(DiagnosticsProperty( + 'onSecondaryFixedVariantTone', onSecondaryFixedVariantTone)); + // properties.add(DiagnosticsProperty('tertiaryTone', tertiaryTone)); properties.add(DiagnosticsProperty('onTertiaryTone', onTertiaryTone)); properties.add(DiagnosticsProperty( 'tertiaryContainerTone', tertiaryContainerTone)); properties.add(DiagnosticsProperty( 'onTertiaryContainerTone', onTertiaryContainerTone)); + properties + .add(DiagnosticsProperty('tertiaryFixedTone', tertiaryFixedTone)); + properties.add( + DiagnosticsProperty('tertiaryFixedDimTone', tertiaryFixedDimTone)); + properties.add( + DiagnosticsProperty('onTertiaryFixedTone', onTertiaryFixedTone)); + properties.add(DiagnosticsProperty( + 'onTertiaryFixedVariantTone', onTertiaryFixedVariantTone)); + // properties.add(DiagnosticsProperty('errorTone', errorTone)); properties.add( DiagnosticsProperty('errorContainerTone', errorContainerTone)); properties.add( DiagnosticsProperty('onErrorContainerTone', onErrorContainerTone)); - properties.add(DiagnosticsProperty('backgroundTone', backgroundTone)); - properties - .add(DiagnosticsProperty('onBackgroundTone', onBackgroundTone)); + // properties.add(DiagnosticsProperty('surfaceTone', surfaceTone)); - properties.add(DiagnosticsProperty('onSurfaceTone', onSurfaceTone)); + properties.add(DiagnosticsProperty('surfaceDimTone', surfaceDimTone)); + properties + .add(DiagnosticsProperty('surfaceBrightTone', surfaceBrightTone)); + properties.add(DiagnosticsProperty( + 'surfaceContainerLowestTone', surfaceContainerLowestTone)); + properties.add(DiagnosticsProperty( + 'surfaceContainerLowTone', surfaceContainerLowTone)); properties.add( - DiagnosticsProperty('surfaceVariantTone', surfaceVariantTone)); + DiagnosticsProperty('surfaceContainerTone', surfaceContainerTone)); + properties.add(DiagnosticsProperty( + 'surfaceContainerHighTone', surfaceContainerHighTone)); + properties.add(DiagnosticsProperty( + 'surfaceContainerHighestTone', surfaceContainerHighestTone)); + + properties.add(DiagnosticsProperty('onSurfaceTone', onSurfaceTone)); properties.add( DiagnosticsProperty('onSurfaceVariantTone', onSurfaceVariantTone)); + // properties.add(DiagnosticsProperty('outlineTone', outlineTone)); properties.add( DiagnosticsProperty('outlineVariantTone', outlineVariantTone)); @@ -1369,6 +1775,13 @@ class FlexTones with Diagnosticable { DiagnosticsProperty('inversePrimaryTone', inversePrimaryTone)); properties .add(DiagnosticsProperty('surfaceTintTone', surfaceTintTone)); + // Deprecated color tones. + properties.add(DiagnosticsProperty('backgroundTone', backgroundTone)); + properties + .add(DiagnosticsProperty('onBackgroundTone', onBackgroundTone)); + properties.add( + DiagnosticsProperty('surfaceVariantTone', surfaceVariantTone)); + // properties.add(DiagnosticsProperty('primaryChroma', primaryChroma)); properties .add(DiagnosticsProperty('primaryMinChroma', primaryMinChroma)); diff --git a/lib/src/mcu/blend/blend.dart b/lib/src/mcu/blend/blend.dart index 0f6d54e..62db0ed 100644 --- a/lib/src/mcu/blend/blend.dart +++ b/lib/src/mcu/blend/blend.dart @@ -16,7 +16,10 @@ import 'dart:math'; -import '../material_color_utilities.dart'; +import '../hct/cam16.dart'; +import '../hct/hct.dart'; +import '../utils/color_utils.dart'; +import '../utils/math_utils.dart'; /// Functions for blending in HCT and CAM16. class Blend { diff --git a/lib/src/mcu/contrast/contrast.dart b/lib/src/mcu/contrast/contrast.dart index 3b7be88..c5c9063 100644 --- a/lib/src/mcu/contrast/contrast.dart +++ b/lib/src/mcu/contrast/contrast.dart @@ -29,12 +29,10 @@ class Contrast { /// [toneA] Tone between 0 and 100. Values outside will be clamped. /// [toneB] Tone between 0 and 100. Values outside will be clamped. static double ratioOfTones(double toneA, double toneB) { - // ignore: parameter_assignments - toneA = MathUtils.clampDouble(0.0, 100.0, toneA); - // ignore: parameter_assignments - toneB = MathUtils.clampDouble(0.0, 100.0, toneB); + final double localToneA = MathUtils.clampDouble(0.0, 100.0, toneA); + final double localToneB = MathUtils.clampDouble(0.0, 100.0, toneB); return _ratioOfYs( - ColorUtils.yFromLstar(toneA), ColorUtils.yFromLstar(toneB)); + ColorUtils.yFromLstar(localToneA), ColorUtils.yFromLstar(localToneB)); } static double _ratioOfYs(double y1, double y2) { diff --git a/lib/src/mcu/dynamiccolor/dynamic_color.dart b/lib/src/mcu/dynamiccolor/dynamic_color.dart index a047a1f..f0fb5db 100644 --- a/lib/src/mcu/dynamiccolor/dynamic_color.dart +++ b/lib/src/mcu/dynamiccolor/dynamic_color.dart @@ -14,7 +14,11 @@ import 'dart:math' as math; -import '../material_color_utilities.dart'; +import '../contrast/contrast.dart'; +import '../dynamiccolor/dynamic_scheme.dart'; +import '../hct/hct.dart'; +import '../palettes/tonal_palette.dart'; +import '../utils/math_utils.dart'; import 'src/contrast_curve.dart'; import 'src/tone_delta_pair.dart'; @@ -38,72 +42,72 @@ import 'src/tone_delta_pair.dart'; /// desired behavior of a color for any design system, but it usually /// unnecessary. See the default constructor for more information. class DynamicColor { - /// The base (explicit) constructor for [DynamicColor]. - /// /// [name] The name of the dynamic color. + final String name; + /// [palette] Function that provides a TonalPalette given /// DynamicScheme. A TonalPalette is defined by a hue and chroma, so this /// replaces the need to specify hue/chroma. By providing a tonal palette, /// when contrast adjustments are made, intended chroma can be preserved. + final TonalPalette Function(DynamicScheme) palette; + /// [tone] Function that provides a tone, given a DynamicScheme. + final double Function(DynamicScheme) tone; + /// [isBackground] Whether this dynamic color is a background, with /// some other color as the foreground. + final bool isBackground; + /// [background] The background of the dynamic color (as a function of a /// `DynamicScheme`), if it exists. + final DynamicColor Function(DynamicScheme)? background; + /// [secondBackground] A second background of the dynamic color (as a function /// of a `DynamicScheme`), if it /// exists. + final DynamicColor Function(DynamicScheme)? secondBackground; + /// [contrastCurve] A [ContrastCurve] object specifying how its contrast /// against its background should behave in various contrast levels options. + final ContrastCurve? contrastCurve; + /// [toneDeltaPair] A [ToneDeltaPair] object specifying a tone delta /// constraint between two colors. One of them must be the color being /// constructed. - DynamicColor({ - required this.name, - required this.palette, - required this.tone, - required this.isBackground, - required this.background, - required this.secondBackground, - required this.contrastCurve, - required this.toneDeltaPair, - }); + final ToneDeltaPair Function(DynamicScheme)? toneDeltaPair; - /// [name] The name of the dynamic color. - final String name; + final Map _hctCache = {}; + /// The base (explicit) constructor for [DynamicColor]. + /// + /// [name] The name of the dynamic color. /// [palette] Function that provides a TonalPalette given /// DynamicScheme. A TonalPalette is defined by a hue and chroma, so this /// replaces the need to specify hue/chroma. By providing a tonal palette, /// when contrast adjustments are made, intended chroma can be preserved. - final TonalPalette Function(DynamicScheme) palette; - /// [tone] Function that provides a tone, given a DynamicScheme. - final double Function(DynamicScheme) tone; - /// [isBackground] Whether this dynamic color is a background, with /// some other color as the foreground. - final bool isBackground; - /// [background] The background of the dynamic color (as a function of a /// `DynamicScheme`), if it exists. - final DynamicColor Function(DynamicScheme)? background; - /// [secondBackground] A second background of the dynamic color (as a function /// of a `DynamicScheme`), if it /// exists. - final DynamicColor Function(DynamicScheme)? secondBackground; - /// [contrastCurve] A [ContrastCurve] object specifying how its contrast /// against its background should behave in various contrast levels options. - final ContrastCurve? contrastCurve; - /// [toneDeltaPair] A [ToneDeltaPair] object specifying a tone delta /// constraint between two colors. One of them must be the color being /// constructed. - final ToneDeltaPair Function(DynamicScheme)? toneDeltaPair; - - final Map _hctCache = {}; + DynamicColor({ + required this.name, + required this.palette, + required this.tone, + required this.isBackground, + required this.background, + required this.secondBackground, + required this.contrastCurve, + required this.toneDeltaPair, + }); /// The convenience constructor for [DynamicColor]. /// @@ -208,10 +212,8 @@ class DynamicColor { final int expansionDir = scheme.isDark ? 1 : -1; // 1st round: solve to min, each - final double nContrast = - nearer.contrastCurve!.getContrast(scheme.contrastLevel); - final double fContrast = - farther.contrastCurve!.getContrast(scheme.contrastLevel); + final double nContrast = nearer.contrastCurve!.get(scheme.contrastLevel); + final double fContrast = farther.contrastCurve!.get(scheme.contrastLevel); // If a color is good enough, it is not adjusted. // Initial and adjusted tones for `nearer` @@ -292,8 +294,7 @@ class DynamicColor { final double bgTone = background!(scheme).getTone(scheme); - final double desiredRatio = - contrastCurve!.getContrast(scheme.contrastLevel); + final double desiredRatio = contrastCurve!.get(scheme.contrastLevel); if (Contrast.ratioOfTones(bgTone, answer) >= desiredRatio) { // Don't "improve" what's good enough. @@ -391,7 +392,7 @@ class DynamicColor { final bool negligibleDifference = (lighterRatio - darkerRatio).abs() < 0.1 && lighterRatio < ratio && - darkerRatio < ratio; + darkerRatio < ratio; // coverage:ignore-line return lighterRatio >= ratio || lighterRatio >= darkerRatio || negligibleDifference diff --git a/lib/src/mcu/dynamiccolor/dynamic_scheme.dart b/lib/src/mcu/dynamiccolor/dynamic_scheme.dart new file mode 100644 index 0000000..b523193 --- /dev/null +++ b/lib/src/mcu/dynamiccolor/dynamic_scheme.dart @@ -0,0 +1,288 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import '../hct/hct.dart'; +import '../palettes/tonal_palette.dart'; +import '../utils/math_utils.dart'; +import 'dynamic_color.dart'; +import 'material_dynamic_colors.dart'; +import 'variant.dart'; + +/// Constructed by a set of values representing the current UI state (such as +/// whether or not its dark theme, what the theme style is, etc.), and +/// provides a set of [TonalPalette]s that can create colors that fit in +/// with the theme style. Used by [DynamicColor] to resolve into a color. +class DynamicScheme { + /// The source color of the theme as an ARGB integer. + final int sourceColorArgb; + + /// The source color of the theme in HCT. + final Hct sourceColorHct; + + /// The variant, or style, of the theme. + final Variant variant; + + /// Whether or not the scheme is in 'dark mode' or 'light mode'. + final bool isDark; + + /// Value from -1 to 1. -1 represents minimum contrast, 0 represents + /// standard (i.e. the design as spec'd), and 1 represents maximum contrast. + final double contrastLevel; + + /// Given a tone, produces a color. Hue and chroma of the color are specified + /// in the design specification of the variant. Usually colorful. + final TonalPalette primaryPalette; + + /// Given a tone, produces a color. Hue and chroma of the color are specified + /// in the design specification of the variant. Usually less colorful. + final TonalPalette secondaryPalette; + + /// Given a tone, produces a color. Hue and chroma of the color are specified + /// in the design specification of the variant. Usually a different hue from + /// primary and colorful. + final TonalPalette tertiaryPalette; + + /// Given a tone, produces a color. Hue and chroma of the color are specified + /// in the design specification of the variant. Usually not colorful at all, + /// intended for background & surface colors. + final TonalPalette neutralPalette; + + /// Given a tone, produces a color. Hue and chroma of the color are specified + /// in the design specification of the variant. Usually not colorful, but + /// slightly more colorful than Neutral. Intended for backgrounds & surfaces. + final TonalPalette neutralVariantPalette; + + /// Given a tone, produces a reddish, colorful, color. + final TonalPalette errorPalette; + + /// Primary constructor for [DynamicScheme]. + DynamicScheme({ + required this.sourceColorArgb, + required this.variant, + this.contrastLevel = 0.0, + required this.isDark, + required this.primaryPalette, + required this.secondaryPalette, + required this.tertiaryPalette, + required this.neutralPalette, + required this.neutralVariantPalette, + }) : sourceColorHct = Hct.fromInt(sourceColorArgb), + errorPalette = TonalPalette.of(25.0, 84.0); + + /// Get the the rotated hue of the source color. + static double getRotatedHue( + Hct sourceColor, List hues, List rotations) { + final double sourceHue = sourceColor.hue; + assert(hues.length == rotations.length, + 'Hues and rotations length must match'); + if (rotations.length == 1) { + return MathUtils.sanitizeDegreesDouble(sourceColor.hue + rotations[0]); + } + final int size = hues.length; + for (int i = 0; i <= (size - 2); i++) { + final double thisHue = hues[i]; + final double nextHue = hues[i + 1]; + if (thisHue < sourceHue && sourceHue < nextHue) { + return MathUtils.sanitizeDegreesDouble(sourceHue + rotations[i]); + } + } + // If this statement executes, something is wrong, there should have been a + // rotation found using the arrays. + return sourceHue; + } + + /// Get the HCT color of the DynamicColor. + Hct getHct(DynamicColor dynamicColor) => dynamicColor.getHct(this); + + /// Get the int ARGB color of the DynamicColor. + int getArgb(DynamicColor dynamicColor) => dynamicColor.getArgb(this); + + // Getters. + /// The primaryPaletteKeyColor color of the theme. + int get primaryPaletteKeyColor => + getArgb(MaterialDynamicColors.primaryPaletteKeyColor); + + /// The secondaryPaletteKeyColor color of the theme. + int get secondaryPaletteKeyColor => + getArgb(MaterialDynamicColors.secondaryPaletteKeyColor); + + /// The tertiaryPaletteKeyColor color of the theme. + int get tertiaryPaletteKeyColor => + getArgb(MaterialDynamicColors.tertiaryPaletteKeyColor); + + /// The neutralPaletteKeyColor color of the theme. + int get neutralPaletteKeyColor => + getArgb(MaterialDynamicColors.neutralPaletteKeyColor); + + /// The neutralVariantPaletteKeyColor variant color of the theme. + int get neutralVariantPaletteKeyColor => + getArgb(MaterialDynamicColors.neutralVariantPaletteKeyColor); + + /// The background color of the theme. + int get background => getArgb(MaterialDynamicColors.background); + + /// The onBackground color of the theme. + int get onBackground => getArgb(MaterialDynamicColors.onBackground); + + /// The surface color of the theme. + int get surface => getArgb(MaterialDynamicColors.surface); + + /// The surfaceDim color of the theme. + int get surfaceDim => getArgb(MaterialDynamicColors.surfaceDim); + + /// The surfaceBright color of the theme. + int get surfaceBright => getArgb(MaterialDynamicColors.surfaceBright); + + /// The surfaceContainerLowest color of the theme. + int get surfaceContainerLowest => + getArgb(MaterialDynamicColors.surfaceContainerLowest); + + /// The surfaceContainerLow color of the theme. + int get surfaceContainerLow => + getArgb(MaterialDynamicColors.surfaceContainerLow); + + /// The surfaceContainer color of the theme. + int get surfaceContainer => getArgb(MaterialDynamicColors.surfaceContainer); + + /// The surfaceContainerHigh color of the theme. + int get surfaceContainerHigh => + getArgb(MaterialDynamicColors.surfaceContainerHigh); + + /// The surfaceContainerHighest color of the theme. + int get surfaceContainerHighest => + getArgb(MaterialDynamicColors.surfaceContainerHighest); + + /// The onSurface color of the theme. + int get onSurface => getArgb(MaterialDynamicColors.onSurface); + + /// The surfaceVariant color of the theme. + int get surfaceVariant => getArgb(MaterialDynamicColors.surfaceVariant); + + /// The onSurfaceVariant color of the theme. + int get onSurfaceVariant => getArgb(MaterialDynamicColors.onSurfaceVariant); + + /// The inverseSurface color of the theme. + int get inverseSurface => getArgb(MaterialDynamicColors.inverseSurface); + + /// The inverseOnSurface color of the theme. + int get inverseOnSurface => getArgb(MaterialDynamicColors.inverseOnSurface); + + /// The inverseSurfaceVariant color of the theme. + int get outline => getArgb(MaterialDynamicColors.outline); + + /// The outlineVariant color of the theme. + int get outlineVariant => getArgb(MaterialDynamicColors.outlineVariant); + + /// The shadow color of the theme. + int get shadow => getArgb(MaterialDynamicColors.shadow); + + /// The scrim color of the theme. + int get scrim => getArgb(MaterialDynamicColors.scrim); + + /// The surfaceTint color of the theme. + int get surfaceTint => getArgb(MaterialDynamicColors.surfaceTint); + + /// The primary color of the theme. + int get primary => getArgb(MaterialDynamicColors.primary); + + /// The onPrimary color of the theme. + int get onPrimary => getArgb(MaterialDynamicColors.onPrimary); + + /// The primaryContainer color of the theme. + int get primaryContainer => getArgb(MaterialDynamicColors.primaryContainer); + + /// The onPrimaryContainer color of the theme. + int get onPrimaryContainer => + getArgb(MaterialDynamicColors.onPrimaryContainer); + + /// The inversePrimary color of the theme. + int get inversePrimary => getArgb(MaterialDynamicColors.inversePrimary); + + /// The secondary color of the theme. + int get secondary => getArgb(MaterialDynamicColors.secondary); + + /// The onSecondary color of the theme. + int get onSecondary => getArgb(MaterialDynamicColors.onSecondary); + + /// The secondaryContainer color of the theme. + int get secondaryContainer => + getArgb(MaterialDynamicColors.secondaryContainer); + + /// The onSecondaryContainer color of the theme. + int get onSecondaryContainer => + getArgb(MaterialDynamicColors.onSecondaryContainer); + + /// The tertiary color of the theme. + int get tertiary => getArgb(MaterialDynamicColors.tertiary); + + /// The onTertiary color of the theme. + int get onTertiary => getArgb(MaterialDynamicColors.onTertiary); + + /// The tertiaryContainer color of the theme. + int get tertiaryContainer => getArgb(MaterialDynamicColors.tertiaryContainer); + + /// The onTertiaryContainer color of the theme. + int get onTertiaryContainer => + getArgb(MaterialDynamicColors.onTertiaryContainer); + + /// The error color of the theme. + int get error => getArgb(MaterialDynamicColors.error); + + /// The onError color of the theme. + int get onError => getArgb(MaterialDynamicColors.onError); + + /// The errorContainer color of the theme. + int get errorContainer => getArgb(MaterialDynamicColors.errorContainer); + + /// The onErrorContainer color of the theme. + int get onErrorContainer => getArgb(MaterialDynamicColors.onErrorContainer); + + /// The primaryFixed color of the theme. + int get primaryFixed => getArgb(MaterialDynamicColors.primaryFixed); + + /// The primaryFixedDim color of the theme. + int get primaryFixedDim => getArgb(MaterialDynamicColors.primaryFixedDim); + + /// The onPrimaryFixed color of the theme. + int get onPrimaryFixed => getArgb(MaterialDynamicColors.onPrimaryFixed); + + /// The onPrimaryFixedVariant color of the theme. + int get onPrimaryFixedVariant => + getArgb(MaterialDynamicColors.onPrimaryFixedVariant); + + /// The secondaryFixed color of the theme. + int get secondaryFixed => getArgb(MaterialDynamicColors.secondaryFixed); + + /// The secondaryFixedDim color of the theme. + int get secondaryFixedDim => getArgb(MaterialDynamicColors.secondaryFixedDim); + + /// The onSecondaryFixed color of the theme. + int get onSecondaryFixed => getArgb(MaterialDynamicColors.onSecondaryFixed); + + /// The onSecondaryFixedVariant color of the theme. + int get onSecondaryFixedVariant => + getArgb(MaterialDynamicColors.onSecondaryFixedVariant); + + /// The tertiaryFixed color of the theme. + int get tertiaryFixed => getArgb(MaterialDynamicColors.tertiaryFixed); + + /// The tertiaryFixedDim color of the theme. + int get tertiaryFixedDim => getArgb(MaterialDynamicColors.tertiaryFixedDim); + + /// The onTertiaryFixed color of the theme. + int get onTertiaryFixed => getArgb(MaterialDynamicColors.onTertiaryFixed); + + /// The onTertiaryFixedVariant color of the theme. + int get onTertiaryFixedVariant => + getArgb(MaterialDynamicColors.onTertiaryFixedVariant); +} diff --git a/lib/src/mcu/dynamiccolor/material_dynamic_colors.dart b/lib/src/mcu/dynamiccolor/material_dynamic_colors.dart index 21e35f3..da04d7b 100644 --- a/lib/src/mcu/dynamiccolor/material_dynamic_colors.dart +++ b/lib/src/mcu/dynamiccolor/material_dynamic_colors.dart @@ -14,7 +14,11 @@ import 'dart:math' as math; -import '../material_color_utilities.dart'; +import '../dislike/dislike_analyzer.dart'; +import '../dynamiccolor/dynamic_scheme.dart'; +import '../dynamiccolor/variant.dart'; +import '../hct/hct.dart'; +import 'dynamic_color.dart'; import 'src/contrast_curve.dart'; import 'src/tone_delta_pair.dart'; @@ -34,11 +38,6 @@ class MaterialDynamicColors { return s.isDark ? surfaceBright : surfaceDim; } - /// Make ViewingConditions for Albers. - static ViewingConditions viewingConditionsForAlbers(DynamicScheme scheme) { - return ViewingConditions.make(backgroundLstar: scheme.isDark ? 30 : 80); - } - /// Get DynamicColor for primaryPaletteKeyColor. static DynamicColor primaryPaletteKeyColor = DynamicColor.fromPalette( name: 'primary_palette_key_color', @@ -82,7 +81,7 @@ class MaterialDynamicColors { isBackground: true, ); - /// Get DynamicColor for onBackground. + /// Get DynamicColor for backgroundDim. static DynamicColor onBackground = DynamicColor.fromPalette( name: 'on_background', palette: (DynamicScheme s) => s.neutralPalette, @@ -103,7 +102,8 @@ class MaterialDynamicColors { static DynamicColor surfaceDim = DynamicColor.fromPalette( name: 'surface_dim', palette: (DynamicScheme s) => s.neutralPalette, - tone: (DynamicScheme s) => s.isDark ? 6 : 87, + tone: (DynamicScheme s) => + s.isDark ? 6 : ContrastCurve(87, 87, 80, 75).get(s.contrastLevel), isBackground: true, ); @@ -111,7 +111,8 @@ class MaterialDynamicColors { static DynamicColor surfaceBright = DynamicColor.fromPalette( name: 'surface_bright', palette: (DynamicScheme s) => s.neutralPalette, - tone: (DynamicScheme s) => s.isDark ? 24 : 98, + tone: (DynamicScheme s) => + s.isDark ? ContrastCurve(24, 24, 29, 34).get(s.contrastLevel) : 98, isBackground: true, ); @@ -119,7 +120,8 @@ class MaterialDynamicColors { static DynamicColor surfaceContainerLowest = DynamicColor.fromPalette( name: 'surface_container_lowest', palette: (DynamicScheme s) => s.neutralPalette, - tone: (DynamicScheme s) => s.isDark ? 4 : 100, + tone: (DynamicScheme s) => + s.isDark ? ContrastCurve(4, 4, 2, 0).get(s.contrastLevel) : 100, isBackground: true, ); @@ -127,7 +129,9 @@ class MaterialDynamicColors { static DynamicColor surfaceContainerLow = DynamicColor.fromPalette( name: 'surface_container_low', palette: (DynamicScheme s) => s.neutralPalette, - tone: (DynamicScheme s) => s.isDark ? 10 : 96, + tone: (DynamicScheme s) => s.isDark + ? ContrastCurve(10, 10, 11, 12).get(s.contrastLevel) + : ContrastCurve(96, 96, 96, 95).get(s.contrastLevel), isBackground: true, ); @@ -135,7 +139,9 @@ class MaterialDynamicColors { static DynamicColor surfaceContainer = DynamicColor.fromPalette( name: 'surface_container', palette: (DynamicScheme s) => s.neutralPalette, - tone: (DynamicScheme s) => s.isDark ? 12 : 94, + tone: (DynamicScheme s) => s.isDark + ? ContrastCurve(12, 12, 16, 20).get(s.contrastLevel) + : ContrastCurve(94, 94, 92, 90).get(s.contrastLevel), isBackground: true, ); @@ -143,7 +149,9 @@ class MaterialDynamicColors { static DynamicColor surfaceContainerHigh = DynamicColor.fromPalette( name: 'surface_container_high', palette: (DynamicScheme s) => s.neutralPalette, - tone: (DynamicScheme s) => s.isDark ? 17 : 92, + tone: (DynamicScheme s) => s.isDark + ? ContrastCurve(17, 17, 21, 25).get(s.contrastLevel) + : ContrastCurve(92, 92, 88, 85).get(s.contrastLevel), isBackground: true, ); @@ -151,7 +159,9 @@ class MaterialDynamicColors { static DynamicColor surfaceContainerHighest = DynamicColor.fromPalette( name: 'surface_container_highest', palette: (DynamicScheme s) => s.neutralPalette, - tone: (DynamicScheme s) => s.isDark ? 22 : 90, + tone: (DynamicScheme s) => s.isDark + ? ContrastCurve(22, 22, 26, 30).get(s.contrastLevel) + : ContrastCurve(90, 90, 84, 80).get(s.contrastLevel), isBackground: true, ); @@ -212,7 +222,7 @@ class MaterialDynamicColors { palette: (DynamicScheme s) => s.neutralVariantPalette, tone: (DynamicScheme s) => s.isDark ? 30 : 80, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(1, 1, 3, 7), + contrastCurve: ContrastCurve(1, 1, 3, 4.5), ); /// Get DynamicColor for shadow. @@ -249,11 +259,11 @@ class MaterialDynamicColors { }, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(3, 4.5, 7, 11), + contrastCurve: ContrastCurve(3, 4.5, 7, 7), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.primaryContainer, MaterialDynamicColors.primary, - 15, + 10, TonePolarity.nearer, false), ); @@ -278,7 +288,7 @@ class MaterialDynamicColors { palette: (DynamicScheme s) => s.primaryPalette, tone: (DynamicScheme s) { if (_isFidelity(s)) { - return _performAlbers(s.sourceColorHct, s); + return s.sourceColorHct.tone; } if (_isMonochrome(s)) { return s.isDark ? 85 : 25; @@ -287,11 +297,11 @@ class MaterialDynamicColors { }, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(1, 1, 3, 7), + contrastCurve: ContrastCurve(1, 1, 3, 4.5), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.primaryContainer, MaterialDynamicColors.primary, - 15, + 10, TonePolarity.nearer, false), ); @@ -320,21 +330,21 @@ class MaterialDynamicColors { palette: (DynamicScheme s) => s.primaryPalette, tone: (DynamicScheme s) => s.isDark ? 40 : 80, background: (DynamicScheme s) => MaterialDynamicColors.inverseSurface, - contrastCurve: ContrastCurve(3, 4.5, 7, 11), + contrastCurve: ContrastCurve(3, 4.5, 7, 7), ); - /// Get DynamicColor for secondary. + /// Get DynamicColor for inverseOnPrimary. static DynamicColor secondary = DynamicColor.fromPalette( name: 'secondary', palette: (DynamicScheme s) => s.secondaryPalette, tone: (DynamicScheme s) => s.isDark ? 80 : 40, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(3, 4.5, 7, 11), + contrastCurve: ContrastCurve(3, 4.5, 7, 7), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.secondaryContainer, MaterialDynamicColors.secondary, - 15, + 10, TonePolarity.nearer, false), ); @@ -366,22 +376,21 @@ class MaterialDynamicColors { if (!_isFidelity(s)) { return initialTone; } - final double answer = _findDesiredChromaByTone( + return _findDesiredChromaByTone( s.secondaryPalette.hue, // ignore: avoid_bool_literals_in_conditional_expressions s.secondaryPalette.chroma, initialTone, // ignore: avoid_bool_literals_in_conditional_expressions s.isDark ? false : true); - return _performAlbers(s.secondaryPalette.getHct(answer), s); }, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(1, 1, 3, 7), + contrastCurve: ContrastCurve(1, 1, 3, 4.5), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.secondaryContainer, MaterialDynamicColors.secondary, - 15, + 10, TonePolarity.nearer, false), ); @@ -413,11 +422,11 @@ class MaterialDynamicColors { }, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(3, 4.5, 7, 11), + contrastCurve: ContrastCurve(3, 4.5, 7, 7), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.tertiaryContainer, MaterialDynamicColors.tertiary, - 15, + 10, TonePolarity.nearer, false), ); @@ -447,18 +456,16 @@ class MaterialDynamicColors { if (!_isFidelity(s)) { return s.isDark ? 30 : 90; } - final double albersTone = - _performAlbers(s.tertiaryPalette.getHct(s.sourceColorHct.tone), s); - final Hct proposedHct = s.tertiaryPalette.getHct(albersTone); + final Hct proposedHct = s.tertiaryPalette.getHct(s.sourceColorHct.tone); return DislikeAnalyzer.fixIfDisliked(proposedHct).tone; }, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(1, 1, 3, 7), + contrastCurve: ContrastCurve(1, 1, 3, 4.5), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.tertiaryContainer, MaterialDynamicColors.tertiary, - 15, + 10, TonePolarity.nearer, false), ); @@ -488,11 +495,11 @@ class MaterialDynamicColors { tone: (DynamicScheme s) => s.isDark ? 80 : 40, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(3, 4.5, 7, 11), + contrastCurve: ContrastCurve(3, 4.5, 7, 7), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.errorContainer, MaterialDynamicColors.error, - 15, + 10, TonePolarity.nearer, false), ); @@ -513,11 +520,11 @@ class MaterialDynamicColors { tone: (DynamicScheme s) => s.isDark ? 30 : 90, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(1, 1, 3, 7), + contrastCurve: ContrastCurve(1, 1, 3, 4.5), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.errorContainer, MaterialDynamicColors.error, - 15, + 10, TonePolarity.nearer, false), ); @@ -538,7 +545,7 @@ class MaterialDynamicColors { tone: (DynamicScheme s) => _isMonochrome(s) ? 40.0 : 90.0, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(1, 1, 3, 7), + contrastCurve: ContrastCurve(1, 1, 3, 4.5), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.primaryFixed, MaterialDynamicColors.primaryFixedDim, @@ -554,7 +561,7 @@ class MaterialDynamicColors { tone: (DynamicScheme s) => _isMonochrome(s) ? 30.0 : 80.0, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(1, 1, 3, 7), + contrastCurve: ContrastCurve(1, 1, 3, 4.5), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.primaryFixed, MaterialDynamicColors.primaryFixedDim, @@ -590,7 +597,7 @@ class MaterialDynamicColors { tone: (DynamicScheme s) => _isMonochrome(s) ? 80.0 : 90.0, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(1, 1, 3, 7), + contrastCurve: ContrastCurve(1, 1, 3, 4.5), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.secondaryFixed, MaterialDynamicColors.secondaryFixedDim, @@ -606,7 +613,7 @@ class MaterialDynamicColors { tone: (DynamicScheme s) => _isMonochrome(s) ? 70.0 : 80.0, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(1, 1, 3, 7), + contrastCurve: ContrastCurve(1, 1, 3, 4.5), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.secondaryFixed, MaterialDynamicColors.secondaryFixedDim, @@ -642,7 +649,7 @@ class MaterialDynamicColors { tone: (DynamicScheme s) => _isMonochrome(s) ? 40.0 : 90.0, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(1, 1, 3, 7), + contrastCurve: ContrastCurve(1, 1, 3, 4.5), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.tertiaryFixed, MaterialDynamicColors.tertiaryFixedDim, @@ -658,7 +665,7 @@ class MaterialDynamicColors { tone: (DynamicScheme s) => _isMonochrome(s) ? 30.0 : 80.0, isBackground: true, background: MaterialDynamicColors.highestSurface, - contrastCurve: ContrastCurve(1, 1, 3, 7), + contrastCurve: ContrastCurve(1, 1, 3, 4.5), toneDeltaPair: (DynamicScheme s) => ToneDeltaPair( MaterialDynamicColors.tertiaryFixed, MaterialDynamicColors.tertiaryFixedDim, @@ -712,17 +719,7 @@ class MaterialDynamicColors { chromaPeak = math.max(chromaPeak, potentialSolution.chroma); } } - return answer; - } - static double _performAlbers(Hct prealbers, DynamicScheme scheme) { - final Hct albersd = - prealbers.inViewingConditions(viewingConditionsForAlbers(scheme)); - if (DynamicColor.tonePrefersLightForeground(prealbers.tone) && - !DynamicColor.toneAllowsLightForeground(albersd.tone)) { - return DynamicColor.enableLightForeground(prealbers.tone); - } else { - return DynamicColor.enableLightForeground(albersd.tone); - } + return answer; } } diff --git a/lib/src/mcu/dynamiccolor/src/contrast_curve.dart b/lib/src/mcu/dynamiccolor/src/contrast_curve.dart index 5b5b827..4443d37 100644 --- a/lib/src/mcu/dynamiccolor/src/contrast_curve.dart +++ b/lib/src/mcu/dynamiccolor/src/contrast_curve.dart @@ -44,12 +44,12 @@ class ContrastCurve { /// [high] Contrast requirement for contrast level 1.0 final double high; - /// Returns the contrast ratio at a given contrast level. + /// Returns the value at a given contrast level. /// /// [contrastLevel] The contrast level. 0.0 is the default (normal); /// -1.0 is the lowest; 1.0 is the highest. - /// Returns The contrast ratio, a number between 1.0 and 21.0. - double getContrast(double contrastLevel) { + /// Returns the value. For contrast ratios, a number between 1.0 and 21.0. + double get(double contrastLevel) { if (contrastLevel <= -1.0) { return low; } else if (contrastLevel < 0.0) { diff --git a/lib/src/mcu/scheme/variant.dart b/lib/src/mcu/dynamiccolor/variant.dart similarity index 71% rename from lib/src/mcu/scheme/variant.dart rename to lib/src/mcu/dynamiccolor/variant.dart index baea33a..f6fc7ca 100644 --- a/lib/src/mcu/scheme/variant.dart +++ b/lib/src/mcu/dynamiccolor/variant.dart @@ -16,7 +16,7 @@ /// Instantiate the corresponding subclass, ex. SchemeTonalSpot, to create /// colors corresponding to the theme. enum Variant { - /// Greyscale colors. + /// All colors are grayscale, no chroma. monochrome('monochrome', 'All colors are grayscale, no chroma.'), /// Close to grayscale, a hint of chroma. @@ -33,54 +33,49 @@ enum Variant { 'vibrant', 'Pastel colors, high chroma palettes. (max).\n' "The primary palette's chroma is at maximum.\n" - 'Use Fidelity instead if tokens should alter their tone to ' - 'match the palette vibrancy.'), + 'Use Fidelity instead if tokens should alter their ' + 'tone to match the palette vibrancy.'), - /// Pastel colors, medium chroma palettes + /// Pastel colors, medium chroma palettes. expressive( 'expressive', 'Pastel colors, medium chroma palettes.\n' - "The primary palette's hue is different from source " - 'color, for variety.'), + "The primary palette's hue is different from source color, " + 'for variety.'), - /// Almost identical to Fidelity, tokens and palettes match source color. + /// Almost identical to Fidelity. content( 'content', 'Almost identical to Fidelity.\n' 'Tokens and palettes match source color.\n' - 'Primary Container is source color, adjusted to ensure ' - 'contrast with surfaces.\n' - '\n' - 'Tertiary palette is analogue of source color.\n' - 'Found by dividing color wheel by 6, then finding the 2 ' - 'colors adjacent to source.\n' + 'Primary Container is source color, adjusted to ensure contrast ' + 'with surfaces.\n\n' + 'Tertiary palette is analogue of source color.\nFound by dividing ' + 'color wheel by 6, then finding the 2 colors adjacent to source.\n' 'The one that increases hue is used.'), /// Tokens and palettes match source color. - /// - /// Tertiary palette is complement of source color. fidelity( 'fidelity', 'Tokens and palettes match source color.\n' - 'Primary Container is source color, adjusted to ensure ' - 'contrast with surfaces.\n' - 'For example, if source color is black, it is lightened ' - "so it doesn't match surfaces in dark mode.\n" - '\n' + 'Primary Container is source color, adjusted to ensure contrast ' + 'with surfaces.\n' + 'For example, if source color is black, it is lightened so it ' + "doesn't match surfaces in dark mode.\n\n" 'Tertiary palette is complement of source color.'), - /// A playful rainbow theme. + /// A playful theme - the source color's hue does not appear in the theme. rainbow('rainbow', "A playful theme - the source color's hue does not appear in the theme."), - /// A playful fruit salad theme. + /// A playful theme - the source color's hue does not appear in the theme. fruitSalad('fruit salad', "A playful theme - the source color's hue does not appear in the theme."); - /// Label for the dynamic color variant. + /// The label of the variant color scheme. final String label; - /// Description of the dynamic color variant. + /// A description of the variant color scheme. final String description; const Variant(this.label, this.description); diff --git a/lib/src/mcu/hct/cam16.dart b/lib/src/mcu/hct/cam16.dart index a4a7a8e..6096124 100644 --- a/lib/src/mcu/hct/cam16.dart +++ b/lib/src/mcu/hct/cam16.dart @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -// ignore_for_file: comment_references - import 'dart:core'; import 'dart:math' as math; -import '../material_color_utilities.dart'; +import '../utils/color_utils.dart'; +import '../utils/math_utils.dart'; +import 'viewing_conditions.dart'; /// CAM16, a color appearance model. Colors are not just defined by their hex /// code, but rather, a hex code and viewing conditions. @@ -155,11 +155,9 @@ class Cam16 { // hue final double atan2 = math.atan2(b, a); final double atanDegrees = atan2 * 180.0 / math.pi; - // print('atanDegrees = $atanDegrees'); final double hue = atanDegrees < 0 ? atanDegrees + 360.0 : atanDegrees >= 360 - // This should never happen, cannot hit test it, assert to catch. ? atanDegrees - 360 // coverage:ignore-line : atanDegrees; final double hueRadians = hue * math.pi / 180.0; @@ -207,7 +205,7 @@ class Cam16 { return fromJchInViewingConditions(j, c, h, ViewingConditions.sRgb); } - /// Create a CAM16 color from lightness [j], chroma [c], and hue [h], + /// Create a CAM16 color from lightness [j], chroma [C], and hue [h], /// in [viewingConditions]. static Cam16 fromJchInViewingConditions( double J, double C, double h, ViewingConditions viewingConditions) { diff --git a/lib/src/mcu/hct/hct.dart b/lib/src/mcu/hct/hct.dart index db4d73d..faeb2bb 100644 --- a/lib/src/mcu/hct/hct.dart +++ b/lib/src/mcu/hct/hct.dart @@ -11,8 +11,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -import '../material_color_utilities.dart'; + +import '../utils/color_utils.dart'; +import 'cam16.dart'; import 'src/hct_solver.dart'; +import 'viewing_conditions.dart'; /// HCT, hue, chroma, and tone. A color system that provides a perceptually /// accurate color measurement system that can also accurately render what @@ -33,23 +36,24 @@ class Hct { return Hct._(argb); } + /// Operator == override @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is! Hct) { + bool operator ==(Object o) { + if (o is! Hct) { return false; } - return other._argb == _argb; + return o._argb == _argb; } + /// The hash code for this object. @override // ignore: avoid_equals_and_hash_code_on_mutable_classes int get hashCode => _argb.hashCode; @override String toString() { - return 'H${hue.round()} ' - 'C${chroma.round()} T${tone.round()}'; + return 'H${hue.round()} C${chroma.round()} T${tone.round()}'; } /// HCT representation of [argb]. @@ -57,7 +61,7 @@ class Hct { return Hct._(argb); } - /// Return HCT as int ARGB value. + /// The color as an integer. int toInt() { return _argb; } diff --git a/lib/src/mcu/hct/src/hct_solver.dart b/lib/src/mcu/hct/src/hct_solver.dart index 65eaabc..ae33eb8 100644 --- a/lib/src/mcu/hct/src/hct_solver.dart +++ b/lib/src/mcu/hct/src/hct_solver.dart @@ -14,11 +14,12 @@ // This file is automatically generated. Do not modify it. -// ignore_for_file: comment_references - import 'dart:math'; -import '../../material_color_utilities.dart'; +import '../../utils/color_utils.dart'; +import '../../utils/math_utils.dart'; +import '../cam16.dart'; +import '../viewing_conditions.dart'; /// A class that solves the HCT equation. class HctSolver { @@ -421,8 +422,7 @@ class HctSolver { final double kG = _yFromLinrgb[1]; final double kB = _yFromLinrgb[2]; final double coordA = n % 4 <= 1 ? 0.0 : 100.0; - // ignore: use_is_even_rather_than_modulo - final double coordB = n % 2 == 0 ? 0.0 : 100.0; + final double coordB = n.isEven ? 0.0 : 100.0; if (n < 4) { final double g = coordA; final double b = coordB; @@ -455,7 +455,7 @@ class HctSolver { /// Finds the segment containing the desired color. /// - /// Given a plane Y = [y] and a desired [target_hue], returns the + /// Given a plane Y = [y] and a desired [targetHue], returns the /// segment containing the desired color, represented as an array of /// its two endpoints. static List> _bisectToSegment(double y, double targetHue) { @@ -650,9 +650,8 @@ class HctSolver { if (chroma < 0.0001 || lstar < 0.0001 || lstar > 99.9999) { return ColorUtils.argbFromLstar(lstar); } - // ignore: parameter_assignments - hueDegrees = MathUtils.sanitizeDegreesDouble(hueDegrees); - final double hueRadians = hueDegrees / 180 * pi; + final double localHueDegrees = MathUtils.sanitizeDegreesDouble(hueDegrees); + final double hueRadians = localHueDegrees / 180 * pi; final double y = ColorUtils.yFromLstar(lstar); final int exactAnswer = _findResultByJ(hueRadians, chroma, y); if (exactAnswer != 0) { diff --git a/lib/src/mcu/hct/viewing_conditions.dart b/lib/src/mcu/hct/viewing_conditions.dart index cffdaed..c3f56b9 100644 --- a/lib/src/mcu/hct/viewing_conditions.dart +++ b/lib/src/mcu/hct/viewing_conditions.dart @@ -17,9 +17,6 @@ import 'dart:math' as math; import '../utils/color_utils.dart'; import '../utils/math_utils.dart'; -// import 'package:material_color_utilities/utils/color_utils.dart'; -// import 'package:material_color_utilities/utils/math_utils.dart'; - /// In traditional color spaces, a color can be identified solely by the /// observer's measurement of the color. Color appearance models such as CAM16 /// also use information about the environment where the color was @@ -137,10 +134,9 @@ class ViewingConditions { xyz[0] * -0.002079 + xyz[1] * 0.048952 + xyz[2] * 0.953127; // Scale input surround, domain (0, 2), to CAM16 surround, domain (0.8, 1.0) - assert(surround >= 0.0 && surround <= 2.0, 'surround must be >= 0 and <=2'); + assert(surround >= 0.0 && surround <= 2.0, 'Surround must be in range 0-2'); final double f = 0.8 + (surround / 10.0); // "Exponential non-linearity" - // print('======> f= $f'); final double c = (f >= 0.9) ? MathUtils.lerp(0.59, 0.69, (f - 0.9) * 10.0) : MathUtils.lerp(0.525, 0.59, (f - 0.8) * 10.0); @@ -183,8 +179,8 @@ class ViewingConditions { // Luminance-level adaptation factor final double fl = (k4 * adaptingLuminance) + (0.1 * k4F * k4F * math.pow(5.0 * adaptingLuminance, 1.0 / 3.0)); - // Intermediate factor, ratio of background relative luminance to - // white relative luminance + // Intermediate factor, ratio of background relative luminance to white + // relative luminance final double n = ColorUtils.yFromLstar(backgroundLstar) / whitePoint[1]; // Base exponential none linearity @@ -196,7 +192,7 @@ class ViewingConditions { final double ncb = nbb; // Discounted cone responses to the white point, adjusted for - // post-saturationtic adaptation perceptual nonlinearities. + // post-saturationtic adaptation perceptual none linearity. final List rgbAFactors = [ math.pow(fl * rgbD[0] * rW / 100.0, 0.42), math.pow(fl * rgbD[1] * gW / 100.0, 0.42), diff --git a/lib/src/mcu/material_color_utilities.dart b/lib/src/mcu/material_color_utilities.dart index 900a536..7b48b61 100644 --- a/lib/src/mcu/material_color_utilities.dart +++ b/lib/src/mcu/material_color_utilities.dart @@ -27,7 +27,9 @@ export 'blend/blend.dart'; export 'contrast/contrast.dart'; export 'dislike/dislike_analyzer.dart'; export 'dynamiccolor/dynamic_color.dart'; +export 'dynamiccolor/dynamic_scheme.dart'; export 'dynamiccolor/material_dynamic_colors.dart'; +export 'dynamiccolor/variant.dart'; export 'hct/cam16.dart'; export 'hct/hct.dart'; export 'hct/viewing_conditions.dart'; @@ -38,7 +40,6 @@ export 'quantize/quantizer_celebi.dart'; export 'quantize/quantizer_map.dart'; export 'quantize/quantizer_wsmeans.dart'; export 'quantize/quantizer_wu.dart'; -export 'scheme/dynamic_scheme.dart'; export 'scheme/scheme.dart'; export 'scheme/scheme_content.dart'; export 'scheme/scheme_expressive.dart'; @@ -49,7 +50,6 @@ export 'scheme/scheme_neutral.dart'; export 'scheme/scheme_rainbow.dart'; export 'scheme/scheme_tonal_spot.dart'; export 'scheme/scheme_vibrant.dart'; -export 'scheme/variant.dart'; export 'score/score.dart'; export 'temperature/temperature_cache.dart'; export 'utils/color_utils.dart'; diff --git a/lib/src/mcu/palettes/tonal_palette.dart b/lib/src/mcu/palettes/tonal_palette.dart index fe62756..6df98d7 100644 --- a/lib/src/mcu/palettes/tonal_palette.dart +++ b/lib/src/mcu/palettes/tonal_palette.dart @@ -12,12 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'dart:math' as math; - import 'package:collection/collection.dart' show ListEquality; -import 'package:flutter/cupertino.dart'; +import 'package:meta/meta.dart'; -import '../material_color_utilities.dart'; +import '../hct/hct.dart'; /// A convenience class for retrieving colors that are constant in hue and /// chroma, but vary in tone. @@ -47,40 +45,40 @@ class TonalPalette { 100, ]; - /// Amount of tone in standard Material3 tonal palette. + /// The number of common tones. static final int commonSize = commonTones.length; - final Hct? _keyColor; + /// The hue of the palette. + final double hue; - /// Get the keyColor used to make this [TonalPalette]. - Hct get keyColor => _keyColor ?? Hct.from(0.0, 0.0, 0.0); - final double? _hue; + /// The chroma of the palette. + final double chroma; - /// Get the Hue value for this [TonalPalette]. - double get hue => _hue ?? 0.0; - final double? _chroma; + /// The key color of the palette. + final Hct keyColor; - /// Get the chroma value for this [TonalPalette]. - double get chroma => _chroma ?? 0.0; + /// A cache containing keys-value pairs where: + /// - keys are integers that represent tones, and + /// - values are colors in ARGB format. final Map _cache; + final bool _isFromCache; TonalPalette._fromHct(Hct hct) : _cache = {}, - _hue = hct.hue, - _chroma = hct.chroma, - _keyColor = hct; + hue = hct.hue, + chroma = hct.chroma, + keyColor = hct, + _isFromCache = false; - TonalPalette._fromHueAndChroma(double hue, double chroma) + TonalPalette._fromHueAndChroma(this.hue, this.chroma) : _cache = {}, - _hue = hue, - _chroma = chroma, - _keyColor = createKeyColor(hue, chroma); + keyColor = createKeyColor(hue, chroma), + _isFromCache = false; - const TonalPalette._fromCache(Map cache) + TonalPalette._fromCache(Map cache, this.hue, this.chroma) : _cache = cache, - _hue = null, - _chroma = null, - _keyColor = null; + keyColor = createKeyColor(hue, chroma), + _isFromCache = true; /// Create colors using [hue] and [chroma]. static TonalPalette of(double hue, double chroma) { @@ -96,18 +94,36 @@ class TonalPalette { /// /// Inverse of [TonalPalette.asList]. static TonalPalette fromList(List colors) { - assert(colors.length == commonSize, 'Length of list must be $commonSize'); + assert(colors.length == commonSize, + 'colors length must be equal to commonSize'); final Map cache = {}; commonTones.asMap().forEach( (int index, int toneValue) => cache[toneValue] = colors[index]); - return TonalPalette._fromCache(cache); + + // Approximately deduces the original hue and chroma that generated this + // list of colors. + // Uses the hue and chroma of the provided color with the highest chroma. + double bestHue = 0.0; + double bestChroma = 0.0; + for (final int argb in colors) { + final Hct hct = Hct.fromInt(argb); + + // If the color is too close to white, its chroma may have been + // affected by a known issue, so we ignore it. + // https://github.com/material-foundation/material-color-utilities/issues/140 + if (hct.tone > 98.0) continue; + + if (hct.chroma > bestChroma) { + bestHue = hct.hue; + bestChroma = hct.chroma; + } + } + return TonalPalette._fromCache(cache, bestHue, bestChroma); } - /// Key color [Hct]. - /// /// Creates a key color from a [hue] and a [chroma]. - /// The key color is the first tone, starting from T50, matching the given hue - /// and chroma. + /// The key color is the first tone, starting from T50, matching the + /// given hue and chroma. Key color [Hct]. static Hct createKeyColor(double hue, double chroma) { const double startTone = 50.0; Hct smallestDeltaHct = Hct.from(hue, chroma, startTone); @@ -150,56 +166,45 @@ class TonalPalette { /// Inverse of [fromList]. List get asList => commonTones.map(get).toList(); - /// Returns the ARGB representation of an HCT color. + /// Returns the ARGB representation of an HCT color at the given [tone]. + /// + /// If the palette is constructed from a list of colors + /// (i.e. using [fromList]), the color provided at construction is returned + /// if possible; otherwise the result is generated from the deduced + /// [hue] and [chroma]. /// - /// If the class was instantiated from [_hue] and [_chroma], will return the - /// color with corresponding [tone]. - /// If the class was instantiated from a fixed-size list of color ints, [tone] - /// must be in [commonTones]. + /// If the palette is constructed from a hue and chroma (i.e. using [of] or + /// [fromHct]), the result is generated from the given [hue] and [chroma]. int get(int tone) { - if (_hue == null || _chroma == null) { - if (!_cache.containsKey(tone)) { - throw ArgumentError.value( - tone, - 'tone', - 'When a TonalPalette is created with fromList, tone must be one of ' - '$commonTones', - ); - } else { - return _cache[tone]!; - } - } - final double chroma = (tone >= 90.0) ? math.min(_chroma!, 40.0) : _chroma!; return _cache.putIfAbsent( - tone, () => Hct.from(_hue!, chroma, tone.toDouble()).toInt()); + tone, + () => Hct.from(hue, chroma, tone.toDouble()).toInt(), + ); } - /// Get the HCT color for a given tone. + /// Returns the HCT color at the given [tone]. + /// + /// If the palette is constructed from a list of colors + /// (i.e. using [fromList]), the color provided at construction is returned + /// if possible; otherwise the result is generated from the deduced + /// [hue] and [chroma]. + /// + /// If the palette is constructed from a hue and chroma (i.e. using [of] or + /// [fromHct]), the result is generated from the given [hue] and [chroma]. Hct getHct(double tone) { - if (_hue == null || _chroma == null) { - if (!_cache.containsKey(tone)) { - throw ArgumentError.value( - tone, - 'tone', - 'When a TonalPalette is created with fromList, tone must be one of ' - '$commonTones', - ); - } else { - return Hct.fromInt(_cache[tone]!); - } + if (_cache.containsKey(tone)) { + return Hct.fromInt(_cache[tone]!); + } else { + return Hct.from(hue, chroma, tone); } - return Hct.from(_hue!, _chroma!, tone); } @override bool operator ==(Object other) { if (other is TonalPalette) { - if (_hue != null && - _chroma != null && - other._hue != null && - other._chroma != null) { + if (!_isFromCache && !other._isFromCache) { // Both created with .of or .fromHct - return _hue == other._hue && _chroma == other._chroma; + return hue == other.hue && chroma == other.chroma; } else { return const ListEquality().equals(asList, other.asList); } @@ -209,8 +214,8 @@ class TonalPalette { @override int get hashCode { - if (_hue != null && _chroma != null) { - return Object.hash(_hue, _chroma); + if (!_isFromCache) { + return Object.hash(hue, chroma); } else { return Object.hashAll(asList); } @@ -218,10 +223,10 @@ class TonalPalette { @override String toString() { - if (_hue != null && _chroma != null) { - return 'TonalPalette.of($_hue, $_chroma)'; + if (!_isFromCache) { + return 'TonalPalette.of($hue, $chroma)'; } else { - return 'TonalPalette.fromList($_cache)'; + return 'TonalPalette.fromList($asList)'; } } } diff --git a/lib/src/mcu/scheme/dynamic_scheme.dart b/lib/src/mcu/scheme/dynamic_scheme.dart deleted file mode 100644 index 2f3df3e..0000000 --- a/lib/src/mcu/scheme/dynamic_scheme.dart +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import '../material_color_utilities.dart'; - -/// Constructed by a set of values representing the current UI state (such as -/// whether or not its dark theme, what the theme style is, etc.), and -/// provides a set of [TonalPalette]s that can create colors that fit in -/// with the theme style. Used by [DynamicColor] to resolve into a color. -class DynamicScheme { - /// The source color of the theme as an ARGB integer. - final int sourceColorArgb; - - /// The source color of the theme in HCT. - final Hct sourceColorHct; - - /// The variant, or style, of the theme. - final Variant variant; - - /// Whether or not the scheme is in 'dark mode' or 'light mode'. - final bool isDark; - - /// Value from -1 to 1. -1 represents minimum contrast, 0 represents - /// standard (i.e. the design as spec'd), and 1 represents maximum contrast. - final double contrastLevel; - - /// Given a tone, produces a color. Hue and chroma of the color are specified - /// in the design specification of the variant. Usually colorful. - final TonalPalette primaryPalette; - - /// Given a tone, produces a color. Hue and chroma of the color are specified - /// in the design specification of the variant. Usually less colorful. - final TonalPalette secondaryPalette; - - /// Given a tone, produces a color. Hue and chroma of the color are specified - /// in the design specification of the variant. Usually a different hue from - /// primary and colorful. - final TonalPalette tertiaryPalette; - - /// Given a tone, produces a color. Hue and chroma of the color are specified - /// in the design specification of the variant. Usually not colorful at all, - /// intended for background & surface colors. - final TonalPalette neutralPalette; - - /// Given a tone, produces a color. Hue and chroma of the color are specified - /// in the design specification of the variant. Usually not colorful, but - /// slightly more colorful than Neutral. Intended for backgrounds & surfaces. - final TonalPalette neutralVariantPalette; - - /// Given a tone, produces a reddish, colorful, color. - final TonalPalette errorPalette; - - /// Default constructor. - DynamicScheme({ - required this.sourceColorArgb, - required this.variant, - this.contrastLevel = 0.0, - required this.isDark, - required this.primaryPalette, - required this.secondaryPalette, - required this.tertiaryPalette, - required this.neutralPalette, - required this.neutralVariantPalette, - }) : sourceColorHct = Hct.fromInt(sourceColorArgb), - errorPalette = TonalPalette.of(25.0, 84.0); - - /// getRotatedHue. - static double getRotatedHue( - Hct sourceColor, List hues, List rotations) { - final double sourceHue = sourceColor.hue; - assert(hues.length == rotations.length, - 'Hues length must be equal to rotations length'); - if (rotations.length == 1) { - return MathUtils.sanitizeDegreesDouble(sourceColor.hue + rotations[0]); - } - final int size = hues.length; - for (int i = 0; i <= (size - 2); i++) { - final double thisHue = hues[i]; - final double nextHue = hues[i + 1]; - if (thisHue < sourceHue && sourceHue < nextHue) { - return MathUtils.sanitizeDegreesDouble(sourceHue + rotations[i]); - } - } - // If this statement executes, something is wrong, there - // should have been a rotation found using the arrays. - return sourceHue; - } -} diff --git a/lib/src/mcu/scheme/scheme.dart b/lib/src/mcu/scheme/scheme.dart index f144683..c0d8bd4 100644 --- a/lib/src/mcu/scheme/scheme.dart +++ b/lib/src/mcu/scheme/scheme.dart @@ -20,6 +20,10 @@ import '../material_color_utilities.dart'; /// Prefer [ColorScheme]. This class is the same concept as Flutter's /// ColorScheme class, inlined to ensure parity across languages. +@Deprecated('The `Scheme` class is deprecated in favor of `DynamicScheme`.\n' + 'Please see ' + 'https://github.com/material-foundation/material-color-utilities/blob/main/make_schemes.md' + 'for migration guidance.') class Scheme { /// primary color as int. final int primary; @@ -109,6 +113,10 @@ class Scheme { final int inversePrimary; /// Default Scheme constructor. + @Deprecated('The `Scheme` class is deprecated in favor of `DynamicScheme`.\n' + 'Please see ' + 'https://github.com/material-foundation/material-color-utilities/blob/main/make_schemes.md' + 'for migration guidance.') const Scheme({ required this.primary, required this.onPrimary, diff --git a/lib/src/mcu/scheme/scheme_content.dart b/lib/src/mcu/scheme/scheme_content.dart index b997edf..c2984bd 100644 --- a/lib/src/mcu/scheme/scheme_content.dart +++ b/lib/src/mcu/scheme/scheme_content.dart @@ -13,10 +13,13 @@ // limitations under the License. import 'dart:math' as math; -import '../material_color_utilities.dart'; - -// import 'dynamic_scheme.dart'; -// import 'variant.dart'; +import '../dislike/dislike_analyzer.dart'; +import '../dynamiccolor/dynamic_scheme.dart'; +import '../dynamiccolor/variant.dart'; +import '../hct/hct.dart'; +import '../palettes/tonal_palette.dart'; +import '../temperature/temperature_cache.dart'; +import 'scheme.dart'; /// A scheme that places the source color in [Scheme.primaryContainer]. /// @@ -28,7 +31,7 @@ import '../material_color_utilities.dart'; /// color wheel divided into 6, and the precise analog is the one found by /// increasing hue. It also maintains constant appearance. class SchemeContent extends DynamicScheme { - /// Default SchemeContent constructor. + /// Create a [SchemeContent] from a source color. SchemeContent({ required Hct sourceColorHct, required super.isDark, diff --git a/lib/src/mcu/scheme/scheme_expressive.dart b/lib/src/mcu/scheme/scheme_expressive.dart index 55cbcf5..3f0a821 100644 --- a/lib/src/mcu/scheme/scheme_expressive.dart +++ b/lib/src/mcu/scheme/scheme_expressive.dart @@ -12,7 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -import '../material_color_utilities.dart'; +import '../dynamiccolor/dynamic_scheme.dart'; +import '../dynamiccolor/variant.dart'; +import '../hct/hct.dart'; +import '../palettes/tonal_palette.dart'; +import '../utils/math_utils.dart'; /// A Dynamic Color theme that is intentionally detached from the input color. class SchemeExpressive extends DynamicScheme { diff --git a/lib/src/mcu/scheme/scheme_fidelity.dart b/lib/src/mcu/scheme/scheme_fidelity.dart index 8ae059a..a5dd025 100644 --- a/lib/src/mcu/scheme/scheme_fidelity.dart +++ b/lib/src/mcu/scheme/scheme_fidelity.dart @@ -13,7 +13,13 @@ // limitations under the License. import 'dart:math' as math; -import '../material_color_utilities.dart'; +import '../dislike/dislike_analyzer.dart'; +import '../dynamiccolor/dynamic_scheme.dart'; +import '../dynamiccolor/variant.dart'; +import '../hct/hct.dart'; +import '../palettes/tonal_palette.dart'; +import '../temperature/temperature_cache.dart'; +import 'scheme.dart'; /// A scheme that places the source color in [Scheme.primaryContainer]. /// diff --git a/lib/src/mcu/scheme/scheme_fruit_salad.dart b/lib/src/mcu/scheme/scheme_fruit_salad.dart index d995c09..099034e 100644 --- a/lib/src/mcu/scheme/scheme_fruit_salad.dart +++ b/lib/src/mcu/scheme/scheme_fruit_salad.dart @@ -12,7 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -import '../material_color_utilities.dart'; +import '../dynamiccolor/dynamic_scheme.dart'; +import '../dynamiccolor/variant.dart'; +import '../hct/hct.dart'; +import '../palettes/tonal_palette.dart'; +import '../utils/math_utils.dart'; /// A playful theme - the source color's hue does not appear in the theme. class SchemeFruitSalad extends DynamicScheme { diff --git a/lib/src/mcu/scheme/scheme_monochrome.dart b/lib/src/mcu/scheme/scheme_monochrome.dart index b8e699a..a7ae51b 100644 --- a/lib/src/mcu/scheme/scheme_monochrome.dart +++ b/lib/src/mcu/scheme/scheme_monochrome.dart @@ -11,7 +11,10 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -import '../material_color_utilities.dart'; +import '../dynamiccolor/dynamic_scheme.dart'; +import '../dynamiccolor/variant.dart'; +import '../hct/hct.dart'; +import '../palettes/tonal_palette.dart'; /// A Dynamic Color theme that is grayscale. class SchemeMonochrome extends DynamicScheme { diff --git a/lib/src/mcu/scheme/scheme_neutral.dart b/lib/src/mcu/scheme/scheme_neutral.dart index 0e284dc..c3fed1f 100644 --- a/lib/src/mcu/scheme/scheme_neutral.dart +++ b/lib/src/mcu/scheme/scheme_neutral.dart @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -import '../material_color_utilities.dart'; +import '../dynamiccolor/dynamic_scheme.dart'; +import '../dynamiccolor/variant.dart'; +import '../hct/hct.dart'; +import '../palettes/tonal_palette.dart'; /// A Dynamic Color theme that is near grayscale. class SchemeNeutral extends DynamicScheme { diff --git a/lib/src/mcu/scheme/scheme_rainbow.dart b/lib/src/mcu/scheme/scheme_rainbow.dart index f9d84cb..e3f1e95 100644 --- a/lib/src/mcu/scheme/scheme_rainbow.dart +++ b/lib/src/mcu/scheme/scheme_rainbow.dart @@ -12,7 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -import '../material_color_utilities.dart'; +import '../dynamiccolor/dynamic_scheme.dart'; +import '../dynamiccolor/variant.dart'; +import '../hct/hct.dart'; +import '../palettes/tonal_palette.dart'; +import '../utils/math_utils.dart'; /// A playful theme - the source color's hue does not appear in the theme. class SchemeRainbow extends DynamicScheme { diff --git a/lib/src/mcu/scheme/scheme_tonal_spot.dart b/lib/src/mcu/scheme/scheme_tonal_spot.dart index b1de30e..5b7388a 100644 --- a/lib/src/mcu/scheme/scheme_tonal_spot.dart +++ b/lib/src/mcu/scheme/scheme_tonal_spot.dart @@ -12,7 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -import '../material_color_utilities.dart'; +import '../dynamiccolor/dynamic_scheme.dart'; +import '../dynamiccolor/variant.dart'; +import '../hct/hct.dart'; +import '../palettes/tonal_palette.dart'; +import '../utils/math_utils.dart'; /// A Dynamic Color theme with low to medium colorfulness and a Tertiary /// [TonalPalette] with a hue related to the source color. The default diff --git a/lib/src/mcu/scheme/scheme_vibrant.dart b/lib/src/mcu/scheme/scheme_vibrant.dart index 0dbf3c4..d55560b 100644 --- a/lib/src/mcu/scheme/scheme_vibrant.dart +++ b/lib/src/mcu/scheme/scheme_vibrant.dart @@ -17,7 +17,10 @@ // import 'dynamic_scheme.dart'; // import 'variant.dart'; -import '../material_color_utilities.dart'; +import '../dynamiccolor/dynamic_scheme.dart'; +import '../dynamiccolor/variant.dart'; +import '../hct/hct.dart'; +import '../palettes/tonal_palette.dart'; /// A Dynamic Color theme that maxes out colorfulness at each position in the /// Primary [TonalPalette]. diff --git a/pubspec.lock b/pubspec.lock index c3cc060..35c2fb1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" async: dependency: transitive description: @@ -119,10 +119,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: @@ -159,34 +159,34 @@ packages: dependency: transitive description: name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "0.7.1" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.3" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" logging: dependency: transitive description: @@ -215,10 +215,10 @@ packages: dependency: "direct main" description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.12.0" mime: dependency: transitive description: @@ -364,26 +364,26 @@ packages: dependency: "direct dev" description: name: test - sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" url: "https://pub.dev" source: hosted - version: "1.24.9" + version: "1.25.2" test_api: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.0" test_core: dependency: transitive description: name: test_core - sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" url: "https://pub.dev" source: hosted - version: "0.5.9" + version: "0.6.0" typed_data: dependency: transitive description: @@ -404,10 +404,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.1" watcher: dependency: transitive description: @@ -428,10 +428,10 @@ packages: dependency: transitive description: name: web_socket_channel - sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" + sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" url: "https://pub.dev" source: hosted - version: "2.4.4" + version: "2.4.5" webkit_inspection_protocol: dependency: transitive description: @@ -450,4 +450,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.3.0 <4.0.0" - flutter: ">=3.10.0" + flutter: ">=3.22.0-0.3.pre" diff --git a/pubspec.yaml b/pubspec.yaml index 5f60c88..fd25730 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flex_seed_scheme description: A more flexible and powerful version of Flutter's ColorScheme.fromSeed. Use multiple seed colors, custom chroma and tone mapping. -version: 1.5.0 +version: 2.0.0-dev.1 homepage: https://github.com/rydmike/flex_seed_scheme repository: https://github.com/rydmike/flex_seed_scheme issue_tracker: https://github.com/rydmike/flex_seed_scheme/issues @@ -29,7 +29,7 @@ topics: environment: sdk: '>=3.0.0 <4.0.0' - flutter: '>=3.10.0' + flutter: '>=3.22.0-0.3.pre' dependencies: # Used by mcu: tonal_palette.dart diff --git a/test/flex_core_palette_test.dart b/test/flex_core_palette_test.dart index a8755a9..7703a68 100644 --- a/test/flex_core_palette_test.dart +++ b/test/flex_core_palette_test.dart @@ -624,6 +624,22 @@ void main() { FlexTonalPalette.of(17.23982263982711, 72), ); }); + final FlexCorePalette mError10 = FlexCorePalette.fromSeeds( + primary: const Color(0xFF6750A4).value, + error: const Color(0xFFCC1839).value, + errorChroma: 62, + errorMinChroma: 72, + useCam16: false, + ); + test( + 'FCP1.Err109: GIVEN error Color #CC1839, chroma 62. min 72 and ' + 'use Cam16 is false EXPECT ' + '(17.23982263982711, 72)', () { + expect( + mError10.error, + FlexTonalPalette.of(17.23982263982711, 72), + ); + }); // }); @@ -652,12 +668,14 @@ void main() { final List m1List = m1.primary.asList; final List m1NoCustomTonesList = []; for (int i = 0; i <= FlexTonalPalette.extendedTones.length - 1; i++) { - if (FlexTonalPalette.extendedTones[i] != 4 && + if (FlexTonalPalette.extendedTones[i] != 2 && + FlexTonalPalette.extendedTones[i] != 4 && FlexTonalPalette.extendedTones[i] != 5 && FlexTonalPalette.extendedTones[i] != 6 && FlexTonalPalette.extendedTones[i] != 12 && FlexTonalPalette.extendedTones[i] != 17 && FlexTonalPalette.extendedTones[i] != 22 && + FlexTonalPalette.extendedTones[i] != 24 && FlexTonalPalette.extendedTones[i] != 87 && FlexTonalPalette.extendedTones[i] != 92 && FlexTonalPalette.extendedTones[i] != 94 && @@ -677,17 +695,19 @@ void main() { 'CorePalette.of using same input color ' 'EXPECT secondary palette lists to be equal without extended tones', () { - // If we remove the tones 5 and 98 that MaterialColorUtilities + // If we remove the tones that MaterialColorUtilities // CorePalette.of does not include, our custom tones list should be equal. final List m1List = m1.secondary.asList; final List m1NoCustomTonesList = []; for (int i = 0; i <= FlexTonalPalette.extendedTones.length - 1; i++) { - if (FlexTonalPalette.extendedTones[i] != 4 && + if (FlexTonalPalette.extendedTones[i] != 2 && + FlexTonalPalette.extendedTones[i] != 4 && FlexTonalPalette.extendedTones[i] != 5 && FlexTonalPalette.extendedTones[i] != 6 && FlexTonalPalette.extendedTones[i] != 12 && FlexTonalPalette.extendedTones[i] != 17 && FlexTonalPalette.extendedTones[i] != 22 && + FlexTonalPalette.extendedTones[i] != 24 && FlexTonalPalette.extendedTones[i] != 87 && FlexTonalPalette.extendedTones[i] != 92 && FlexTonalPalette.extendedTones[i] != 94 && @@ -706,17 +726,19 @@ void main() { 'FCP2.03: GIVEN same FlexCorePalette.fromSeeds extended and ' 'CorePalette.of using same input color ' 'EXPECT tertiary palette lists to be equal without extended tones', () { - // If we remove the tones 5 and 98 that MaterialColorUtilities + // If we remove the tones that MaterialColorUtilities // CorePalette.of does not include, our custom tones list should be equal. final List m1List = m1.tertiary.asList; final List m1NoCustomTonesList = []; for (int i = 0; i <= FlexTonalPalette.extendedTones.length - 1; i++) { - if (FlexTonalPalette.extendedTones[i] != 4 && + if (FlexTonalPalette.extendedTones[i] != 2 && + FlexTonalPalette.extendedTones[i] != 4 && FlexTonalPalette.extendedTones[i] != 5 && FlexTonalPalette.extendedTones[i] != 6 && FlexTonalPalette.extendedTones[i] != 12 && FlexTonalPalette.extendedTones[i] != 17 && FlexTonalPalette.extendedTones[i] != 22 && + FlexTonalPalette.extendedTones[i] != 24 && FlexTonalPalette.extendedTones[i] != 87 && FlexTonalPalette.extendedTones[i] != 92 && FlexTonalPalette.extendedTones[i] != 94 && @@ -740,12 +762,14 @@ void main() { final List m1List = m1.error.asList; final List m1NoCustomTonesList = []; for (int i = 0; i <= FlexTonalPalette.extendedTones.length - 1; i++) { - if (FlexTonalPalette.extendedTones[i] != 4 && + if (FlexTonalPalette.extendedTones[i] != 2 && + FlexTonalPalette.extendedTones[i] != 4 && FlexTonalPalette.extendedTones[i] != 5 && FlexTonalPalette.extendedTones[i] != 6 && FlexTonalPalette.extendedTones[i] != 12 && FlexTonalPalette.extendedTones[i] != 17 && FlexTonalPalette.extendedTones[i] != 22 && + FlexTonalPalette.extendedTones[i] != 24 && FlexTonalPalette.extendedTones[i] != 87 && FlexTonalPalette.extendedTones[i] != 92 && FlexTonalPalette.extendedTones[i] != 94 && @@ -764,17 +788,19 @@ void main() { 'FCP2.05: GIVEN same FlexCorePalette.fromSeeds extended and ' 'CorePalette.of using same input color ' 'EXPECT neutral palette lists to be equal without extended tones', () { - // If we remove the tones 5 and 98 that MaterialColorUtilities + // If we remove the tones that MaterialColorUtilities // CorePalette.of does not include, our custom tones list should be equal. final List m1List = m1.neutral.asList; final List m1NoCustomTonesList = []; for (int i = 0; i <= FlexTonalPalette.extendedTones.length - 1; i++) { - if (FlexTonalPalette.extendedTones[i] != 4 && + if (FlexTonalPalette.extendedTones[i] != 2 && + FlexTonalPalette.extendedTones[i] != 4 && FlexTonalPalette.extendedTones[i] != 5 && FlexTonalPalette.extendedTones[i] != 6 && FlexTonalPalette.extendedTones[i] != 12 && FlexTonalPalette.extendedTones[i] != 17 && FlexTonalPalette.extendedTones[i] != 22 && + FlexTonalPalette.extendedTones[i] != 24 && FlexTonalPalette.extendedTones[i] != 87 && FlexTonalPalette.extendedTones[i] != 92 && FlexTonalPalette.extendedTones[i] != 94 && @@ -793,17 +819,19 @@ void main() { 'FCP2.06: GIVEN same FlexCorePalette.fromSeeds extended and ' 'CorePalette.of using same input color ' 'EXPECT neutralVariant palette lists equal without extended tones', () { - // If we remove the tones 5 and 98 that MaterialColorUtilities + // If we remove the tones that MaterialColorUtilities // CorePalette.of does not include, our custom tones list should be equal. final List m1List = m1.neutralVariant.asList; final List m1NoCustomTonesList = []; for (int i = 0; i <= FlexTonalPalette.extendedTones.length - 1; i++) { - if (FlexTonalPalette.extendedTones[i] != 4 && + if (FlexTonalPalette.extendedTones[i] != 2 && + FlexTonalPalette.extendedTones[i] != 4 && FlexTonalPalette.extendedTones[i] != 5 && FlexTonalPalette.extendedTones[i] != 6 && FlexTonalPalette.extendedTones[i] != 12 && FlexTonalPalette.extendedTones[i] != 17 && FlexTonalPalette.extendedTones[i] != 22 && + FlexTonalPalette.extendedTones[i] != 24 && FlexTonalPalette.extendedTones[i] != 87 && FlexTonalPalette.extendedTones[i] != 92 && FlexTonalPalette.extendedTones[i] != 94 && @@ -832,6 +860,7 @@ void main() { 'EXPECT a given list result', () { expect(m3.asList(), [ 4278190080, + 4278845480, 4279435322, 4279631937, 4279828552, @@ -840,6 +869,7 @@ void main() { 4281407084, 4281867890, 4282131319, + 4282460284, 4283381642, 4284960932, 4286605759, @@ -857,6 +887,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4278781205, 4279241501, 4279438880, 4279570466, @@ -865,6 +896,7 @@ void main() { 4281149242, 4281544001, 4281872965, + 4282136138, 4283057240, 4284636016, 4286280842, @@ -882,6 +914,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4279697673, 4280353808, 4280550930, 4280748053, @@ -890,6 +923,7 @@ void main() { 4282523436, 4283049266, 4283377974, + 4283706939, 4284693320, 4286468704, 4288244345, @@ -907,6 +941,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4278716170, 4279176721, 4279373844, 4279505686, @@ -915,6 +950,7 @@ void main() { 4281018669, 4281413683, 4281742392, + 4282005564, 4282926666, 4284505442, 4286150266, @@ -932,6 +968,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4278715917, 4279176468, 4279373847, 4279505434, @@ -940,6 +977,7 @@ void main() { 4281018673, 4281478968, 4281742140, + 4282071104, 4282991950, 4284570982, 4286215551, @@ -957,6 +995,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4279894016, 4280811521, 4281139201, 4281401345, @@ -965,6 +1004,7 @@ void main() { 4284219396, 4285071365, 4285595653, + 4286119942, 4287823882, 4290386458, 4292753200, @@ -1001,6 +1041,7 @@ void main() { m4.asList(), [ 4278190080, + 4278845480, 4279435322, 4279631937, 4279828552, @@ -1009,6 +1050,7 @@ void main() { 4281407084, 4281867890, 4282131319, + 4282460284, 4283381642, 4284960932, 4286605759, @@ -1026,6 +1068,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4278781206, 4279241501, 4279438880, 4279636003, @@ -1034,6 +1077,7 @@ void main() { 4281149242, 4281544001, 4281872966, + 4282136138, 4283056984, 4284636017, 4286280586, @@ -1051,6 +1095,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4279697673, 4280288272, 4280550930, 4280748309, @@ -1059,6 +1104,7 @@ void main() { 4282523436, 4282983730, 4283312438, + 4283641403, 4284693320, 4286403168, 4288178809, @@ -1076,6 +1122,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4278716170, 4279176721, 4279373844, 4279505686, @@ -1084,6 +1131,7 @@ void main() { 4281018669, 4281413683, 4281742392, + 4282005564, 4282926666, 4284505442, 4286150266, @@ -1101,6 +1149,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4278715917, 4279176468, 4279373847, 4279505434, @@ -1109,6 +1158,7 @@ void main() { 4281018673, 4281478968, 4281742140, + 4282071104, 4282991950, 4284570982, 4286215551, @@ -1126,6 +1176,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4279894016, 4280811521, 4281139201, 4281401345, @@ -1134,6 +1185,7 @@ void main() { 4284219396, 4285071365, 4285595653, + 4286119942, 4287823882, 4290386458, 4292753200, @@ -1238,6 +1290,7 @@ void main() { equals( FlexCorePalette.fromList(const [ 4278190080, + 4278845480, 4279435322, 4279631937, 4279828552, @@ -1246,6 +1299,7 @@ void main() { 4281407084, 4281867890, 4282131319, + 4282460284, 4283381642, 4284960932, 4286605759, @@ -1263,6 +1317,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4278781205, 4279241501, 4279438880, 4279570466, @@ -1271,6 +1326,7 @@ void main() { 4281149242, 4281544001, 4281872965, + 4282136138, 4283057240, 4284636016, 4286280842, @@ -1288,6 +1344,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4279697673, 4280353808, 4280550930, 4280748053, @@ -1296,6 +1353,7 @@ void main() { 4282523436, 4283049266, 4283377974, + 4283706939, 4284693320, 4286468704, 4288244345, @@ -1313,6 +1371,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4278716170, 4279176721, 4279373844, 4279505686, @@ -1321,6 +1380,7 @@ void main() { 4281018669, 4281413683, 4281742392, + 4282005564, 4282926666, 4284505442, 4286150266, @@ -1338,6 +1398,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4278715917, 4279176468, 4279373847, 4279505434, @@ -1346,6 +1407,7 @@ void main() { 4281018673, 4281478968, 4281742140, + 4282071104, 4282991950, 4284570982, 4286215551, @@ -1363,6 +1425,7 @@ void main() { 4294966271, 4294967295, 4278190080, + 4279894016, 4280811521, 4281139201, 4281401345, @@ -1371,6 +1434,7 @@ void main() { 4284219396, 4285071365, 4285595653, + 4286119942, 4287823882, 4290386458, 4292753200, diff --git a/test/flex_scheme_variant_test.dart b/test/flex_scheme_variant_test.dart new file mode 100644 index 0000000..5cd268e --- /dev/null +++ b/test/flex_scheme_variant_test.dart @@ -0,0 +1,57 @@ +import 'package:flex_seed_scheme/flex_seed_scheme.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + //**************************************************************************** + // FlexSchemeVariant unit tests. + //**************************************************************************** + group('FSVA1: WITH FlexSchemeVariant ', () { + const Brightness brightness = Brightness.light; + FlexTones tones; + for (final FlexSchemeVariant variant in FlexSchemeVariant.values) { + final FlexTones flexTones = variant.tones(brightness); + + test( + 'FSVA1.01: GIVEN a FlexSchemeVariant EXPECT variant to return ' + 'correct tones for the FlexSchemeVariant', () { + switch (variant) { + case FlexSchemeVariant.tonalSpot: + case FlexSchemeVariant.fidelity: + case FlexSchemeVariant.monochrome: + case FlexSchemeVariant.neutral: + case FlexSchemeVariant.vibrant: + case FlexSchemeVariant.expressive: + case FlexSchemeVariant.content: + case FlexSchemeVariant.rainbow: + case FlexSchemeVariant.fruitSalad: + case FlexSchemeVariant.material: + tones = FlexTones.material(brightness); + case FlexSchemeVariant.material3Legacy: + tones = FlexTones.material3Legacy(brightness); + case FlexSchemeVariant.soft: + tones = FlexTones.soft(brightness); + case FlexSchemeVariant.vivid: + tones = FlexTones.vivid(brightness); + case FlexSchemeVariant.vividSurfaces: + tones = FlexTones.vividSurfaces(brightness); + case FlexSchemeVariant.highContrast: + tones = FlexTones.highContrast(brightness); + case FlexSchemeVariant.ultraContrast: + tones = FlexTones.ultraContrast(brightness); + case FlexSchemeVariant.jolly: + tones = FlexTones.jolly(brightness); + case FlexSchemeVariant.vividBackground: + tones = FlexTones.vividBackground(brightness); + case FlexSchemeVariant.oneHue: + tones = FlexTones.oneHue(brightness); + case FlexSchemeVariant.candyPop: + tones = FlexTones.candyPop(brightness); + case FlexSchemeVariant.chroma: + tones = FlexTones.chroma(brightness); + } + expect(flexTones, tones); + }); + } + }); +} diff --git a/test/flex_seed_scheme_test.dart b/test/flex_seed_scheme_test.dart index 0b98161..e00bacc 100644 --- a/test/flex_seed_scheme_test.dart +++ b/test/flex_seed_scheme_test.dart @@ -1,4 +1,5 @@ import 'package:flex_seed_scheme/flex_seed_scheme.dart'; +import 'package:flex_seed_scheme/src/mcu/dynamiccolor/material_dynamic_colors.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -20,29 +21,40 @@ void main() { test( 'FCS7.001-l: GIVEN a SeedColorScheme.fromSeeds using only one seed ' 'EXPECT equal to ColorScheme.fromSeed using same color as key.', () { + final ColorScheme flex = SeedColorScheme.fromSeeds( + brightness: Brightness.light, + primaryKey: primarySeedColor, + ); + + final ColorScheme flutter = ColorScheme.fromSeed( + brightness: Brightness.light, + seedColor: primarySeedColor, + ); + // print('flex : $flex'); + // print('flutter: $flutter'); + // const Color flexColor = Color(0xff6750a4); + // const Color flutterColor = Color(0xff65558f); + expect( - SeedColorScheme.fromSeeds( - brightness: Brightness.light, - primaryKey: primarySeedColor, - ), - equals(ColorScheme.fromSeed( - brightness: Brightness.light, - seedColor: primarySeedColor, - )), + flex, + equals(flutter), ); }); test( 'FCS7.001-d: GIVEN a ColorScheme.fromSeeds using only one seed ' 'EXPECT equal to ColorScheme.fromSeed using same color as key.', () { + final ColorScheme flex = SeedColorScheme.fromSeeds( + brightness: Brightness.dark, + primaryKey: primarySeedColor, + ); + + final ColorScheme flutter = ColorScheme.fromSeed( + brightness: Brightness.dark, + seedColor: primarySeedColor, + ); expect( - SeedColorScheme.fromSeeds( - brightness: Brightness.dark, - primaryKey: primarySeedColor, - ), - equals(ColorScheme.fromSeed( - brightness: Brightness.dark, - seedColor: primarySeedColor, - )), + flex, + equals(flutter), ); }); // Custom tests seed tests. We don't have any real refs to lock them @@ -60,7 +72,7 @@ void main() { ).toString(minLevel: DiagnosticLevel.fine), equalsIgnoringHashCodes( // ignore: lines_longer_than_80_chars - 'ColorScheme#00000(brightness: Brightness.light, primary: Color(0xff6750a4), onPrimary: Color(0xffffffff), primaryContainer: Color(0xffe9ddff), onPrimaryContainer: Color(0xff22005d), secondary: Color(0xff555f71), onSecondary: Color(0xffffffff), secondaryContainer: Color(0xffd9e3f8), onSecondaryContainer: Color(0xff121c2b), tertiary: Color(0xff7e5260), onTertiary: Color(0xffffffff), tertiaryContainer: Color(0xffffd9e3), onTertiaryContainer: Color(0xff31101d), error: Color(0xffba1a1a), onError: Color(0xffffffff), errorContainer: Color(0xffffdad6), onErrorContainer: Color(0xff410002), background: Color(0xfffffbff), onBackground: Color(0xff1c1b1e), surface: Color(0xfffffbff), onSurface: Color(0xff1c1b1e), surfaceVariant: Color(0xffe7e0eb), onSurfaceVariant: Color(0xff49454e), outline: Color(0xff7a757f), outlineVariant: Color(0xffcac4cf), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xff313033), onInverseSurface: Color(0xfff4eff4), inversePrimary: Color(0xffcfbcff), surfaceTint: Color(0xff6750a4))', + 'ColorScheme#00000(brightness: Brightness.light, primary: Color(0xff65558f), onPrimary: Color(0xffffffff), primaryContainer: Color(0xffe9ddff), onPrimaryContainer: Color(0xff201047), primaryFixed: Color(0xffe9ddff), primaryFixedDim: Color(0xffcfbdfe), onPrimaryFixed: Color(0xff201047), onPrimaryFixedVariant: Color(0xff4d3d75), secondary: Color(0xff555f71), onSecondary: Color(0xffffffff), secondaryContainer: Color(0xffd9e3f8), onSecondaryContainer: Color(0xff121c2b), secondaryFixed: Color(0xffd9e3f8), secondaryFixedDim: Color(0xffbdc7dc), onSecondaryFixed: Color(0xff121c2b), onSecondaryFixedVariant: Color(0xff3d4758), tertiary: Color(0xff7e5260), onTertiary: Color(0xffffffff), tertiaryContainer: Color(0xffffd9e3), onTertiaryContainer: Color(0xff31101d), tertiaryFixed: Color(0xffffd9e3), tertiaryFixedDim: Color(0xffefb8c8), onTertiaryFixed: Color(0xff31101d), onTertiaryFixedVariant: Color(0xff633b48), error: Color(0xffba1a1a), onError: Color(0xffffffff), errorContainer: Color(0xffffdad6), onErrorContainer: Color(0xff410002), surface: Color(0xfffdf7ff), onSurface: Color(0xff1d1b20), surfaceDim: Color(0xffded8e0), surfaceBright: Color(0xfffdf7ff), surfaceContainerLowest: Color(0xffffffff), surfaceContainerLow: Color(0xfff8f2fa), surfaceContainer: Color(0xfff2ecf4), surfaceContainerHigh: Color(0xffece6ee), surfaceContainerHighest: Color(0xffe6e0e9), onSurfaceVariant: Color(0xff49454e), outline: Color(0xff7a757f), outlineVariant: Color(0xffcac4cf), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xff322f35), onInverseSurface: Color(0xfff5eff7), inversePrimary: Color(0xffcfbdfe), surfaceTint: Color(0xff65558f), background: Color(0xfffdf7ff), onBackground: Color(0xff1d1b20), surfaceVariant: Color(0xffe7e0eb))', ), ); }); @@ -75,7 +87,7 @@ void main() { ).toString(minLevel: DiagnosticLevel.fine), equalsIgnoringHashCodes( // ignore: lines_longer_than_80_chars - 'ColorScheme#00000(brightness: Brightness.dark, primary: Color(0xffcfbcff), onPrimary: Color(0xff381e72), primaryContainer: Color(0xff4f378a), onPrimaryContainer: Color(0xffe9ddff), secondary: Color(0xffbdc7dc), onSecondary: Color(0xff273141), secondaryContainer: Color(0xff3d4758), onSecondaryContainer: Color(0xffd9e3f8), tertiary: Color(0xffefb8c8), onTertiary: Color(0xff4a2532), tertiaryContainer: Color(0xff633b48), onTertiaryContainer: Color(0xffffd9e3), error: Color(0xffffb4ab), onError: Color(0xff690005), errorContainer: Color(0xff93000a), onErrorContainer: Color(0xffffb4ab), background: Color(0xff1c1b1e), onBackground: Color(0xffe6e1e6), surface: Color(0xff1c1b1e), onSurface: Color(0xffe6e1e6), surfaceVariant: Color(0xff49454e), onSurfaceVariant: Color(0xffcac4cf), outline: Color(0xff948f99), outlineVariant: Color(0xff49454e), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xffe6e1e6), onInverseSurface: Color(0xff313033), inversePrimary: Color(0xff6750a4), surfaceTint: Color(0xffcfbcff))', + 'ColorScheme#00000(brightness: Brightness.dark, primary: Color(0xffcfbdfe), onPrimary: Color(0xff36275d), primaryContainer: Color(0xff4d3d75), onPrimaryContainer: Color(0xffe9ddff), primaryFixed: Color(0xffe9ddff), primaryFixedDim: Color(0xffcfbdfe), onPrimaryFixed: Color(0xff201047), onPrimaryFixedVariant: Color(0xff4d3d75), secondary: Color(0xffbdc7dc), onSecondary: Color(0xff273141), secondaryContainer: Color(0xff3d4758), onSecondaryContainer: Color(0xffd9e3f8), secondaryFixed: Color(0xffd9e3f8), secondaryFixedDim: Color(0xffbdc7dc), onSecondaryFixed: Color(0xff121c2b), onSecondaryFixedVariant: Color(0xff3d4758), tertiary: Color(0xffefb8c8), onTertiary: Color(0xff4a2532), tertiaryContainer: Color(0xff633b48), onTertiaryContainer: Color(0xffffd9e3), tertiaryFixed: Color(0xffffd9e3), tertiaryFixedDim: Color(0xffefb8c8), onTertiaryFixed: Color(0xff31101d), onTertiaryFixedVariant: Color(0xff633b48), error: Color(0xffffb4ab), onError: Color(0xff690005), errorContainer: Color(0xff93000a), onErrorContainer: Color(0xffffdad6), surface: Color(0xff141218), onSurface: Color(0xffe6e0e9), surfaceDim: Color(0xff141218), surfaceBright: Color(0xff3b383e), surfaceContainerLowest: Color(0xff0f0d13), surfaceContainerLow: Color(0xff1d1b20), surfaceContainer: Color(0xff211f24), surfaceContainerHigh: Color(0xff2b292f), surfaceContainerHighest: Color(0xff36343a), onSurfaceVariant: Color(0xffcac4cf), outline: Color(0xff948f99), outlineVariant: Color(0xff49454e), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xffe6e0e9), onInverseSurface: Color(0xff322f35), inversePrimary: Color(0xff65558f), surfaceTint: Color(0xffcfbdfe), background: Color(0xff141218), onBackground: Color(0xffe6e0e9), surfaceVariant: Color(0xff49454e))', ), ); }); @@ -92,7 +104,7 @@ void main() { ).toString(minLevel: DiagnosticLevel.fine), equalsIgnoringHashCodes( // ignore: lines_longer_than_80_chars - 'ColorScheme#00000(brightness: Brightness.light, primary: Color(0xff6750a4), onPrimary: Color(0xffffffff), primaryContainer: Color(0xffe9ddff), onPrimaryContainer: Color(0xff22005d), secondary: Color(0xff555f71), onSecondary: Color(0xffffffff), secondaryContainer: Color(0xffd9e3f8), onSecondaryContainer: Color(0xff121c2b), tertiary: Color(0xff4f6442), onTertiary: Color(0xffffffff), tertiaryContainer: Color(0xffd1eabe), onTertiaryContainer: Color(0xff0d2005), error: Color(0xffba1a1a), onError: Color(0xffffffff), errorContainer: Color(0xffffdad6), onErrorContainer: Color(0xff410002), background: Color(0xfffffbff), onBackground: Color(0xff1c1b1e), surface: Color(0xfffffbff), onSurface: Color(0xff1c1b1e), surfaceVariant: Color(0xffe7e0eb), onSurfaceVariant: Color(0xff49454e), outline: Color(0xff7a757f), outlineVariant: Color(0xffcac4cf), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xff313033), onInverseSurface: Color(0xfff4eff4), inversePrimary: Color(0xffcfbcff), surfaceTint: Color(0xff6750a4))', + 'ColorScheme#00000(brightness: Brightness.light, primary: Color(0xff65558f), onPrimary: Color(0xffffffff), primaryContainer: Color(0xffe9ddff), onPrimaryContainer: Color(0xff201047), primaryFixed: Color(0xffe9ddff), primaryFixedDim: Color(0xffcfbdfe), onPrimaryFixed: Color(0xff201047), onPrimaryFixedVariant: Color(0xff4d3d75), secondary: Color(0xff555f71), onSecondary: Color(0xffffffff), secondaryContainer: Color(0xffd9e3f8), onSecondaryContainer: Color(0xff121c2b), secondaryFixed: Color(0xffd9e3f8), secondaryFixedDim: Color(0xffbdc7dc), onSecondaryFixed: Color(0xff121c2b), onSecondaryFixedVariant: Color(0xff3d4758), tertiary: Color(0xff4f6442), onTertiary: Color(0xffffffff), tertiaryContainer: Color(0xffd1eabe), onTertiaryContainer: Color(0xff0d2005), tertiaryFixed: Color(0xffd1eabe), tertiaryFixedDim: Color(0xffb5cea4), onTertiaryFixed: Color(0xff0d2005), onTertiaryFixedVariant: Color(0xff384c2c), error: Color(0xffba1a1a), onError: Color(0xffffffff), errorContainer: Color(0xffffdad6), onErrorContainer: Color(0xff410002), surface: Color(0xfffdf7ff), onSurface: Color(0xff1d1b20), surfaceDim: Color(0xffded8e0), surfaceBright: Color(0xfffdf7ff), surfaceContainerLowest: Color(0xffffffff), surfaceContainerLow: Color(0xfff8f2fa), surfaceContainer: Color(0xfff2ecf4), surfaceContainerHigh: Color(0xffece6ee), surfaceContainerHighest: Color(0xffe6e0e9), onSurfaceVariant: Color(0xff49454e), outline: Color(0xff7a757f), outlineVariant: Color(0xffcac4cf), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xff322f35), onInverseSurface: Color(0xfff5eff7), inversePrimary: Color(0xffcfbdfe), surfaceTint: Color(0xff65558f), background: Color(0xfffdf7ff), onBackground: Color(0xff1d1b20), surfaceVariant: Color(0xffe7e0eb))', ), ); }); @@ -108,7 +120,7 @@ void main() { ).toString(minLevel: DiagnosticLevel.fine), equalsIgnoringHashCodes( // ignore: lines_longer_than_80_chars - 'ColorScheme#00000(brightness: Brightness.dark, primary: Color(0xffcfbcff), onPrimary: Color(0xff381e72), primaryContainer: Color(0xff4f378a), onPrimaryContainer: Color(0xffe9ddff), secondary: Color(0xffbdc7dc), onSecondary: Color(0xff273141), secondaryContainer: Color(0xff3d4758), onSecondaryContainer: Color(0xffd9e3f8), tertiary: Color(0xffb5cea4), onTertiary: Color(0xff223518), tertiaryContainer: Color(0xff384c2c), onTertiaryContainer: Color(0xffd1eabe), error: Color(0xffffb4ab), onError: Color(0xff690005), errorContainer: Color(0xff93000a), onErrorContainer: Color(0xffffb4ab), background: Color(0xff1c1b1e), onBackground: Color(0xffe6e1e6), surface: Color(0xff1c1b1e), onSurface: Color(0xffe6e1e6), surfaceVariant: Color(0xff49454e), onSurfaceVariant: Color(0xffcac4cf), outline: Color(0xff948f99), outlineVariant: Color(0xff49454e), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xffe6e1e6), onInverseSurface: Color(0xff313033), inversePrimary: Color(0xff6750a4), surfaceTint: Color(0xffcfbcff))', + 'ColorScheme#00000(brightness: Brightness.dark, primary: Color(0xffcfbdfe), onPrimary: Color(0xff36275d), primaryContainer: Color(0xff4d3d75), onPrimaryContainer: Color(0xffe9ddff), primaryFixed: Color(0xffe9ddff), primaryFixedDim: Color(0xffcfbdfe), onPrimaryFixed: Color(0xff201047), onPrimaryFixedVariant: Color(0xff4d3d75), secondary: Color(0xffbdc7dc), onSecondary: Color(0xff273141), secondaryContainer: Color(0xff3d4758), onSecondaryContainer: Color(0xffd9e3f8), secondaryFixed: Color(0xffd9e3f8), secondaryFixedDim: Color(0xffbdc7dc), onSecondaryFixed: Color(0xff121c2b), onSecondaryFixedVariant: Color(0xff3d4758), tertiary: Color(0xffb5cea4), onTertiary: Color(0xff223518), tertiaryContainer: Color(0xff384c2c), onTertiaryContainer: Color(0xffd1eabe), tertiaryFixed: Color(0xffd1eabe), tertiaryFixedDim: Color(0xffb5cea4), onTertiaryFixed: Color(0xff0d2005), onTertiaryFixedVariant: Color(0xff384c2c), error: Color(0xffffb4ab), onError: Color(0xff690005), errorContainer: Color(0xff93000a), onErrorContainer: Color(0xffffdad6), surface: Color(0xff141218), onSurface: Color(0xffe6e0e9), surfaceDim: Color(0xff141218), surfaceBright: Color(0xff3b383e), surfaceContainerLowest: Color(0xff0f0d13), surfaceContainerLow: Color(0xff1d1b20), surfaceContainer: Color(0xff211f24), surfaceContainerHigh: Color(0xff2b292f), surfaceContainerHighest: Color(0xff36343a), onSurfaceVariant: Color(0xffcac4cf), outline: Color(0xff948f99), outlineVariant: Color(0xff49454e), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xffe6e0e9), onInverseSurface: Color(0xff322f35), inversePrimary: Color(0xff65558f), surfaceTint: Color(0xffcfbdfe), background: Color(0xff141218), onBackground: Color(0xffe6e0e9), surfaceVariant: Color(0xff49454e))', ), ); }); @@ -127,7 +139,7 @@ void main() { ).toString(minLevel: DiagnosticLevel.fine), equalsIgnoringHashCodes( // ignore: lines_longer_than_80_chars - 'ColorScheme#00000(brightness: Brightness.light, primary: Color(0xff3a0a8c), onPrimary: Color(0xffffffff), primaryContainer: Color(0xffe9ddff), onPrimaryContainer: Color(0xff160041), secondary: Color(0xff005eb2), onSecondary: Color(0xffffffff), secondaryContainer: Color(0xffd5e3ff), onSecondaryContainer: Color(0xff001129), tertiary: Color(0xff1b5200), onTertiary: Color(0xffffffff), tertiaryContainer: Color(0xffceffb2), onTertiaryContainer: Color(0xff031500), error: Color(0xffba1a1a), onError: Color(0xffffffff), errorContainer: Color(0xffffedea), onErrorContainer: Color(0xff2d0001), background: Color(0xfffffbff), onBackground: Color(0xff000000), surface: Color(0xfffffbff), onSurface: Color(0xff000000), surfaceVariant: Color(0xfff5eff7), onSurfaceVariant: Color(0xff1d1b20), outline: Color(0xff605d64), outlineVariant: Color(0xffaea9b1), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xff313032), onInverseSurface: Color(0xfffffbff), inversePrimary: Color(0xffe9ddff), surfaceTint: Color(0xff3a0a8c))', + 'ColorScheme#00000(brightness: Brightness.light, primary: Color(0xff3a0a8c), onPrimary: Color(0xffffffff), primaryContainer: Color(0xffe9ddff), onPrimaryContainer: Color(0xff160041), primaryFixed: Color(0xffe9ddff), primaryFixedDim: Color(0xffcfbcff), onPrimaryFixed: Color(0xff22005d), onPrimaryFixedVariant: Color(0xff512da3), secondary: Color(0xff005eb2), onSecondary: Color(0xffffffff), secondaryContainer: Color(0xffd5e3ff), onSecondaryContainer: Color(0xff001129), secondaryFixed: Color(0xffd5e3ff), secondaryFixedDim: Color(0xffa7c8ff), onSecondaryFixed: Color(0xff001b3b), onSecondaryFixedVariant: Color(0xff004788), tertiary: Color(0xff1b5200), onTertiary: Color(0xffffffff), tertiaryContainer: Color(0xffcdffb0), onTertiaryContainer: Color(0xff031500), tertiaryFixed: Color(0xffa3f879), tertiaryFixedDim: Color(0xff88db60), onTertiaryFixed: Color(0xff072100), onTertiaryFixedVariant: Color(0xff1b5200), error: Color(0xffba1a1a), onError: Color(0xffffffff), errorContainer: Color(0xffffedea), onErrorContainer: Color(0xff2d0001), surface: Color(0xffffffff), onSurface: Color(0xff000000), surfaceDim: Color(0xffddd9dc), surfaceBright: Color(0xfffdf8fb), surfaceContainerLowest: Color(0xffffffff), surfaceContainerLow: Color(0xfffdf8fb), surfaceContainer: Color(0xfff7f2f5), surfaceContainerHigh: Color(0xffece7ea), surfaceContainerHighest: Color(0xffe6e1e4), onSurfaceVariant: Color(0xff141218), outline: Color(0xff605d64), outlineVariant: Color(0xffaea9b1), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xff313032), onInverseSurface: Color(0xfffffbff), inversePrimary: Color(0xffe9ddff), surfaceTint: Color(0xff3a0a8c), background: Color(0xffffffff), onBackground: Color(0xff000000), surfaceVariant: Color(0xfff8f2fa))', ), ); }); @@ -145,7 +157,7 @@ void main() { ).toString(minLevel: DiagnosticLevel.fine), equalsIgnoringHashCodes( // ignore: lines_longer_than_80_chars - 'ColorScheme#00000(brightness: Brightness.dark, primary: Color(0xffe9ddff), onPrimary: Color(0xff160041), primaryContainer: Color(0xff512da3), onPrimaryContainer: Color(0xfffdf7ff), secondary: Color(0xffebf1ff), onSecondary: Color(0xff001129), secondaryContainer: Color(0xff004788), onSecondaryContainer: Color(0xfff9f9ff), tertiary: Color(0xffceffb2), onTertiary: Color(0xff031500), tertiaryContainer: Color(0xff1b5200), onTertiaryContainer: Color(0xffeeffde), error: Color(0xffffb4ab), onError: Color(0xff2d0001), errorContainer: Color(0xff93000a), onErrorContainer: Color(0xfffff8f7), background: Color(0xff111013), onBackground: Color(0xfffffbff), surface: Color(0xff111013), onSurface: Color(0xfffffbff), surfaceVariant: Color(0xff322f35), onSurfaceVariant: Color(0xfff5eff7), outline: Color(0xffcac5cc), outlineVariant: Color(0xff79767d), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xffe6e1e4), onInverseSurface: Color(0xff1c1b1e), inversePrimary: Color(0xff6948bc), surfaceTint: Color(0xffe9ddff))', + 'ColorScheme#00000(brightness: Brightness.dark, primary: Color(0xffe9ddff), onPrimary: Color(0xff0a0028), primaryContainer: Color(0xff512da3), onPrimaryContainer: Color(0xfffdf7ff), primaryFixed: Color(0xffe9ddff), primaryFixedDim: Color(0xffcfbcff), onPrimaryFixed: Color(0xff22005d), onPrimaryFixedVariant: Color(0xff512da3), secondary: Color(0xffebf1ff), onSecondary: Color(0xff000717), secondaryContainer: Color(0xff004788), onSecondaryContainer: Color(0xfff9f9ff), secondaryFixed: Color(0xffd5e3ff), secondaryFixedDim: Color(0xffa7c8ff), onSecondaryFixed: Color(0xff001b3b), onSecondaryFixedVariant: Color(0xff004788), tertiary: Color(0xffcdffb0), onTertiary: Color(0xff010a00), tertiaryContainer: Color(0xff1b5200), onTertiaryContainer: Color(0xffeeffde), tertiaryFixed: Color(0xffa3f879), tertiaryFixedDim: Color(0xff88db60), onTertiaryFixed: Color(0xff072100), onTertiaryFixedVariant: Color(0xff1b5200), error: Color(0xffffb4ab), onError: Color(0xff1a0000), errorContainer: Color(0xff93000a), onErrorContainer: Color(0xfffff8f7), surface: Color(0xff080709), onSurface: Color(0xfffffbff), surfaceDim: Color(0xff141315), surfaceBright: Color(0xff3a383b), surfaceContainerLowest: Color(0xff000000), surfaceContainerLow: Color(0xff141315), surfaceContainer: Color(0xff201f22), surfaceContainerHigh: Color(0xff2b292c), surfaceContainerHighest: Color(0xff363437), onSurfaceVariant: Color(0xfff5eff7), outline: Color(0xffcac5cc), outlineVariant: Color(0xff79767d), shadow: Color(0xff000000), scrim: Color(0xff000000), inverseSurface: Color(0xffe6e1e4), onInverseSurface: Color(0xff1c1b1e), inversePrimary: Color(0xff6948bc), surfaceTint: Color(0xffe9ddff), background: Color(0xff080709), onBackground: Color(0xfffffbff), surfaceVariant: Color(0xff322f35))', ), ); }); @@ -163,10 +175,16 @@ void main() { ); expect(scheme.onPrimary, Colors.white); expect(scheme.onPrimaryContainer, Colors.black); + expect(scheme.onPrimaryFixed, Colors.black); + expect(scheme.onPrimaryFixedVariant, Colors.black); expect(scheme.onSecondary, Colors.white); expect(scheme.onSecondaryContainer, Colors.black); + expect(scheme.onSecondaryFixed, Colors.black); + expect(scheme.onSecondaryFixedVariant, Colors.black); expect(scheme.onTertiary, Colors.white); expect(scheme.onTertiaryContainer, Colors.black); + expect(scheme.onTertiaryFixed, Colors.black); + expect(scheme.onTertiaryFixedVariant, Colors.black); expect(scheme.onError, Colors.white); expect(scheme.onErrorContainer, Colors.black); }); @@ -204,10 +222,16 @@ void main() { ); expect(scheme.onPrimary, Colors.black); expect(scheme.onPrimaryContainer, Colors.white); + expect(scheme.onPrimaryFixed, Colors.black); + expect(scheme.onPrimaryFixedVariant, Colors.black); expect(scheme.onSecondary, Colors.black); expect(scheme.onSecondaryContainer, Colors.white); + expect(scheme.onSecondaryFixed, Colors.black); + expect(scheme.onSecondaryFixedVariant, Colors.black); expect(scheme.onTertiary, Colors.black); expect(scheme.onTertiaryContainer, Colors.white); + expect(scheme.onTertiaryFixed, Colors.black); + expect(scheme.onTertiaryFixedVariant, Colors.black); expect(scheme.onError, Colors.black); expect(scheme.onErrorContainer, Colors.white); }); @@ -248,7 +272,7 @@ void main() { ); expect(scheme.onBackground, Colors.black); expect(scheme.onSurface, Colors.black); - expect(scheme.onSurfaceVariant, Colors.black); + // expect(scheme.onSurfaceVariant, Colors.black); expect(scheme.onInverseSurface, Colors.white); }); test( @@ -489,7 +513,7 @@ void main() { 'FCS7.009-l: GIVEN a SeedColorScheme.fromSeeds using five seeds ' 'and tones map FlexTones.material for a light scheme with ' 'error no neutral and variant chroma set ' - 'EXPECT scheme equal to neutral 4 and variant 8', () { + 'EXPECT scheme equal to neutral 6 and variant 8', () { final ColorScheme scheme = SeedColorScheme.fromSeeds( brightness: Brightness.light, primaryKey: primarySeedColor, @@ -507,7 +531,7 @@ void main() { neutralKey: secondarySeedColor, neutralVariantKey: tertiarySeedColor, tones: FlexTones.material(Brightness.light).copyWith( - neutralChroma: 4, + neutralChroma: 6, neutralVariantChroma: 8, ), ); @@ -517,7 +541,7 @@ void main() { 'FCS7.009-d: GIVEN a SeedColorScheme.fromSeeds using five seeds ' 'and tones map FlexTones.material for a dark scheme with ' 'error no neutral and variant chroma set ' - 'EXPECT scheme equal to neutral 4 and variant 8', () { + 'EXPECT scheme equal to neutral 8 and variant 8', () { final ColorScheme scheme = SeedColorScheme.fromSeeds( brightness: Brightness.dark, primaryKey: primarySeedColor, @@ -535,7 +559,7 @@ void main() { neutralKey: secondarySeedColor, neutralVariantKey: tertiarySeedColor, tones: FlexTones.material(Brightness.dark).copyWith( - neutralChroma: 4, + neutralChroma: 6, neutralVariantChroma: 8, ), ); @@ -675,5 +699,178 @@ void main() { ); expect(scheme, scheme2); }); + test( + 'FCS7.012: GIVEN a SeedColorScheme.fromSeeds using three seeds ' + 'and no tones or variant ' + 'EXPECT same as when null assigned to both variant and tones', () { + final ColorScheme scheme = SeedColorScheme.fromSeeds( + brightness: Brightness.dark, + primaryKey: primarySeedColor, + secondaryKey: secondarySeedColor, + tertiaryKey: tertiarySeedColor, + ); + final ColorScheme scheme2 = SeedColorScheme.fromSeeds( + brightness: Brightness.dark, + primaryKey: primarySeedColor, + secondaryKey: secondarySeedColor, + tertiaryKey: tertiarySeedColor, + variant: null, + tones: null, + ); + expect(scheme, equals(scheme2)); + }); + test( + 'FCS7.013: GIVEN a SeedColorScheme.fromSeeds using three seeds ' + 'and variant vivid ' + 'EXPECT same as when null assigned to variant and tones ' + 'using FlexTones.vivid.', () { + final ColorScheme scheme = SeedColorScheme.fromSeeds( + brightness: Brightness.dark, + primaryKey: primarySeedColor, + secondaryKey: secondarySeedColor, + tertiaryKey: tertiarySeedColor, + variant: FlexSchemeVariant.vivid, + ); + final ColorScheme scheme2 = SeedColorScheme.fromSeeds( + brightness: Brightness.dark, + primaryKey: primarySeedColor, + secondaryKey: secondarySeedColor, + tertiaryKey: tertiarySeedColor, + tones: FlexTones.vivid(Brightness.dark), + ); + expect(scheme, equals(scheme2)); + }); + + // ColorScheme test with DynamicScheme + + test( + 'FCS7.013: GIVEN Color values in SeedColorScheme.fromSeeds with ' + 'different variants EXPECT that it matches color values in ' + 'DynamicScheme when Flutter SDK scheme is used', () { + const Color seedColor = Colors.orange; + for (final FlexSchemeVariant schemeVariant in FlexSchemeVariant.values) { + final DynamicScheme dynamicScheme = SeedColorScheme.buildDynamicScheme( + Brightness.light, seedColor, schemeVariant); + final ColorScheme colorScheme = SeedColorScheme.fromSeeds( + primaryKey: seedColor, + variant: schemeVariant, + ); + + if (schemeVariant.isFlutterScheme) { + 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)); + } else { + expect(true, true); + } + } + }); }); } diff --git a/test/flex_tonal_palette_test.dart b/test/flex_tonal_palette_test.dart index 776244a..968981b 100644 --- a/test/flex_tonal_palette_test.dart +++ b/test/flex_tonal_palette_test.dart @@ -1,4 +1,5 @@ import 'package:flex_seed_scheme/src/flex/flex_tonal_palette.dart'; +import 'package:flex_seed_scheme/src/mcu/hct/hct.dart'; import 'package:flex_seed_scheme/src/mcu/palettes/tonal_palette.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -152,7 +153,7 @@ void main() { m4.toString(), equals( // ignore: lines_longer_than_80_chars - 'FlexTonalPalette.fromList({0: 4278190080, 5: 4280616704, 10: 4281798144, 20: 4284095488, 30: 4286524160, 40: 4288692500, 50: 4290795563, 60: 4292964674, 70: 4294937692, 80: 4294948249, 90: 4294958030, 95: 4294962663, 98: 4294965494, 99: 4294966271, 100: 4294967295}, FlexPaletteType.common)'), + 'FlexTonalPalette.fromList([4278190080, 4280616704, 4281798144, 4284095488, 4286524160, 4288692500, 4290795563, 4292964674, 4294937692, 4294948249, 4294958030, 4294962663, 4294965494, 4294966271, 4294967295], FlexPaletteType.common)'), ); }); test( @@ -207,14 +208,23 @@ void main() { m5.get(FlexTonalPalette.commonTones[i]), equals(m5List[i]), ); + expect( + m5.getHct(FlexTonalPalette.commonTones[i].toDouble()).toInt(), + equals(m5List[i]), + ); } }); test( 'FTP1.U10: GIVEN a FlexTonalPalette.fromList ' - 'EXPECT accessing none existing to tone to throw argument error', () { + 'EXPECT accessing none existing to tone to return a computed implied ' + 'tone value', () { expect( - () => m5.get(7), - throwsArgumentError, + m5.getHct(7).toInt(), + 4281141760, + ); + expect( + m5.get(7), + 4281141760, ); }); // @@ -242,6 +252,7 @@ void main() { // m4, is tonal palette from list final FlexTonalPalette m4 = FlexTonalPalette.fromList(const [ 4278190080, + 4279567104, 4280354304, 4280616704, 4280879360, @@ -250,6 +261,7 @@ void main() { 4283373568, 4284095488, 4284555008, + 4285014528, 4286524160, 4288692500, 4290795563, @@ -270,6 +282,7 @@ void main() { // m5, is tonal palette from list, same as m4 final FlexTonalPalette m5 = FlexTonalPalette.fromList(const [ 4278190080, + 4279567104, 4280354304, 4280616704, 4280879360, @@ -278,6 +291,7 @@ void main() { 4283373568, 4284095488, 4284555008, + 4285014528, 4286524160, 4288692500, 4290795563, @@ -368,12 +382,14 @@ void main() { final List m1List = m1.asList; final List m1NoCustomTonesList = []; for (int i = 0; i <= FlexTonalPalette.extendedTones.length - 1; i++) { - if (FlexTonalPalette.extendedTones[i] != 4 && + if (FlexTonalPalette.extendedTones[i] != 2 && + FlexTonalPalette.extendedTones[i] != 4 && FlexTonalPalette.extendedTones[i] != 5 && FlexTonalPalette.extendedTones[i] != 6 && FlexTonalPalette.extendedTones[i] != 12 && FlexTonalPalette.extendedTones[i] != 17 && FlexTonalPalette.extendedTones[i] != 22 && + FlexTonalPalette.extendedTones[i] != 24 && FlexTonalPalette.extendedTones[i] != 87 && FlexTonalPalette.extendedTones[i] != 92 && FlexTonalPalette.extendedTones[i] != 94 && @@ -406,7 +422,7 @@ void main() { m4.toString(), equals( // ignore: lines_longer_than_80_chars - 'FlexTonalPalette.fromList({0: 4278190080, 4: 4280354304, 5: 4280616704, 6: 4280879360, 10: 4281798144, 12: 4282257664, 17: 4283373568, 20: 4284095488, 22: 4284555008, 30: 4286524160, 40: 4288692500, 50: 4290795563, 60: 4292964674, 70: 4294937692, 80: 4294948249, 87: 4294955198, 90: 4294958030, 92: 4294959832, 94: 4294961634, 95: 4294962663, 96: 4294963692, 97: 4294964465, 98: 4294965494, 99: 4294966271, 100: 4294967295}, FlexPaletteType.extended)'), + 'FlexTonalPalette.fromList([4278190080, 4279567104, 4280354304, 4280616704, 4280879360, 4281798144, 4282257664, 4283373568, 4284095488, 4284555008, 4285014528, 4286524160, 4288692500, 4290795563, 4292964674, 4294937692, 4294948249, 4294955198, 4294958030, 4294959832, 4294961634, 4294962663, 4294963692, 4294964465, 4294965494, 4294966271, 4294967295], FlexPaletteType.extended)'), ); }); test( @@ -414,6 +430,7 @@ void main() { 'EXPECT each of its tones to match output asList via get', () { const List m1List = [ 4278190080, + 4279567104, 4280354304, 4280616704, 4280879360, @@ -422,6 +439,7 @@ void main() { 4283373568, 4284095488, 4284555008, + 4285014528, 4286524160, 4288692500, 4290795563, @@ -451,6 +469,7 @@ void main() { 'EXPECT each of its tones to match output asList via get', () { const List m5List = [ 4278190080, + 4279567104, 4280354304, 4280616704, 4280879360, @@ -459,6 +478,7 @@ void main() { 4283373568, 4284095488, 4284555008, + 4285014528, 4286524160, 4288692500, 4290795563, @@ -485,10 +505,37 @@ void main() { }); test( 'FTP2.U10: GIVEN a FlexTonalPalette.fromList extended ' - 'EXPECT accessing none existing to tone to throw argument error', () { + 'EXPECT accessing none existing tone to return implied computed ' + 'tone value', () { + expect( + m5.get(7), + 4281141760, + ); + }); + + /// + test( + 'FTP1.U11: GIVEN a FlexTonalPalette of and from HCT common tones ' + 'EXPECT equal tonal palettes', () { + final Hct hct = Hct.fromInt(4294961634); + final FlexTonalPalette tonal = FlexTonalPalette.of(hct.hue, hct.chroma); + final FlexTonalPalette tonalHct = FlexTonalPalette.fromHct(hct); + expect( + tonal, + tonalHct, + ); + }); + test( + 'FTP1.U12: GIVEN a FlexTonalPalette of and from HCT extended tones ' + 'EXPECT equal tonal palettes', () { + final Hct hct = Hct.fromInt(4294961634); + final FlexTonalPalette tonal = + FlexTonalPalette.of(hct.hue, hct.chroma, FlexPaletteType.extended); + final FlexTonalPalette tonalHct = + FlexTonalPalette.fromHct(hct, FlexPaletteType.extended); expect( - () => m5.get(7), - throwsArgumentError, + tonal, + tonalHct, ); }); }); diff --git a/test/flex_tones_test.dart b/test/flex_tones_test.dart index 7e325f8..d1f4fdc 100644 --- a/test/flex_tones_test.dart +++ b/test/flex_tones_test.dart @@ -16,24 +16,45 @@ void main() { onPrimaryTone: 100, primaryContainerTone: 90, onPrimaryContainerTone: 10, + primaryFixedTone: 90, + primaryFixedDimTone: 80, + onPrimaryFixedTone: 10, + onPrimaryFixedVariantTone: 30, + // secondaryTone: 40, onSecondaryTone: 100, secondaryContainerTone: 90, onSecondaryContainerTone: 10, + secondaryFixedTone: 90, + secondaryFixedDimTone: 80, + onSecondaryFixedTone: 10, + onSecondaryFixedVariantTone: 30, + // tertiaryTone: 40, onTertiaryTone: 100, tertiaryContainerTone: 90, onTertiaryContainerTone: 10, + tertiaryFixedTone: 90, + tertiaryFixedDimTone: 80, + onTertiaryFixedTone: 10, + onTertiaryFixedVariantTone: 30, + // errorTone: 40, onErrorTone: 100, errorContainerTone: 90, onErrorContainerTone: 10, - backgroundTone: 99, - onBackgroundTone: 10, - surfaceTone: 99, + // + surfaceTone: 98, + surfaceDimTone: 87, + surfaceBrightTone: 98, + surfaceContainerLowestTone: 100, + surfaceContainerLowTone: 96, + surfaceContainerTone: 94, + surfaceContainerHighTone: 92, + surfaceContainerHighestTone: 90, onSurfaceTone: 10, - surfaceVariantTone: 90, onSurfaceVariantTone: 30, + // outlineTone: 50, outlineVariantTone: 80, shadowTone: 0, @@ -42,6 +63,11 @@ void main() { onInverseSurfaceTone: 95, inversePrimaryTone: 80, surfaceTintTone: 40, + // Deprecated colors + backgroundTone: 98, + onBackgroundTone: 10, + surfaceVariantTone: 90, + // primaryChroma: null, primaryMinChroma: null, secondaryChroma: null, @@ -51,7 +77,7 @@ void main() { tertiaryHueRotation: null, errorChroma: null, errorMinChroma: null, - neutralChroma: 4, + neutralChroma: 6, neutralMinChroma: null, neutralVariantChroma: 8, neutralVariantMinChroma: null, @@ -130,24 +156,45 @@ void main() { onPrimaryTone: 100, primaryContainerTone: 90, onPrimaryContainerTone: 10, + primaryFixedTone: 90, + primaryFixedDimTone: 80, + onPrimaryFixedTone: 10, + onPrimaryFixedVariantTone: 30, + // secondaryTone: 40, onSecondaryTone: 100, secondaryContainerTone: 90, onSecondaryContainerTone: 10, + secondaryFixedTone: 90, + secondaryFixedDimTone: 80, + onSecondaryFixedTone: 10, + onSecondaryFixedVariantTone: 30, + // tertiaryTone: 40, onTertiaryTone: 100, tertiaryContainerTone: 90, onTertiaryContainerTone: 10, + tertiaryFixedTone: 90, + tertiaryFixedDimTone: 80, + onTertiaryFixedTone: 10, + onTertiaryFixedVariantTone: 30, + // errorTone: 40, onErrorTone: 100, errorContainerTone: 90, onErrorContainerTone: 10, - backgroundTone: 99, - onBackgroundTone: 10, - surfaceTone: 99, + // + surfaceTone: 98, + surfaceDimTone: 87, + surfaceBrightTone: 98, + surfaceContainerLowestTone: 100, + surfaceContainerLowTone: 96, + surfaceContainerTone: 94, + surfaceContainerHighTone: 92, + surfaceContainerHighestTone: 90, onSurfaceTone: 10, - surfaceVariantTone: 90, onSurfaceVariantTone: 30, + // outlineTone: 50, outlineVariantTone: 80, shadowTone: 0, @@ -156,15 +203,21 @@ void main() { onInverseSurfaceTone: 95, inversePrimaryTone: 80, surfaceTintTone: 40, + // Deprecated colors + backgroundTone: 98, + onBackgroundTone: 10, + surfaceVariantTone: 90, + // primaryChroma: null, primaryMinChroma: null, secondaryChroma: null, secondaryMinChroma: null, tertiaryChroma: null, tertiaryMinChroma: null, + tertiaryHueRotation: null, errorChroma: null, errorMinChroma: null, - neutralChroma: 4, + neutralChroma: 6, neutralMinChroma: null, neutralVariantChroma: 8, neutralVariantMinChroma: null, @@ -187,7 +240,7 @@ void main() { // equalsIgnoringHashCodes( // ignore: lines_longer_than_80_chars - 'FlexTones#00000(primaryTone: 40, onPrimaryTone: 100, primaryContainerTone: 90, onPrimaryContainerTone: 10, secondaryTone: 40, onSecondaryTone: 100, secondaryContainerTone: 90, onSecondaryContainerTone: 10, tertiaryTone: 40, onTertiaryTone: 100, tertiaryContainerTone: 90, onTertiaryContainerTone: 10, errorTone: 40, errorContainerTone: 90, onErrorContainerTone: 10, backgroundTone: 99, onBackgroundTone: 10, surfaceTone: 99, onSurfaceTone: 10, surfaceVariantTone: 90, onSurfaceVariantTone: 30, outlineTone: 50, outlineVariantTone: 80, shadowTone: 0, scrimTone: 0, inverseSurfaceTone: 20, onInverseSurfaceTone: 95, inversePrimaryTone: 80, surfaceTintTone: 40, primaryChroma: null, primaryMinChroma: null, secondaryChroma: null, secondaryMinChroma: null, tertiaryChroma: null, tertiaryHueRotation: null, tertiaryMinChroma: null, errorChroma: null, errorMinChroma: null, neutralChroma: 4.0, neutralMinChroma: null, neutralVariantChroma: 8.0, neutralVariantMinChroma: null, paletteType: common)')); + 'FlexTones#00000(primaryTone: 40, onPrimaryTone: 100, primaryContainerTone: 90, onPrimaryContainerTone: 10, primaryFixedTone: 90, primaryFixedDimTone: 80, onPrimaryFixedTone: 10, onPrimaryFixedVariantTone: 30, secondaryTone: 40, onSecondaryTone: 100, secondaryContainerTone: 90, onSecondaryContainerTone: 10, secondaryFixedTone: 90, secondaryFixedDimTone: 80, onSecondaryFixedTone: 10, onSecondaryFixedVariantTone: 30, tertiaryTone: 40, onTertiaryTone: 100, tertiaryContainerTone: 90, onTertiaryContainerTone: 10, tertiaryFixedTone: 90, tertiaryFixedDimTone: 80, onTertiaryFixedTone: 10, onTertiaryFixedVariantTone: 30, errorTone: 40, errorContainerTone: 90, onErrorContainerTone: 10, surfaceTone: 98, surfaceDimTone: 87, surfaceBrightTone: 98, surfaceContainerLowestTone: 100, surfaceContainerLowTone: 96, surfaceContainerTone: 94, surfaceContainerHighTone: 92, surfaceContainerHighestTone: 90, onSurfaceTone: 10, onSurfaceVariantTone: 30, outlineTone: 50, outlineVariantTone: 80, shadowTone: 0, scrimTone: 0, inverseSurfaceTone: 20, onInverseSurfaceTone: 95, inversePrimaryTone: 80, surfaceTintTone: 40, backgroundTone: 98, onBackgroundTone: 10, surfaceVariantTone: 90, primaryChroma: null, primaryMinChroma: null, secondaryChroma: null, secondaryMinChroma: null, tertiaryChroma: null, tertiaryHueRotation: null, tertiaryMinChroma: null, errorChroma: null, errorMinChroma: null, neutralChroma: 6.0, neutralMinChroma: null, neutralVariantChroma: 8.0, neutralVariantMinChroma: null, paletteType: extended)')); }); test( 'FTO1.11: Test toStringShort implemented via debugFillProperties ' @@ -219,24 +272,45 @@ void main() { onPrimaryTone: 100, primaryContainerTone: 90, onPrimaryContainerTone: 10, + primaryFixedTone: 90, + primaryFixedDimTone: 80, + onPrimaryFixedTone: 10, + onPrimaryFixedVariantTone: 30, + // secondaryTone: 40, onSecondaryTone: 100, secondaryContainerTone: 90, onSecondaryContainerTone: 10, + secondaryFixedTone: 90, + secondaryFixedDimTone: 80, + onSecondaryFixedTone: 10, + onSecondaryFixedVariantTone: 30, + // tertiaryTone: 40, onTertiaryTone: 100, tertiaryContainerTone: 90, onTertiaryContainerTone: 10, + tertiaryFixedTone: 90, + tertiaryFixedDimTone: 80, + onTertiaryFixedTone: 10, + onTertiaryFixedVariantTone: 30, + // errorTone: 40, onErrorTone: 100, errorContainerTone: 90, onErrorContainerTone: 10, - backgroundTone: 99, - onBackgroundTone: 10, - surfaceTone: 99, + // + surfaceTone: 98, + surfaceDimTone: 87, + surfaceBrightTone: 98, + surfaceContainerLowestTone: 100, + surfaceContainerLowTone: 96, + surfaceContainerTone: 94, + surfaceContainerHighTone: 92, + surfaceContainerHighestTone: 90, onSurfaceTone: 10, - surfaceVariantTone: 90, onSurfaceVariantTone: 30, + // outlineTone: 50, outlineVariantTone: 80, shadowTone: 0, @@ -245,6 +319,11 @@ void main() { onInverseSurfaceTone: 95, inversePrimaryTone: 80, surfaceTintTone: 40, + // Deprecated colors + backgroundTone: 98, + onBackgroundTone: 10, + surfaceVariantTone: 90, + // primaryChroma: null, primaryMinChroma: null, secondaryChroma: null, @@ -254,7 +333,7 @@ void main() { tertiaryHueRotation: null, errorChroma: null, errorMinChroma: null, - neutralChroma: 4, + neutralChroma: 6, neutralMinChroma: null, neutralVariantChroma: 8, neutralVariantMinChroma: null, @@ -271,24 +350,45 @@ void main() { onPrimaryTone: 20, primaryContainerTone: 30, onPrimaryContainerTone: 90, + primaryFixedTone: 90, + primaryFixedDimTone: 80, + onPrimaryFixedTone: 10, + onPrimaryFixedVariantTone: 30, + // secondaryTone: 80, onSecondaryTone: 20, secondaryContainerTone: 30, onSecondaryContainerTone: 90, + secondaryFixedTone: 90, + secondaryFixedDimTone: 80, + onSecondaryFixedTone: 10, + onSecondaryFixedVariantTone: 30, + // tertiaryTone: 80, onTertiaryTone: 20, tertiaryContainerTone: 30, onTertiaryContainerTone: 90, + tertiaryFixedTone: 90, + tertiaryFixedDimTone: 80, + onTertiaryFixedTone: 10, + onTertiaryFixedVariantTone: 30, + // errorTone: 80, onErrorTone: 20, errorContainerTone: 30, - onErrorContainerTone: 80, - backgroundTone: 10, - onBackgroundTone: 90, - surfaceTone: 10, + onErrorContainerTone: 90, + // + surfaceTone: 6, + surfaceDimTone: 6, + surfaceBrightTone: 24, + surfaceContainerLowestTone: 4, + surfaceContainerLowTone: 10, + surfaceContainerTone: 12, + surfaceContainerHighTone: 17, + surfaceContainerHighestTone: 22, onSurfaceTone: 90, - surfaceVariantTone: 30, onSurfaceVariantTone: 80, + // outlineTone: 60, outlineVariantTone: 30, shadowTone: 0, @@ -297,6 +397,11 @@ void main() { onInverseSurfaceTone: 20, inversePrimaryTone: 40, surfaceTintTone: 80, + // Deprecated colors + backgroundTone: 6, + onBackgroundTone: 90, + surfaceVariantTone: 30, + // primaryChroma: null, primaryMinChroma: null, secondaryChroma: null, @@ -306,7 +411,7 @@ void main() { tertiaryHueRotation: null, errorChroma: null, errorMinChroma: null, - neutralChroma: 4, + neutralChroma: 6, neutralMinChroma: null, neutralVariantChroma: 8, neutralVariantMinChroma: null, @@ -318,6 +423,8 @@ void main() { expect( FlexTones.material(Brightness.light), equals(const FlexTones.light( + primaryChroma: 36, + primaryMinChroma: 0, secondaryChroma: 16, tertiaryChroma: 24, )), @@ -327,6 +434,35 @@ void main() { expect( FlexTones.material(Brightness.dark), equals(const FlexTones.dark( + primaryChroma: 36, + primaryMinChroma: 0, + secondaryChroma: 16, + tertiaryChroma: 24, + )), + ); + }); + test('FTO1.017legacy: Verify FlexTones.material3Legacy(Brightness.light).', + () { + expect( + FlexTones.material3Legacy(Brightness.light), + equals(const FlexTones.light( + primaryChroma: 48, + primaryMinChroma: 0, + secondaryChroma: 16, + tertiaryChroma: 24, + )), + ); + }); + test('FTO1.018Legacy: Verify FlexTones.material3Legacy(Brightness.dark).', + () { + expect( + FlexTones.material3Legacy(Brightness.dark), + equals(const FlexTones.dark( + surfaceTone: 8, + backgroundTone: 8, + onErrorContainerTone: 90, + primaryChroma: 48, + primaryMinChroma: 0, secondaryChroma: 16, tertiaryChroma: 24, )), @@ -476,14 +612,12 @@ void main() { equals( const FlexTones.light( primaryTone: 30, - secondaryTone: 40, tertiaryTone: 30, - errorTone: 40, - primaryContainerTone: 90, - secondaryContainerTone: 90, tertiaryContainerTone: 95, errorContainerTone: 95, surfaceTintTone: 30, + surfaceTone: 99, + backgroundTone: 99, primaryChroma: null, secondaryChroma: null, tertiaryChroma: null, @@ -499,10 +633,6 @@ void main() { FlexTones.highContrast(Brightness.dark), equals( const FlexTones.dark( - primaryTone: 80, - secondaryTone: 80, - tertiaryTone: 80, - errorTone: 80, onPrimaryTone: 10, onSecondaryTone: 10, onTertiaryTone: 10, @@ -512,7 +642,12 @@ void main() { tertiaryContainerTone: 20, errorContainerTone: 20, onErrorContainerTone: 90, - surfaceTintTone: 80, + backgroundTone: 4, + onBackgroundTone: 96, + surfaceTone: 4, + onSurfaceTone: 96, + surfaceContainerLowestTone: 0, + surfaceContainerLowTone: 6, primaryChroma: null, secondaryChroma: null, tertiaryChroma: null, @@ -529,19 +664,22 @@ void main() { equals( const FlexTones.light( primaryTone: 20, - tertiaryTone: 30, - onBackgroundTone: 0, - onSurfaceTone: 0, - primaryContainerTone: 90, - secondaryContainerTone: 90, - tertiaryContainerTone: 95, - errorContainerTone: 95, onPrimaryContainerTone: 5, onSecondaryContainerTone: 5, + tertiaryTone: 30, + tertiaryContainerTone: 95, onTertiaryContainerTone: 5, + errorContainerTone: 95, onErrorContainerTone: 5, - surfaceVariantTone: 95, - onSurfaceVariantTone: 10, + // + surfaceTone: 100, + backgroundTone: 100, + surfaceContainerLowTone: 98, + surfaceContainerTone: 96, + onBackgroundTone: 0, + onSurfaceTone: 0, + surfaceVariantTone: 96, + onSurfaceVariantTone: 6, onInverseSurfaceTone: 99, inversePrimaryTone: 90, outlineTone: 40, @@ -563,20 +701,22 @@ void main() { equals( const FlexTones.dark( primaryTone: 90, - secondaryTone: 95, - tertiaryTone: 95, - onPrimaryTone: 5, - onSecondaryTone: 5, - onTertiaryTone: 5, - onErrorTone: 5, + onPrimaryTone: 2, onPrimaryContainerTone: 98, + secondaryTone: 95, + onSecondaryTone: 2, onSecondaryContainerTone: 98, + tertiaryTone: 95, + onTertiaryTone: 2, onTertiaryContainerTone: 98, + onErrorTone: 2, onErrorContainerTone: 98, // - surfaceTone: 5, - backgroundTone: 5, + backgroundTone: 2, onBackgroundTone: 99, + surfaceTone: 2, + surfaceContainerLowestTone: 0, + surfaceContainerLowTone: 6, onSurfaceTone: 99, surfaceVariantTone: 20, onSurfaceVariantTone: 95, @@ -751,7 +891,7 @@ void main() { ); }); // - test('FTO1.033: Verify FlexTones.oneHue(Brightness.light).', () { + test('FTO1.033: Verify FlexTones.chroma(Brightness.light).', () { expect( FlexTones.chroma(Brightness.light), equals( @@ -766,10 +906,10 @@ void main() { tertiaryContainerTone: 95, onTertiaryContainerTone: 6, // - backgroundTone: 98, - onBackgroundTone: 6, - surfaceTone: 98, - onSurfaceTone: 6, + backgroundTone: 99, + onBackgroundTone: 4, + surfaceTone: 99, + onSurfaceTone: 4, surfaceVariantTone: 92, onSurfaceVariantTone: 10, onInverseSurfaceTone: 98, @@ -788,7 +928,7 @@ void main() { ), ); }); - test('FTO1.034: Verify FlexTones.oneHue(Brightness.dark).', () { + test('FTO1.034: Verify FlexTones.chroma(Brightness.dark).', () { expect( FlexTones.chroma(Brightness.dark), equals( @@ -807,9 +947,11 @@ void main() { onErrorTone: 6, onErrorContainerTone: 95, // - backgroundTone: 6, + backgroundTone: 4, onBackgroundTone: 95, - surfaceTone: 6, + surfaceTone: 4, + surfaceContainerLowestTone: 2, + surfaceContainerLowTone: 6, onSurfaceTone: 95, surfaceVariantTone: 20, onSurfaceVariantTone: 90, @@ -838,24 +980,45 @@ void main() { onPrimaryTone: 100, primaryContainerTone: 90, onPrimaryContainerTone: 10, + primaryFixedTone: 90, + primaryFixedDimTone: 80, + onPrimaryFixedTone: 10, + onPrimaryFixedVariantTone: 30, + // secondaryTone: 40, onSecondaryTone: 100, secondaryContainerTone: 90, onSecondaryContainerTone: 10, + secondaryFixedTone: 90, + secondaryFixedDimTone: 80, + onSecondaryFixedTone: 10, + onSecondaryFixedVariantTone: 30, + // tertiaryTone: 40, onTertiaryTone: 100, tertiaryContainerTone: 90, onTertiaryContainerTone: 10, + tertiaryFixedTone: 90, + tertiaryFixedDimTone: 80, + onTertiaryFixedTone: 10, + onTertiaryFixedVariantTone: 30, + // errorTone: 40, onErrorTone: 100, errorContainerTone: 90, onErrorContainerTone: 10, - backgroundTone: 99, - onBackgroundTone: 10, - surfaceTone: 99, + // + surfaceTone: 98, + surfaceDimTone: 87, + surfaceBrightTone: 98, + surfaceContainerLowestTone: 100, + surfaceContainerLowTone: 96, + surfaceContainerTone: 94, + surfaceContainerHighTone: 92, + surfaceContainerHighestTone: 90, onSurfaceTone: 10, - surfaceVariantTone: 90, onSurfaceVariantTone: 30, + // outlineTone: 50, outlineVariantTone: 80, shadowTone: 0, @@ -864,6 +1027,11 @@ void main() { onInverseSurfaceTone: 95, inversePrimaryTone: 80, surfaceTintTone: 40, + // Deprecated colors + backgroundTone: 98, + onBackgroundTone: 10, + surfaceVariantTone: 90, + // primaryChroma: null, primaryMinChroma: 48, secondaryChroma: null, @@ -871,8 +1039,12 @@ void main() { tertiaryChroma: null, tertiaryMinChroma: 0, tertiaryHueRotation: 60, - neutralChroma: 4, + errorChroma: null, + errorMinChroma: null, + neutralChroma: 6, + neutralMinChroma: null, neutralVariantChroma: 8, + neutralVariantMinChroma: null, ); // m2, has same definition as m1, but via default values const FlexTones m2 = FlexTones.light( @@ -883,7 +1055,7 @@ void main() { tertiaryChroma: null, tertiaryMinChroma: 0, tertiaryHueRotation: 60, - neutralChroma: 4, + neutralChroma: 6, neutralVariantChroma: 8, ); // m3, has same definition as m1, but one value is different. @@ -895,7 +1067,7 @@ void main() { tertiaryChroma: null, tertiaryMinChroma: 0, tertiaryHueRotation: 60, - neutralChroma: 4, + neutralChroma: 6, neutralVariantChroma: 10, ); // Do identity tests @@ -951,24 +1123,45 @@ void main() { onPrimaryTone: 100, primaryContainerTone: 90, onPrimaryContainerTone: 10, + primaryFixedTone: 90, + primaryFixedDimTone: 80, + onPrimaryFixedTone: 10, + onPrimaryFixedVariantTone: 30, + // secondaryTone: 40, onSecondaryTone: 100, secondaryContainerTone: 90, onSecondaryContainerTone: 10, + secondaryFixedTone: 90, + secondaryFixedDimTone: 80, + onSecondaryFixedTone: 10, + onSecondaryFixedVariantTone: 30, + // tertiaryTone: 40, onTertiaryTone: 100, tertiaryContainerTone: 90, onTertiaryContainerTone: 10, + tertiaryFixedTone: 90, + tertiaryFixedDimTone: 80, + onTertiaryFixedTone: 10, + onTertiaryFixedVariantTone: 30, + // errorTone: 40, onErrorTone: 100, errorContainerTone: 90, onErrorContainerTone: 10, - backgroundTone: 99, - onBackgroundTone: 10, - surfaceTone: 99, + // + surfaceTone: 98, + surfaceDimTone: 87, + surfaceBrightTone: 98, + surfaceContainerLowestTone: 100, + surfaceContainerLowTone: 96, + surfaceContainerTone: 94, + surfaceContainerHighTone: 92, + surfaceContainerHighestTone: 90, onSurfaceTone: 10, - surfaceVariantTone: 90, onSurfaceVariantTone: 30, + // outlineTone: 50, outlineVariantTone: 80, shadowTone: 0, @@ -977,6 +1170,11 @@ void main() { onInverseSurfaceTone: 95, inversePrimaryTone: 80, surfaceTintTone: 40, + // Deprecated colors + backgroundTone: 98, + onBackgroundTone: 10, + surfaceVariantTone: 90, + // primaryChroma: null, primaryMinChroma: 48, secondaryChroma: null, @@ -984,7 +1182,7 @@ void main() { tertiaryChroma: null, tertiaryMinChroma: 0, tertiaryHueRotation: 60, - neutralChroma: 4, + neutralChroma: 6, neutralVariantChroma: 8, ), ), @@ -1007,24 +1205,45 @@ void main() { onPrimaryTone: 20, primaryContainerTone: 30, onPrimaryContainerTone: 90, + primaryFixedTone: 90, + primaryFixedDimTone: 80, + onPrimaryFixedTone: 10, + onPrimaryFixedVariantTone: 30, + // secondaryTone: 80, onSecondaryTone: 20, secondaryContainerTone: 30, onSecondaryContainerTone: 90, + secondaryFixedTone: 90, + secondaryFixedDimTone: 80, + onSecondaryFixedTone: 10, + onSecondaryFixedVariantTone: 30, + // tertiaryTone: 80, onTertiaryTone: 20, tertiaryContainerTone: 30, onTertiaryContainerTone: 90, + tertiaryFixedTone: 90, + tertiaryFixedDimTone: 80, + onTertiaryFixedTone: 10, + onTertiaryFixedVariantTone: 30, + // errorTone: 80, onErrorTone: 20, errorContainerTone: 30, - onErrorContainerTone: 80, - backgroundTone: 10, - onBackgroundTone: 90, - surfaceTone: 10, + onErrorContainerTone: 90, + // + surfaceTone: 6, + surfaceDimTone: 6, + surfaceBrightTone: 24, + surfaceContainerLowestTone: 4, + surfaceContainerLowTone: 10, + surfaceContainerTone: 12, + surfaceContainerHighTone: 17, + surfaceContainerHighestTone: 22, onSurfaceTone: 90, - surfaceVariantTone: 30, onSurfaceVariantTone: 80, + // outlineTone: 60, outlineVariantTone: 30, shadowTone: 0, @@ -1033,6 +1252,11 @@ void main() { onInverseSurfaceTone: 20, inversePrimaryTone: 40, surfaceTintTone: 80, + // Deprecated colors + backgroundTone: 6, + onBackgroundTone: 90, + surfaceVariantTone: 30, + // primaryChroma: null, primaryMinChroma: 48, secondaryChroma: null, @@ -1040,7 +1264,7 @@ void main() { tertiaryChroma: null, tertiaryMinChroma: 0, tertiaryHueRotation: 60, - neutralChroma: 4, + neutralChroma: 6, neutralVariantChroma: 8, ), ), diff --git a/test/mcu/dynamic_color_test.dart b/test/mcu/dynamic_color_test.dart index 786603e..a76feaa 100644 --- a/test/mcu/dynamic_color_test.dart +++ b/test/mcu/dynamic_color_test.dart @@ -476,5 +476,11 @@ void main() { expect(dScheme.getArgb(scheme), Hct.fromInt(4294955442).toInt()); expect(dScheme.getTone(scheme), 87); }); + // Rydmike: Extra tests. + test('Raw DynamicColor', () { + expect(DynamicColor.enableLightForeground(10), 10); + expect(DynamicColor.enableLightForeground(90), 90); + expect(DynamicColor.enableLightForeground(58), 49); + }); }); } diff --git a/test/mcu/dynamic_scheme_test.dart b/test/mcu/dynamic_scheme_test.dart index fa3c9c3..3597a0b 100644 --- a/test/mcu/dynamic_scheme_test.dart +++ b/test/mcu/dynamic_scheme_test.dart @@ -11,7 +11,10 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// ignore_for_file: lines_longer_than_80_chars + import 'package:flex_seed_scheme/src/mcu/material_color_utilities.dart'; +import 'package:flutter/material.dart'; import 'package:test/test.dart'; void main() { @@ -51,4 +54,206 @@ void main() { ); expect(hue, closeTo(163, 1.0)); }); + + // RydMike: More tests: Dynamic Scheme test via ColorScheme. + test( + 'Color values in ColorScheme.fromSeed with different variants matches ' + 'values in DynamicScheme', () { + const Color seedColor = Colors.orange; + final Hct sourceColor = Hct.fromInt(seedColor.value); + final DynamicScheme dynamicScheme = SchemeTonalSpot( + sourceColorHct: sourceColor, isDark: false, contrastLevel: 0.0); + + // Test getters for key colors + expect(dynamicScheme.primaryPaletteKeyColor, 4288834351); + expect(dynamicScheme.secondaryPaletteKeyColor, 4287459929); + expect(dynamicScheme.tertiaryPaletteKeyColor, 4285627473); + expect(dynamicScheme.neutralPaletteKeyColor, 4286608748); + expect(dynamicScheme.neutralVariantPaletteKeyColor, 4286805096); + + final DynamicColor surfaceHighest = + MaterialDynamicColors.highestSurface(dynamicScheme); + expect(dynamicScheme.getHct(surfaceHighest).toInt(), + surfaceHighest.getArgb(dynamicScheme)); + + // TODO(rydmike): Add DynamicSchemeVariant when they land in Flutter. + // 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)); + + // Test the getter for the dynamic scheme. + expect(colorScheme.primary.value, dynamicScheme.primary); + expect(colorScheme.onPrimary.value, dynamicScheme.onPrimary); + expect(colorScheme.primaryContainer.value, dynamicScheme.primaryContainer); + expect( + colorScheme.onPrimaryContainer.value, dynamicScheme.onPrimaryContainer); + expect(colorScheme.primaryFixed.value, dynamicScheme.primaryFixed); + expect(colorScheme.primaryFixedDim.value, dynamicScheme.primaryFixedDim); + expect(colorScheme.onPrimaryFixed.value, dynamicScheme.onPrimaryFixed); + expect(colorScheme.onPrimaryFixedVariant.value, + dynamicScheme.onPrimaryFixedVariant); + expect(colorScheme.secondary.value, dynamicScheme.secondary); + expect(colorScheme.onSecondary.value, dynamicScheme.onSecondary); + expect( + colorScheme.secondaryContainer.value, dynamicScheme.secondaryContainer); + expect(colorScheme.onSecondaryContainer.value, + dynamicScheme.onSecondaryContainer); + expect(colorScheme.secondaryFixed.value, dynamicScheme.secondaryFixed); + expect( + colorScheme.secondaryFixedDim.value, dynamicScheme.secondaryFixedDim); + expect(colorScheme.onSecondaryFixed.value, dynamicScheme.onSecondaryFixed); + expect(colorScheme.onSecondaryFixedVariant.value, + dynamicScheme.onSecondaryFixedVariant); + expect(colorScheme.tertiary.value, dynamicScheme.tertiary); + expect(colorScheme.onTertiary.value, dynamicScheme.onTertiary); + expect( + colorScheme.tertiaryContainer.value, dynamicScheme.tertiaryContainer); + expect(colorScheme.onTertiaryContainer.value, + dynamicScheme.onTertiaryContainer); + expect(colorScheme.tertiaryFixed.value, dynamicScheme.tertiaryFixed); + expect(colorScheme.tertiaryFixedDim.value, dynamicScheme.tertiaryFixedDim); + expect(colorScheme.onTertiaryFixed.value, dynamicScheme.onTertiaryFixed); + expect(colorScheme.onTertiaryFixedVariant.value, + dynamicScheme.onTertiaryFixedVariant); + expect(colorScheme.error.value, dynamicScheme.error); + expect(colorScheme.onError.value, dynamicScheme.onError); + expect(colorScheme.errorContainer.value, dynamicScheme.errorContainer); + expect(colorScheme.onErrorContainer.value, dynamicScheme.onErrorContainer); + expect(colorScheme.background.value, dynamicScheme.background); + expect(colorScheme.onBackground.value, dynamicScheme.onBackground); + expect(colorScheme.surface.value, dynamicScheme.surface); + expect(colorScheme.surfaceDim.value, dynamicScheme.surfaceDim); + expect(colorScheme.surfaceBright.value, dynamicScheme.surfaceBright); + expect(colorScheme.surfaceContainerLowest.value, + dynamicScheme.surfaceContainerLowest); + expect(colorScheme.surfaceContainerLow.value, + dynamicScheme.surfaceContainerLow); + expect(colorScheme.surfaceContainer.value, dynamicScheme.surfaceContainer); + expect(colorScheme.surfaceContainerHigh.value, + dynamicScheme.surfaceContainerHigh); + expect(colorScheme.surfaceContainerHighest.value, + dynamicScheme.surfaceContainerHighest); + expect(colorScheme.onSurface.value, dynamicScheme.onSurface); + expect(colorScheme.surfaceVariant.value, dynamicScheme.surfaceVariant); + expect(colorScheme.onSurfaceVariant.value, dynamicScheme.onSurfaceVariant); + expect(colorScheme.outline.value, dynamicScheme.outline); + expect(colorScheme.outlineVariant.value, dynamicScheme.outlineVariant); + expect(colorScheme.shadow.value, dynamicScheme.shadow); + expect(colorScheme.scrim.value, dynamicScheme.scrim); + expect(colorScheme.inverseSurface.value, dynamicScheme.inverseSurface); + expect(colorScheme.onInverseSurface.value, dynamicScheme.inverseOnSurface); + expect(colorScheme.inversePrimary.value, dynamicScheme.inversePrimary); + expect(colorScheme.surfaceTint.value, dynamicScheme.surfaceTint); + }); } diff --git a/test/mcu/palettes_test.dart b/test/mcu/palettes_test.dart index 3a70d06..99ada24 100644 --- a/test/mcu/palettes_test.dart +++ b/test/mcu/palettes_test.dart @@ -51,9 +51,8 @@ void main() { expect( c1.toString(), equals( - 'TonalPalette.fromList({0: 123, 10: 123, 20: 123, 30: 123, ' - '40: 123, 50: 123, 60: 123, 70: 123, 80: 123, 90: 123, ' - '95: 123, 99: 123, 100: 123})', + 'TonalPalette.fromList([123, 123, 123, 123, 123, 123, ' + '123, 123, 123, 123, 123, 123, 123])', ), ); }); @@ -145,7 +144,9 @@ void main() { expect(tones.get(0), 0); /// Tone not in [TonalPalette.commonTones] - expect(() => tones.get(3), throwsA(isA())); + /// Before version 2.0.0 this would have thrown an exception. + /// but now we can get any tone. + expect(tones.get(3), 4278716699); // RydMike Extra tests // @@ -163,7 +164,12 @@ void main() { expect(tones.getHct(95).toInt(), 10); expect(tones.getHct(99).toInt(), 11); expect(tones.getHct(100).toInt(), 12); - expect(() => tones.getHct(3), throwsA(isA())); + + /// Tone not in [TonalPalette.commonTones] + /// Before version 2.0.0 this would have thrown an exception. + /// but now we can get any tone. + expect(tones.getHct(3).toInt(), 4278716699); + expect(tones.get(3), 4278716699); }); test('asList', () { diff --git a/test/mcu/scheme_content_test.dart b/test/mcu/scheme_content_test.dart index 4995a08..a86c2d9 100644 --- a/test/mcu/scheme_content_test.dart +++ b/test/mcu/scheme_content_test.dart @@ -47,7 +47,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: false, contrastLevel: 0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff0001c3)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff0001BB)); }); test('lightTheme_maxContrast_primary', () { @@ -55,7 +55,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: false, contrastLevel: 1); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff000181)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff00019F)); }); test('lightTheme_minContrast_primaryContainer', () { @@ -73,7 +73,7 @@ void main() { isDark: false, contrastLevel: 0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff2d36ff)); + isColor(0xff0000FF)); }); test('lightTheme_maxContrast_primaryContainer', () { @@ -82,7 +82,7 @@ void main() { isDark: false, contrastLevel: 1); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff0000e3)); + isColor(0xff0000F6)); }); test('lightTheme_minContrast_tertiaryContainer', () { @@ -100,7 +100,7 @@ void main() { isDark: false, contrastLevel: 0); expect(MaterialDynamicColors.tertiaryContainer.getArgb(scheme), - isColor(0xff9221af)); + isColor(0xff81009F)); }); test('lightTheme_maxContrast_tertiaryContainer', () { @@ -109,7 +109,7 @@ void main() { isDark: false, contrastLevel: 1); expect(MaterialDynamicColors.tertiaryContainer.getArgb(scheme), - isColor(0xff73008e)); + isColor(0xff7D009A)); }); test('lightTheme_minContrast_objectionableTertiaryContainerLightens', () { @@ -128,7 +128,7 @@ void main() { isDark: false, contrastLevel: 0); expect(MaterialDynamicColors.tertiaryContainer.getArgb(scheme), - isColor(0xffac1b57)); + isColor(0xff980249)); }); test('lightTheme_maxContrast_objectionableTertiaryContainerDarkens', () { @@ -137,7 +137,7 @@ void main() { isDark: false, contrastLevel: 1); expect(MaterialDynamicColors.tertiaryContainer.getArgb(scheme), - isColor(0xff870040)); + isColor(0xff930046)); }); test('lightTheme_minContrast_onPrimaryContainer', () { @@ -155,7 +155,7 @@ void main() { isDark: false, contrastLevel: 0); expect(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme), - isColor(0xffffffff)); + isColor(0xffE8E7FF)); }); test('lightTheme_maxContrast_onPrimaryContainer', () { @@ -212,7 +212,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: true, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xfffdf9ff)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xffF0EEFF)); }); test('darkTheme_minContrast_primaryContainer', () { @@ -230,7 +230,7 @@ void main() { isDark: true, contrastLevel: 0.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff0000e6)); + isColor(0xff0000FF)); }); test('darkTheme_maxContrast_primaryContainer', () { @@ -239,7 +239,7 @@ void main() { isDark: true, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xffc4c6ff)); + isColor(0xffBABDFF)); }); test('darkTheme_minContrast_onPrimaryContainer', () { @@ -257,7 +257,7 @@ void main() { isDark: true, contrastLevel: 0.0); expect(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme), - isColor(0xffd7d8ff)); + isColor(0xffE8E7FF)); }); test('darkTheme_maxContrast_onPrimaryContainer', () { @@ -284,7 +284,7 @@ void main() { isDark: true, contrastLevel: 0.0); expect(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme), - isColor(0xfffbccff)); + isColor(0xffFFDFFF)); }); test('darkTheme_maxContrast_onTertiaryContainer', () { diff --git a/test/mcu/scheme_correctness_test.dart b/test/mcu/scheme_correctness_test.dart new file mode 100644 index 0000000..b53838d --- /dev/null +++ b/test/mcu/scheme_correctness_test.dart @@ -0,0 +1,410 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// ignore_for_file: one_member_abstracts, library_private_types_in_public_api + +import 'package:flex_seed_scheme/src/mcu/dynamiccolor/src/contrast_curve.dart'; +import 'package:flex_seed_scheme/src/mcu/dynamiccolor/src/tone_delta_pair.dart'; +import 'package:flex_seed_scheme/src/mcu/material_color_utilities.dart'; +import 'package:test/test.dart'; + +import 'utils/scheme_from_variant.dart'; + +abstract class _Constraint { + /// Tests this constraint against [scheme], failing if constraint not met. + void testAgainst(DynamicScheme scheme); +} + +class _ContrastConstraint extends _Constraint { + _ContrastConstraint(this.foreground, this.background, + {required this.contrastCurve}); + final DynamicColor foreground; + final DynamicColor background; + final ContrastCurve contrastCurve; + static const double _contrastTolerance = 0.05; + + @override + void testAgainst(DynamicScheme scheme) { + final Hct foregroundColor = foreground.getHct(scheme); + final Hct backgroundColor = background.getHct(scheme); + final double actualContrast = + Contrast.ratioOfTones(foregroundColor.tone, backgroundColor.tone); + final double desiredContrast = contrastCurve.get(scheme.contrastLevel); + + if (desiredContrast <= 4.5) { + // A requirement of <= 4.5 must be met (with tolerance) + if (actualContrast < desiredContrast - _contrastTolerance) { + fail('Dynamic scheme $scheme fails contrast constraint:\n' + '${foreground.name} should have contrast at least $desiredContrast ' + 'against ${background.name}, but has $actualContrast\n\n' + 'Foreground: ${foreground.name}\n' + 'Background: ${background.name}\n' + 'Scheme parameters:\n' + ' Variant: ${scheme.variant}\n' + ' Source color: ${scheme.sourceColorHct}\n' + ' Brightness: ${scheme.isDark ? "dark" : "light"}\n' + ' Contrast level: ${scheme.contrastLevel}\n' + 'Desired contrast: $desiredContrast\n' + 'Actual contrast: $actualContrast'); + } + } else { + if (actualContrast < 4.5 - _contrastTolerance) { + fail('Dynamic scheme $scheme fails contrast constraint:\n' + '${foreground.name} should have contrast at least 4.5 ' + 'against ${background.name}, but has $actualContrast\n\n' + 'Foreground: ${foreground.name}\n' + 'Background: ${background.name}\n' + 'Scheme parameters:\n' + ' Variant: ${scheme.variant}\n' + ' Source color: ${scheme.sourceColorHct}\n' + ' Brightness: ${scheme.isDark ? "dark" : "light"}\n' + ' Contrast level: ${scheme.contrastLevel}\n' + 'Desired contrast: $desiredContrast\n' + 'Actual contrast: $actualContrast'); + } else if (actualContrast < desiredContrast - _contrastTolerance && + foregroundColor.tone != 100.0 && + foregroundColor.tone != 0.0) { + fail('Dynamic scheme $scheme fails contrast constraint:\n' + '${foreground.name} should have contrast at least $desiredContrast ' + 'against ${background.name}, but has $actualContrast, and no color ' + 'has a tone of 0 or 100\n\n' + 'Foreground: ${foreground.name}\n' + 'Background: ${background.name}\n' + 'Scheme parameters:\n' + ' Variant: ${scheme.variant}\n' + ' Source color: ${scheme.sourceColorHct}\n' + ' Brightness: ${scheme.isDark ? "dark" : "light"}\n' + ' Contrast level: ${scheme.contrastLevel}\n' + 'Desired contrast: $desiredContrast\n' + 'Actual contrast: $actualContrast'); + } + } + } +} + +class _DeltaConstraint extends _Constraint { + _DeltaConstraint(this.roleA, this.roleB, + {required this.delta, required this.polarity}); + final DynamicColor roleA; + final DynamicColor roleB; + final double delta; + final TonePolarity polarity; + static const double _deltaTolerance = 0.5; + + @override + void testAgainst(DynamicScheme scheme) { + final Hct roleAColor = roleA.getHct(scheme); + final Hct roleBColor = roleB.getHct(scheme); + final bool roleAShouldBeLighter = (polarity == TonePolarity.lighter) || + (polarity == TonePolarity.nearer && !scheme.isDark) || + (polarity == TonePolarity.farther && scheme.isDark); + final String lighterOrDarker = roleAShouldBeLighter ? 'lighter' : 'darker'; + + final double actualDelta = roleAShouldBeLighter + ? roleAColor.tone - roleBColor.tone + : roleBColor.tone - roleAColor.tone; + if (actualDelta < delta - _deltaTolerance) { + fail('Dynamic scheme $scheme fails delta constraint:\n' + '${roleA.name} should be $delta $lighterOrDarker than ${roleB.name}, ' + 'but they have tones ${roleAColor.tone} and ${roleBColor.tone}, ' + 'respectively\n\n' + 'Role A: ${roleA.name}\n' + 'Role B: ${roleB.name}\n' + 'Scheme parameters:\n' + ' Variant: ${scheme.variant}\n' + ' Source color: ${scheme.sourceColorHct}\n' + ' Brightness: ${scheme.isDark ? "dark" : "light"}\n' + ' Contrast level: ${scheme.contrastLevel}\n' + 'Desired delta: $delta\n' + 'Actual delta: $actualDelta'); + } + } +} + +class _BackgroundConstraint extends _Constraint { + _BackgroundConstraint(this.background); + final DynamicColor background; + + @override + void testAgainst(DynamicScheme scheme) { + final Hct color = background.getHct(scheme); + if (color.tone >= 50.5 && color.tone < 59.5) { + fail('Dynamic scheme $scheme fails background constraint:\n' + '${background.name} has tone ${color.tone} which is in the ' + 'forbidden zone 50.5 <= tone < 59.5\n\n' + 'Background: ${background.name}\n' + 'Scheme parameters:\n' + ' Variant: ${scheme.variant}\n' + ' Source color: ${scheme.sourceColorHct}\n' + ' Brightness: ${scheme.isDark ? "dark" : "light"}\n' + ' Contrast level: ${scheme.contrastLevel}\n' + 'Actual tone: ${color.tone}'); + } + } +} + +final List<_Constraint> constraints = <_Constraint>[ + _ContrastConstraint( + MaterialDynamicColors.onSurface, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint( + MaterialDynamicColors.onSurface, MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint( + MaterialDynamicColors.primary, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(3, 4.5, 7, 7)), + _ContrastConstraint( + MaterialDynamicColors.primary, MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(3, 4.5, 7, 7)), + _ContrastConstraint( + MaterialDynamicColors.secondary, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(3, 4.5, 7, 7)), + _ContrastConstraint( + MaterialDynamicColors.secondary, MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(3, 4.5, 7, 7)), + _ContrastConstraint( + MaterialDynamicColors.tertiary, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(3, 4.5, 7, 7)), + _ContrastConstraint( + MaterialDynamicColors.tertiary, MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(3, 4.5, 7, 7)), + _ContrastConstraint( + MaterialDynamicColors.error, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(3, 4.5, 7, 7)), + _ContrastConstraint( + MaterialDynamicColors.error, MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(3, 4.5, 7, 7)), + _ContrastConstraint( + MaterialDynamicColors.onSurfaceVariant, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(3, 4.5, 7, 11)), + _ContrastConstraint(MaterialDynamicColors.onSurfaceVariant, + MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(3, 4.5, 7, 11)), + _ContrastConstraint( + MaterialDynamicColors.outline, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(1.5, 3, 4.5, 7)), + _ContrastConstraint( + MaterialDynamicColors.outline, MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(1.5, 3, 4.5, 7)), + _ContrastConstraint( + MaterialDynamicColors.primaryContainer, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint(MaterialDynamicColors.primaryContainer, + MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.primaryFixed, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.primaryFixed, MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.primaryFixedDim, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint(MaterialDynamicColors.primaryFixedDim, + MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint(MaterialDynamicColors.secondaryContainer, + MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint(MaterialDynamicColors.secondaryContainer, + MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.secondaryFixed, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.secondaryFixed, MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.secondaryFixedDim, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint(MaterialDynamicColors.secondaryFixedDim, + MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.tertiaryContainer, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint(MaterialDynamicColors.tertiaryContainer, + MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.tertiaryFixed, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.tertiaryFixed, MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.tertiaryFixedDim, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint(MaterialDynamicColors.tertiaryFixedDim, + MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.errorContainer, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.errorContainer, MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.outlineVariant, MaterialDynamicColors.surfaceDim, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint( + MaterialDynamicColors.outlineVariant, MaterialDynamicColors.surfaceBright, + contrastCurve: ContrastCurve(0, 0, 3, 4.5)), + _ContrastConstraint(MaterialDynamicColors.inverseOnSurface, + MaterialDynamicColors.inverseSurface, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint(MaterialDynamicColors.inversePrimary, + MaterialDynamicColors.inverseSurface, + contrastCurve: ContrastCurve(3, 4.5, 7, 7)), + _ContrastConstraint( + MaterialDynamicColors.onPrimary, MaterialDynamicColors.primary, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint( + MaterialDynamicColors.onSecondary, MaterialDynamicColors.secondary, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint( + MaterialDynamicColors.onTertiary, MaterialDynamicColors.tertiary, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint( + MaterialDynamicColors.onError, MaterialDynamicColors.error, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint(MaterialDynamicColors.onPrimaryContainer, + MaterialDynamicColors.primaryContainer, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint(MaterialDynamicColors.onSecondaryContainer, + MaterialDynamicColors.secondaryContainer, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint(MaterialDynamicColors.onTertiaryContainer, + MaterialDynamicColors.tertiaryContainer, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint(MaterialDynamicColors.onErrorContainer, + MaterialDynamicColors.errorContainer, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint( + MaterialDynamicColors.onPrimaryFixed, MaterialDynamicColors.primaryFixed, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint(MaterialDynamicColors.onPrimaryFixed, + MaterialDynamicColors.primaryFixedDim, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint(MaterialDynamicColors.onSecondaryFixed, + MaterialDynamicColors.secondaryFixed, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint(MaterialDynamicColors.onSecondaryFixed, + MaterialDynamicColors.secondaryFixedDim, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint(MaterialDynamicColors.onTertiaryFixed, + MaterialDynamicColors.tertiaryFixed, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint(MaterialDynamicColors.onTertiaryFixed, + MaterialDynamicColors.tertiaryFixedDim, + contrastCurve: ContrastCurve(4.5, 7, 11, 21)), + _ContrastConstraint(MaterialDynamicColors.onPrimaryFixedVariant, + MaterialDynamicColors.primaryFixed, + contrastCurve: ContrastCurve(3, 4.5, 7, 11)), + _ContrastConstraint(MaterialDynamicColors.onPrimaryFixedVariant, + MaterialDynamicColors.primaryFixedDim, + contrastCurve: ContrastCurve(3, 4.5, 7, 11)), + _ContrastConstraint(MaterialDynamicColors.onSecondaryFixedVariant, + MaterialDynamicColors.secondaryFixed, + contrastCurve: ContrastCurve(3, 4.5, 7, 11)), + _ContrastConstraint(MaterialDynamicColors.onSecondaryFixedVariant, + MaterialDynamicColors.secondaryFixedDim, + contrastCurve: ContrastCurve(3, 4.5, 7, 11)), + _ContrastConstraint(MaterialDynamicColors.onTertiaryFixedVariant, + MaterialDynamicColors.tertiaryFixed, + contrastCurve: ContrastCurve(3, 4.5, 7, 11)), + _ContrastConstraint(MaterialDynamicColors.onTertiaryFixedVariant, + MaterialDynamicColors.tertiaryFixedDim, + contrastCurve: ContrastCurve(3, 4.5, 7, 11)), + _DeltaConstraint( + MaterialDynamicColors.primary, MaterialDynamicColors.primaryContainer, + delta: 10, polarity: TonePolarity.farther), + _DeltaConstraint( + MaterialDynamicColors.secondary, MaterialDynamicColors.secondaryContainer, + delta: 10, polarity: TonePolarity.farther), + _DeltaConstraint( + MaterialDynamicColors.tertiary, MaterialDynamicColors.tertiaryContainer, + delta: 10, polarity: TonePolarity.farther), + _DeltaConstraint( + MaterialDynamicColors.error, MaterialDynamicColors.errorContainer, + delta: 10, polarity: TonePolarity.farther), + _DeltaConstraint( + MaterialDynamicColors.primaryFixedDim, MaterialDynamicColors.primaryFixed, + delta: 10, polarity: TonePolarity.darker), + _DeltaConstraint(MaterialDynamicColors.secondaryFixedDim, + MaterialDynamicColors.secondaryFixed, + delta: 10, polarity: TonePolarity.darker), + _DeltaConstraint(MaterialDynamicColors.tertiaryFixedDim, + MaterialDynamicColors.tertiaryFixed, + delta: 10, polarity: TonePolarity.darker), + _BackgroundConstraint(MaterialDynamicColors.background), + _BackgroundConstraint(MaterialDynamicColors.error), + _BackgroundConstraint(MaterialDynamicColors.errorContainer), + _BackgroundConstraint(MaterialDynamicColors.primary), + _BackgroundConstraint(MaterialDynamicColors.primaryContainer), + _BackgroundConstraint(MaterialDynamicColors.primaryFixed), + _BackgroundConstraint(MaterialDynamicColors.primaryFixedDim), + _BackgroundConstraint(MaterialDynamicColors.secondary), + _BackgroundConstraint(MaterialDynamicColors.secondaryContainer), + _BackgroundConstraint(MaterialDynamicColors.secondaryFixed), + _BackgroundConstraint(MaterialDynamicColors.secondaryFixedDim), + _BackgroundConstraint(MaterialDynamicColors.surface), + _BackgroundConstraint(MaterialDynamicColors.surfaceBright), + _BackgroundConstraint(MaterialDynamicColors.surfaceContainer), + _BackgroundConstraint(MaterialDynamicColors.surfaceContainerHigh), + _BackgroundConstraint(MaterialDynamicColors.surfaceContainerHighest), + _BackgroundConstraint(MaterialDynamicColors.surfaceContainerLow), + _BackgroundConstraint(MaterialDynamicColors.surfaceContainerLowest), + _BackgroundConstraint(MaterialDynamicColors.surfaceDim), + _BackgroundConstraint(MaterialDynamicColors.surfaceTint), + _BackgroundConstraint(MaterialDynamicColors.surfaceVariant), + _BackgroundConstraint(MaterialDynamicColors.tertiary), + _BackgroundConstraint(MaterialDynamicColors.tertiaryContainer), + _BackgroundConstraint(MaterialDynamicColors.tertiaryFixed), + _BackgroundConstraint(MaterialDynamicColors.tertiaryFixedDim), +]; + +void main() { + group('scheme_correctness_test', () { + for (final Variant variant in Variant.values) { + for (final double contrastLevel in [-1.0, 0.0, 0.5, 1.0]) { + // For each variant-contrast combination, tests across four + // seed colors as well as two brightnesses. + test('${variant.label}, $contrastLevel', () { + for (final int sourceColorArgb in [ + 0xFF0000FF, + 0xFF00FF00, + 0xFFFFFF00, + 0xFFFF0000 + ]) { + for (final bool isDark in [false, true]) { + final DynamicScheme s = schemeFromVariant( + variant: variant, + sourceColorHct: Hct.fromInt(sourceColorArgb), + isDark: isDark, + contrastLevel: contrastLevel, + ); + // Ensures all constraints are satisfied. + for (final _Constraint constraint in constraints) { + constraint.testAgainst(s); + } + } + } + }); + } + } + }); +} diff --git a/test/mcu/scheme_expressive_test.dart b/test/mcu/scheme_expressive_test.dart index 5806fd2..d38bd23 100644 --- a/test/mcu/scheme_expressive_test.dart +++ b/test/mcu/scheme_expressive_test.dart @@ -56,7 +56,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: false, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff002818)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff00341F)); }); test('lightTheme_minContrast_primaryContainer', () { @@ -83,7 +83,7 @@ void main() { isDark: false, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff004d31)); + isColor(0xff005436)); }); test('lightTheme_minContrast_onPrimaryContainer', () { @@ -159,7 +159,7 @@ void main() { isDark: true, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xffeefff2)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xffBBFFD7)); }); test('darkTheme_minContrast_primaryContainer', () { @@ -186,7 +186,7 @@ void main() { isDark: true, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff8bdbaf)); + isColor(0xff83D3A8)); }); test('darkTheme_minContrast_onPrimaryContainer', () { diff --git a/test/mcu/scheme_fidelity_test.dart b/test/mcu/scheme_fidelity_test.dart index 80d3bc1..8bd18a4 100644 --- a/test/mcu/scheme_fidelity_test.dart +++ b/test/mcu/scheme_fidelity_test.dart @@ -48,7 +48,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: false, contrastLevel: 0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff0001c3)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff0001BB)); }); test('lightTheme_maxContrast_primary', () { @@ -56,7 +56,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: false, contrastLevel: 1); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff000181)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff00019F)); }); test('lightTheme_minContrast_primaryContainer', () { @@ -74,7 +74,7 @@ void main() { isDark: false, contrastLevel: 0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff2d36ff)); + isColor(0xff0000FF)); }); test('lightTheme_maxContrast_primaryContainer', () { @@ -83,7 +83,7 @@ void main() { isDark: false, contrastLevel: 1); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff0000e3)); + isColor(0xff0000F6)); }); test('lightTheme_minContrast_tertiaryContainer', () { @@ -101,7 +101,7 @@ void main() { isDark: false, contrastLevel: 0); expect(MaterialDynamicColors.tertiaryContainer.getArgb(scheme), - isColor(0xffb31910)); + isColor(0xff9D0002)); }); test('lightTheme_maxContrast_tertiaryContainer', () { @@ -110,7 +110,7 @@ void main() { isDark: false, contrastLevel: 1); expect(MaterialDynamicColors.tertiaryContainer.getArgb(scheme), - isColor(0xff8c0002)); + isColor(0xff980002)); }); test('lightTheme_minContrast_objectionableTertiaryContainerLightens', () { @@ -138,7 +138,7 @@ void main() { isDark: false, contrastLevel: 1); expect(MaterialDynamicColors.tertiaryContainer.getArgb(scheme), - isColor(0xff4d4300)); + isColor(0xff544900)); }); test('lightTheme_minContrast_onPrimaryContainer', () { @@ -156,7 +156,7 @@ void main() { isDark: false, contrastLevel: 0); expect(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme), - isColor(0xffffffff)); + isColor(0xffE8E7FF)); }); test('lightTheme_maxContrast_onPrimaryContainer', () { @@ -213,7 +213,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: true, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xfffdf9ff)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xffF0EEFF)); }); test('darkTheme_minContrast_primaryContainer', () { @@ -231,7 +231,7 @@ void main() { isDark: true, contrastLevel: 0.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff0000e6)); + isColor(0xff0000FF)); }); test('darkTheme_maxContrast_primaryContainer', () { @@ -240,7 +240,7 @@ void main() { isDark: true, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xffc4c6ff)); + isColor(0xffBABDFF)); }); test('darkTheme_minContrast_onPrimaryContainer', () { @@ -258,7 +258,7 @@ void main() { isDark: true, contrastLevel: 0.0); expect(MaterialDynamicColors.onPrimaryContainer.getArgb(scheme), - isColor(0xffd7d8ff)); + isColor(0xffE8E7FF)); }); test('darkTheme_maxContrast_onPrimaryContainer', () { @@ -285,7 +285,7 @@ void main() { isDark: true, contrastLevel: 0.0); expect(MaterialDynamicColors.onTertiaryContainer.getArgb(scheme), - isColor(0xffffcfc7)); + isColor(0xffFFE2DE)); }); test('darkTheme_maxContrast_onTertiaryContainer', () { diff --git a/test/mcu/scheme_fruit_salad_test.dart b/test/mcu/scheme_fruit_salad_test.dart index 8f33afc..983df69 100644 --- a/test/mcu/scheme_fruit_salad_test.dart +++ b/test/mcu/scheme_fruit_salad_test.dart @@ -56,7 +56,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: false, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff002635)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff003042)); }); test('lightTheme_minContrast_primaryContainer', () { @@ -83,7 +83,7 @@ void main() { isDark: false, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff004862)); + isColor(0xff004F6B)); }); test('lightTheme_minContrast_tertiaryContainer', () { @@ -110,7 +110,7 @@ void main() { isDark: false, contrastLevel: 1.0); expect(MaterialDynamicColors.tertiaryContainer.getArgb(scheme), - isColor(0xff3a3e74)); + isColor(0xff40447B)); }); test('lightTheme_minContrast_onPrimaryContainer', () { @@ -203,7 +203,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: true, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xfff7fbff)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xffE0F3FF)); }); test('darkTheme_minContrast_primaryContainer', () { @@ -230,7 +230,7 @@ void main() { isDark: true, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff83d5ff)); + isColor(0xff68CEFF)); }); test('darkTheme_minContrast_onPrimaryContainer', () { diff --git a/test/mcu/scheme_neutral_test.dart b/test/mcu/scheme_neutral_test.dart index 8dbe4bd..803bebb 100644 --- a/test/mcu/scheme_neutral_test.dart +++ b/test/mcu/scheme_neutral_test.dart @@ -56,7 +56,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: false, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff21212e)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff2B2B38)); }); test('lightTheme_minContrast_primaryContainer', () { @@ -83,7 +83,7 @@ void main() { isDark: false, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff414250)); + isColor(0xff484856)); }); test('lightTheme_minContrast_onPrimaryContainer', () { @@ -158,7 +158,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: true, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xfffdf9ff)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xffF0EEFF)); }); test('darkTheme_minContrast_primaryContainer', () { @@ -185,7 +185,7 @@ void main() { isDark: true, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xffcac9da)); + isColor(0xffC2C1D2)); }); test('darkTheme_minContrast_onPrimaryContainer', () { diff --git a/test/mcu/scheme_rainbow_test.dart b/test/mcu/scheme_rainbow_test.dart index 391226a..ab374b4 100644 --- a/test/mcu/scheme_rainbow_test.dart +++ b/test/mcu/scheme_rainbow_test.dart @@ -56,7 +56,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: false, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff0f136a)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff1B2074)); }); test('lightTheme_minContrast_primaryContainer', () { @@ -83,7 +83,7 @@ void main() { isDark: false, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff34398b)); + isColor(0xff3A4092)); }); test('lightTheme_minContrast_tertiaryContainer', () { @@ -110,7 +110,7 @@ void main() { isDark: false, contrastLevel: 1.0); expect(MaterialDynamicColors.tertiaryContainer.getArgb(scheme), - isColor(0xff5a384e)); + isColor(0xff613E55)); }); test('lightTheme_minContrast_onPrimaryContainer', () { @@ -203,7 +203,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: true, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xfffdf9ff)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xffF0EEFF)); }); test('darkTheme_minContrast_primaryContainer', () { @@ -230,7 +230,7 @@ void main() { isDark: true, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xffc4c6ff)); + isColor(0xffBABDFF)); }); test('darkTheme_minContrast_onPrimaryContainer', () { diff --git a/test/mcu/scheme_tonal_spot_test.dart b/test/mcu/scheme_tonal_spot_test.dart index db64f62..965db20 100644 --- a/test/mcu/scheme_tonal_spot_test.dart +++ b/test/mcu/scheme_tonal_spot_test.dart @@ -57,7 +57,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: false, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff21212e)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff2B2B38)); }); test('lightTheme_minContrast_primaryContainer', () { @@ -84,7 +84,7 @@ void main() { isDark: false, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff414250)); + isColor(0xff484856)); }); test('lightTheme_minContrast_onPrimaryContainer', () { @@ -159,7 +159,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: true, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xfffdf9ff)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xffF0EEFF)); }); test('darkTheme_minContrast_primaryContainer', () { @@ -186,7 +186,7 @@ void main() { isDark: true, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xffcac9da)); + isColor(0xffC2C1D2)); }); test('darkTheme_minContrast_onPrimaryContainer', () { @@ -289,7 +289,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: false, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff181C51)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff22265C)); }); test('lightTheme_minContrast_primaryContainer', () { @@ -316,7 +316,7 @@ void main() { isDark: false, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff3A3E74)); + isColor(0xff40447B)); }); test('lightTheme_minContrast_onPrimaryContainer', () { @@ -496,7 +496,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: true, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xffFDF9FF)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xffF0EEFF)); }); test('darkTheme_minContrast_primaryContainer', () { @@ -523,7 +523,7 @@ void main() { isDark: true, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xffc4c6ff)); + isColor(0xffBABEFD)); }); test('darkTheme_minContrast_onPrimaryContainer', () { diff --git a/test/mcu/scheme_vibrant_test.dart b/test/mcu/scheme_vibrant_test.dart index aa914d3..c55c69e 100644 --- a/test/mcu/scheme_vibrant_test.dart +++ b/test/mcu/scheme_vibrant_test.dart @@ -56,7 +56,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: false, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff000181)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xff00019F)); }); test('lightTheme_minContrast_primaryContainer', () { @@ -83,7 +83,7 @@ void main() { isDark: false, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xff0000e3)); + isColor(0xff0000F6)); }); test('lightTheme_minContrast_onPrimaryContainer', () { @@ -158,7 +158,7 @@ void main() { sourceColorHct: Hct.fromInt(0xff0000ff), isDark: true, contrastLevel: 1.0); - expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xfffdf9ff)); + expect(MaterialDynamicColors.primary.getArgb(scheme), isColor(0xffF0EEFF)); }); test('darkTheme_minContrast_primaryContainer', () { @@ -185,7 +185,7 @@ void main() { isDark: true, contrastLevel: 1.0); expect(MaterialDynamicColors.primaryContainer.getArgb(scheme), - isColor(0xffc4c6ff)); + isColor(0xffBABDFF)); }); test('darkTheme_minContrast_onPrimaryContainer', () { diff --git a/test/mcu/utils/scheme_from_variant.dart b/test/mcu/utils/scheme_from_variant.dart new file mode 100644 index 0000000..06abb67 --- /dev/null +++ b/test/mcu/utils/scheme_from_variant.dart @@ -0,0 +1,79 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import 'package:flex_seed_scheme/src/mcu/material_color_utilities.dart'; + +DynamicScheme schemeFromVariant({ + required Variant variant, + required Hct sourceColorHct, + required bool isDark, + required double contrastLevel, +}) { + switch (variant) { + case Variant.content: + return SchemeContent( + sourceColorHct: sourceColorHct, + isDark: isDark, + contrastLevel: contrastLevel, + ); + case Variant.expressive: + return SchemeExpressive( + sourceColorHct: sourceColorHct, + isDark: isDark, + contrastLevel: contrastLevel, + ); + case Variant.fidelity: + return SchemeFidelity( + sourceColorHct: sourceColorHct, + isDark: isDark, + contrastLevel: contrastLevel, + ); + case Variant.fruitSalad: + return SchemeFruitSalad( + sourceColorHct: sourceColorHct, + isDark: isDark, + contrastLevel: contrastLevel, + ); + case Variant.monochrome: + return SchemeMonochrome( + sourceColorHct: sourceColorHct, + isDark: isDark, + contrastLevel: contrastLevel, + ); + case Variant.neutral: + return SchemeNeutral( + sourceColorHct: sourceColorHct, + isDark: isDark, + contrastLevel: contrastLevel, + ); + case Variant.rainbow: + return SchemeRainbow( + sourceColorHct: sourceColorHct, + isDark: isDark, + contrastLevel: contrastLevel, + ); + case Variant.tonalSpot: + return SchemeTonalSpot( + sourceColorHct: sourceColorHct, + isDark: isDark, + contrastLevel: contrastLevel, + ); + case Variant.vibrant: + return SchemeVibrant( + sourceColorHct: sourceColorHct, + isDark: isDark, + contrastLevel: contrastLevel, + ); + } +}