toTheme property

ThemeData toTheme

Returns the ThemeData object defined by FlexColorScheme properties and its theming logic.

After you have defined your scheme with FlexColorScheme or one of its factories FlexColorScheme.light, FlexColorScheme.dark, use toTheme to get the resulting ThemeData object defined by your FlexColorScheme definition.

The returned ThemeData contains some opinionated modifications and dark theme corrections, compared to what you get if you would just use the standard ThemeData.from a ColorScheme. You can always override these with your own theme modifications by using the copyWith method on the resulting theme.

The differences from the standard ThemeData.from factory are:

  • ScaffoldBackground has its own color property in FlexColorScheme and can if so desired differ from the ColorScheme.background color. In the branding implementation, the scaffoldBackground typically gets no primary branding applied, only in the heavy choice is there a small amount. Whereas background in a FlexColorScheme receives the most color branding of the surface colors. This fits well for where the background color is used on Material in Widgets, but it does not go so well together with scaffoldBackground, which is the reason why it has its own color value in this implementation.

  • The dialogBackgroundColor uses the ColorScheme.surface color instead of the ColorScheme.background. The background color needed the strongest branding when branding is used, but this did not look so good on dialogs, so its color choice was changed to surface instead, that gets lighter branding in FlexColorScheme when it is used. With standard Material surface colors the background and surface colors are the same, so there is no difference when using the default background and surface colors.

  • The indicatorColor is same as effectiveTabColor which uses a function with logic to determine its color bases on if a TabBarTheme was selected that should work on current app bar background color, or on surface/background colors.

  • For toggleableActiveColor the ColorScheme.secondary color is used. The Flutter default just uses the default ThemeData colors and not the actual colors you define in the ColorScheme you create your theme from. Perhaps an oversight in Flutter? See issue: https:///github.com/flutter/flutter/issues/65782.

  • Flutter themes created with ThemeData.from does not define any color scheme related color for the primaryColorDark color, this method does. See issue: https:///github.com/flutter/flutter/issues/65782. The ThemeData.from leaves this color at ThemeData factory default, this may not match your scheme. Widgets seldom use this color, so the issue is rarely seen.

  • Flutter themes created with ThemeData.from does not define any color scheme based color for the primaryColorLight color, this method does. See issue: https:///github.com/flutter/flutter/issues/65782. The ThemeData.from leaves this color at ThemeData factory default this may not match your scheme. Widgets seldom use this color, so the issue is rarely seen.

  • Flutter themes created with ThemeData.from does not define any color scheme based color for the secondaryHeaderColor color, this method does. See issue: https:///github.com/flutter/flutter/issues/65782. ThemeData.from leaves this color at ThemeData factory default this may not match your scheme. Widgets seldom use this color, so the issue is rarely seen.

  • Background color for AppBarTheme can use a custom color theme in both light and dark themes, that is not dependent on theme primary or surface color. In the versions prior to Flutter 2.0.0 doing this was difficult to do. As presented in https://github.com/flutter/flutter/issues/50606 A new feature in Flutter 2.0.0 implemented via: https://github.com/flutter/flutter/pull/71184 makes this easy and better. FlexColorScheme's implementation has been changed to use this new AppBarTheme feature starting with version 2.0.0-nullsafety.2.

  • The AppBarTheme elevation defaults to 0, an iOs style influenced opinionated choice. It can easily be adjusted directly in the FlexColorScheme definition with property value appBarElevation without creating a sub theme or using copyWith. For the main less used constructor of FlexColorScheme it is required and cannot be null. The FlexColorScheme light and dark factories can be null but it will default to 0 if null.

  • The bottomAppBarColor uses color scheme background color to match the background color of the drawer, bottom navigation bar, possible side menu and system navigation bar on android (if theming of it is used). This is a slight change from the ColorScheme default that uses surface color.

  • The BottomAppBarTheme elevation defaults to appBarElevation or 0 if it is null, an iOs style influenced opinionated choice. It can easily be adjusted directly in the FlexColorScheme definition with property value bottomAppBarElevation without creating a sub theme or using copyWith.

  • In TextSelectionThemeData, the standard for selectionColor is colorScheme.primary with opacity value 0.4 for dark-mode and 0.12 for light mode. Here primary with 0.5 for dark-mode and 0.3 for light mode is used. The standard for selectionHandleColor is colorScheme.primary, here we use the slightly darker shade primaryColorDark instead, which does not have a proper color scheme color value in Flutter standard ColorScheme based themes.

  • A predefined slightly opinionated InputDecorationTheme is used. It sets filled to true and fill color to color scheme primary color with opacity 0.035 in light mode and opacity 0.06 in dark-mode.

  • The property fixTextFieldOutlineLabel is set to true by default, it looks better. The only reason why it is not the default in Flutter, is for default backwards legacy design compatibility.

NOTE: Since the old buttons have been deprecated in Flutter 2.0.0 they are no longer presented or used in code in FlexColorScheme and its examples. However, FlexColorScheme still defines the theme for them described below. Defining the theme does not yet issue any deprecation warnings or errors, as long as that is the case. this theming will be kept available to support out of the box nice themes for the old buttons as before.

  • Button theming is applied to ThemeData.buttonColor using color colorScheme.primary color.

  • For ThemeData.buttonTheme the entire color scheme is passed to its colorScheme property and it uses textTheme set to ButtonTextTheme.primary, plus minor changes to padding and tap target size. These modifications make the old buttons almost match the default design and look of their corresponding newer buttons. Thus the RaisedButton looks very similar to ElevatedButton, OutlineButton to OutlinedButton and FlatButton to TextButton. There are some differences in margins and looks, especially in dark-mode, but they are very similar.

  • The default theme for Chips contain a design bug that makes the selected ChoiceChip() widget look disabled in dark-mode, regardless if was created with ThemeData or ThemeData.from factory. See issue: https:///github.com/flutter/flutter/issues/65663 The ChipThemeData modification used here fixes the issue.

  • For TabBarTheme, the Flutter standard selected tab and indicator color is onSurface in dark mode and on Primary in light mode, which is designed to fit an AppBar colored TabBar. This is kept, and the default via FlexTabBarStyle.forAppBar style, with a minor modification. If AppBar is "light", then black87 is used, not black, it is the same as the textTheme on AppBar in light app bar brightness. If the FlexTabBarStyle.forBackground style was used, the selected color is always color scheme primary color, which works well on surface, background and scaffold background colors.

    The unselected TabBar color when FlexTabBarStyle.forBackground style is used, is always the onSurface color with 60% opacity. This is also the color if the AppBar background color brightness is light AND its color is white, surface or background colored. Otherwise when the style FlexTabBarStyle.forAppBar is used, the unselected tab bar color is the selected tab color with 70% opacity. This opacity value is the same as Flutter default for the default theme that is also designed for AppBar usage.

  • The BottomNavigationBarThemeData uses color scheme primary color for the selected item. Flutter defaults to secondary color. Primary color is a design used on iOS by default for the bottom navigation bar. We agree and think it looks better as the default choice for apps.

  • Default tooltip theme in Flutter is currently a bit flawed on desktop and web, because it defaults to using a very small font (10 dp). See issue: https:///github.com/flutter/flutter/issues/71429

    The default theming also does not handle multiline tooltips very well. The here used TooltipThemeData theme design corrects both these issues. It uses 12 dp font on desktop and web instead of 10 dp, and some padding instead of a height constraint to ensure that multiline tooltips look nice too.

    FlexColorScheme also includes a new boolean property tooltipsMatchBackground, that can be toggled to not used Flutter's Material default that has a theme mode inverted background. Tooltips using light background in light theme and dark in dark, are commonly used on the Windows desktop platform. You can tie the extra property to used platform to make an automatic platform adaptation of the tooltip style if you like, or give users a preference toggle the tooltip style to their liking.

  • The property transparentStatusBar is set to true by default and used to make to the AppBar one-toned on Android device like on iOS. Set it to false to restore default Android design.

    It would be nice if we could also make the system navigation button area on Android transparent via a theme, but it does not work. The style is doable, but requires modifying Android config files, not possible from Flutter only (as per current information). Related issue: https:///github.com/flutter/flutter/issues/69999.

    FlexColorScheme offers a static helper themedSystemNavigationBar that allows us to easily create an annotated region for the system navigation bar that uses the active color scheme and theme mode to make it at least use a correctly colored theme colored background for the active theme. See example 5 for a demo on how to use this.

Implementation

ThemeData get toTheme {
  // A convenience bool to check if this theme is for light or dark mode
  final bool _isDark = brightness == Brightness.dark;
  // Create a TextTheme that is appropriate for the light/dark mode
  final TextTheme _textTheme =
      (_isDark ? ThemeData.dark() : ThemeData.light()).textTheme;
  // Check brightness of primary, secondary, error, surface and background
  // colors, and then calculate appropriate colors for their onColors, if an
  // "on" color was not passed in.
  final FlexSchemeOnColors _onColors = FlexSchemeOnColors.from(
    primary: primary,
    secondary: secondary,
    surface: surface ??
        (_isDark
            ? FlexColor.materialDarkSurface
            : FlexColor.materialLightSurface),
    background: background ??
        (_isDark
            ? FlexColor.materialDarkBackground
            : FlexColor.materialLightBackground),
    error: error ??
        (_isDark
            ? FlexColor.materialDarkError
            : FlexColor.materialLightError),
    onPrimary: onPrimary,
    onSecondary: onSecondary,
    onSurface: onSurface,
    onBackground: onBackground,
    onError: onError,
  );
  // Define a standard Flutter ColorScheme from the provided brightness and
  // provided/computes/default colors.
  final ColorScheme _colorScheme = ColorScheme(
    primary: primary,
    primaryVariant: primaryVariant,
    secondary: secondary,
    secondaryVariant: secondaryVariant,
    surface: surface ??
        (_isDark
            ? FlexColor.materialDarkSurface
            : FlexColor.materialLightSurface),
    background: background ??
        (_isDark
            ? FlexColor.materialDarkBackground
            : FlexColor.materialLightBackground),
    error: error ??
        (_isDark
            ? FlexColor.materialDarkError
            : FlexColor.materialLightError),
    onBackground: _onColors.onBackground,
    onSurface: _onColors.onSurface,
    onError: _onColors.onError,
    onPrimary: _onColors.onPrimary,
    onSecondary: _onColors.onSecondary,
    brightness: brightness,
  );

  // When working with color scheme based colors, there is no longer a
  // Material primary swatch that we can use to create some of the old
  // Theme colors from that are needed. To be able to do so we make
  // a complete material color swatch from the provided primary color,
  // using the primary color as its middle [500] index color.
  final MaterialColor _primarySwatch =
      createPrimarySwatch(_colorScheme.primary);
  // We now have a swatch of the primary color provided via a color scheme,
  // we can use it do define some of the traditional theme colors in a way
  // that relates to the color scheme primary color, like ThemeData factory
  // does when you create a theme from a swatch. This gives us some missing
  // critical primary shades to work with.
  final Color? _primaryColorDark =
      _isDark ? _primarySwatch[700] : _primarySwatch[800];
  final Color? _primaryColorLight = _primarySwatch[100];
  final Color? _secondaryHeaderColor = _primarySwatch[50];

  // We need some logic for the appBarColor. If a custom color for the
  // app bar was passed in, we use that, if not we use the surface color in
  // dark mode and primary color in light mode, the latter part is the same
  // logic the standard Flutter ThemeData.from color scheme factory uses.
  final Color _effectiveAppBarColor = appBarBackground ??
      (_isDark ? _colorScheme.surface : _colorScheme.primary);
  // Calculate brightness for the app bar from the resulting effective color.
  final Brightness _appBarBrightness =
      ThemeData.estimateBrightnessForColor(_effectiveAppBarColor);

  // Use passed in target platform or the default one.
  final TargetPlatform _platform = platform ?? defaultTargetPlatform;

  // With Typography we deviate from the Flutter standard that uses the
  // old Typography.material2014 in favor of the newer Typography.material2018
  // as default, if one is not provided.
  final Typography _typography =
      typography ?? Typography.material2018(platform: _platform);

  // The Flutter standard selected tab and indicator color is onSurface in
  // dark mode and onPrimary in light mode, which is designed to fit an AppBar
  // colored TabBar. We keep this default when FlexTabBarStyle.forAppBar style
  // is used, with a minor modification. If AppBar is "light", then we use
  // black87, not black, so its like the textTheme on AppBar.
  // If the FlexTabBarStyle.forBackground style was used, the selected
  // color is always color scheme primary color, which will work on surface,
  // background and scaffold background colors.
  Color _effectiveTabColor() {
    if (tabBarStyle == FlexTabBarStyle.forBackground) {
      return _colorScheme.primary;
    } else {
      // We use default style for usage in an AppBar, or some other case.
      if (_appBarBrightness == Brightness.light) {
        return Colors.black87; // Match AppBar texTheme style on light.
      } else {
        return Colors.white;
      }
    }
  }

  // Calculate the selected tab bar color and store it in a local variable.
  final Color _selectedTabColor = _effectiveTabColor();

  // The unselected TabBar color when [FlexTabBarStyle.forBackground] style
  // is used, is always the onSurface color with 60% opacity. This is also
  // the color if the AppBar background color brightness is light AND its
  // color is white, surface or background colored.
  // Otherwise when the style [FlexTabBarStyle.forAppBar] is used, the
  // unselectedTabColor is the selected tab color with 70% opacity. This
  // opacity value is the same  as Flutter default for the default theme
  // that is also designed for AppBar usage.
  //
  // This conditional expression is not so pretty, but I preferred it as an
  // expression. Since it only has two outcomes, I thought it was
  // still reasonable to write it like this, instead of via a function like
  // the effectiveTabColor, that has 3 outcomes. If it needs more logic
  // later, consider a rewrite with a function with logic.
  final Color _unselectedTabColor =
      (tabBarStyle == FlexTabBarStyle.forBackground ||
              (_appBarBrightness == Brightness.light &&
                  (_effectiveAppBarColor == Colors.white ||
                      _effectiveAppBarColor == _colorScheme.surface ||
                      _effectiveAppBarColor == _colorScheme.background)))
          ? _onColors.onSurface.withOpacity(0.6)
          : _selectedTabColor.withOpacity(0.7);

  // The current default theme for Material themed Tooltips are poor design
  // choices for desktop https://material.io/components/tooltips#specs.
  // See issue: https://github.com/flutter/flutter/issues/71429
  // The font size of 10 dp is just too small for desktops with pixel density
  // 1.0 also the dark tooltips on light theme and light tooltips on dark
  // themes seem more reminiscent of bootstrap Web theme and does not fit so
  // well on desktop, windows native for example uses light tooltips on light
  // themes. This default theme for tooltips uses that design choice and also
  // makes desktop and hence Web tooltips a bit larger as well, by using
  // 12dp font size instead of the too small 10 dp.
  double _tooltipFontSize() {
    switch (_platform) {
      case TargetPlatform.macOS:
      case TargetPlatform.linux:
      case TargetPlatform.windows:
        return 12;
      default:
        return 14;
    }
  }

  // This padding on tooltips fixes that the default tooltip does not work
  // well if two row tooltips are used.
  EdgeInsets _tooltipPadding() {
    switch (_platform) {
      case TargetPlatform.macOS:
      case TargetPlatform.linux:
      case TargetPlatform.windows:
        return const EdgeInsets.fromLTRB(8, 3, 8, 4);
      default:
        return const EdgeInsets.symmetric(horizontal: 16, vertical: 8);
    }
  }

  // Same as in ThemeData.from, but defined for reuse access in sub-themes.
  final Color _dividerColor = _colorScheme.onSurface.withOpacity(0.12);
  // Same as in ThemeData, but defined here for reuse in custom sub-themes.
  final Color _disabledColor = _isDark ? Colors.white38 : Colors.black38;
  final Color _hintColor =
      _isDark ? Colors.white60 : Colors.black.withOpacity(0.6);

  // Make and return the ThemeData object defined by the FlexColorScheme
  // properties and the designed slightly opinionated theme design choices
  // over default Flutter Material theme implementation.
  return ThemeData(
    // These properties we just pass along these to the standard ThemeData
    // factory. They are included in FlexColorScheme so we do not have to
    // apply them via ThemeData copyWith separately for cases when we want
    // to use them in a FlexColorSchemes, which might often be the case. Some
    // of the values may be null and get defaults via the ThemeData() factory.
    fontFamily: fontFamily,
    visualDensity: visualDensity,
    typography: _typography,
    platform: _platform,
    // Most definitions below are very close to the ones used by the Flutter
    // factory ThemeData.from for creating a theme from a color scheme and
    // text theme. Any modifications to it are explained.
    brightness: _colorScheme.brightness,
    primaryColor: _colorScheme.primary,
    primaryColorBrightness:
        ThemeData.estimateBrightnessForColor(_colorScheme.primary),
    canvasColor: _colorScheme.background,

    // TODO: Remove accentColor when deprecated on stable.
    accentColor: _colorScheme.secondary,
    accentColorBrightness:
        ThemeData.estimateBrightnessForColor(_colorScheme.secondary),

    // Flutter standard for scaffoldBackgroundColor is colorScheme.background.
    // Here it is replaced with a separate color for the scaffold background,
    // so we can use a configuration with a separate scaffold background
    // color from scheme background and surface, if so desired. Flutter's
    // standard ThemeData.from a ColorScheme cannot do this. The good old
    // ThemeData factory can of course, but color scheme based themes in
    // flutter cannot specify it separately. We need to be able to do so
    // in order to make elegantly primary color branded themes.
    scaffoldBackgroundColor: scaffoldBackground ?? _colorScheme.background,
    // Card, divider and background colors are same as in ThemeData.from.
    cardColor: _colorScheme.surface,
    dividerColor: _dividerColor,
    backgroundColor: _colorScheme.background,
    // Same as in ThemeData factory, but defined via final value in build for
    // easy reuse access in sub-themes further below.
    disabledColor: _disabledColor,
    hintColor: _hintColor,
    // Flutter standard dialogBackgroundColor for color scheme based themes
    // uses colorScheme.background.
    // We use surface color instead of background for the dialog background.
    // In Flutter ColorScheme .dark and .light, they are the same, but
    // background color affects things like drawer, bottom bar and we
    // like them slightly darker than surface, and when using primary blended
    // background, we want it to be a stronger blend than surface, but this
    // does not fit so well on dialogs, so we use colorScheme.surface for
    // dialog background instead. This modification keeps the dialog color
    // as expected for standard default surfaces, but also works well when
    // using a slightly darker or stronger branded color for background.
    dialogBackgroundColor: _colorScheme.surface,

    // Define errorColor via color scheme error color.
    errorColor: _colorScheme.error,

    // Replaced Flutter standard indicator color with colorScheme.primary.
    // The default is onSurface in dark mode and onPrimary in light mode,
    // which is designed to fit an app bar colored tab bar. Since we made
    // the tab bar to be used primarily on surface color, we want the
    // indicator to be primary colored both in dark and light mode.
    indicatorColor: _selectedTabColor,

    // Elevation overlay on dark material elevation is used on dark themes
    // on surfaces by default. Flutter ThemeData.from ColorScheme based
    // themes also uses this by default, but ThemeData factory does not.
    applyElevationOverlayColor: _isDark,

    // Pass the from FlexColorScheme defined colorScheme to ThemeData
    // colorScheme. Newer standard Flutter sub themes use the colorScheme
    // for their theming and all sub themes will eventually be converted to
    // be based on the defined color scheme colors. FlexColorScheme passes
    // the scheme it has created to the colorScheme property in ThemeData.
    // More info here: https://flutter.dev/go/material-theme-system-updates
    colorScheme: _colorScheme,

    // ----------------------------------------------------------------------
    // The theme settings below are corrective additions to the Flutter
    // standard Theme.from(colorScheme) factory. They are needed because it
    // omits some definitions that will not be aligned with the ColorScheme
    // theme if they are not added to it manually.
    // This as per the state in master channel December 15, 2020.
    // This document again relates to the on going transition:
    // https://flutter.dev/go/material-theme-system-updates
    // This issue explains and demos some of the current gaps:
    // https://github.com/flutter/flutter/issues/65782
    // Some of the gaps will probably be solved when Flutter's theme
    // migration progresses. This package will monitor the development and
    // remove no longer needed corrections or remove totally deprecated
    // ThemeData properties when it is appropriate and timely to do so.
    // ----------------------------------------------------------------------

    // This color is important, if it is not set we get a teal color for it
    // in dark mode, and not actually the secondary color that we want for
    // our color scheme based theme. The Flutter color scheme based theme
    // does not include this, in our opinion correct application of the color
    // scheme based theme, it should really do the same as below.
    // See issue: https://github.com/flutter/flutter/issues/65782
    toggleableActiveColor: _colorScheme.secondary,

    // The primary dark color no longer exists in ColorScheme themes, but
    // it still needs to be set to match the ColorScheme theme, otherwise we
    // get a default dark blue theme color for it coming from default
    // primarySwatch. This will not look good if your theme uses any primary
    // color that is not a blue hue. To fix this we use the [700] value from
    // the calculated primary swatch for dark mode and [800] for light mode.
    // See issue: https://github.com/flutter/flutter/issues/65782
    primaryColorDark: _primaryColorDark,

    // The light primary color no longer exists in ColorScheme themes, but it
    // still needs to be set to match the ColorScheme theme, otherwise we
    // get a default blue color for it coming from the default primarySwatch.
    // We use the [100] value from the calculated primary swatch.
    // See issue: https://github.com/flutter/flutter/issues/65782
    primaryColorLight: _primaryColorLight,

    // Define a secondary header color, not sure what uses it, but we should
    // give it a color that will work with ColorScheme based themes. If it is
    // not set, it gets a super light [50] hue of the primary color from
    // default theme.light factory. We use the [50] value from the
    // calculated primary swatch instead.
    // See issue: https://github.com/flutter/flutter/issues/65782
    secondaryHeaderColor: _secondaryHeaderColor,

    // The app bar theme allows us to use a custom colored appbar theme
    // in both light and dark themes that is not dependent on theme primary
    // or surface color, and still gets a correct working text and icon theme.
    // In the versions prior to Flutter 2.0.0 doing this was difficult, as
    // presented in https://github.com/flutter/flutter/issues/50606 doing
    // this is a bit tricky. A new feature in Flutter 2.0.0 implemented via:
    // https://github.com/flutter/flutter/pull/71184 makes this easy and
    // better. The FlexColorScheme implementation below has been changed to
    // use this new AppBarTheme feature from version 2.0.0-nullsafety.2
    appBarTheme: AppBarTheme(
      // Use the defined appbar color for the theme
      backgroundColor: _effectiveAppBarColor,
      foregroundColor:
          _appBarBrightness == Brightness.dark ? Colors.white : Colors.black,
      // Define appropriate brightness on the icon themes
      iconTheme: _appBarBrightness == Brightness.dark
          ? const IconThemeData(color: Colors.white)
          : const IconThemeData(color: Colors.black87),
      actionsIconTheme: _appBarBrightness == Brightness.dark
          ? const IconThemeData(color: Colors.white)
          : const IconThemeData(color: Colors.black87),
      elevation: appBarElevation,
      systemOverlayStyle: SystemUiOverlayStyle(
        // AppBar overlay style.
        statusBarColor: transparentStatusBar
            ? Colors.transparent
            // This is the actual scrim color used by Android by default,
            // here we just re-apply if false or if it had been removed
            // earlier, using `null` does not restore we need the actual used
            // scrim by Android ro restore if it has been removed earlier.
            : const Color(0x40000000),
        statusBarBrightness: _appBarBrightness,
        statusBarIconBrightness: _appBarBrightness == Brightness.dark
            ? Brightness.light
            : Brightness.dark,

        // The systemNavigationBarColor used by default AppBar in SDK:
        systemNavigationBarColor: const Color(0xFF000000),
        // Would be nice if this worked instead of above, but it does not:
        // systemNavigationBarColor: _isDark ? Colors.black : Colors.white;,

        // The systemNavigationBarIconBrightness used by the AppBar in SDK:
        systemNavigationBarIconBrightness: Brightness.dark,
        // Would be nice if this worked instead of above, but it does not:
        // systemNavigationBarIconBrightness:
        //     _isDark ? Brightness.light : Brightness.dark,

        // The systemNavigationBarDividerColor used by default AppBar in SDK:
        // ignore: avoid_redundant_argument_values
        systemNavigationBarDividerColor: null,
      ),
      // We use the new AppBarTheme that has more features, but is not
      // backwards compatible.
      backwardsCompatibility: false,
    ),

    // The bottom app bar uses color scheme background color to match the
    // background color of the drawer, bottom navigation bar, possible side
    // menu and system navigation bar on android (if theming of it is used).
    // This is a slight change from the ColorScheme default that uses
    // surface color.
    bottomAppBarColor: _colorScheme.background,
    bottomAppBarTheme: BottomAppBarTheme(
      color: _colorScheme.background,
      elevation: bottomAppBarElevation,
    ),

    // ----------------------------------------------------------------------
    // The additions below are theme customizations that differs from the
    // defaults Flutter provides out of the box. They go nicely together with
    // the rest of the theme settings used by FlexColorScheme based themes.
    // The choices are of course opinionated and you can define own values
    // that override them with copyWith, just as you would on the default
    // ThemeData factory.
    // ----------------------------------------------------------------------
    // Set to true, because it looks better and it should be true in standard
    // too, but it is kept as false there for legacy compatibility.
    fixTextFieldOutlineLabel: true,
    // In TextSelectionThemeData, the standard for selectionColor is
    // colorScheme.primary with opacity value 0.4 for dark and 0.12 light
    // mode. Here we use primary with 0.5 for dark mode and 0.3 for light
    // mode. The standard selectionHandleColor is colorScheme.primary,
    // here we use the slightly darker shade primaryColorDark instead.
    textSelectionTheme: TextSelectionThemeData(
      selectionColor: _isDark
          ? _colorScheme.primary.withOpacity(0.50)
          : _colorScheme.primary.withOpacity(0.30),
      selectionHandleColor: _primaryColorDark,
    ),
    // Input decoration theme
    inputDecorationTheme: InputDecorationTheme(
      filled: true,
      fillColor: _isDark
          ? _colorScheme.primary.withOpacity(0.06)
          : _colorScheme.primary.withOpacity(0.035),
    ),

    // NOTE: Since the old buttons have been deprecated in Flutter 2.0.0
    // they are no longer presented or used in the code in FlexColorScheme.
    // However, FlexColorScheme still defines the themes for them described
    // below. Defining the theme does not yet issue any deprecation warning
    // or error, as long as that is the case this theming will be kept.
    //
    // The button color and button theming below makes the old buttons almost
    // look like the defaults for the new ElevatedButton, TextButton and
    // OutlinedButton. These were defaults I used previously for the old
    // buttons. With these themes as defaults for the old buttons,
    // transitioning to the new buttons goes almost un-noticed.
    // There is no custom theming for the new buttons applied as they look
    // pretty good out of the box. But the old ones did not, the next two
    // theme settings fixes that.
    //
    // Set buttonColor to colorScheme.primary and not to grey. Similar to
    // to the Material design for the newer buttons.
    buttonColor: _colorScheme.primary,
    // When the button color is set to primary, we also need to define the
    // [ButtonThemeData] so that we get correct onSurface colors for the
    // buttons. This buttonColor and buttonTheme setup, makes the older
    // Flutter Material buttons [RaisedButton], [OutlineButton] and
    // [FlatButton] very similar in style to the default color scheme based
    // style used for the newer Material buttons [ElevatedButton],
    // [OutlinedButton] and [TextButton]. There are some differences in margin
    // and outline color and the elevation behavior on the raised button.
    // But they are close enough, this is a button style I was using before
    // the introduction of the new buttons and their defaults, it just happens
    // to be very close as I had based it loosely on how things looked in the
    // design guide prior to Flutter releasing the new buttons. The newer
    // buttons are still nicer when it come to their interactions and all the
    // theming options they provide, but they are tedious to theme. If you
    // want to make custom styled buttons I recommend using the newer buttons
    // instead of the old ones as they offer more customization possibilities.
    buttonTheme: ButtonThemeData(
      colorScheme: _colorScheme,
      textTheme: ButtonTextTheme.primary,
      materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
      padding: const EdgeInsets.symmetric(horizontal: 16),
    ),

    // The default chip theme in Flutter does not work correctly with dark
    // themes. See issue: https://github.com/flutter/flutter/issues/65663
    // The chip theme below fixes it by using the colorScheme.primary color.
    chipTheme: ChipThemeData.fromDefaults(
      secondaryColor: _colorScheme.primary,
      brightness: _colorScheme.brightness,
      labelStyle: _textTheme.bodyText1!,
    ),

    // Define the TabBar theme that will fit nicely in an AppBar
    // (default) or on background color for use eg in a Scaffold, the choice
    // depends on tabBarStyle `FlexTabBarStyle`, that defaults to
    // `FlexTabBarStyle.forAppBar`.
    tabBarTheme: TabBarTheme(
      indicatorSize: TabBarIndicatorSize.tab,
      labelStyle: const TextTheme().button,
      labelColor: _selectedTabColor,
      unselectedLabelColor: _unselectedTabColor,
    ),

    // Opinionated theming for the bottom navigation bar.
    // It uses primary color for the selected item. Flutter default uses
    // secondary color. Primary color is also "iOS" style for the bottom nav.
    bottomNavigationBarTheme: BottomNavigationBarThemeData(
      selectedIconTheme: IconThemeData(
        color: _colorScheme.primary,
      ),
      selectedItemColor: _colorScheme.primary,
    ),

    // Opinionated theming of Tooltips, as stated previously above, the
    // default theme for Material themed Tooltips are poor design choices
    // https://material.io/components/tooltips#specs.
    // The theming below is an opinionated nicer design with an option
    // to also invert the tooltip background color.
    // See issue: https://github.com/flutter/flutter/issues/71429
    tooltipTheme: TooltipThemeData(
      // We do not use the min height, the custom padding handles it instead.
      padding: _tooltipPadding(),
      margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
      textStyle: _textTheme.bodyText2!.copyWith(
        inherit: false,
        color: tooltipsMatchBackground
            ? _isDark
                ? Colors.white
                : Colors.black
            : _isDark
                ? Colors.black
                : Colors.white,
        fontSize: _tooltipFontSize(),
      ),
      decoration: tooltipsMatchBackground
          ? BoxDecoration(
              color:
                  _isDark ? const Color(0xED444444) : const Color(0xF0FCFCFC),
              borderRadius: const BorderRadius.all(Radius.circular(4)),
              border: Border.all(color: _dividerColor),
            )
          : null,
    ),
  );
}