From 2249169b7ddb38f7e327fa67d4b5fab40abffb29 Mon Sep 17 00:00:00 2001 From: Rydmike Date: Tue, 5 Jul 2022 23:21:05 +0300 Subject: [PATCH] Custom surfaceTint and surface blends support in Playground --- CHANGELOG.md | 4 +- .../lib/example5/theme/flex_theme_dark.dart | 2 + .../lib/example5/theme/flex_theme_light.dart | 2 + .../utils/generate_theme_dart_code.dart | 8 ++ .../seeded_color_scheme/scheme_colors.dart | 23 ++++ .../panels/surface_blends/surface_blends.dart | 112 +++++++++++++++++- .../widgets/shared/color_picker_inkwell.dart | 11 +- .../shared/color_scheme_popup_menu.dart | 4 +- example/lib/shared/const/store.dart | 29 +++++ .../shared/controllers/theme_controller.dart | 32 +++++ lib/src/flex_color_scheme.dart | 4 + 11 files changed, 222 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4b2a5b0..64079589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -118,8 +118,8 @@ All notable changes to the **FlexColorScheme** package are documented here. the same issue the Playground app did, but the issue is a Flutter SDK issue that FlexColorScheme cannot fix. Most likely 99% of apps will never run into this issue. -* **TODO**: Add support in Themes Playground to customize `surfaceTint` color and hence also the - used color for surface blends. +* Added support in Themes Playground to customize `surfaceTint` color, and also use it as custom + color for surface blends. ## v5.0.1 - April 29, 2022 diff --git a/example/lib/example5/theme/flex_theme_dark.dart b/example/lib/example5/theme/flex_theme_dark.dart index 213221f9..6be29165 100644 --- a/example/lib/example5/theme/flex_theme_dark.dart +++ b/example/lib/example5/theme/flex_theme_dark.dart @@ -208,6 +208,8 @@ FlexColorScheme flexColorSchemeDark(ThemeController controller) { useMaterial3ErrorColors: controller.useM3ErrorColors, tones: AppColor.flexTonesConfig(Brightness.dark, controller.usedFlexToneSetup), + // Use custom surface tint color. + surfaceTint: controller.surfaceTintDark, // // ThemeData properties passed along directly to ThemeData. visualDensity: AppData.visualDensity, diff --git a/example/lib/example5/theme/flex_theme_light.dart b/example/lib/example5/theme/flex_theme_light.dart index 2cfc7c85..d97b94b7 100644 --- a/example/lib/example5/theme/flex_theme_light.dart +++ b/example/lib/example5/theme/flex_theme_light.dart @@ -270,6 +270,8 @@ FlexColorScheme flexColorSchemeLight(ThemeController controller) { // between a few pre-configured ones. tones: AppColor.flexTonesConfig( Brightness.light, controller.usedFlexToneSetup), + // Use custom surface tint color. + surfaceTint: controller.surfaceTintLight, // // ThemeData properties passed along directly to ThemeData. // diff --git a/example/lib/example5/utils/generate_theme_dart_code.dart b/example/lib/example5/utils/generate_theme_dart_code.dart index fcc43ea7..561eb9e0 100644 --- a/example/lib/example5/utils/generate_theme_dart_code.dart +++ b/example/lib/example5/utils/generate_theme_dart_code.dart @@ -143,6 +143,12 @@ String generateThemeDartCode(ThemeController controller) { final String useMaterial3 = controller.useMaterial3 ? ' useMaterial3: ${controller.useMaterial3},\n' : ''; + final String tintLightColor = controller.surfaceTintLight != null + ? ' surfaceTint: ${controller.surfaceTintLight},\n' + : ''; + final String tintDarkColor = controller.surfaceTintDark != null + ? ' surfaceTint: ${controller.surfaceTintDark},\n' + : ''; // // Code for FlexSubThemesData setup. // @@ -855,6 +861,7 @@ String generateThemeDartCode(ThemeController controller) { '$tabBarStyle' '$lightIsWhite' '$swapLightColors' + '$tintLightColor' '$tooltipsMatchBackground' '$lightSubTheme' '$useKeyColorsLight' @@ -877,6 +884,7 @@ String generateThemeDartCode(ThemeController controller) { '$tabBarStyle' '$darkIsTrueBlack' '$swapDarkColors' + '$tintDarkColor' '$tooltipsMatchBackground' '$darkSubTheme' '$useKeyColorsDark' diff --git a/example/lib/example5/widgets/panels/seeded_color_scheme/scheme_colors.dart b/example/lib/example5/widgets/panels/seeded_color_scheme/scheme_colors.dart index a5ae9a7a..36547cc8 100644 --- a/example/lib/example5/widgets/panels/seeded_color_scheme/scheme_colors.dart +++ b/example/lib/example5/widgets/panels/seeded_color_scheme/scheme_colors.dart @@ -1049,6 +1049,29 @@ class SchemeColors extends StatelessWidget { ), ), ), + const Divider(height: 1, thickness: 1), + Expanded( + child: MouseRegion( + onEnter: (PointerEvent details) { + tc.setHoverColor(colorScheme.surfaceTint); + tc.setHoverTonalPalette(TonalPalettes.primary); + }, + onExit: (PointerEvent details) { + tc.setHoverColor(null); + tc.setHoverTonalPalette(null); + }, + child: Material( + color: colorScheme.surfaceTint, + child: ColorNameValue( + color: colorScheme.surfaceTint, + textColor: _onColor(colorScheme.surfaceTint), + label: 'surfaceTint', + tone: tones.primaryTone, + showTone: showTones, + ), + ), + ), + ), ], ), ), diff --git a/example/lib/example5/widgets/panels/surface_blends/surface_blends.dart b/example/lib/example5/widgets/panels/surface_blends/surface_blends.dart index 9f118f21..80034434 100644 --- a/example/lib/example5/widgets/panels/surface_blends/surface_blends.dart +++ b/example/lib/example5/widgets/panels/surface_blends/surface_blends.dart @@ -1,8 +1,11 @@ +import 'package:flex_color_picker/flex_color_picker.dart'; import 'package:flex_color_scheme/flex_color_scheme.dart'; import 'package:flutter/material.dart'; import '../../../../shared/controllers/theme_controller.dart'; import '../../../../shared/widgets/universal/switch_list_tile_adaptive.dart'; +import '../../shared/color_picker_inkwell.dart'; +import '../../shared/color_scheme_popup_menu.dart'; import 'surface_mode_buttons.dart'; // Panel used to define how primary color is blended into surfaces and @@ -53,7 +56,36 @@ class SurfaceBlends extends StatelessWidget { @override Widget build(BuildContext context) { - final bool isLight = Theme.of(context).brightness == Brightness.light; + final ThemeData theme = Theme.of(context); + final bool isLight = theme.brightness == Brightness.light; + final ColorScheme colorScheme = theme.colorScheme; + + // Default color is in use, make a light label to use in custom color. + final String defaultTintLightLabel = + controller.surfaceTintLight == null ? ' primary (default):' : ':'; + // Current light tint color + final Color? previousTintLight = controller.surfaceTintLight; + final Color effectiveTintLight = + controller.surfaceTintLight ?? colorScheme.surfaceTint; + // Names for the light tint colors. + final String materialNameLight = + ColorTools.materialName(effectiveTintLight); + final String nameThatColorLight = + ColorTools.nameThatColor(effectiveTintLight); + final String spaceLight = materialNameLight == '' ? '' : ' '; + // Default color is in use, make a dark label to use in custom color. + final String defaultTintDarkLabel = + controller.surfaceTintDark == null ? ' primary (default)' : ''; + // Current dark tint color. + final Color? previousTintDark = controller.surfaceTintDark; + final Color effectiveTintDark = + controller.surfaceTintDark ?? colorScheme.surfaceTint; + // Names for the dark tint colors. + final String materialNameDark = ColorTools.materialName(effectiveTintDark); + final String nameThatColorDark = + ColorTools.nameThatColor(effectiveTintDark); + final String spaceDark = materialNameDark == '' ? '' : ' '; + // return Column( children: [ const SizedBox(height: 8), @@ -89,6 +121,45 @@ class SurfaceBlends extends StatelessWidget { const SizedBox(width: 16), ], ), + const SizedBox(height: 8), + ListTile( + enabled: controller.surfaceTintLight != null, + title: const Text('Set light blend and tint color back to default'), + subtitle: const Text('Sets custom blend and tint color back ' + 'to primary color'), + trailing: ElevatedButton( + onPressed: controller.surfaceTintLight != null + ? () { + controller.setSurfaceTintLight(null); + } + : null, + child: const Text('Default'), + ), + onTap: () { + controller.setSurfaceTintLight(null); + }, + ), + ColorPickerInkWell( + color: controller.surfaceTintLight ?? colorScheme.primary, + onChanged: controller.setSurfaceTintLight, + recentColors: controller.recentColors, + onRecentColorsChanged: controller.setRecentColors, + wasCancelled: (bool cancelled) { + if (cancelled) { + controller.setSurfaceTintLight(previousTintLight); + } + }, + enabled: true, + child: ListTile( + title: const Text('Light theme blend and surface tint color'), + subtitle: Text('Color$defaultTintLightLabel ' + '$nameThatColorLight $materialNameLight$spaceLight' + '#${effectiveTintLight.hexCode}'), + trailing: ColorSchemeBox( + color: controller.surfaceTintLight ?? colorScheme.primary, + ), + ), + ), const ListTile( title: Text('Light theme blend level'), subtitle: Text('Adjust the surface, background, scaffold and ' @@ -213,6 +284,45 @@ class SurfaceBlends extends StatelessWidget { const SizedBox(width: 16), ], ), + const SizedBox(height: 8), + ListTile( + enabled: controller.surfaceTintDark != null, + title: const Text('Set dark blend and tint color back to default'), + subtitle: const Text('Sets custom blend and tint color back ' + 'to primary color'), + trailing: ElevatedButton( + onPressed: controller.surfaceTintDark != null + ? () { + controller.setSurfaceTintDark(null); + } + : null, + child: const Text('Default'), + ), + onTap: () { + controller.setSurfaceTintDark(null); + }, + ), + ColorPickerInkWell( + color: controller.surfaceTintDark ?? colorScheme.primary, + onChanged: controller.setSurfaceTintDark, + recentColors: controller.recentColors, + onRecentColorsChanged: controller.setRecentColors, + wasCancelled: (bool cancelled) { + if (cancelled) { + controller.setSurfaceTintDark(previousTintDark); + } + }, + enabled: true, + child: ListTile( + title: const Text('Dark theme blend and surface tint color'), + subtitle: Text('Color$defaultTintDarkLabel ' + '$nameThatColorDark $materialNameDark$spaceDark' + '#${effectiveTintDark.hexCode}'), + trailing: ColorSchemeBox( + color: controller.surfaceTintDark ?? colorScheme.primary, + ), + ), + ), const ListTile( title: Text('Dark theme blend level'), subtitle: Text('Adjust the surface, background, scaffold and ' diff --git a/example/lib/example5/widgets/shared/color_picker_inkwell.dart b/example/lib/example5/widgets/shared/color_picker_inkwell.dart index b23fc6bb..bcbd0fb3 100644 --- a/example/lib/example5/widgets/shared/color_picker_inkwell.dart +++ b/example/lib/example5/widgets/shared/color_picker_inkwell.dart @@ -225,12 +225,13 @@ class ColorPickerInkWell extends StatelessWidget { final bool isLight = Theme.of(context).brightness == Brightness.light; return InkWell( + // TODO(rydmike): Remove this commented customized InkWell style. // We want a bit more pronounced hover color for this case than normally. - hoverColor: isLight ? const Color(0x40BCBCBC) : const Color(0x30FFFFFF), - splashColor: isLight ? const Color(0x40BCBCBC) : const Color(0x30FFFFFF), - focusColor: isLight ? const Color(0x40BCBCBC) : const Color(0x30FFFFFF), - highlightColor: - isLight ? const Color(0x40BCBCBC) : const Color(0x30FFFFFF), + // hoverColor: isLight ? const Color(0x40BCBCBC):const Color(0x30FFFFFF), + // splashColor: isLight ? const Color(0x40BCBCBC):const Color(0x30FFFFFF), + // focusColor: isLight ? const Color(0x40BCBCBC):const Color(0x30FFFFFF), + // highlightColor: + // isLight ? const Color(0x40BCBCBC) : const Color(0x30FFFFFF), onHover: (bool value) { onHover?.call(value); }, diff --git a/example/lib/example5/widgets/shared/color_scheme_popup_menu.dart b/example/lib/example5/widgets/shared/color_scheme_popup_menu.dart index 21c80e17..6329a0d6 100644 --- a/example/lib/example5/widgets/shared/color_scheme_popup_menu.dart +++ b/example/lib/example5/widgets/shared/color_scheme_popup_menu.dart @@ -16,6 +16,7 @@ class ColorSchemePopupMenu extends StatelessWidget { this.subtitle, this.contentPadding, this.labelForDefault = 'default (primary)', + this.popupLabelDefault, }); final int index; final ValueChanged? onChanged; @@ -23,6 +24,7 @@ class ColorSchemePopupMenu extends StatelessWidget { final Widget? subtitle; final EdgeInsetsGeometry? contentPadding; // Defaults to 16. final String labelForDefault; + final String? popupLabelDefault; @override Widget build(BuildContext context) { @@ -68,7 +70,7 @@ class ColorSchemePopupMenu extends StatelessWidget { ), title: i >= SchemeColor.values.length - 2 // If we reached first deprecated color, make default label. - ? Text(labelForDefault, style: txtStyle) + ? Text(popupLabelDefault ?? labelForDefault, style: txtStyle) : Text(SchemeColor.values[i].name, style: txtStyle), ), ) diff --git a/example/lib/shared/const/store.dart b/example/lib/shared/const/store.dart index d271bb5e..4c18ac98 100644 --- a/example/lib/shared/const/store.dart +++ b/example/lib/shared/const/store.dart @@ -788,6 +788,35 @@ class Store { // We use NULL as default, on nullable settings. static const double? defaultDialogBorderRadius = null; + // Custom surface tint color SETTINGS. + // =========================================================================== + + // Key used to read and save the surfaceTintLight color value. + static const String keySurfaceTintLight = 'surfaceTintLight'; + // Default value for the surfaceTintLight color, also to reset settings. + // We use NULL as default, on nullable settings. + static const Color? defaultSurfaceTintLight = null; + + // Key used to read and save the surfaceTintLightSchemeColor value. + static const String keySurfaceTintLightSchemeColor = + 'surfaceTintLightSchemeColor'; + // Default value for the surfaceTintLightSchemeColor, also used to + // reset settings. We use NULL as default, on nullable settings. + static const SchemeColor? defaultSurfaceTintLightSchemeColor = null; + + // Key used to read and save the surfaceTintDark color value. + static const String keySurfaceTintDark = 'surfaceTintDark'; + // Default value for the surfaceTintDark color, also to reset settings. + // We use NULL as default, on nullable settings. + static const Color? defaultSurfaceTintDark = null; + + // Key used to read and save the surfaceTintDarkSchemeColor value. + static const String keySurfaceTintDarkSchemeColor = + 'surfaceTintDarkSchemeColor'; + // Default value for the surfaceTintDarkSchemeColor, also used to + // reset settings. We use NULL as default, on nullable settings. + static const SchemeColor? defaultSurfaceTintDarkSchemeColor = null; + // Custom color SETTINGS. // =========================================================================== diff --git a/example/lib/shared/controllers/theme_controller.dart b/example/lib/shared/controllers/theme_controller.dart index f7c92ecc..aa47e713 100644 --- a/example/lib/shared/controllers/theme_controller.dart +++ b/example/lib/shared/controllers/theme_controller.dart @@ -373,6 +373,12 @@ class ThemeController with ChangeNotifier { _dialogBorderRadius = await _themeService.load( Store.keyDialogBorderRadius, Store.defaultDialogBorderRadius); // + // Custom surface tint color SETTINGS. + _surfaceTintLight = await _themeService.load( + Store.keySurfaceTintLight, Store.defaultSurfaceTintLight); + _surfaceTintDark = await _themeService.load( + Store.keySurfaceTintDark, Store.defaultSurfaceTintDark); + // // Custom color SETTINGS. _primaryLight = await _themeService.load( Store.keyPrimaryLight, Store.defaultPrimaryLight); @@ -617,6 +623,11 @@ class ThemeController with ChangeNotifier { await setDialogBackgroundSchemeColor( Store.defaultDialogBackgroundSchemeColor, false); await setDialogBorderRadius(Store.defaultDialogBorderRadius, false); + // + // Surface tint colors. + await setSurfaceTintLight(Store.defaultSurfaceTintLight, false); + await setSurfaceTintDark(Store.defaultSurfaceTintDark, false); + // // Not persisted, locally controlled popup selection for ThemeService, // resets to actual used platform when settings are reset or app loaded. await setPlatform(defaultTargetPlatform, false); @@ -2001,6 +2012,27 @@ class ThemeController with ChangeNotifier { await _themeService.save(Store.keyDialogBorderRadius, value); } + // Custom surface tint color SETTINGS. + // =========================================================================== + + late Color? _surfaceTintLight; + Color? get surfaceTintLight => _surfaceTintLight; + Future setSurfaceTintLight(Color? value, [bool notify = true]) async { + if (value == _surfaceTintLight) return; + _surfaceTintLight = value; + if (notify) notifyListeners(); + await _themeService.save(Store.keySurfaceTintLight, value); + } + + late Color? _surfaceTintDark; + Color? get surfaceTintDark => _surfaceTintDark; + Future setSurfaceTintDark(Color? value, [bool notify = true]) async { + if (value == _surfaceTintDark) return; + _surfaceTintDark = value; + if (notify) notifyListeners(); + await _themeService.save(Store.keySurfaceTintDark, value); + } + // Custom color SETTINGS. // =========================================================================== diff --git a/lib/src/flex_color_scheme.dart b/lib/src/flex_color_scheme.dart index 4f468741..c38a3c4c 100644 --- a/lib/src/flex_color_scheme.dart +++ b/lib/src/flex_color_scheme.dart @@ -2603,6 +2603,7 @@ class FlexColorScheme with Diagnosticable { tertiaryKey: seed.useTertiary ? effectiveColors.tertiary : null, // Use provided tones configuration or default one. tones: tones ?? const FlexTones.light(), + surfaceTint: surfaceTint, ); // Update effective main colors to seed colors, keeping configured // effective main color values when so defined. @@ -2795,6 +2796,7 @@ class FlexColorScheme with Diagnosticable { // surfaceVariant and inverseSurface on purpose. surfaceVariant: effectiveSurfaceVariantColor, inverseSurface: effectiveInverseSurfaceColor, + surfaceTint: surfaceTint, ) ?? // We had a colorScheme passed in, we use as passed in, but set // override values for props we have not handled via FCS direct @@ -4294,6 +4296,7 @@ class FlexColorScheme with Diagnosticable { // defaults that can produce same results as Flutter SDK, // ColorScheme.fromSeed(color), when only primary color is used as key. tones: tones ?? const FlexTones.dark(), + surfaceTint: surfaceTint, ); // Update effective main colors to seed colors, keeping configured // effective main color values when so defined. The main colors to keep @@ -4487,6 +4490,7 @@ class FlexColorScheme with Diagnosticable { // surfaceVariant and inverseSurface on purpose. surfaceVariant: effectiveSurfaceVariantColor, inverseSurface: effectiveInverseSurfaceColor, + surfaceTint: surfaceTint, ) ?? // We had a colorScheme passed in, we use as passed in, but set // override values for props we have not handled via FCS direct