- 
                Notifications
    
You must be signed in to change notification settings  - Fork 167
 
[dynamic_color] Add tone-based colors to color scheme #599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 6 commits
02ca6c7
              9cdfd8c
              96c1f1d
              afe5763
              95b450a
              293eabf
              78667e1
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| import 'package:flutter/material.dart'; | ||
| 
     | 
||
| class ColorSchemes { | ||
| final ColorScheme light; | ||
| final ColorScheme dark; | ||
| 
     | 
||
| const ColorSchemes({required this.light, required this.dark}); | ||
| 
     | 
||
| factory ColorSchemes.fromList(List<int> colors) { | ||
| return ColorSchemes( | ||
| light: _colorSchemeFromList(colors, 0, Brightness.light), | ||
| dark: _colorSchemeFromList(colors, 1, Brightness.dark), | ||
| ); | ||
| } | ||
| } | ||
| 
     | 
||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is somewhat fragile an difficult to validate correctness with DynamicColorPlugin.kt There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, I'll see if I can improve that. Perhaps a map with readable names instead of a list?  | 
||
| ColorScheme _colorSchemeFromList( | ||
| List<int> colors, int n, Brightness brightness) { | ||
| int offset = (colors.length ~/ 2) * n; | ||
| return ColorScheme( | ||
| brightness: brightness, | ||
| primary: Color(colors[offset + 0]), | ||
| onPrimary: Color(colors[offset + 1]), | ||
| primaryContainer: Color(colors[offset + 2]), | ||
| onPrimaryContainer: Color(colors[offset + 3]), | ||
| primaryFixed: Color(colors[offset + 4]), | ||
| primaryFixedDim: Color(colors[offset + 5]), | ||
| onPrimaryFixed: Color(colors[offset + 6]), | ||
| onPrimaryFixedVariant: Color(colors[offset + 7]), | ||
| secondary: Color(colors[offset + 8]), | ||
| onSecondary: Color(colors[offset + 9]), | ||
| secondaryContainer: Color(colors[offset + 10]), | ||
| onSecondaryContainer: Color(colors[offset + 11]), | ||
| secondaryFixed: Color(colors[offset + 12]), | ||
| secondaryFixedDim: Color(colors[offset + 13]), | ||
| onSecondaryFixed: Color(colors[offset + 14]), | ||
| onSecondaryFixedVariant: Color(colors[offset + 15]), | ||
| tertiary: Color(colors[offset + 16]), | ||
| onTertiary: Color(colors[offset + 17]), | ||
| tertiaryContainer: Color(colors[offset + 18]), | ||
| onTertiaryContainer: Color(colors[offset + 19]), | ||
| tertiaryFixed: Color(colors[offset + 20]), | ||
| tertiaryFixedDim: Color(colors[offset + 21]), | ||
| onTertiaryFixed: Color(colors[offset + 22]), | ||
| onTertiaryFixedVariant: Color(colors[offset + 23]), | ||
| error: Color(colors[offset + 24]), | ||
| onError: Color(colors[offset + 25]), | ||
| errorContainer: Color(colors[offset + 26]), | ||
| onErrorContainer: Color(colors[offset + 27]), | ||
| surface: Color(colors[offset + 28]), | ||
| onSurface: Color(colors[offset + 29]), | ||
| surfaceDim: Color(colors[offset + 30]), | ||
| surfaceBright: Color(colors[offset + 31]), | ||
| onSurfaceVariant: Color(colors[offset + 32]), | ||
| surfaceContainerLowest: Color(colors[offset + 33]), | ||
| surfaceContainerLow: Color(colors[offset + 34]), | ||
| surfaceContainer: Color(colors[offset + 35]), | ||
| surfaceContainerHigh: Color(colors[offset + 36]), | ||
| surfaceContainerHighest: Color(colors[offset + 37]), | ||
| inverseSurface: Color(colors[offset + 38]), | ||
| onInverseSurface: Color(colors[offset + 39]), | ||
| inversePrimary: Color(colors[offset + 40]), | ||
| outline: Color(colors[offset + 41]), | ||
| outlineVariant: Color(colors[offset + 42]), | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,6 +1,3 @@ | ||
| // TODO(guidezpl): remove ignore after migration to new color roles | ||
| // ignore_for_file: deprecated_member_use | ||
| 
     | 
||
| import 'package:flutter/material.dart'; | ||
| import 'package:material_color_utilities/material_color_utilities.dart'; | ||
| 
     | 
||
| 
        
          
        
         | 
    @@ -9,47 +6,137 @@ extension CorePaletteToColorScheme on CorePalette { | |
| ColorScheme toColorScheme({ | ||
| Brightness brightness = Brightness.light, | ||
| }) { | ||
| final Scheme scheme; | ||
| 
     | 
||
| switch (brightness) { | ||
| case Brightness.light: | ||
| scheme = Scheme.lightFromCorePalette(this); | ||
| break; | ||
| return _toLightColorScheme(); | ||
| case Brightness.dark: | ||
| scheme = Scheme.darkFromCorePalette(this); | ||
| break; | ||
| return _toDarkColorScheme(); | ||
| } | ||
| } | ||
| 
     | 
||
| ColorScheme _toLightColorScheme() { | ||
| return ColorScheme( | ||
| primary: Color(scheme.primary), | ||
| onPrimary: Color(scheme.onPrimary), | ||
| primaryContainer: Color(scheme.primaryContainer), | ||
| onPrimaryContainer: Color(scheme.onPrimaryContainer), | ||
| secondary: Color(scheme.secondary), | ||
| onSecondary: Color(scheme.onSecondary), | ||
| secondaryContainer: Color(scheme.secondaryContainer), | ||
| onSecondaryContainer: Color(scheme.onSecondaryContainer), | ||
| tertiary: Color(scheme.tertiary), | ||
| onTertiary: Color(scheme.onTertiary), | ||
| tertiaryContainer: Color(scheme.tertiaryContainer), | ||
| onTertiaryContainer: Color(scheme.onTertiaryContainer), | ||
| error: Color(scheme.error), | ||
| onError: Color(scheme.onError), | ||
| errorContainer: Color(scheme.errorContainer), | ||
| onErrorContainer: Color(scheme.onErrorContainer), | ||
| outline: Color(scheme.outline), | ||
| outlineVariant: Color(scheme.outlineVariant), | ||
| background: Color(scheme.background), | ||
| onBackground: Color(scheme.onBackground), | ||
| surface: Color(scheme.surface), | ||
| onSurface: Color(scheme.onSurface), | ||
| surfaceVariant: Color(scheme.surfaceVariant), | ||
| onSurfaceVariant: Color(scheme.onSurfaceVariant), | ||
| inverseSurface: Color(scheme.inverseSurface), | ||
| onInverseSurface: Color(scheme.inverseOnSurface), | ||
| inversePrimary: Color(scheme.inversePrimary), | ||
| shadow: Color(scheme.shadow), | ||
| scrim: Color(scheme.scrim), | ||
| brightness: brightness, | ||
| brightness: Brightness.light, | ||
| primary: Color(primary.get(40)), | ||
| onPrimary: Color(primary.get(100)), | ||
| primaryContainer: Color(primary.get(90)), | ||
| onPrimaryContainer: Color(primary.get(10)), | ||
| primaryFixed: Color(primary.get(90)), | ||
| primaryFixedDim: Color(primary.get(80)), | ||
| onPrimaryFixed: Color(primary.get(10)), | ||
| onPrimaryFixedVariant: Color(primary.get(30)), | ||
| secondary: Color(secondary.get(40)), | ||
| onSecondary: Color(secondary.get(100)), | ||
| secondaryContainer: Color(secondary.get(90)), | ||
| onSecondaryContainer: Color(secondary.get(10)), | ||
| secondaryFixed: Color(secondary.get(90)), | ||
| secondaryFixedDim: Color(secondary.get(80)), | ||
| onSecondaryFixed: Color(secondary.get(10)), | ||
| onSecondaryFixedVariant: Color(secondary.get(30)), | ||
| tertiary: Color(tertiary.get(40)), | ||
| onTertiary: Color(tertiary.get(100)), | ||
| tertiaryContainer: Color(tertiary.get(90)), | ||
| onTertiaryContainer: Color(tertiary.get(10)), | ||
| tertiaryFixed: Color(tertiary.get(90)), | ||
| tertiaryFixedDim: Color(tertiary.get(80)), | ||
| onTertiaryFixed: Color(tertiary.get(10)), | ||
| onTertiaryFixedVariant: Color(tertiary.get(30)), | ||
| error: Color(error.get(40)), | ||
| onError: Color(error.get(100)), | ||
| errorContainer: Color(error.get(90)), | ||
| onErrorContainer: Color(error.get(10)), | ||
| surface: _guessTone(neutral, 98), | ||
| onSurface: Color(neutral.get(10)), | ||
| surfaceDim: _guessTone(neutral, 87), | ||
| surfaceBright: _guessTone(neutral, 98), | ||
| onSurfaceVariant: Color(neutralVariant.get(30)), | ||
| surfaceContainerLowest: Color(neutral.get(100)), | ||
| surfaceContainerLow: _guessTone(neutral, 96), | ||
| surfaceContainer: _guessTone(neutral, 94), | ||
| surfaceContainerHigh: _guessTone(neutral, 92), | ||
| surfaceContainerHighest: Color(neutral.get(90)), | ||
| inverseSurface: Color(neutral.get(20)), | ||
| onInverseSurface: Color(neutral.get(95)), | ||
| inversePrimary: Color(primary.get(80)), | ||
| outline: Color(neutralVariant.get(50)), | ||
| outlineVariant: Color(neutralVariant.get(80)), | ||
| ); | ||
| } | ||
| 
     | 
||
| ColorScheme _toDarkColorScheme() { | ||
| return ColorScheme( | ||
| brightness: Brightness.dark, | ||
| primary: Color(primary.get(80)), | ||
| onPrimary: Color(primary.get(20)), | ||
| primaryContainer: Color(primary.get(30)), | ||
| onPrimaryContainer: Color(primary.get(90)), | ||
| primaryFixed: Color(primary.get(90)), | ||
| primaryFixedDim: Color(primary.get(80)), | ||
| onPrimaryFixed: Color(primary.get(10)), | ||
| onPrimaryFixedVariant: Color(primary.get(30)), | ||
| secondary: Color(secondary.get(80)), | ||
| onSecondary: Color(secondary.get(20)), | ||
| secondaryContainer: Color(secondary.get(30)), | ||
| onSecondaryContainer: Color(secondary.get(90)), | ||
| secondaryFixed: Color(secondary.get(90)), | ||
| secondaryFixedDim: Color(secondary.get(80)), | ||
| onSecondaryFixed: Color(secondary.get(10)), | ||
| onSecondaryFixedVariant: Color(secondary.get(30)), | ||
| tertiary: Color(tertiary.get(80)), | ||
| onTertiary: Color(tertiary.get(20)), | ||
| tertiaryContainer: Color(tertiary.get(30)), | ||
| onTertiaryContainer: Color(tertiary.get(90)), | ||
| tertiaryFixed: Color(tertiary.get(90)), | ||
| tertiaryFixedDim: Color(tertiary.get(80)), | ||
| onTertiaryFixed: Color(tertiary.get(10)), | ||
| onTertiaryFixedVariant: Color(tertiary.get(30)), | ||
| error: Color(error.get(80)), | ||
| onError: Color(error.get(20)), | ||
| errorContainer: Color(error.get(30)), | ||
| onErrorContainer: Color(error.get(90)), | ||
| surface: _guessTone(neutral, 6), | ||
| onSurface: Color(neutral.get(90)), | ||
| surfaceDim: _guessTone(neutral, 6), | ||
| surfaceBright: _guessTone(neutral, 24), | ||
| onSurfaceVariant: Color(neutralVariant.get(80)), | ||
| surfaceContainerLowest: _guessTone(neutral, 4), | ||
| surfaceContainerLow: Color(neutral.get(10)), | ||
| surfaceContainer: _guessTone(neutral, 12), | ||
| surfaceContainerHigh: _guessTone(neutral, 17), | ||
| surfaceContainerHighest: _guessTone(neutral, 22), | ||
| inverseSurface: Color(neutral.get(90)), | ||
| onInverseSurface: Color(neutral.get(20)), | ||
| inversePrimary: Color(primary.get(40)), | ||
| outline: Color(neutralVariant.get(60)), | ||
| outlineVariant: Color(neutralVariant.get(30)), | ||
| ); | ||
| } | ||
| } | ||
| 
     | 
||
| // This logic is taken from material_color_utilities 0.12 - https://github.com/material-foundation/material-color-utilities/blob/be615fc90286787bbe0c04ef58a6987e0e8fdc29/dart/lib/palettes/tonal_palette.dart#L93C5-L111. | ||
| // Once flutter updates to the latest version, this workaround can be removed. | ||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Best to wait for flutter/flutter#170000 rather than introduce workarounds IMO  | 
||
| Color _guessTone(TonalPalette palette, double tone) { | ||
| // 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. | ||
| 
     | 
||
| var bestHue = 0.0, bestChroma = 0.0; | ||
| for (final argb in palette.asList) { | ||
| final hct = Hct.fromInt(argb); | ||
| if (hct.tone == tone) { | ||
| return Color(hct.toInt()); | ||
| } | ||
| 
     | 
||
| // 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 Color(Hct.from(bestHue, bestChroma, tone).toInt()); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not obtain
system_palette_key_color_primary_lightand other key colors and generate the scheme directly?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that guaranteed to return the same colours as this code that is querying from the system? Again, this code is based on the official Android implementation here, and I think it would be good to keep the implementation as similar as possible to ensure consistency with non-Flutter apps.