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 ThemeData.copyWith method on the resulting theme.

The differences from the standard ThemeData.from factory are:

  • ScaffoldBackgroundColor has its own color property in FlexColorScheme and can if so desired differ from the ColorScheme.background color. When using primary color blended surfaces and backgrounds, it is important to be able to vary the very prominent ScaffoldBackgroundColor separately from other surfaces and backgrounds.

  • The dialogBackgroundColor in M2 uses the ColorScheme.surface color instead of the default ColorScheme.background. In order to preserve the elevationOverlayColor in dark mode when ColorScheme.surface and ColorScheme.background differs due to different surface blends, the ColorScheme.surface was used to ensure dialogs that are always elevated gets the overlay color applied in dark theme mode. For more info see: issue #90353. In M3 ColorScheme.surface is used by the SDK as well.

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

  • Flutter themes created with ThemeData.from does not define any color scheme related color for the primaryColorDark color, FCS 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. This color property will be deprecated in Flutter, see issue 91772.

  • Flutter themes created with ThemeData.from does not define any color scheme related color for the primaryColorDark color, FCS 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. This color property will be deprecated in Flutter, see issue 91772.

  • Flutter themes created with ThemeData.from does not define any color scheme related color for the primaryColorDark color, FCS 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. This color property will be deprecated in Flutter, see issue 91772.

  • 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 M2 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 BottomAppBarTheme when not using subThemes, we in M2 mode always get a BottomAppBarTheme with at least background color defined to be ColorScheme.surface, even if bottomAppBarElevation is null. This is done to avoid issues with deprecation of ThemeData.bottomAppBarColor that is still used in M2 mode defaults. When using M3 mode and if bottomAppBarElevation is null, we actually get a default BottomAppBarTheme() all null theme made by FlexSubThemes.bottomAppBarTheme.

  • 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.

  • 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. These legacy buttons are deprecated in Flutter and some no longer exists. The buttonTheme is also on a deprecation path and will be removed when it is.

  • In older Flutter version, the default theme for Chips contained a design bug that makes the selected ChoiceChip() widget look disabled in dark-mode, regardless of if it was created with ThemeData or ThemeData.from factory. See issue: https:///github.com/flutter/flutter/issues/65663 The ChipThemeData modification originally used in core FlexColorScheme fixed the issue. The issue has been resolved but same ChipThemeData is still in use for backward style compatibility.

  • For TabBarTheme, in M2 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. When using M3 the FlexTabBarStyle.flutterDefault is used. producing a TabBar with the default M3 design.

    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 ListTileThemeData is added to core defaults and it sets ListTileThemeData.tileColor to Colors.transparent if ThemeData.useMaterial3 is true. This is done to avoid issue: https://github.com/flutter/flutter/issues/117700. This extra M3 core default theme fix may be removed when the issue is fixed.

  • The BottomNavigationBarThemeData uses color scheme primary color for the selected item in both light and dark theme. Flutter SDK defaults to secondary color in dark mode. Using only 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 also in dark mode.

  • The ToolTipThemeData will when tooltipsMatchBackground is set to true, make tooltip background color will match the brightness of the theme's background color.

By default Flutter's Material tooltips use a theme where the tooltip background color brightness is inverted in relation to the overall theme's background color.

FlexColorScheme allows you to use a single toggle to invert this. Light tooltips on light background is e.g. the default style on Windows Desktop toggle. You can use this toggle to use this style, or use it as a means to create a platform adaptive tooltip style, where the Material and Flutter style is used on devices and Web, but the inverted scheme is used on e.g. Windows platform.

Defaults to false, and uses same background style as Material Design guide and Flutter.

Additional tooltip styles when NOT opting in on FlexColorScheme sub themes are:

  • tooltipsMatchBackground: false

    • none
  • tooltipsMatchBackground: true

    • light theme:
      • background: Color(0xF0FCFCFC),
      • text: black
    • Dark theme:
      • background: Color(0xED444444),
      • text: white
    • Border radius: 4 dp
    • Border: Yes, dividerColor
    • Desktop OS (macOS, Linux, Windows)
      • Font size : 12 dp
    • Mobile OS (iOS, Android, Fuchsia)
      • Font size : 14 dp

Additional styles when opting in on FlexColorScheme sub themes are:

  • Desktop OS (macOS, Linux, Windows)
    • Font size : 12 dp
  • Mobile OS (iOS, Android, Fuchsia)
    • Font size : 14 dp
  • Border radius: 8 dp
  • Border: Yes, dividerColor
  • tooltipsMatchBackground: false
    • light theme:
      • background: Color(0xFF111111).blendAlpha(primary, 45%) opacity 95%
      • text: white
    • Dark theme:
      • background: Color(0xFFFFFFFF).blendAlpha(primary, 39%) opacity 95%
      • text: black
  • tooltipsMatchBackground: true
    • light theme:
      • background: Color(0xFFFFFFFF).blendAlpha(primary, 4%) opacity 95%
      • text: black
    • Dark theme:
      • background: Color(0xFF111111).blendAlpha(primary, 16%) opacity 95%
      • text: white

When using additional theming via sub-themes properties, its properties will if used override background color, text color and background opacity as well as border radius.


  • 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 {
  // Returns true if the color is dark, it needs light text for contrast.
  bool isColorDark(final Color color) =>
      ThemeData.estimateBrightnessForColor(color) == Brightness.dark;

  // On color used when a color property does not have a theme onColor.
  Color onColor(final Color color) =>
      isColorDark(color) ? Colors.white : Colors.black;

  // Use sub-themes if a none null FlexSubThemesData was passed in.
  final bool useSubThemes = subThemesData != null;
  // If we did not have any sub-theme data, we make one instead that cannot
  // be null. It makes the logic easier to deal with when we create
  // sub-themes, when it cannot be nullable.
  final FlexSubThemesData subTheme =
      subThemesData ?? const FlexSubThemesData();

  // Get the effective ColorScheme from the provided brightness and
  // provided or computed or default colors.
  final ColorScheme colorScheme = toScheme;

  // A convenience bool to check if this theme is for light or dark mode
  final bool isDark = colorScheme.brightness == Brightness.dark;

  // Use passed in target platform, else use actual host platform.
  final TargetPlatform effectivePlatform = platform ?? defaultTargetPlatform;

  // Remove elevation tint in M3?
  final FlexAdaptive subTint =
      subTheme.adaptiveRemoveElevationTint ?? const FlexAdaptive.off();
  final bool removeTint = useMaterial3 && subTint.adapt(effectivePlatform);

  // Remove NavigationBar elevation tint in M3?
  final FlexAdaptive navBarTint =
      subTheme.adaptiveRemoveNavigationBarTint ?? const FlexAdaptive.off();
  final bool removeNavBarTint =
      useMaterial3 && navBarTint.adapt(effectivePlatform);

  // Use elevation shadow in M3?
  final FlexAdaptive subShadow =
      subTheme.adaptiveElevationShadowsBack ?? const FlexAdaptive.off();
  final bool useShadow = useMaterial3 && subShadow.adapt(effectivePlatform);

  // No AppBar scroll under elevation tint
  final FlexAdaptive scrollUnderOff =
      subTheme.adaptiveAppBarScrollUnderOff ?? const FlexAdaptive.off();
  final bool noScrollUnder =
      useMaterial3 && scrollUnderOff.adapt(effectivePlatform);

  // Use defaultRadiusAdaptive instead of defaultRadius?
  final FlexAdaptive adaptiveRadius =
      subTheme.adaptiveRadius ?? const FlexAdaptive.off();
  // Get the correct platform default radius.
  final double? platformRadius = adaptiveRadius.adapt(effectivePlatform)
      ? subTheme.defaultRadiusAdaptive
      : subTheme.defaultRadius;

  // Use adaptive dialog radius?
  final FlexAdaptive adaptiveDialogRadius =
      subTheme.adaptiveDialogRadius ?? const FlexAdaptive.off();
  // Get the effective used adaptive dialog default radius.
  final double? platformDialogRadius =
      adaptiveDialogRadius == const FlexAdaptive.off() &&
              subTheme.dialogRadius == null
          ? null
          : adaptiveDialogRadius.adapt(effectivePlatform)
              ? subTheme.dialogRadiusAdaptive ?? kDialogRadius
              : subTheme.dialogRadius ?? kDialogRadius;

  // Use adaptive splash?
  final FlexAdaptive adaptiveSplashType =
      subTheme.adaptiveSplash ?? const FlexAdaptive.off();
  // Get the effective used platform adaptive ink feature.
  final InteractiveInkFeatureFactory? platformSplash =
      adaptiveSplashType.adapt(effectivePlatform)
          ? subTheme.splashTypeAdaptive?.splashFactory(useMaterial3)
          : subTheme.splashType?.splashFactory(useMaterial3);

  // We need to make a special case for component splash factories,
  // if we are using Material2 we need to override the platformSplash factory
  // for the buttons to get the selected splash in M2 mode, since
  // in M2 mode the buttons do not fallback to ThemeData.splashFactory, but
  // in M3 mode they do so we can skip defining th factory for them then.
  // In M2 mode we also need to fall back to InkSplash.splashFactory, since
  // in M2 mode FilledButton gets InkRipple by default, but other buttons
  // get InkSplash by default in M2 mode, Flutter inconsistencies, sigh.
  final InteractiveInkFeatureFactory? buttonsSplashFactory =
      useMaterial3 ? null : platformSplash ?? InkSplash.splashFactory;

  // Logic to determine the default Typography to use.
  //
  // Used Typography deviates from the Flutter standard that _still_ uses the
  // old Typography.material2014 in favor of the newer Typography.material2018
  // as default in M2, if one is not provided. We use the Material 2 correct
  // 2018 typography as the default when not using M3. If using M3 or
  // opting-in via sub-themes on using M3 TextTheme geometry, the new 2021
  // Typography is used that was released in Flutter 3.0.0.
  //
  // A little know thing Typography.material2021 factory also needs the used
  // M3 colorscheme for a correct style.
  Typography defaultTypography() {
    // ignore: use_if_null_to_convert_nulls_to_bools
    if (useSubThemes && subTheme.useTextTheme == true) {
      return Typography.material2021(
          platform: effectivePlatform, colorScheme: colorScheme);
    }
    if (useSubThemes && subTheme.useTextTheme == null && useMaterial3) {
      return Typography.material2021(
          platform: effectivePlatform, colorScheme: colorScheme);
    }
    if (!useSubThemes && useMaterial3) {
      return Typography.material2021(
          platform: effectivePlatform, colorScheme: colorScheme);
    }
    return Typography.material2018(platform: effectivePlatform);
  }

  final Typography effectiveTypography = typography ?? defaultTypography();
  // We need the text themes locally for the theming, so we must form them
  // fully using the same process that the ThemeData() factory uses.
  TextTheme defText =
      isDark ? effectiveTypography.white : effectiveTypography.black;
  final bool primaryIsDark = isColorDark(colorScheme.primary);
  TextTheme defPrimaryText =
      primaryIsDark ? effectiveTypography.white : effectiveTypography.black;

  // ThemeData uses this to apply a font from fontFamily, fontFamilyFallback
  // and package in this order to default text theme and primary text theme.
  // We excluded the accent text theme since it is deprecated, Flutter SDK
  // still applies font to it as well, not sure why it is kept around.
  // This all works OK, but it resets all typography and it uses regular style
  // and weight for all styles in the text theme. Consider defining the text
  // theme explicitly via textTheme and primaryTextTheme with the custom
  // font applied, at least if you want to use custom fonts and keep the
  // standard typography, or supply your own complete typography with your
  // custom text theme.
  if (fontFamily != null) {
    defText = defText.apply(fontFamily: fontFamily);
    defPrimaryText = defPrimaryText.apply(fontFamily: fontFamily);
  }
  if (fontFamilyFallback != null) {
    defText = defText.apply(fontFamilyFallback: fontFamilyFallback);
    defPrimaryText =
        defPrimaryText.apply(fontFamilyFallback: fontFamilyFallback);
  }
  if (package != null) {
    defText = defText.apply(package: package);
    defPrimaryText = defPrimaryText.apply(package: package);
  }

  // TextTheme is a default GoogleFonts TextTheme.
  //
  // Let's take a look at provided TextTheme, if it is a match for a
  // GoogleFont TextTheme, remove its default colors so we can make one with
  // correct M2/M3 defaults.
  TextTheme? pTextTheme = textTheme;
  if (pTextTheme != null) {
    final TextTheme gFontTextTheme = ThemeData.light().textTheme.apply(
      fontFamily: '',
      fontFamilyFallback: <String>[''],
    );
    final TextTheme passedTextTheme = pTextTheme.apply(
      fontFamily: '',
      fontFamilyFallback: <String>[''],
    );
    if (gFontTextTheme == passedTextTheme) {
      pTextTheme = TextThemeColor.nullFontColor(pTextTheme);
    }
  }
  // Make default TextThemes, by also merging in the two TextThemes
  // passed in via the constructor. The 2nd copyWith, ensures putting back
  // correct contrast color on any passed in text theme. FCS does not
  // require defining correct contrast colors for light/dark mode text theme,
  // nor for the primary color contrast text theme. It always fixes them
  // to be correct and also uses correct opacities on M2 typography, and
  // opaque ones on M3 typography, regardless of used M2/M3 mode.
  defText = defText.merge(pTextTheme);

  // TextTheme is a default GoogleFonts TextTheme.
  //
  // Let's take a look at provided TextTheme, if it is a match for a
  // GoogleFont TextTheme, remove its default colors so we can make one with
  // correct M2/M3 defaults.
  TextTheme? pPrimTextTheme = primaryTextTheme;
  if (pPrimTextTheme != null) {
    final TextTheme gFontTextTheme = ThemeData.light().textTheme.apply(
      fontFamily: '',
      fontFamilyFallback: <String>[''],
    );
    final TextTheme passedTextTheme = pPrimTextTheme.apply(
      fontFamily: '',
      fontFamilyFallback: <String>[''],
    );
    if (gFontTextTheme == passedTextTheme) {
      pPrimTextTheme = TextThemeColor.nullFontColor(pPrimTextTheme);
    }
  }
  // Equivalent text theme and color correct for primary TextTheme that will
  // always get correct contrast color to be used on primary color.
  defPrimaryText = defPrimaryText.merge(pPrimTextTheme);

  // We are using sub themes and blend colors on text themes. If surfaces and
  // background are not set to use blends, the effect will be slightly
  // different, a bit less colorful, but only very marginally.
  if (useSubThemes && subTheme.blendTextTheme) {
    // Calculate colors for the different TextStyles, color blend strength are
    // inline with opacities on the 2014/2018/2021 typographies.
    // For main text theme we are using surface tint instead of primary,
    // normally it defaults to primary, but if it is customized we should base
    // tinted text theme on it instead.
    Color blendText(Color? color, int blend, int alpha) {
      final Color baseColor = color ?? (isDark ? Colors.white : Colors.black);
      return baseColor.blend(colorScheme.surfaceTint, blend).withAlpha(alpha);
    }

    // The tinted text theme is based of white/black, but if a custom color
    // was provided, it is based of it and tinted with surfaceTint.
    final Color cDisplayLarge = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.displayLarge?.color, kHiDarkTextBlend,
            kHiDarkTextAlpha) // 92%
        : blendText(pTextTheme?.displayLarge?.color, kHiLightTextBlend,
            kHiLightTextAlpha); // 85%
    final Color cDisplayMedium = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.displayMedium?.color, kHiDarkTextBlend,
            kHiDarkTextAlpha) // 92%
        : blendText(pTextTheme?.displayMedium?.color, kHiLightTextBlend,
            kHiLightTextAlpha); // 85%
    final Color cDisplaySmall = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.displaySmall?.color, kHiDarkTextBlend,
            kHiDarkTextAlpha) // 92%
        : blendText(pTextTheme?.displaySmall?.color, kHiLightTextBlend,
            kHiLightTextAlpha); // 85%
    //
    final Color cHeadlineLarge = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.headlineLarge?.color, kHiDarkTextBlend,
            kHiDarkTextAlpha) // 92%
        : blendText(pTextTheme?.headlineLarge?.color, kHiLightTextBlend,
            kHiLightTextAlpha); // 85%
    final Color cHeadlineMedium = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.headlineMedium?.color, kHiDarkTextBlend,
            kHiDarkTextAlpha) // 92%
        : blendText(pTextTheme?.headlineMedium?.color, kHiLightTextBlend,
            kHiLightTextAlpha); // 85%
    final Color cHeadlineSmall = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.headlineSmall?.color, kMedDarkTextBlend,
            kMedDarkTextAlpha) // 100%
        : blendText(pTextTheme?.headlineSmall?.color, kMedLightTextBlend,
            kMedLightTextAlpha); // 96%
    //
    final Color cTitleLarge = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.titleLarge?.color, kMedDarkTextBlend,
            kMedDarkTextAlpha) // 100%
        : blendText(pTextTheme?.titleLarge?.color, kMedLightTextBlend,
            kMedLightTextAlpha); // 96%
    final Color cTitleMedium = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.titleMedium?.color, kMedDarkTextBlend,
            kMedDarkTextAlpha) // 100%
        : blendText(pTextTheme?.titleMedium?.color, kMedLightTextBlend,
            kMedLightTextAlpha); // 96%
    final Color cTitleSmall = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.titleSmall?.color, kLoDarkTextBlend,
            kLoDarkTextAlpha) // 100%
        : blendText(pTextTheme?.titleSmall?.color, kLoLightTextBlend,
            kLoLightTextAlpha); // 100%
    //
    final Color cBodyLarge = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.bodyLarge?.color, kMedDarkTextBlend,
            kMedDarkTextAlpha) // 100%
        : blendText(pTextTheme?.bodyLarge?.color, kMedLightTextBlend,
            kMedLightTextAlpha); // 96%
    final Color cBodyMedium = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.bodyMedium?.color, kMedDarkTextBlend,
            kMedDarkTextAlpha) // 100%
        : blendText(pTextTheme?.bodyMedium?.color, kMedLightTextBlend,
            kMedLightTextAlpha); // 96%
    final Color cBodySmall = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.bodySmall?.color, kHiDarkTextBlend,
            kHiDarkTextAlpha) // 92%
        : blendText(pTextTheme?.bodySmall?.color, kHiLightTextBlend,
            kHiLightTextAlpha); // 85%
    //
    final Color cLabelLarge = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.labelLarge?.color, kMedDarkTextBlend,
            kMedDarkTextAlpha) // 100%
        : blendText(pTextTheme?.labelLarge?.color, kMedLightTextBlend,
            kMedLightTextAlpha); // 96%
    final Color cLabelMedium = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.labelMedium?.color, kLoDarkTextBlend,
            kLoDarkTextAlpha) // 100%
        : blendText(pTextTheme?.labelMedium?.color, kLoLightTextBlend,
            kLoLightTextAlpha); // 100%
    final Color cLabelSmall = isDark // SDK dark 70%, light 54%
        ? blendText(pTextTheme?.labelSmall?.color, kLoDarkTextBlend,
            kLoDarkTextAlpha) // 100%
        : blendText(pTextTheme?.labelSmall?.color, kLoLightTextBlend,
            kLoLightTextAlpha); // 100%

    // Apply the computed colors. With this opt-in style, text gets a hint
    // of primary and less opacity than defaults. The primary tint may
    // not work so well if you need to put text on a completely different
    // colored container than the background color. Which is why this
    // feature can be opted out of.
    // M3 has separate on colors for all colorscheme colors that can also
    // be used for color matched text on each container color.
    // This slightly primary colored default text works very well for the
    // slight primary colored M3 "neutral" surface colors that by default have
    // a primary tint too.
    defText = defText.copyWith(
      // The textHiOpacity color style group.
      displayLarge: defText.displayLarge!.copyWith(color: cDisplayLarge),
      displayMedium: defText.displayMedium!.copyWith(color: cDisplayMedium),
      displaySmall: defText.displaySmall!.copyWith(color: cDisplaySmall),
      headlineLarge: defText.headlineLarge!.copyWith(color: cHeadlineLarge),
      headlineMedium:
          defText.headlineMedium!.copyWith(color: cHeadlineMedium),
      bodySmall: defText.bodySmall!.copyWith(color: cBodySmall),
      // The textMediumOpacity color style group.
      headlineSmall: defText.headlineSmall!.copyWith(color: cHeadlineSmall),
      titleLarge: defText.titleLarge!.copyWith(color: cTitleLarge),
      titleMedium: defText.titleMedium!.copyWith(color: cTitleMedium),
      bodyLarge: defText.bodyLarge!.copyWith(color: cBodyLarge),
      bodyMedium: defText.bodyMedium!.copyWith(color: cBodyMedium),
      labelLarge: defText.labelLarge!.copyWith(color: cLabelLarge),
      // The textNoOpacity color style group.
      titleSmall: defText.titleSmall!.copyWith(color: cTitleSmall),
      labelMedium: defText.labelMedium!.copyWith(color: cLabelMedium),
      labelSmall: defText.labelSmall!.copyWith(color: cLabelSmall),
    );

    // Calculate colors for the different TextStyles, color blend strength are
    // inline with opacities on the 2014/2018/2021 typographies.
    // For main text theme we are using surface tint instead of primary,
    // normally it defaults to primary, but if it is customized we should base
    // tinted text theme on it instead.
    Color blendPrimText(Color? color, int blend, int alpha) {
      final Color baseColor =
          color ?? (primaryIsDark ? Colors.white : Colors.black);
      return baseColor.blend(colorScheme.primary, blend).withAlpha(alpha);
    }

    // The tinted text theme is based of white/black, but if a custom color
    // was provided, it is based of it and tinted with surfaceTint.
    final Color cPrimDisplayLarge = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.displayLarge?.color,
            kHiDarkPrimTextBlend, kHiDarkPrimTextAlpha) // 90%
        : blendPrimText(pPrimTextTheme?.displayLarge?.color,
            kHiLightPrimTextBlend, kHiLightPrimTextAlpha); // 85%
    final Color cPrimDisplayMedium = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.displayMedium?.color,
            kHiDarkPrimTextBlend, kHiDarkPrimTextAlpha) // 90%
        : blendPrimText(pPrimTextTheme?.displayMedium?.color,
            kHiLightPrimTextBlend, kHiLightPrimTextAlpha); // 85%
    final Color cPrimDisplaySmall = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.displaySmall?.color,
            kHiDarkPrimTextBlend, kHiDarkPrimTextAlpha) // 90%
        : blendPrimText(pPrimTextTheme?.displaySmall?.color,
            kHiLightPrimTextBlend, kHiLightPrimTextAlpha); // 85%
    //
    final Color cPrimHeadlineLarge = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.headlineLarge?.color,
            kHiDarkPrimTextBlend, kHiDarkPrimTextAlpha) // 90%
        : blendPrimText(pPrimTextTheme?.headlineLarge?.color,
            kHiLightPrimTextBlend, kHiLightPrimTextAlpha); // 85%
    final Color cPrimHeadlineMedium = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.headlineMedium?.color,
            kHiDarkPrimTextBlend, kHiDarkPrimTextAlpha) // 90%
        : blendPrimText(pPrimTextTheme?.headlineMedium?.color,
            kHiLightPrimTextBlend, kHiLightPrimTextAlpha); // 85%
    final Color cPrimHeadlineSmall = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.headlineSmall?.color,
            kMedDarkPrimTextBlend, kMedDarkPrimTextAlpha) // 100%
        : blendPrimText(pPrimTextTheme?.headlineSmall?.color,
            kMedLightPrimTextBlend, kMedLightPrimTextAlpha); // 95%
    //
    final Color cPrimTitleLarge = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.titleLarge?.color,
            kMedDarkPrimTextBlend, kMedDarkPrimTextAlpha) // 100%
        : blendPrimText(pPrimTextTheme?.titleLarge?.color,
            kMedLightPrimTextBlend, kMedLightPrimTextAlpha); // 95%
    final Color cPrimTitleMedium = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.titleMedium?.color,
            kMedDarkPrimTextBlend, kMedDarkPrimTextAlpha) // 100%
        : blendPrimText(pPrimTextTheme?.titleMedium?.color,
            kMedLightPrimTextBlend, kMedLightPrimTextAlpha); // 95%
    final Color cPrimTitleSmall = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.titleSmall?.color,
            kLoDarkPrimTextBlend, kLoDarkPrimTextAlpha) // 100%
        : blendPrimText(pPrimTextTheme?.titleSmall?.color,
            kLoLightPrimTextBlend, kLoLightPrimTextAlpha); // 100%
    //
    final Color cPrimBodyLarge = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.bodyLarge?.color,
            kMedDarkPrimTextBlend, kMedDarkPrimTextAlpha) // 100%
        : blendPrimText(pPrimTextTheme?.bodyLarge?.color,
            kMedLightPrimTextBlend, kMedLightPrimTextAlpha); // 95%
    final Color cPrimBodyMedium = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.bodyMedium?.color,
            kMedDarkPrimTextBlend, kMedDarkPrimTextAlpha) // 100%
        : blendPrimText(pPrimTextTheme?.bodyMedium?.color,
            kMedLightPrimTextBlend, kMedLightPrimTextAlpha); // 95%
    final Color cPrimBodySmall = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.bodySmall?.color,
            kHiDarkPrimTextBlend, kHiDarkPrimTextAlpha) // 92%
        : blendPrimText(pPrimTextTheme?.bodySmall?.color,
            kHiLightPrimTextBlend, kHiLightPrimTextAlpha); // 85%
    //
    final Color cPrimLabelLarge = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.labelLarge?.color,
            kMedDarkPrimTextBlend, kMedDarkPrimTextAlpha) // 100%
        : blendPrimText(pPrimTextTheme?.labelLarge?.color,
            kMedLightPrimTextBlend, kMedLightPrimTextAlpha); // 95%
    final Color cPrimLabelMedium = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.labelMedium?.color,
            kLoDarkPrimTextBlend, kLoDarkPrimTextAlpha) // 100%
        : blendPrimText(pPrimTextTheme?.labelMedium?.color,
            kLoLightPrimTextBlend, kLoLightPrimTextAlpha); // 100%
    final Color cPrimLabelSmall = primaryIsDark // SDK dark 70%, light 54%
        ? blendPrimText(pPrimTextTheme?.labelSmall?.color,
            kLoDarkPrimTextBlend, kLoDarkPrimTextAlpha) // 100%
        : blendPrimText(pPrimTextTheme?.labelSmall?.color,
            kLoLightPrimTextBlend, kLoLightPrimTextAlpha); // 100%
    // Equivalent blend text styles for primary text theme.
    defPrimaryText = defPrimaryText.copyWith(
      // The primeHiOpacity color style group.
      displayLarge:
          defPrimaryText.displayLarge!.copyWith(color: cPrimDisplayLarge),
      displayMedium:
          defPrimaryText.displayMedium!.copyWith(color: cPrimDisplayMedium),
      displaySmall:
          defPrimaryText.displaySmall!.copyWith(color: cPrimDisplaySmall),
      headlineLarge:
          defPrimaryText.headlineLarge!.copyWith(color: cPrimHeadlineLarge),
      headlineMedium:
          defPrimaryText.headlineMedium!.copyWith(color: cPrimHeadlineMedium),
      bodySmall: defPrimaryText.bodySmall!.copyWith(color: cPrimBodySmall),
      // The primeMediumOpacity color style group.
      headlineSmall:
          defPrimaryText.headlineSmall!.copyWith(color: cPrimHeadlineSmall),
      titleLarge: defPrimaryText.titleLarge!.copyWith(color: cPrimTitleLarge),
      titleMedium:
          defPrimaryText.titleMedium!.copyWith(color: cPrimTitleMedium),
      bodyLarge: defPrimaryText.bodyLarge!.copyWith(color: cPrimBodyLarge),
      bodyMedium: defPrimaryText.bodyMedium!.copyWith(color: cPrimBodyMedium),
      labelLarge: defPrimaryText.labelLarge!.copyWith(color: cPrimLabelLarge),
      // The primeNoOpacity color style group.
      titleSmall: defPrimaryText.titleSmall!.copyWith(color: cPrimTitleSmall),
      labelMedium:
          defPrimaryText.labelMedium!.copyWith(color: cPrimLabelMedium),
      labelSmall: defPrimaryText.labelSmall!.copyWith(color: cPrimLabelSmall),
    );
  }
  // Assigning results to effective text themes. In older versions a merge
  // of original text themes were done here, but that is incorrect. It should
  // be earlier above, where it is now. In principle we could use the "def"
  // text themes further below in the code. But using the past final copies
  // for now to indicate nothing more can or should be done to them.
  final TextTheme effectiveTextTheme = defText;
  final TextTheme effectivePrimaryTextTheme = defPrimaryText;

  // Custom computed shades from primary color using alpha blends works well
  // for these rarely used colors that are on deprecation path in Flutter SDK.
  // https://github.com/flutter/flutter/issues/91772
  final Color primaryColorDark = isDark
      ? colorScheme.primary.blend(Colors.black, 45)
      : colorScheme.primary.blend(Colors.black, 40);
  final Color primaryColorLight = isDark
      ? colorScheme.primary.blend(Colors.white, 35)
      : colorScheme.primary.blend(Colors.white, 40);
  final Color secondaryHeaderColor = isDark
      ? colorScheme.primary.blend(Colors.black, 60)
      : colorScheme.primary.blend(Colors.white, 80);

  // AppBar background color:
  // - If a color is passed in, that is used first. If light/dark factory
  //   created a none default background or with transparency, this will
  //   be the case
  // - If we use sub-themes, with this raw constructor, we use its scheme
  //   based color.
  // - If neither was given and M2 we use the surface color in dark mode and
  //   primary color in light mode, the same logic that Flutter SDK
  //   ThemeData.from factory sets the AppBar background color in M2, in
  //   M3 we always use surface color.
  final Color effectiveAppBarBackgroundColor = appBarBackground ??
      (useSubThemes && subTheme.appBarBackgroundSchemeColor != null
          ? FlexSubThemes.schemeColor(
              subTheme.appBarBackgroundSchemeColor!, colorScheme)
          : useMaterial3
              ? colorScheme.surface
              : isDark
                  ? colorScheme.surface
                  : colorScheme.primary);
  final Brightness appBarBrightness =
      ThemeData.estimateBrightnessForColor(effectiveAppBarBackgroundColor);
  Color appBarForeground =
      appBarBrightness == Brightness.dark ? Colors.white : Colors.black;
  // Icons are slightly black  transparent in light mode! This per SDK.
  Color appBarIconColor =
      appBarBrightness == Brightness.dark ? Colors.white : Colors.black87;
  // If we are using subThemes and blend text, use it for the AppBar text too.
  if (useSubThemes && subTheme.blendTextTheme) {
    if (appBarBrightness == Brightness.dark) {
      appBarForeground =
          FlexColor.lightSurface.blend(effectiveAppBarBackgroundColor, 12);
    } else {
      appBarForeground =
          FlexColor.darkSurface.blend(effectiveAppBarBackgroundColor, 12);
    }
    appBarIconColor = appBarForeground;
  }

  // The FlexColorScheme AppBar's customizable system UI overlay style.
  // This refers to the top status bar on Android and iOS. Some features
  // only apply to Android. These settings have no effect on other platforms
  // than Android and iOS.
  final SystemUiOverlayStyle systemOverlayStyle = SystemUiOverlayStyle(
    systemStatusBarContrastEnforced: false,
    // 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 it, we need to re-apply
        // the used scrim color by Android to restore if it has been
        // removed earlier.
        : const Color(0x40000000),
    statusBarBrightness: appBarBrightness,
    statusBarIconBrightness: appBarBrightness == Brightness.dark
        ? Brightness.light
        : Brightness.dark,

    // TODO(rydmike): Monitor sys-nav AppBar systemOverlayStyle issue.
    // It would be useful if we could set system navbar properties too and not
    // only status bar properties. While it might be odd to do so, it
    // seems even more odd that a part of the SystemUiOverlayStyle has
    // no effect when used here.
    // See https://github.com/flutter/flutter/issues/104410
    // and https://github.com/flutter/flutter/issues/100027#issuecomment-1077697819
    // PR: https://github.com/flutter/flutter/pull/104827
    // The systemNavigationBarColor used by default AppBar in SDK is
    // always black, like so:
    // systemNavigationBarColor: const Color(0xFF000000),
    // If we try to set it to scheme background instead in AppBar theme, it
    // does not do anything, result will be black anyway.
    systemNavigationBarColor: colorScheme.background,
    // The systemNavigationBarIconBrightness used by the AppBar in SDK, is
    // always light, for the black background it get, like so:
    // systemNavigationBarIconBrightness: Brightness.light,
    // We try to match it to the color of our scheme background, but we
    // always get the light ones anyway, which is fine, as long as the
    // system navbar remains black anyway.
    systemNavigationBarIconBrightness:
        isDark ? Brightness.light : Brightness.dark,
    // Keeping the above system navbar changes, even if they up to at
    // least Flutter 2.10.3 did not do anything, maybe they start to
    // work one day, then we do not not need an AnnotatedRegion for it
    // anymore but can get it via AppBar theme, the way it should work.
    // The systemNavigationBarDividerColor used by default AppBar in SDK:
    systemNavigationBarDividerColor: null,
    systemNavigationBarContrastEnforced: false,
  );

  // Selected TabBar color is based on FlexTabBarStyle tabBarStyle.
  // The `flutterDefault` sets values corresponding to SDK Default behavior,
  // it can be used, but is not as useful as the `forAppBar` version which
  // is the default here.
  final FlexTabBarStyle effectiveTabBarStyle = tabBarStyle ??
      (useMaterial3
          ? FlexTabBarStyle.flutterDefault
          : FlexTabBarStyle.forAppBar);
  Color tabBarStyleColor() {
    switch (effectiveTabBarStyle) {
      case FlexTabBarStyle.flutterDefault:
        return useMaterial3
            ? colorScheme.primary
            : isDark
                ? Colors.white
                : colorScheme.onPrimary;
      case FlexTabBarStyle.forBackground:
        return colorScheme.primary;
      case FlexTabBarStyle.forAppBar:
        return appBarBrightness == Brightness.light
            ? Colors.black87
            : Colors.white;
      case FlexTabBarStyle.universal:
        // TODO(rydmike): Chore: Better FlexTabBarStyle.universal algo?
        //   Maybe try a contrasting color from tonal palettes? Might work if
        //   using seeded color scheme, but not necessarily otherwise.
        return isDark
            ? colorScheme.primary.blendAlpha(Colors.white, 0xE6) // 90%
            : colorScheme.primary.blendAlpha(Colors.white, 0xB2); // 50%
    }
  }

  // Unselected TabBar color is based on FexTabBarStyle tabBarStyle.
  // The `flutterDefault` sets values corresponding to SDK Default behavior.
  Color unselectedTabColor() {
    switch (effectiveTabBarStyle) {
      case FlexTabBarStyle.flutterDefault:
        return useMaterial3
            ? colorScheme.onSurface
            : tabBarStyleColor().withAlpha(0xB2); // 70%
      case FlexTabBarStyle.forBackground:
        return useSubThemes
            ? colorScheme.onSurface
                .blendAlpha(colorScheme.primary,
                    kUnselectedBackgroundPrimaryAlphaBlend)
                .withAlpha(kUnselectedAlphaBlend)
            : colorScheme.onSurface.withAlpha(0x99); // 60%
      case FlexTabBarStyle.forAppBar:
        return (appBarBrightness == Brightness.light &&
                (effectiveAppBarBackgroundColor == Colors.white ||
                    effectiveAppBarBackgroundColor == colorScheme.surface ||
                    effectiveAppBarBackgroundColor == colorScheme.background))
            ? colorScheme.onSurface.withAlpha(0x99) // 60%
            : tabBarStyleColor().withAlpha(0xB2); // 70% alpha
      case FlexTabBarStyle.universal:
        return isDark
            ? colorScheme.primary
                .blendAlpha(Colors.white, 0xE6) // 90%
                .withAlpha(0xB2) // 70% alpha
            : colorScheme.primary
                .blendAlpha(Colors.white, 0x7F)
                .withAlpha(0x7F); // 50%
    }
  }

  // TabBar unselected alpha based opacity, effective value;
  final int tabBarUnselectedAlpha = Color.getAlphaFromOpacity(useMaterial3
      ? subTheme.tabBarUnselectedItemOpacity ?? 1
      : subTheme.tabBarUnselectedItemOpacity ?? 0.7);

  // Platform adjusting font size for tooltips.
  double tooltipFontSize() {
    switch (effectivePlatform) {
      case TargetPlatform.macOS:
      case TargetPlatform.linux:
      case TargetPlatform.windows:
        return 12;
      case TargetPlatform.iOS:
      case TargetPlatform.fuchsia:
      case TargetPlatform.android:
        return 14;
    }
  }

  // Tooltip background defaults logic.
  Color? tooltipBackground() {
    if (useSubThemes && subTheme.tooltipSchemeColor != null) return null;
    if (useSubThemes && tooltipsMatchBackground) {
      if (isDark) {
        // 16% blend
        return FlexColor.darkSurface.blendAlpha(colorScheme.primary, 0x28);
      }
      // 4% blend
      return FlexColor.lightSurface.blendAlpha(colorScheme.primary, 0x0A);
    }
    if (useSubThemes && !tooltipsMatchBackground) {
      if (isDark) {
        // 39% blend
        return FlexColor.lightSurface.blendAlpha(colorScheme.primary, 0x63);
      }
      // 45% blend
      return FlexColor.darkSurface.blendAlpha(colorScheme.primary, 0x72);
    }
    if (!useSubThemes && tooltipsMatchBackground) {
      if (isDark) return const Color(0xFF444444);
      return const Color(0xFFFCFCFC);
    }
    return null;
  }

  // Tooltip foreground colors, defaults logic.
  Color? tooltipForeground() {
    if (useSubThemes && subTheme.tooltipSchemeColor != null) return null;
    if (tooltipsMatchBackground) {
      if (isDark) return Colors.white;
      return Colors.black;
    } else {
      if (isDark) return Colors.black;
      return Colors.white;
    }
  }

  // Tooltip opacity via alpha values, defaults logic.
  int? tooltipAlpha() {
    if (useSubThemes && subTheme.tooltipSchemeColor != null) {
      return Color.getAlphaFromOpacity(subTheme.tooltipOpacity ?? 1);
    }
    if (useSubThemes && tooltipsMatchBackground) {
      return 0xF2; // 95%
    }
    if (!useSubThemes && tooltipsMatchBackground) {
      if (isDark) return 0xED; // 93%
      return 0xF0; // 94%
    }
    return null;
  }

  // Tooltip border radius value;
  double? tooltipBorderRadius() {
    if (!useSubThemes) return 4; // Flutter SDK default
    return subTheme.tooltipRadius ?? kTooltipRadius; // FCS default
  }

  // FCS opinionated tinted semi transparent background color. Used as
  // background on SnackBar (default) and as an option on Slider value.
  Color tintedBackground({
    required Color background,
    required Color blend,
    required Brightness brightness,
  }) =>
      brightness == Brightness.dark
          ? background
              .blendAlpha(blend, 0x63) // 39%
              .withAlpha(0xF2) // 95%
          : background
              .blendAlpha(blend, 0x72) // 45%
              .withAlpha(0xED); // 93%

  // Effective and opinionated sliderValueIndicator color for themed Slider.
  final Color? sliderValueIndicator = subTheme.sliderValueTinted
      ? tintedBackground(
          background: colorScheme.onSurface,
          blend: FlexSubThemes.schemeColor(
              subTheme.sliderIndicatorSchemeColor ??
                  subTheme.sliderBaseSchemeColor ??
                  SchemeColor.primary,
              colorScheme),
          brightness: colorScheme.brightness)
      : subTheme.sliderIndicatorSchemeColor != null ||
              subTheme.sliderBaseSchemeColor != null
          ? FlexSubThemes.schemeColor(
              subTheme.sliderIndicatorSchemeColor ??
                  subTheme.sliderBaseSchemeColor ??
                  SchemeColor.primary,
              colorScheme)
          : null;
  final Color sliderValueStyleOnColor =
      onColor((sliderValueIndicator ?? colorScheme.primary).withAlpha(0xFF));
  final TextStyle? sliderValueStyle =
      subTheme.sliderIndicatorSchemeColor != null ||
              subTheme.sliderBaseSchemeColor != null
          ? effectiveTextTheme.labelMedium!
              .copyWith(color: sliderValueStyleOnColor)
          : null;

  // In M3 mode we use the new dividerColor colorScheme.outlineVariant,
  // unless useM2StyleDividerInM3 is set to true, if it is true
  // we use the M2 style also in M3.
  // If no sub theme usage and not M3 we use same style as in ThemeData.
  // The resulting Color is used by the old ThemeData.DividerColor and by
  // the newer DividerTheme. The tooltip theme also uses it for a discrete
  // outline border color.
  final Color dividerColor =
      (useMaterial3 && (useSubThemes && !subTheme.useM2StyleDividerInM3)) ||
              (useMaterial3 && !useSubThemes)
          ? colorScheme.outlineVariant
          : isDark
              ? const Color(0x1FFFFFFF) // White 12%
              : const Color(0x1F000000); // Black 12%

  // Use tinted interaction effects on hover, focus, highlight and splash?
  final bool tintedInteractions = useSubThemes && subTheme.interactionEffects;
  // Use tinted disabled color?
  final bool tintedDisabled = useSubThemes && subTheme.tintedDisabledControls;

  // Make the effective input decoration theme, by using FCS sub themes
  // if opted in, otherwise use pre v4 version as before. This decoration
  // theme is also passed into the TimePickerTheme, and DropdownMenu so we
  // get the same style used on them too.
  final InputDecorationTheme? effectiveInputDecorationTheme = useSubThemes
      // FCS V4 and later sub-theme based input decorator used.
      ? FlexSubThemes.inputDecorationTheme(
          colorScheme: colorScheme,
          baseSchemeColor: subTheme.inputDecoratorSchemeColor,
          borderSchemeColor: subTheme.inputDecoratorBorderSchemeColor,
          radius: subTheme.inputDecoratorRadius ?? platformRadius,
          borderType: subTheme.inputDecoratorBorderType,
          filled: subTheme.inputDecoratorIsFilled,
          fillColor: subTheme.inputDecoratorFillColor,
          backgroundAlpha: subTheme.inputDecoratorBackgroundAlpha,
          prefixIconSchemeColor: subTheme.inputDecoratorPrefixIconSchemeColor,
          focusedBorderWidth: subTheme.inputDecoratorFocusedBorderWidth ??
              subTheme.thickBorderWidth,
          focusedHasBorder: subTheme.inputDecoratorFocusedHasBorder,
          unfocusedBorderWidth:
              subTheme.inputDecoratorBorderWidth ?? subTheme.thinBorderWidth,
          unfocusedHasBorder: subTheme.inputDecoratorUnfocusedHasBorder,
          unfocusedBorderIsColored:
              subTheme.inputDecoratorUnfocusedBorderIsColored,
          tintedInteractions: tintedInteractions,
          tintedDisabled: tintedDisabled,
          useMaterial3: useMaterial3,
        )
      : useMaterial3
          // In M3 if not using sub themes, use default InputDecorationTheme.
          ? null
          // Default decorator in M2 is a bit opinionated, this is the legacy
          // FCS default one in all previous versions before version 4.0.0.
          // Kept for backwards defaults compatibility. Used when not using
          // opinionated component sub-themes in M2 mode.
          : InputDecorationTheme(
              filled: subTheme.inputDecoratorIsFilled,
              fillColor: isDark
                  ? colorScheme.primary.withAlpha(0x0F) // 6%
                  : colorScheme.primary.withAlpha(0x09), // 3.5%
            );

  // BottomSheet Colors and elevations.
  final Color bottomSheetColor = subTheme.bottomSheetBackgroundColor != null
      ? FlexSubThemes.schemeColor(
          subTheme.bottomSheetBackgroundColor!, colorScheme)
      : colorScheme.surface;
  final Color bottomSheetModalColor =
      subTheme.bottomSheetModalBackgroundColor != null
          ? FlexSubThemes.schemeColor(
              subTheme.bottomSheetModalBackgroundColor!, colorScheme)
          : colorScheme.surface;
  final double bottomSheetElevation = subTheme.bottomSheetElevation ??
      (useMaterial3 ? kBottomSheetElevation : kBottomSheetElevationM2);
  final double bottomSheetModalElevation =
      subTheme.bottomSheetModalElevation ??
          (useMaterial3
              ? kBottomSheetModalElevation
              : kBottomSheetModalElevationM2);

  // Popupmenu menu background Color and elevation.
  final double popupMenuElevation = subTheme.popupMenuElevation ??
      (useMaterial3 ? kPopupMenuM3Elevation : kPopupMenuM2Elevation);
  final Color? popupMenuBackgroundColor = subTheme.popupMenuOpacity == null
      ? subTheme.popupMenuSchemeColor == null
          ? null
          : FlexSubThemes.schemeColor(
              subTheme.popupMenuSchemeColor!,
              colorScheme,
            )
      : subTheme.popupMenuSchemeColor == null
          ? colorScheme.surface.withOpacity(subTheme.popupMenuOpacity!)
          : FlexSubThemes.schemeColor(
              subTheme.popupMenuSchemeColor!,
              colorScheme,
            ).withOpacity(subTheme.popupMenuOpacity!);

  // Return the ThemeData object defined by the FlexColorScheme
  // properties and the designed opinionated theme design choices.
  //
  // The used properties are sorted in the same order they are in
  // ThemeData factory. For sake of sanity, let's keep it that way.
  return ThemeData(
    // Some properties we just pass along to the standard ThemeData factory.
    // They are included in FlexColorScheme (FCS) 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
    // som might pass along given value, which we may have used internally
    // in FlexColorScheme as well.
    //
    // Not all properties in ThemeData are included, if you need to modify
    // them, use copyWith on ThemeData returned by FCS.

    // GENERAL CONFIGURATION
    //
    // Elevation overlay on dark material elevation is used on dark themes
    // on surfaces when so requested in M2, applyElevationOverlayColor
    // defaults to true in FlexColorScheme themes, but you can turn it off.
    // Flutter ThemeData.from ColorScheme based themes also uses this by
    // default, but older ThemeData factories do not use it by default.
    // A correct Material 2 design should use it.
    applyElevationOverlayColor: isDark && applyElevationOverlayColor,
    extensions: extensions,
    materialTapTargetSize: materialTapTargetSize,
    pageTransitionsTheme: pageTransitionsTheme,
    platform: effectivePlatform,
    useMaterial3: useMaterial3,
    visualDensity: visualDensity,
    // Add SplashFactory, first custom value, then sub-theme platform
    // dependent configured choice.
    splashFactory: splashFactory ?? platformSplash,
    // Input decoration theme.
    inputDecorationTheme: effectiveInputDecorationTheme,

    // COLOR
    //
    // [colorScheme] is the preferred way to configure colors. The other color
    // properties (as well as primaryColorBrightness, and primarySwatch)
    // will gradually be phased out,
    // see https://github.com/flutter/flutter/issues/91772.
    //
    // Most color definitions below are very close to the ones used by the
    // Flutter factory ThemeData.from() for creating a theme from a
    // ColorScheme and TextTheme.
    brightness: colorScheme.brightness,
    // TODO(rydmike): Monitor Flutter SDK deprecation of canvasColor.
    canvasColor: colorScheme.background,
    // TODO(rydmike): Monitor Flutter SDK deprecation of cardColor.
    cardColor: colorScheme.surface,
    // 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.cn/go/material-theme-system-updates
    colorScheme: colorScheme,
    // TODO(rydmike): Monitor Flutter SDK deprecation of dialogBackgroundColor
    // Flutter standard dialogBackgroundColor for color scheme based themes
    // uses colorScheme.background.
    // The FlexColorScheme.from() factory constructor uses passed in dialog
    // background color that is same as surface color if not defined, but
    // may also be any other other color.
    // If using surface blends that are not equal for all Material surface
    // backgrounds colors. There will be no elevation overlay color in dark
    // M2 mode, even if so configured.
    // Use dialogs with background color that equals theme
    // colorScheme.surface to ensure it gets elevation overlay color applied
    // in dark mode. See : https://github.com/flutter/flutter/issues/90353
    // The dialogBackgroundColor in ThemeData is going to be deprecated.
    dialogBackgroundColor: dialogBackground ?? colorScheme.surface,
    // TODO(rydmike): Monitor Flutter SDK deprecation of disabledColor.
    // Disabled color uses a different style when using tinted disabled.
    // effects, if not opted in same as before v4.0.0 = ThemeData default.
    disabledColor: tintedDisabled
        ? FlexSubThemes.tintedDisable(
            isDark ? Colors.white : Colors.black, colorScheme.primary)
        : null,
    // TODO(rydmike): Monitor Flutter SDK deprecation of dividerColor.
    dividerColor: dividerColor,

    // TODO(rydmike): Monitor Flutter SDK deprecation of interaction colors.
    // See: https://github.com/flutter/flutter/issues/91772
    // Special theming on hover, focus, highlight and splash, if opting in on
    // tintedInteractions, otherwise use ThemeData defaults by passing in null
    // and letting it assign its values.
    // TODO(rydmike): Monitor Flutter SDK deprecation of focusColor.
    focusColor: tintedInteractions
        ? FlexSubThemes.tintedFocused(
            isDark ? Colors.white : Colors.black, colorScheme.surfaceTint)
        : null,
    // TODO(rydmike): Monitor Flutter SDK deprecation of highlightColor.
    highlightColor: tintedInteractions
        ? FlexSubThemes.tintedHighlight(
            isDark ? Colors.white : Colors.black, colorScheme.surfaceTint)
        : null,
    // TODO(rydmike): Monitor Flutter SDK deprecation of hoverColor
    hoverColor: tintedInteractions
        ? FlexSubThemes.tintedHovered(
            isDark ? Colors.white : Colors.black, colorScheme.surfaceTint)
        : null,
    // TODO(rydmike): Monitor Flutter SDK deprecation of splashColor
    splashColor: tintedInteractions
        ? FlexSubThemes.tintedSplash(
            isDark ? Colors.white : Colors.black, colorScheme.surfaceTint)
        : null,

    // TODO(rydmike): Monitor Flutter SDK deprecation of indicatorColor.
    // https://github.com/flutter/flutter/issues/91772#issuecomment-1198206279
    // Use TabBar style dependent function for selected Tab as indicatorColor,
    // if no SchemeColor color selection for it is made.
    indicatorColor: subTheme.tabBarIndicatorSchemeColor == null
        ? tabBarStyleColor()
        : FlexSubThemes.schemeColor(
            subTheme.tabBarIndicatorSchemeColor!, colorScheme),

    // TODO(rydmike): Monitor Flutter SDK deprecation of primaryColor.
    primaryColor: colorScheme.primary,
    // TODO(rydmike): Monitor Flutter SDK deprecation of primaryColorDark.
    // See: https://github.com/flutter/flutter/issues/91772
    // 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.
    // This property is used by `CircleAvatar` and `Slider`.
    // See issue: https://github.com/flutter/flutter/issues/65782
    primaryColorDark: primaryColorDark,
    // TODO(rydmike): Monitor Flutter SDK deprecation of primaryColorLight.
    // See: https://github.com/flutter/flutter/issues/91772
    // 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.
    // This property is used by `CircleAvatar` and `Slider`.
    // See issue: https://github.com/flutter/flutter/issues/65782
    primaryColorLight: primaryColorLight,

    // TODO(rydmike): Monitor Flutter SDK deprecation of scaffoldBackground.
    // See: https://github.com/flutter/flutter/issues/91772
    // 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. Flutter's 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 alone. We want to do so in order to make elegantly nuanced
    // primary color branded themes.
    scaffoldBackgroundColor: scaffoldBackground ?? colorScheme.background,

    // TODO(rydmike): Monitor Flutter SDK deprecation of secondaryHeaderColor
    // See: https://github.com/flutter/flutter/issues/91772
    // Define a secondary header color, this property is only used in Flutter
    // SDK by `PaginatedDataTable`. It gets a super light [50] hue of the
    // primary color from default theme.light factory. Here we use the [50]
    // value from the calculated primary swatch.
    // See issue: https://github.com/flutter/flutter/issues/65782
    secondaryHeaderColor: secondaryHeaderColor,

    // TYPOGRAPHY & ICONOGRAPHY
    //
    fontFamily: fontFamily,
    fontFamilyFallback: fontFamilyFallback,
    package: package,
    // TextTheme properties use the same logic as in ThemeData, allowing us
    // to optionally define them. AccentTextTheme is omitted since it has
    // been deprecated in Flutter 2.5.0.
    primaryTextTheme: effectivePrimaryTextTheme,
    textTheme: effectiveTextTheme,
    typography: effectiveTypography,

    // COMPONENT THEMES
    //
    // AppBar Theme.
    // Theme allows us to use a custom colored appbar theme
    // in both light and dark themes that is not dependent on ThemeData
    // `primaryColor` or surface color, and still gets correct working text
    // and icon theme. Historically, in versions prior to Flutter 2.0.0,
    // doing this was very difficult, 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 made doing this easier.
    // FlexColorScheme has used the SDK supported way since it was launched.
    appBarTheme: useSubThemes
        ? FlexSubThemes.appBarTheme(
            colorScheme: colorScheme,
            centerTitle: subTheme.appBarCenterTitle,
            backgroundColor: effectiveAppBarBackgroundColor,
            foregroundColor: appBarForeground,
            elevation: appBarElevation ?? 0,
            scrolledUnderElevation: subTheme.appBarScrolledUnderElevation,
            iconTheme: IconThemeData(color: appBarIconColor),
            actionsIconTheme: IconThemeData(color: appBarIconColor),
            systemOverlayStyle: systemOverlayStyle,
            shadowColor: useShadow ? colorScheme.shadow : null,
            // Surface tint on AppBar is removed via the scroll under setting.
            surfaceTintColor: noScrollUnder ? Colors.transparent : null,
          )
        : useMaterial3
            ? (appBarElevation != null && appBarElevation != 0) ||
                    !transparentStatusBar ||
                    (appBarBackground != null)
                ? FlexSubThemes.appBarTheme(
                    colorScheme: colorScheme,
                    backgroundColor: effectiveAppBarBackgroundColor,
                    foregroundColor: appBarForeground,
                    elevation: appBarElevation,
                    iconTheme: IconThemeData(color: appBarIconColor),
                    actionsIconTheme: IconThemeData(color: appBarIconColor),
                    systemOverlayStyle: systemOverlayStyle,
                  )
                : null
            : FlexSubThemes.appBarTheme(
                colorScheme: colorScheme,
                backgroundColor: effectiveAppBarBackgroundColor,
                foregroundColor: appBarForeground,
                elevation: appBarElevation ?? 0,
                iconTheme: IconThemeData(color: appBarIconColor),
                actionsIconTheme: IconThemeData(color: appBarIconColor),
                systemOverlayStyle: systemOverlayStyle,
              ),
    //
    // badgeTheme: NOT YET DEFINED BY FCS. USE: .copyWith
    //
    // bannerTheme:  NOT YET DEFINED BY FCS. USE: .copyWith
    //
    // BottomAppBar Theme.
    bottomAppBarTheme: useSubThemes
        ? FlexSubThemes.bottomAppBarTheme(
            colorScheme: colorScheme,
            backgroundSchemeColor: subTheme.bottomAppBarSchemeColor,
            elevation: bottomAppBarElevation,
            shadowColor: useShadow ? colorScheme.shadow : null,
            surfaceTintColor: removeTint ? Colors.transparent : null,
            useMaterial3: useMaterial3,
          )
        // When not using subThemes we will in M2 mode always get a
        // BottomAppBarTheme with at least background color defined to be
        // ColorScheme.surface, even if [bottomAppBarElevation] is null.
        // This is done to avoid issues with deprecation of
        // ThemeData.bottomAppBarColor that is still used in M2 mode defaults.
        // When using M3 mode and if [bottomAppBarElevation] is null, we
        // actually get a default [BottomAppBarTheme()] all null theme made by
        // FlexSubThemes.bottomAppBarTheme.
        : FlexSubThemes.bottomAppBarTheme(
            colorScheme: colorScheme,
            elevation: bottomAppBarElevation,
          ),
    //
    // BottomNavigationBar Theme.
    // Opinionated default theming for it:
    // Use primary for selected item. Flutter defaults to using secondary
    // color in  dark mode, we want primary in dark mode too, like it is in
    // light mode. Primary color is an iOS influenced style for the bottom
    // nav. The above is a description of default in version < 4, or now
    // when not using sub-themes. When we use sub-themes we can completely
    // customize its appearance as done below. The none sub-themes using
    // option further below if the past pre-version 4 default.
    bottomNavigationBarTheme: useSubThemes
        ? FlexSubThemes.bottomNavigationBar(
            colorScheme: colorScheme,
            labelTextStyle: subTheme.bottomNavigationBarLabelTextStyle ??
                (subTheme.useFlutterDefaults
                    ? null
                    : effectiveTextTheme.bodyMedium),
            selectedLabelSize: subTheme.bottomNavigationBarSelectedLabelSize,
            unselectedLabelSize:
                subTheme.bottomNavigationBarUnselectedLabelSize,
            selectedLabelSchemeColor:
                subTheme.bottomNavigationBarSelectedLabelSchemeColor,
            unselectedLabelSchemeColor:
                subTheme.bottomNavigationBarUnselectedLabelSchemeColor,
            mutedUnselectedLabel:
                subTheme.bottomNavigationBarMutedUnselectedLabel,
            selectedIconSize: subTheme.bottomNavigationBarSelectedIconSize,
            unselectedIconSize:
                subTheme.bottomNavigationBarUnselectedIconSize,
            selectedIconSchemeColor:
                subTheme.bottomNavigationBarSelectedIconSchemeColor,
            unselectedIconSchemeColor:
                subTheme.bottomNavigationBarUnselectedIconSchemeColor,
            mutedUnselectedIcon:
                subTheme.bottomNavigationBarMutedUnselectedIcon,
            backgroundSchemeColor:
                subTheme.bottomNavigationBarBackgroundSchemeColor,
            opacity: subTheme.bottomNavigationBarOpacity,
            elevation: subTheme.bottomNavigationBarElevation,
            type: subTheme.bottomNavigationBarType,
            showSelectedLabels:
                subTheme.bottomNavigationBarShowSelectedLabels,
            showUnselectedLabels:
                subTheme.bottomNavigationBarShowUnselectedLabels,
            landscapeLayout: subTheme.bottomNavigationBarLandscapeLayout,
            unselectedAlphaBlend: kUnselectedBackgroundPrimaryAlphaBlend,
            unselectedAlpha: kUnselectedAlphaBlend,
            useFlutterDefaults: subTheme.useFlutterDefaults,
          )
        : useMaterial3
            ? null
            // Opinionated FCS M2 legacy style sub-theme for
            // BottomNavigationBarThemeData that we get without
            // opting in on sub-themes. This is a nice fix for dark mode
            // BottomNavigationBar, but decided to not do it in M3 when not
            // opting in on sub-themes. If you opt-in, you get the "fix",
            // You are supposed to use the NavigationBar in M3 anyway.
            : BottomNavigationBarThemeData(
                selectedIconTheme: IconThemeData(
                  color: colorScheme.primary,
                ),
                selectedItemColor: colorScheme.primary,
              ),
    //
    // BottomSheet Theme.
    bottomSheetTheme: useSubThemes
        ? FlexSubThemes.bottomSheetTheme(
            backgroundColor: bottomSheetColor,
            modalBackgroundColor: bottomSheetModalColor,
            elevation: bottomSheetElevation,
            modalElevation: bottomSheetModalElevation,
            radius: subTheme.bottomSheetRadius ?? platformRadius,
            shadowColor: useShadow ? colorScheme.shadow : null,
            surfaceTintColor: removeTint ? Colors.transparent : null,
          )
        : null,
    //
    // buttonBarTheme: NOT YET DEFINED BY FCS. USE: .copyWith
    //
    // Button Theme.
    // TODO(rydmike): Monitor Flutter SDK deprecation of buttonTheme.
    // Since the old buttons have been deprecated in Flutter 2.0.0
    // they are no longer presented or used in the code in FlexColorScheme.
    // The button theming below still makes the old buttons almost
    // look like the defaults for the new ElevatedButton, TextButton and
    // OutlinedButton.
    // This buttonTheme setup, makes the old legacy 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.
    // A useSubThemes was added in version 4.0.0 to also still support
    // the old buttons.
    // The legacy buttons will be completely removed in Flutter.
    // The `ButtonThemeData` this helper uses will
    // however remain available after that for a while, because widgets
    // [ButtonBar] and [DropdownButton], plus [MaterialButton] (marked as
    // obsolete in SDK docs though) still use this theme. It is thus kept
    // around in FlexColorScheme package as long as it might have some use.
    // Be aware that the buttonTheme will be removed from
    // FlexColorScheme when/if ButtonThemeData becomes deprecated Flutter SDK.
    buttonTheme: useSubThemes
        ? FlexSubThemes.buttonTheme(
            colorScheme: colorScheme,
            baseSchemeColor: subTheme.materialButtonSchemeColor,
            radius: subTheme.textButtonRadius ?? platformRadius,
            minButtonSize: subTheme.buttonMinSize,
            alignedDropdown: subTheme.alignedDropdown,
            padding: subTheme.buttonPadding,
          )
        : useMaterial3
            ? null
            // Opinionated FCS M2 legacy style sub-theme for ButtonThemeData,
            // that we get without opting in on sub-themes. In M3 mode you
            // get these fixes only when you opt-in on sub-themes. This
            // theme may soon be deprecated in Flutter SDK.
            : ButtonThemeData(
                colorScheme: colorScheme,
                textTheme: ButtonTextTheme.primary,
                materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                padding: const EdgeInsets.symmetric(horizontal: 16),
              ),
    //
    // Card Theme.
    cardTheme: useSubThemes
        ? FlexSubThemes.cardTheme(
            radius: subTheme.cardRadius ?? platformRadius,
            elevation: subTheme.cardElevation,
            surfaceTintColor: removeTint ? Colors.transparent : null,
          )
        : null,
    //
    // Checkbox theme.
    checkboxTheme: useSubThemes
        ? FlexSubThemes.checkboxTheme(
            colorScheme: colorScheme,
            baseSchemeColor: subTheme.checkboxSchemeColor,
            unselectedIsColored: subTheme.unselectedToggleIsColored,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // Chip Theme.
    // TODO(rydmike): Monitor Chip theming improvements in Flutter SDK.
    // 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.
    // The option when useSubThemes is true uses even more elaborate theming
    // of chips. It is possible that there will be new Chips entirely for
    // Material 3. This theme brings the look closer to M3 look, but cannot
    // reach all the way.
    chipTheme: useSubThemes
        ? FlexSubThemes.chipTheme(
            colorScheme: colorScheme,
            baseSchemeColor: subTheme.chipSchemeColor,
            selectedSchemeColor: subTheme.chipSelectedSchemeColor,
            deleteIconSchemeColor: subTheme.chipDeleteIconSchemeColor,
            labelStyle: effectiveTextTheme.labelLarge!,
            radius: subTheme.chipRadius ?? platformRadius,
            surfaceTintColor: removeTint ? Colors.transparent : null,
            useTintedDisable: subTheme.tintedDisabledControls,
            useMaterial3: useMaterial3,
          )
        : useMaterial3
            ? null
            // Opinionated FCS M2 legacy style sub-theme for Chips,
            // that we get without opting in on sub-themes.
            : ChipThemeData.fromDefaults(
                secondaryColor: colorScheme.primary,
                brightness: colorScheme.brightness,
                labelStyle: effectiveTextTheme.bodyLarge!,
              ),
    //
    // dataTableTheme: NOT YET DEFINED BY FCS. USE: .copyWith to modify.
    //
    // DatePicker theme
    datePickerTheme: useSubThemes
        ? FlexSubThemes.datePickerTheme(
            colorScheme: colorScheme,
            backgroundColor: dialogBackground,
            backgroundSchemeColor: subTheme.dialogBackgroundSchemeColor,
            headerBackgroundSchemeColor:
                subTheme.datePickerHeaderBackgroundSchemeColor,
            elevation: subTheme.dialogElevation,
            radius: subTheme.datePickerDialogRadius ??
                platformDialogRadius ??
                platformRadius,
            inputDecorationTheme: effectiveInputDecorationTheme,
            useInputDecoratorTheme: subTheme.useInputDecoratorThemeInDialogs,
            shadowColor: useShadow ? colorScheme.shadow : null,
            surfaceTintColor: removeTint ? Colors.transparent : null,
          )
        : null,
    //
    // Dialog Theme.
    dialogTheme: useSubThemes
        ? FlexSubThemes.dialogTheme(
            backgroundColor: dialogBackground,
            colorScheme: colorScheme,
            backgroundSchemeColor: subTheme.dialogBackgroundSchemeColor,
            radius: platformDialogRadius ?? platformRadius,
            elevation: subTheme.dialogElevation,
            shadowColor: useShadow ? colorScheme.shadow : null,
            surfaceTintColor: removeTint ? Colors.transparent : null,
          )
        : null,
    //
    // Divider Theme.
    // Create a Divider theme only when sub themes is used and we want M2
    // style in M3. Otherwise we keep the theme as default, with null props.
    dividerTheme:
        useMaterial3 && (useSubThemes && subTheme.useM2StyleDividerInM3)
            ? DividerThemeData(color: dividerColor)
            : null,
    //
    // Drawer Theme.
    drawerTheme: useSubThemes
        ? FlexSubThemes.drawerTheme(
            colorScheme: colorScheme,
            backgroundSchemeColor: subTheme.drawerBackgroundSchemeColor,
            radius: subTheme.drawerRadius ?? platformRadius,
            width: subTheme.drawerWidth ??
                (useMaterial3
                    ? kNavigationDrawerM3Width
                    : kNavigationDrawerM2Width),
            elevation: subTheme.drawerElevation,
            shadowColor: useShadow ? colorScheme.shadow : null,
            surfaceTintColor: removeTint ? Colors.transparent : null,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // DropDownMenu Theme.
    dropdownMenuTheme: useSubThemes
        ? FlexSubThemes.dropdownMenuTheme(
            colorScheme: colorScheme,
            textStyle: subTheme.dropdownMenuTextStyle ??
                effectiveTextTheme.bodyLarge,
            // Style match its InputDecoration to same as TextField.
            inputDecorationTheme: effectiveInputDecorationTheme,
            surfaceTintColor: removeTint ? Colors.transparent : null,
          )
        : null,
    //
    // ElevatedButton Theme.
    elevatedButtonTheme: useSubThemes
        ? FlexSubThemes.elevatedButtonTheme(
            colorScheme: colorScheme,
            baseSchemeColor: subTheme.elevatedButtonSchemeColor,
            onBaseSchemeColor: subTheme.elevatedButtonSecondarySchemeColor,
            radius: subTheme.elevatedButtonRadius ?? platformRadius,
            elevation: subTheme.elevatedButtonElevation,
            padding: subTheme.buttonPadding,
            minButtonSize: subTheme.buttonMinSize,
            textStyle: subTheme.elevatedButtonTextStyle,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
            splashFactory: buttonsSplashFactory,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // expansionTileTheme: NOT YET DEFINED BY FCS. USE: .copyWith to modify.
    //
    // FilledButton Theme.
    filledButtonTheme: useSubThemes
        ? FlexSubThemes.filledButtonTheme(
            colorScheme: colorScheme,
            backgroundSchemeColor: subTheme.filledButtonSchemeColor,
            radius: subTheme.filledButtonRadius ?? platformRadius,
            padding: subTheme.buttonPadding,
            minButtonSize: subTheme.buttonMinSize,
            textStyle: subTheme.filledButtonTextStyle,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
            splashFactory: buttonsSplashFactory,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // FAB, floating action button theme.
    floatingActionButtonTheme: useSubThemes
        ? FlexSubThemes.floatingActionButtonTheme(
            colorScheme: colorScheme,
            backgroundSchemeColor: subTheme.fabSchemeColor,
            radius: subTheme.fabRadius ?? platformRadius,
            useShape: subTheme.fabUseShape,
            alwaysCircular: subTheme.fabAlwaysCircular,
            useTintedInteraction: subTheme.interactionEffects,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // IconButton theme.
    //
    // TODO(rydmike): iconButtonTheme limited due Flutter SDK issue.
    // Supports new IconButton styles (filled, filledTonal, outlined)
    // with interaction effects. Tinted disable is only supported on the
    // foreground color supported due to issue:
    // https://github.com/flutter/flutter/issues/123829
    // No custom color theming of them supported due to this issue.
    iconButtonTheme: useSubThemes
        ? FlexSubThemes.iconButtonTheme(
            colorScheme: colorScheme,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
          )
        : null,
    //
    // ListTileTheme: NOT YET DEFINED BY FCS. USE: .copyWith to modify.
    listTileTheme: const ListTileThemeData(),
    //

    // MenuBar theme, used by MenuBar.
    menuBarTheme: useSubThemes
        ? FlexSubThemes.menuBarTheme(
            colorScheme: colorScheme,
            backgroundSchemeColor: subTheme.menuBarBackgroundSchemeColor ??
                subTheme.menuSchemeColor,
            surfaceTintColor: removeTint ? Colors.transparent : null,
            shadowColor: subTheme.menuBarShadowColor,
            radius: subTheme.menuBarRadius,
            elevation: subTheme.menuBarElevation,
          )
        : null,
    //
    // MenuButton theme, used by SubmenuButton and MenuItemButton.
    menuButtonTheme: useSubThemes
        ? FlexSubThemes.menuButtonTheme(
            colorScheme: colorScheme,
            menuBackgroundSchemeColor: subTheme.menuSchemeColor,
            backgroundSchemeColor: subTheme.menuItemBackgroundSchemeColor,
            foregroundSchemeColor: subTheme.menuItemForegroundSchemeColor,
            indicatorBackgroundSchemeColor:
                subTheme.menuIndicatorBackgroundSchemeColor,
            indicatorForegroundSchemeColor:
                subTheme.menuIndicatorForegroundSchemeColor,
            radius: subTheme.menuIndicatorRadius,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
          )
        : null,
    //
    // Menu content theme.
    // Used by the menu container for MenuBar, MenuAnchor and DropDownMenu.
    menuTheme: useSubThemes
        ? FlexSubThemes.menuTheme(
            colorScheme: colorScheme,
            backgroundSchemeColor: subTheme.menuSchemeColor,
            opacity: subTheme.menuOpacity,
            radius: subTheme.menuRadius,
            elevation: subTheme.menuElevation,
            padding: subTheme.menuPadding,
            surfaceTintColor: removeTint ? Colors.transparent : null,
          )
        : null,
    //
    // NavigationBar Theme.
    navigationBarTheme: useSubThemes
        ? FlexSubThemes.navigationBarTheme(
            colorScheme: colorScheme,
            labelTextStyle: subTheme.navigationBarLabelTextStyle ??
                (subTheme.useFlutterDefaults
                    ? null
                    : effectiveTextTheme.labelMedium),
            selectedLabelSize: subTheme.navigationBarSelectedLabelSize,
            unselectedLabelSize: subTheme.navigationBarUnselectedLabelSize,
            selectedLabelSchemeColor:
                subTheme.navigationBarSelectedLabelSchemeColor,
            unselectedLabelSchemeColor:
                subTheme.navigationBarUnselectedLabelSchemeColor,
            mutedUnselectedLabel: subTheme.navigationBarMutedUnselectedLabel,
            selectedIconSize: subTheme.navigationBarSelectedIconSize,
            unselectedIconSize: subTheme.navigationBarUnselectedIconSize,
            selectedIconSchemeColor:
                subTheme.navigationBarSelectedIconSchemeColor,
            unselectedIconSchemeColor:
                subTheme.navigationBarUnselectedIconSchemeColor,
            mutedUnselectedIcon: subTheme.navigationBarMutedUnselectedIcon,
            indicatorSchemeColor: subTheme.navigationBarIndicatorSchemeColor,
            backgroundSchemeColor:
                subTheme.navigationBarBackgroundSchemeColor,
            opacity: subTheme.navigationBarOpacity,
            elevation: subTheme.navigationBarElevation,
            height: subTheme.navigationBarHeight,
            labelBehavior: subTheme.navigationBarLabelBehavior,
            indicatorRadius: subTheme.navigationBarIndicatorRadius,
            indicatorAlpha: subTheme.navigationBarIndicatorOpacity != null
                ? Color.getAlphaFromOpacity(
                    subTheme.navigationBarIndicatorOpacity!)
                : null,
            unselectedAlphaBlend: kUnselectedBackgroundPrimaryAlphaBlend,
            unselectedAlpha: kUnselectedAlphaBlend,
            useMaterial3: useMaterial3,
            useFlutterDefaults: subTheme.useFlutterDefaults,
            surfaceTintColor: removeNavBarTint ? Colors.transparent : null,
            shadowColor: useShadow ? colorScheme.shadow : null,
          )
        : null,
    //
    // NavigationDrawerTheme Theme.
    navigationDrawerTheme: useSubThemes
        ? FlexSubThemes.navigationDrawerTheme(
            colorScheme: colorScheme,
            backgroundSchemeColor: subTheme.drawerBackgroundSchemeColor,
            indicatorWidth: subTheme.drawerIndicatorWidth ??
                ((subTheme.drawerWidth ??
                        (useMaterial3
                            ? kNavigationDrawerM3Width
                            : kNavigationDrawerM2Width)) -
                    2 * kNavigationDrawerIndicatorPadding),
            indicatorRadius: subTheme.drawerIndicatorRadius ?? platformRadius,
            indicatorSchemeColor: subTheme.drawerIndicatorSchemeColor,
            indicatorOpacity: subTheme.drawerIndicatorOpacity,
            selectedItemSchemeColor: subTheme.drawerSelectedItemSchemeColor,
            unselectedItemSchemeColor:
                subTheme.drawerUnselectedItemSchemeColor,
            textStyle: effectiveTextTheme.bodyLarge,
            surfaceTintColor: removeTint ? Colors.transparent : null,
            shadowColor: useShadow ? colorScheme.shadow : null,
          )
        : null,
    //
    // NavigationRail Theme.
    navigationRailTheme: useSubThemes
        ? FlexSubThemes.navigationRailTheme(
            colorScheme: colorScheme,
            labelTextStyle: subTheme.navigationRailLabelTextStyle ??
                (subTheme.useFlutterDefaults
                    ? null
                    : effectiveTextTheme.labelMedium),
            selectedLabelSize: subTheme.navigationRailSelectedLabelSize,
            unselectedLabelSize: subTheme.navigationRailUnselectedLabelSize,
            selectedLabelSchemeColor:
                subTheme.navigationRailSelectedLabelSchemeColor,
            unselectedLabelSchemeColor:
                subTheme.navigationRailUnselectedLabelSchemeColor,
            mutedUnselectedLabel: subTheme.navigationRailMutedUnselectedLabel,
            selectedIconSize: subTheme.navigationRailSelectedIconSize,
            unselectedIconSize: subTheme.navigationRailUnselectedIconSize,
            selectedIconSchemeColor:
                subTheme.navigationRailSelectedIconSchemeColor,
            unselectedIconSchemeColor:
                subTheme.navigationRailUnselectedIconSchemeColor,
            mutedUnselectedIcon: subTheme.navigationRailMutedUnselectedIcon,
            useIndicator: subTheme.navigationRailUseIndicator,
            indicatorSchemeColor: subTheme.navigationRailIndicatorSchemeColor,
            backgroundSchemeColor:
                subTheme.navigationRailBackgroundSchemeColor,
            opacity: subTheme.navigationRailOpacity,
            elevation: subTheme.navigationRailElevation,
            labelType: subTheme.navigationRailLabelType,
            groupAlignment: subTheme.navigationRailGroupAlignment,
            indicatorAlpha: subTheme.navigationRailIndicatorOpacity != null
                ? Color.getAlphaFromOpacity(
                    subTheme.navigationRailIndicatorOpacity!)
                : null,
            indicatorRadius: subTheme.navigationRailIndicatorRadius,
            unselectedAlphaBlend: kUnselectedBackgroundPrimaryAlphaBlend,
            unselectedAlpha: kUnselectedAlphaBlend,
            useMaterial3: useMaterial3,
            useFlutterDefaults: subTheme.useFlutterDefaults,
          )
        : null,
    //
    // OutlinedButton Theme.
    outlinedButtonTheme: useSubThemes
        ? FlexSubThemes.outlinedButtonTheme(
            colorScheme: colorScheme,
            baseSchemeColor: subTheme.outlinedButtonSchemeColor,
            outlineSchemeColor: subTheme.outlinedButtonOutlineSchemeColor,
            radius: subTheme.outlinedButtonRadius ?? platformRadius,
            pressedOutlineWidth: subTheme.outlinedButtonPressedBorderWidth ??
                subTheme.thickBorderWidth,
            outlineWidth: subTheme.outlinedButtonBorderWidth ??
                subTheme.thinBorderWidth,
            padding: subTheme.buttonPadding,
            minButtonSize: subTheme.buttonMinSize,
            textStyle: subTheme.outlinedButtonTextStyle,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
            splashFactory: buttonsSplashFactory,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // PopupMenuButton Theme.
    popupMenuTheme: useSubThemes
        ? FlexSubThemes.popupMenuTheme(
            colorScheme: colorScheme,
            radius: subTheme.popupMenuRadius,
            elevation: popupMenuElevation,
            color: popupMenuBackgroundColor,
            backgroundSchemeColor: subTheme.popupMenuSchemeColor,
            surfaceTintColor: removeTint ? Colors.transparent : null,
          )
        : null,
    //
    // progressIndicatorTheme: NOT YET DEFINED BY FCS. USE: .copyWith
    //
    // Radio Theme.
    radioTheme: useSubThemes
        ? FlexSubThemes.radioTheme(
            colorScheme: colorScheme,
            baseSchemeColor: subTheme.radioSchemeColor,
            unselectedIsColored: subTheme.unselectedToggleIsColored,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // SegmentedButton Theme.
    segmentedButtonTheme: useSubThemes
        ? FlexSubThemes.segmentedButtonTheme(
            colorScheme: colorScheme,
            selectedSchemeColor: subTheme.segmentedButtonSchemeColor,
            unselectedSchemeColor:
                subTheme.segmentedButtonUnselectedSchemeColor,
            unselectedForegroundSchemeColor:
                subTheme.segmentedButtonUnselectedForegroundSchemeColor,
            borderSchemeColor: subTheme.segmentedButtonBorderSchemeColor,
            borderWidth: subTheme.segmentedButtonBorderWidth ??
                subTheme.thinBorderWidth,
            radius: subTheme.segmentedButtonRadius ?? platformRadius,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
            splashFactory: buttonsSplashFactory,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // Slider theme.
    sliderTheme: useSubThemes
        ? FlexSubThemes.sliderTheme(
            colorScheme: colorScheme,
            baseSchemeColor: subTheme.sliderBaseSchemeColor,
            trackHeight: subTheme.sliderTrackHeight,
            valueIndicatorColor: sliderValueIndicator,
            valueIndicatorTextStyle: sliderValueStyle,
            valueIndicatorType: subTheme.sliderValueIndicatorType,
            showValueIndicator: subTheme.sliderShowValueIndicator,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // SnackBar Theme.
    snackBarTheme: useSubThemes
        ? FlexSubThemes.snackBarTheme(
            radius: subTheme.snackBarRadius,
            elevation: subTheme.snackBarElevation,
            colorScheme: colorScheme,
            backgroundSchemeColor: subTheme.snackBarBackgroundSchemeColor,
            actionTextSchemeColor: subTheme.snackBarActionSchemeColor,
            backgroundColor: tintedBackground(
              background: colorScheme.onSurface,
              blend: colorScheme.primary,
              brightness: colorScheme.brightness,
            ),
          )
        : null,
    //
    // Switch theme.
    switchTheme: useSubThemes
        ? FlexSubThemes.switchTheme(
            colorScheme: colorScheme,
            baseSchemeColor: subTheme.switchSchemeColor,
            thumbSchemeColor: subTheme.switchThumbSchemeColor,
            thumbFixedSize: subTheme.switchThumbFixedSize,
            unselectedIsColored: subTheme.unselectedToggleIsColored,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // TabBar Theme.
    // Defines 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`. Using different theme styles for intended
    // target usage avoids this challenge:
    // https://github.com/flutter/flutter/pull/68171#pullrequestreview-517753917
    // That still has some issue related to it, is using default is used, we
    // pass in `null` and let ThemeData use default sub-theme for TabBarTheme.
    tabBarTheme: FlexSubThemes.tabBarTheme(
      colorScheme: colorScheme,
      indicatorColor: subTheme.tabBarIndicatorSchemeColor == null
          ? tabBarStyleColor()
          : FlexSubThemes.schemeColor(
              subTheme.tabBarIndicatorSchemeColor!, colorScheme),
      labelStyle: effectiveTextTheme.bodyLarge,
      labelColor: subTheme.tabBarItemSchemeColor == null
          ? tabBarStyleColor()
          : FlexSubThemes.schemeColor(
              subTheme.tabBarItemSchemeColor!, colorScheme),
      unselectedLabelStyle: effectiveTextTheme.bodyLarge,
      unselectedLabelColor: subTheme.tabBarItemSchemeColor == null
          ? unselectedTabColor()
          : subTheme.tabBarUnselectedItemSchemeColor == null
              ? useMaterial3
                  ? FlexSubThemes.schemeColor(
                          SchemeColor.onSurfaceVariant, colorScheme)
                      .withAlpha(tabBarUnselectedAlpha)
                  : FlexSubThemes.schemeColor(
                          subTheme.tabBarItemSchemeColor!, colorScheme)
                      .withAlpha(tabBarUnselectedAlpha)
              : FlexSubThemes.schemeColor(
                      subTheme.tabBarUnselectedItemSchemeColor!, colorScheme)
                  .withAlpha(tabBarUnselectedAlpha),
      indicatorSize: subTheme.tabBarIndicatorSize,
      indicatorWeight: subTheme.tabBarIndicatorWeight,
      indicatorTopRadius: subTheme.tabBarIndicatorTopRadius,
      dividerColor: subTheme.tabBarDividerColor,
      useTintedInteraction: subTheme.interactionEffects,
      useMaterial3: useMaterial3,
    ),
    //
    // TextButton Theme.
    textButtonTheme: useSubThemes
        ? FlexSubThemes.textButtonTheme(
            colorScheme: colorScheme,
            baseSchemeColor: subTheme.textButtonSchemeColor,
            radius: subTheme.textButtonRadius ?? platformRadius,
            padding: subTheme.buttonPadding,
            minButtonSize: subTheme.buttonMinSize,
            textStyle: subTheme.textButtonTextStyle,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
            splashFactory: buttonsSplashFactory,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // TextSelection Theme.
    textSelectionTheme: useSubThemes
        ? FlexSubThemes.textSelectionTheme(
            colorScheme: colorScheme,
            cursorSchemeColor: subTheme.inputCursorSchemeColor ??
                subTheme.inputDecoratorSchemeColor,
            selectionSchemeColor: subTheme.inputSelectionSchemeColor ??
                subTheme.inputDecoratorSchemeColor,
            selectionOpacity: subTheme.inputSelectionOpacity ??
                (isDark
                    ? kTextSelectionDarkOpacity
                    : kTextSelectionLightOpacity),
            selectionHandleSchemeColor:
                subTheme.inputSelectionHandleSchemeColor ??
                    subTheme.inputDecoratorSchemeColor,
            // An FCS opinionated custom darker handle as default value, when
            // we don't have selected inputSelectionHandleSchemeColor or when
            // inputDecoratorSchemeColor has no selection or uses primary.
            // This gives us previous primaryColorDark, when we have no
            // selection as before, but one that uses
            // inputSelectionHandleSchemeColor as first priority and also
            // follows inputDecoratorSchemeColor when it is different from
            // primary, where primaryColorDark, might not fit.
            selectionHandleCustomColor:
                (subTheme.inputSelectionHandleSchemeColor != null) ||
                        (subTheme.inputDecoratorSchemeColor != null &&
                            subTheme.inputDecoratorSchemeColor !=
                                SchemeColor.primary)
                    ? null
                    : primaryColorDark,
          )
        : null,
    //
    // TimePicker Theme.
    timePickerTheme: useSubThemes
        ? FlexSubThemes.timePickerTheme(
            colorScheme: colorScheme,
            backgroundColor: dialogBackground,
            backgroundSchemeColor: subTheme.dialogBackgroundSchemeColor,
            elevation: subTheme.dialogElevation,
            radius: subTheme.timePickerDialogRadius ??
                platformDialogRadius ??
                platformRadius,
            elementRadius: subTheme.timePickerElementRadius,
            inputDecorationTheme: effectiveInputDecorationTheme,
            useInputDecoratorTheme: subTheme.useInputDecoratorThemeInDialogs,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // ToggleButtons Theme.
    toggleButtonsTheme: useSubThemes
        ? FlexSubThemes.toggleButtonsTheme(
            colorScheme: colorScheme,
            baseSchemeColor: subTheme.toggleButtonsSchemeColor,
            unselectedSchemeColor:
                subTheme.toggleButtonsUnselectedSchemeColor,
            borderSchemeColor: subTheme.toggleButtonsBorderSchemeColor,
            borderWidth:
                subTheme.toggleButtonsBorderWidth ?? subTheme.thinBorderWidth,
            radius: subTheme.toggleButtonsRadius ?? platformRadius,
            minButtonSize: subTheme.buttonMinSize,
            visualDensity: visualDensity,
            useTintedInteraction: subTheme.interactionEffects,
            useTintedDisable: subTheme.tintedDisabledControls,
            useMaterial3: useMaterial3,
          )
        : null,
    //
    // Tooltip theme
    // If we don't use subThemes and don't change tooltipsMatchBackground from
    // default, we get default un-opinionated styles.
    tooltipTheme: !useSubThemes && !tooltipsMatchBackground
        ? null
        : FlexSubThemes.tooltipTheme(
            colorScheme: colorScheme,
            backgroundSchemeColor: subTheme.tooltipSchemeColor,
            backgroundColor: tooltipBackground(),
            backgroundAlpha: tooltipAlpha(),
            foregroundColor: tooltipForeground(),
            textStyle: effectiveTextTheme.bodyMedium!.copyWith(
              fontSize: tooltipFontSize(),
            ),
            borderRadius: tooltipBorderRadius(),
            borderColor: dividerColor,
            waitDuration: subTheme.tooltipWaitDuration,
            showDuration: subTheme.tooltipShowDuration,
          ),
  );
}