FlexSchemeSurfaceColors.blend constructor

FlexSchemeSurfaceColors.blend({
  1. Brightness brightness = Brightness.light,
  2. FlexSurfaceMode surfaceMode = FlexSurfaceMode.highBackgroundLowScaffold,
  3. int blendLevel = 0,
  4. FlexSchemeColor? schemeColors,
  5. FlexSchemeSurfaceColors? blendColors,
  6. FlexSchemeSurfaceColors? surfaceColors,
})

Create nuanced surface colors using pre-defined behavior via enum FlexSurfaceMode property surfaceMode or make totally custom color blended surfaces.

FlexSchemeSurfaceColors were in versions before 4.0 created with the FlexSchemeSurfaceColors.from factory. Version 4.0 and later recommends using the FlexSchemeSurfaceColors.blend factory for even more nuanced surface color branding options and control.

This kind of surface branding is based on the Material guide found under "Accessibility and contrast" https://material.io/design/color/dark-theme.html#properties for branded surfaces.

The brightness controls if we are creating surface colors for light or dark surfaces.

To get elevation overlay color in dark themes on all surfaces used by Material, use a FlexSurfaceMode surfaceMode that start with equal in its name. Other modes will only use elevation overlay if their background happens to be equal to resulting colorScheme.surface color. For more information see issue: https://github.com/flutter/flutter/issues/90353

The surface colors returned by this factory can also be used to make branded surface colors for Flutter's standard ColorScheme, it does not have to be used exclusively by FlexColorScheme.

Implementation

factory FlexSchemeSurfaceColors.blend({
  /// Controls if we create surface colors for light or dark surfaces.
  final Brightness brightness = Brightness.light,

  /// The used surface mode to create different surface color blends.
  ///
  /// Defaults to highBackground.
  final FlexSurfaceMode surfaceMode =
      FlexSurfaceMode.highBackgroundLowScaffold,

  /// The the blend level strength used for the mode.
  final int blendLevel = 0,

  /// The colors used to blend into surfaces when using `surfaceMode` mode
  /// based styles and modes.
  ///
  /// If null, default material light or dark scheme colors will be used as
  /// fallback, depending on if we are making light or dark surfaces.
  ///
  /// If a blend color for a surface is provided in `blendColors`, that color
  /// color always overrides used color from `schemeColor` selected based on
  /// `surfaceMode`.
  FlexSchemeColor? schemeColors,

  /// Custom colors to be blended into each surface color.
  ///
  /// If provided, these colors will be blended into each equivalent surface
  /// color.
  ///
  /// If it is null, then `schemeColors.primary` will be assigned to all
  /// surfaces. The used `surfaceMode` does in some modes override this and
  /// also uses other color from `schemeColors` to be blended into some
  /// surfaces.
  FlexSchemeSurfaceColors? blendColors,

  /// The surface colors that we will mix the blend colors into.
  ///
  /// If null, then Material default surface colors will be used for all
  /// surfaces, that we then mix in the `blendColors` into, unless the
  /// `surfaceMode` defines surface starting colors otherwise.
  ///
  /// In some modes the `surfaceMode` defines and overwrites `surfaceColors`
  /// with its own mode based starting surface colors for each surface.
  /// To ensure that the passed in `surfaceColors` are kept when using
  /// custom surface colors, use the mode [FlexSurfaceMode.custom]
  /// to construct surface colors with custom base surface colors.
  FlexSchemeSurfaceColors? surfaceColors,
}) {
  assert(
      blendLevel >= 0 && blendLevel <= 40,
      'Only blend levels from 0 to 40 '
      'are allowed. Very high alpha blend levels may not produce results '
      'that are visually very appealing or useful.');
  int _blendLevel = blendLevel;
  // If above happens in none debug mode, use 0, no blends.
  if (blendLevel < 0 || blendLevel > 40) _blendLevel = 0;

  final bool isLight = brightness == Brightness.light;

  // We get scheme default blend in colors via brightness and Material
  // default colors for the theme mode, if it was not provided. It is
  // typically provided when making branded surfaces, but Material default
  // colors are used as fallback colors.
  final FlexSchemeColor scheme = schemeColors ??
      (isLight ? FlexColor.material.light : FlexColor.material.dark);
  // The color that should be blended into each surface, defaults to primary
  // color for all surfaces.
  FlexSchemeSurfaceColors blendColor = blendColors ??
      FlexSchemeSurfaceColors(
        surface: scheme.primary,
        dialogBackground: scheme.primary,
        background: scheme.primary,
        scaffoldBackground: scheme.primary,
      );
  // Set dialog blend colors to secondary variant color for modes using it.
  if (surfaceMode == FlexSurfaceMode.levelSurfacesLowScaffoldVariantDialog ||
      surfaceMode == FlexSurfaceMode.highScaffoldLowSurfacesVariantDialog) {
    blendColor =
        blendColor.copyWith(dialogBackground: scheme.secondaryVariant);
  }
  // We get surface starting default colors via brightness and Material
  // default colors if it was not provided. It is normally provided when
  // making branded surfaces, but Material default colors are used as
  // fallback colors.
  FlexSchemeSurfaceColors surface = surfaceColors ??
      (isLight
          ? const FlexSchemeSurfaceColors(
              surface: FlexColor.materialLightSurface,
              background: FlexColor.materialLightBackground,
              scaffoldBackground: FlexColor.materialLightScaffoldBackground,
              dialogBackground: FlexColor.materialLightSurface,
            )
          : const FlexSchemeSurfaceColors(
              surface: FlexColor.materialDarkSurface,
              background: FlexColor.materialDarkBackground,
              scaffoldBackground: FlexColor.materialDarkScaffoldBackground,
              dialogBackground: FlexColor.materialDarkSurface,
            ));
  // If using `highBackgroundLowScaffold` or `highSurfaceLowScaffold` or
  // `highScaffoldLevelSurface` and `_blendLevel` is zero,
  // we use Material default surfaces.
  // This is the same style as used in versions before 4.0 when using
  // `surfaceStyle` based surfaces and no blends via `FlexSurface.material`.
  if (surfaceMode == FlexSurfaceMode.highBackgroundLowScaffold ||
      surfaceMode == FlexSurfaceMode.highSurfaceLowScaffold ||
      surfaceMode == FlexSurfaceMode.highScaffoldLevelSurface) {
    if (_blendLevel == 0) {
      if (isLight) {
        surface = const FlexSchemeSurfaceColors(
          surface: FlexColor.materialLightSurface,
          background: FlexColor.materialLightBackground,
          scaffoldBackground: FlexColor.materialLightScaffoldBackground,
          dialogBackground: FlexColor.materialLightSurface,
        );
      } else {
        surface = const FlexSchemeSurfaceColors(
          surface: FlexColor.materialDarkSurface,
          background: FlexColor.materialDarkBackground,
          scaffoldBackground: FlexColor.materialDarkScaffoldBackground,
          dialogBackground: FlexColor.materialDarkSurface,
        );
      }
    } else {
      // For other `_blendLevel` values than `0` we use the
      // surface color defined by [FlexColor] surfaces. They differ slightly
      // from Material starting colors to provide better blend effects.
      // White is slightly off-white for background and in dark mode
      // surface is slightly darker and background even darker, while
      // scaffold background matches the Material design background.
      if (isLight) {
        surface = const FlexSchemeSurfaceColors(
          surface: FlexColor.lightSurface,
          background: FlexColor.lightBackground,
          scaffoldBackground: FlexColor.lightScaffoldBackground,
          dialogBackground: FlexColor.lightSurface,
        );
      } else {
        surface = const FlexSchemeSurfaceColors(
          surface: FlexColor.darkSurface,
          background: FlexColor.darkBackground,
          scaffoldBackground: FlexColor.darkScaffoldBackground,
          dialogBackground: FlexColor.darkSurface,
        );
      }
    }
  }
  // In these modes we use FlexColor default surface color on all surfaces.
  if (surfaceMode == FlexSurfaceMode.level ||
      surfaceMode == FlexSurfaceMode.highScaffoldLowSurface ||
      surfaceMode == FlexSurfaceMode.levelSurfacesLowScaffold ||
      surfaceMode == FlexSurfaceMode.levelSurfacesLowScaffoldVariantDialog) {
    if (isLight) {
      surface = const FlexSchemeSurfaceColors(
        surface: FlexColor.lightSurface,
        background: FlexColor.lightSurface,
        scaffoldBackground: FlexColor.lightSurface,
        dialogBackground: FlexColor.lightSurface,
      );
    } else {
      surface = const FlexSchemeSurfaceColors(
        surface: FlexColor.darkSurface,
        background: FlexColor.darkSurface,
        scaffoldBackground: FlexColor.darkSurface,
        dialogBackground: FlexColor.darkSurface,
      );
    }
  }
  // In mode `highScaffoldLowSurfaces` and
  // `highScaffoldLowSurfacesVariantDialog`, we use FlexColor
  // default background color on all surfaces. The FlexColor background color
  // is slightly darker in dark mode and a bit off white in light mode,
  // as compared to FlexColor.lightSurface and dark surface.
  if (surfaceMode == FlexSurfaceMode.highScaffoldLowSurfaces ||
      surfaceMode == FlexSurfaceMode.highScaffoldLowSurfacesVariantDialog) {
    if (isLight) {
      surface = const FlexSchemeSurfaceColors(
        surface: FlexColor.lightBackground,
        background: FlexColor.lightBackground,
        scaffoldBackground: FlexColor.lightBackground,
        dialogBackground: FlexColor.lightBackground,
      );
    } else {
      surface = const FlexSchemeSurfaceColors(
        surface: FlexColor.darkBackground,
        background: FlexColor.darkBackground,
        scaffoldBackground: FlexColor.darkBackground,
        dialogBackground: FlexColor.darkBackground,
      );
    }
  }
  // Get alpha blend values corresponding to used mode, level and brightness.
  final _AlphaValues _blend =
      _AlphaValues.getAlphas(surfaceMode, _blendLevel, brightness);
  // Return the computed and resulting surface colors.
  return FlexSchemeSurfaceColors(
    surface:
        surface.surface.blendAlpha(blendColor.surface, _blend.surfaceAlpha),
    dialogBackground: surface.dialogBackground
        .blendAlpha(blendColor.dialogBackground, _blend.dialogAlpha),
    background: surface.background
        .blendAlpha(blendColor.background, _blend.backgroundAlpha),
    scaffoldBackground: surface.scaffoldBackground
        .blendAlpha(blendColor.scaffoldBackground, _blend.scaffoldAlpha),
  );
}