flex_color_scheme 8.0.0 flex_color_scheme: ^8.0.0 copied to clipboard
A Flutter package to use and make beautiful Material design based themes.
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'shared/const/app.dart';
import 'shared/widgets/examples/responsive_scaffold.dart';
import 'shared/widgets/examples/show_color_scheme_colors.dart';
import 'shared/widgets/examples/show_sub_pages.dart';
import 'shared/widgets/examples/show_sub_theme_colors.dart';
import 'shared/widgets/examples/show_theme_data_colors.dart';
import 'shared/widgets/universal/responsive_center.dart';
import 'shared/widgets/universal/showcase_material.dart';
import 'shared/widgets/universal/theme_mode_switch.dart';
/// DEFAULT EXAMPLE - Hot Reload Playground
///
/// This example shows how you can define custom colors, use [FlexColorScheme]
/// to theme your app with them, or use a predefined theme.
///
/// It offers a playground you can use to experiment with all its
/// theming properties and optional opinionated sub-theming.
///
/// It also demonstrates how to use a [GoogleFonts] based font as the default
/// font for your app theme, and how to customize the used [TextTheme].
///
/// To learn more about how to use [FlexColorScheme] and all its features,
/// please go through the five tutorial examples in the readme documentation.
void main() => runApp(const DemoApp());
// This default example contains a long list of const and final property values
// that are just passed in to the corresponding properties in
// FlexThemeData.light() and FlexThemeData.dark() convenience extension on
// ThemeData to FlexColorScheme.light().toTheme and
// FlexColorScheme.dark().toTheme.
//
// The purpose is to provide an easy to use in-code based playground that
// you can experiment with and use as a quick starter template to start using
// FlexColorScheme to make beautiful Flutter themes for your applications.
// It is also a code and comment based quick guide for developers that
// don't read long documentation.
//
// This setup is convenient since you can edit the values for both the light
// and dark theme mode via shared property values and observe the changes
// in the built app using hot reload.
//
// In a real app you might tuck away your color definitions and FlexColorScheme
// settings in a static class with const and final values, and static functions
// as required. The other tutorials show examples of this as well.
//
// To learn more about using FlexColorScheme, it is recommended to go through
// the step-by-step tutorial that uses examples 1 to 5 that explain and
// demonstrate the features with increasing complexity. Example 5 represents
// the full bonanza where pretty much everything can be changed dynamically
// while running the app. It doubles as the web online Themes Playground app
// that can also generate FlexColorScheme setup code for the theme you have
// configured. Using it and studying the setup code it generates is another
// quick way to learn about the different APIs and features it provides.
// For our custom color scheme we define primary and secondary colors,
// but no container or other colors.
final FlexSchemeColor _schemeLight = FlexSchemeColor.from(
primary: const Color(0xFF00296B),
// If you do not want to define secondary, primaryVariant and
// secondaryVariant, error and appBar colors you do not have to,
// they will get defined automatically when using the FlexSchemeColor.from()
// factory. When using FlexSchemeColor.from() you only have to define the
// primary color, anything not defined will get derived automatically from
// the primary color and you get a theme that is based just on shades of
// the provided primary color.
//
// With the default constructor FlexSchemeColor() you have to define
// all 4 main color properties required for a complete color scheme. If you
// do define them all, then prefer using it, since it can be const.
//
// Here we define a secondary color, but if you don't it will get a
// default shade based on the primary color. When you do define a secondary
// color, but not a secondaryVariant color, the secondary container will get
// derived from the secondary color, instead of from the primary color.
secondary: const Color(0xFFFF7B00),
// New in version 5.
// Specifying a brightness value computes missing colors based on given colors
// using a strategy that is compatible with Material3 based ColorScheme
// introduced in Flutter SDK in version 2.10.0. If you don't specify a
// brightness value, you still get all needed colors computed, but the used
// strategy for missing colors is more inline with the usage as it was
// in Material 2 design. The new M3 colors primary.container and
// secondary.container receives the color values that would have been given to
// deprecated colors primary.variant and secondary.variant, the color values
// are OK for using them as variant colors in an M2 based app, but the values
// are not ideal for an M3 design. For better M3 results, prefer giving also
// the brightness you are targeting.
brightness: Brightness.light,
);
// These are custom defined matching dark mode colors. Further below we show
// how to compute them based on the light color scheme. You can swap them in the
// code example further below and compare the result of these manually defined
// matching dark mode colors, to the ones computed via the "lazy" designer
// matching dark colors.
final FlexSchemeColor _schemeDark = FlexSchemeColor.from(
primary: const Color(0xFF6B8BC3),
secondary: const Color(0xffff7155),
brightness: Brightness.dark,
);
// To use a pre-defined color scheme, don't assign any FlexSchemeColor to
// `colors` instead, just pick a FlexScheme enum based value and assign it
// to the `scheme`. Try eg the new "flutterDash" color scheme, based on colors
// found in the 4k wallpaper Google shared before the Flutter 2.10.0 release.
const FlexScheme _scheme = FlexScheme.flutterDash;
// To make it easy to toggle between using the above custom colors, or the
// selected predefined scheme in this example, set _useScheme to true to use the
// selected predefined scheme above, set it to false to use the custom colors
// defined earlier above.
const bool _useScheme = true;
// A quick setting for the themed app bar elevation, it defaults to 0.
// A very low, like 0.5 is pretty nice too, since it gives an underline effect
// visible with e.g. white or light colored app bars.
const double _appBarElevation = 0.5;
// There is setting to put an opacity value on the app bar. If used, we can see
// content scroll behind it, if we also extend the Scaffold behind the AppBar.
const double _appBarOpacity = 0.94;
// If you set _computeDarkTheme below to true, the dark scheme will be computed
// both for the selected scheme and the custom colors, from the light scheme.
// There is a bit of logic hoops below to make it happen via this bool toggle.
//
// Going "toDark()" on your light FlexSchemeColor definition is just a quick
// way you can make a dark scheme from a light color scheme definition, without
// figuring out usable color values yourself. This is useful during development,
// when you test custom colors. For production and final colors you probably
// want to fine tune your custom dark color scheme colors and use const values.
const bool _computeDarkTheme = false;
// When you use _computeDarkTheme, use this de-saturation % level to calculate
// the dark scheme from the light scheme colors. The default is 35%, but values
// from 20% might work on less saturated light scheme colors. For more
// deep and colorful starting values, you can try 40%. Trivia: The default
// red dark error color in the Material design guide, is computed from the light
// theme error color value, by using 40% with the same algorithm used here.
const int _toDarkLevel = 30;
// To swap primary and secondary colors, set to true. With some color schemes
// interesting and even useful inverted primary-secondary themes can be obtained
// by only swapping the colors on your dark scheme. Some schemes where even
// designed with this usage in mind, but not all look so well when using it.
const bool _swapColors = false;
// The `usedColors` is a convenience property that allows you to vary which
// colors to use of the primary, secondary and variant colors included in
// `colors` in `FlexSchemeColor`, or the `FlexSchemeColor` the enum based
// selection specifies. The integer number corresponds to using:
//
// * 1 = Only the primary color
// * 2 = Primary & Secondary colors
// * 3 = Primary + container & Secondary colors
// * 4 = Primary + container & Secondary + container
// * 5 = Primary + container & Secondary + container & tertiary colors
// * 6 = Primary + container & Secondary + container & tertiary + container
// * 7 = PST, Primary, Secondary and Tertiary, containers computed.
//
// This can be a quick way to try what you theme looks like when using less
// source colors and just different shades of the same color, that are still
// correctly tuned for their ColorScheme color values.
//
// The values default to 6, so that any color values that are defined are always
// used as defined and given.
const int _usedColors = 6;
// New in version 5: Key color seed based theming.
//
// If you want to use Material 3 based seed generated color schemes, using
// the current FlexColorScheme's colors as input to the seed generation. You
// can do so by passing in just a default `FlexKeyColors()` object to the
// `keyColors` property in FlexColorScheme.light and .dark factories.
//
// FlexKeyColors can be also configured, if its `useKeyColors` is false it is
// no being used, likewise it is not if the property `keyColors` is null.
//
// The default constructor `FlexKeyColors()` has the properties `useKeyColors`,
// `useSecondary` and `useTertiary` defaulting to true. This means the primary,
// secondary and tertiary colors from your active FlexColorScheme's colors will
// all be used as key colors to generate the theme's ColorScheme.
//
// The primary color is always using useKeyColors is true, but using secondary
// and tertiary colors to generate the ColorScheme are optional.
// They are on by default in the default constructor, to omit them set any
// of them to false.
//
// Flutter SDK `ColorScheme.fromSeed` only accepts a/ single color,
// the main/primary color as a seed color for the Material 3 ColorScheme
// it generates from a seed color. If you set both `useSecondary`
// and `useTertiary` to false, the result is the same as if you would have
// provided the current primary color value from the active FlexColorScheme
// to `ColorScheme.fromSeed` to generate the theme used `ColorScheme`.
// When you also use secondary and tertiary colors as input to generate the
// ColorScheme, their color values are based on them, instead of being sourced
// in fixed manner from the single primary color. This makes the generated
// ColorScheme follow the colors in your specified keys to a larger degree
// than Flutter SDK `ColorScheme.fromSeed` does.
//
// When you use seeded ColorSchemes, the key color used as seed color as primary
// color, secondary and tertiary usually do not end up in the resulting
// ColorScheme. This can be problematic when your spec calls for a specific
// specific e.g. brand color for certain color properties.
//
// With FlexColorscheme you can, for e.g. branding or other purposes, decide to
// keep one or more of the defined color values in your FlexColorScheme at its
// defined color value, despite otherwise using seeded color values to produce
// the resulting `ColorScheme`from them. There is a `keep` toggle in
// `FlexKeyColors` for all the six main colors in a `ColorScheme`, you can
// set any of them to true, to keep the color in question it has as input
// in your FlexColorScheme.
const FlexKeyColors _keyColors = FlexKeyColors(
useKeyColors: false, // <-- set to true enable M3 seeded ColorScheme.
useSecondary: true,
useTertiary: true,
keepPrimary: true, // <-- Keep defined value, do not use the seeded result.
keepPrimaryContainer: false,
keepSecondary: false,
keepSecondaryContainer: false,
keepTertiary: false,
keepTertiaryContainer: false,
);
// New in version 5: Custom configuration for seed color calculations.
//
// Not only does FlexColorScheme enable using more than one seed color, you
// can also completely customize the tone mapping and CAM16 chroma limits
// imposed on used seed generation algorithm.
//
// When using Material 3 design and key colors, it generates 6 different tonal
// palettes `TonalPalette` for the colors in a M3 ColorScheme:
//
// * Primary tonal palette
// * Secondary tonal palette
// * Tertiary tonal palette
// * Error tonal palette
// * Neutral tonal palette
// * Neutral variant tonal palette
//
// Each palette contains 13 colors starting from black and ending in white, with
// different "tones" in-between of the color used for the palette.
// ColorScheme.from generates all the palettes from a single input color, and
// a hard coded value for the error palettes. FlexColorScheme allows you to as
// seen also specify the input colors for secondary and tertiary tonal palette.
// The neutral palettes are also generated from the input primary color, but
// with very little chroma of it left it, a bit more in the variant palette.
// this is a bit like the surface alpha blend that FlexColorScheme has
// been using since its first version.
//
// The algorithm used by ColorScheme.from also lock chroma for secondary and
// tertiary to a given value, and primary is min 48, after tha it uses
// chroma from the provided color. When tonal palettes have been created, it
// uses fixed tones (indexes) from relevant tonal palette and assigns them
// to given color properties in the ColorScheme. It is also worth noticing
// to you should use the same key color for both dark and light theme mode.
// the algorithm uses the same tonal palette for light and dark modes, but
// different tones from same palette.
//
// FlexColorScheme opens up this algorithm and logic and enables you to
// modify the color seed logic and behavior. The used algorithm is really
// fascinating, and the M3 usage of it is fine too. But maybe you want to it
// produce colors that are even more earthy and softer than M3, that is pretty
// soft already. Maybe your want more vivid tones, more in classic M2 style, or
// perhaps you need to seed schemes with much higher contrast for accessibility
// reasons. With FlexColorScheme you can. You do this by making a custom
// FlexTones data class to configure how the seeding engine maps palette colors
// the ColorScheme and how it uses chroma values in the key colors.
//
// The `FlexTones` has a `FlexTones.light` and `FlexTones.dark` factory, that
// are used for respective theme mode when using key colors in FlexColorScheme
// by default.
//
// The `FlexTones.light` factory by default provides the same chroma limits and
// tone mappings as used by:
// `ColorScheme.fromSeed(seedColor: color, brightness: Brightness.light)`
//
// Likewise the `FlexTones.dark` corresponds to same chroma limits and tone
// mappings as used by:
// `ColorScheme.fromSeed(seedColor: color, brightness: Brightness.dark)`.
//
// However, with the factories you can customize which tone each ColorScheme
// color properties uses as its color from its corresponding tonal palette.
// You can also change if primary, secondary and tertiary colors use the
// chroma in their key color value, if it should have a at least a given
// minimum chroma value, and after that use the key color's chroma value,
// or if it should be locked to a given chroma value.
//
// There is also a static that returns a default FlexTones.light and
// FlexTones.dark, when you pass it a brightness, called FlexTones.material,
// to indicate that it is using the default Material 3 specification.
//
// There are few more pre-made static configurations, for example:
//
// * FlexTones.soft
// * FlexTones.vivid
// * FlexTones.highContrast
// * FlexTones.chroma
//
// You can swap in them in below to try slightly different styles on generated
// seeded ColorScheme. The `FlexTones.chroma` for example, keeps the chroma as
// is in key colors for secondary and tertiary, and will thus produce a seeded
// ColorScheme that is closer to the provided key/seed colors, than the Flutter
// SDK M3 spec version does.
final FlexTones _flexTonesLight = FlexTones.material(Brightness.light);
final FlexTones _flexTonesDark = FlexTones.material(Brightness.dark);
// Use a GoogleFonts font as default font for your theme.
final String? _fontFamily = GoogleFonts.notoSans().fontFamily;
// Define a custom text theme for the app. Here we have decided that
// display fonts are too big to be useful for us, so we make them a bit smaller
// and that labelSmall is a bit too small and has weird letter spacing, so we
// make it bigger and change its letter spacing.
const TextTheme _textTheme = TextTheme(
displayMedium: TextStyle(fontSize: 41),
displaySmall: TextStyle(fontSize: 36),
labelSmall: TextStyle(fontSize: 11, letterSpacing: 0.5),
);
// The `surfaceMode` takes `FlexSurfaceMode` that is used to select the used
// strategy for blending primary color into different surface colors.
const FlexSurfaceMode _surfaceMode = FlexSurfaceMode.highBackgroundLowScaffold;
// The alpha blend level strength can be defined separately from the
// SurfaceMode strategy, and has 40 alpha blend level strengths.
const int _blendLevel = 8;
// The `useSubThemes` sets weather you want to opt-in or not on additional
// opinionated sub-theming. By default FlexColorScheme as before does very
// little styling on widgets, other than a few important adjustments, described
// in detail in the readme. By using the sub-theme opt-in, it now also offers
// easy to use additional out-of the box opinionated styling of SDK UI Widgets.
// One key feature is the rounded corners on Widgets that support it.
const bool _useSubThemes = true;
// The opt-in opinionated sub-theming offers easy to use consistent corner
// radius rounding setting on all sub-themes and a ToggleButtons design that
// matches the normal buttons style and size.
// It comes with Material 3 like rounded defaults, but you can adjust
// its configuration via simple parameters in a passed in configuration class
// called FlexSubThemesData.
//
// Here are some some configuration examples:
const FlexSubThemesData _subThemesData = FlexSubThemesData(
// Opt in for themed hover, focus, highlight and splash effects.
// New buttons use primary themed effects by default, this setting makes
// the general ThemeData hover, focus, highlight and splash match that.
// True by default when opting in on sub themes, but you can turn it off.
interactionEffects: true,
// When it is null = undefined, the sub themes will use their default style
// behavior that aims to follow new Material 3 (M3) standard for all widget
// corner radius. Current Flutter SDK corner radius is 4, as defined by
// the Material 2 design guide. M3 uses much higher corner radius, and it
// varies by widget type.
//
// When you set [defaultRadius] to a value, it will override these defaults
// with this global default. You can still set and lock each individual
// border radius back for these widget sub themes to some specific value, or
// to its Material3 standard, which is mentioned in each theme as the used
// default when its value is null.
//
// Set global corner radius. Default is null, resulting in M3 styles, but make
// it whatever you like, even 0 for a hip to be square style.
defaultRadius: null,
// You can also override individual corner radius for each sub-theme to make
// it different from the global `cornerRadius`. Here eg. the bottom sheet
// radius is defined to always be 24:
bottomSheetRadius: 24,
// Use the Material3 text theme and typography. Defaults to null.
// When null, the correct M2/M3 TextTheme and Typography for respective mode
// is used. If true, M3 style is enforced, if false, M2 mode is enforced.
useMaterial3Typography: true,
// Select input decorator type, only SDK options outline and underline
// supported no, but custom ones may be added later.
inputDecoratorBorderType: FlexInputBorderType.outline,
// For a primary color tinted background on the input decorator set to true.
inputDecoratorIsFilled: true,
// If you do not want any underline/outline on the input decorator when it is
// not in focus, then set this to false.
inputDecoratorUnfocusedHasBorder: false,
// Select the ColorScheme color used for input decoration border.
// Primary is default so no need to set that, used here as placeholder to
// enable easy selection of other options.
inputDecoratorSchemeColor: SchemeColor.primary,
// Set some alpha channel opacity value input decorator.
inputDecoratorBackgroundAlpha: 20,
// Some FAB (Floating Action Button) settings.
//
// // If fabUseShape is false, no shape will be added to FAB theme, it will get
// // whatever default shape the widget default behavior applies.
// //
// fabUseShape: false,
// //
// // Select the ColorScheme color used by FABs as their base/background color
// // Secondary is default so no need to set that, used here as placeholder to
// // enable easy selection of other options.
// //
// fabSchemeColor: SchemeColor.secondaryContainer,
// Set some custom colors used by Chips.
chipSchemeColor: SchemeColor.surfaceContainerHighest,
chipSelectedSchemeColor: SchemeColor.tertiaryContainer,
chipSecondarySelectedSchemeColor: SchemeColor.primaryContainer,
chipBlendColors: false,
// Elevations have easy override values as well.
elevatedButtonElevation: 1,
// Widgets that use outline borders can be easily adjusted via these
// properties, they affect the outline input decorator, outlined button and
// toggle buttons.
thickBorderWidth: 1.5, // Default is 2.0.
thinBorderWidth: 1, // Default is 1.0.
// Select the ColorScheme color used for selected TabBar indicator.
// Defaults to same color as selected tab if not defined.
// tabBarIndicatorSchemeColor: SchemeColor.secondary,
// Select the ColorScheme color used for selected bottom navigation bar item.
// Primary is default so no need to set that, used here as placeholder to
// enable easy selection of other options.
bottomNavigationBarSelectedLabelSchemeColor: SchemeColor.primary,
// Select the ColorScheme color used for bottom navigation bar background.
// Background is default so no need to set that, provided here as placeholder
// to enable easy selection of other options.
bottomNavigationBarBackgroundSchemeColor: SchemeColor.surfaceContainer,
// Below are some example quick override properties that you can use on the
// M3 based NavigationBar. The section is double commented out, so it its
// easy to uncomment to try them all.
//
// // SchemeColor based color for [NavigationBar]'s selected item icon.
// // navigationBarSelectedIconSchemeColor: SchemeColor.tertiary,
// // SchemeColor based color for [NavigationBar]'s selected item label.
// navigationBarSelectedLabelSchemeColor: SchemeColor.tertiary,
// // SchemeColor based color for [NavigationBar]'s unselected item icons.
// navigationBarUnselectedIconSchemeColor: SchemeColor.onSurface,
// // SchemeColor based color for [NavigationBar]'s unselected item icons.
// navigationBarUnselectedLabelSchemeColor: SchemeColor.onSurface,
// // SchemeColor based color for [NavigationBar]'s selected item highlight.
// navigationBarIndicatorSchemeColor: SchemeColor.tertiaryContainer,
// // If you use suitable M3 designed container color for the indicator, it
// // does not need any opacity.
// navigationBarIndicatorOpacity: 1,
// // Select the ColorScheme color used for [NavigationBar]'s background.
// navigationBarBackgroundSchemeColor: SchemeColor.surfaceContainerHigh,
// // When set to true [NavigationBar] unselected icons use a more muted
// // version of color defined by [navigationBarUnselectedIconSchemeColor].
// navigationBarMutedUnselectedIcon: true,
// // When set to true [NavigationBar] unselected labels use a more muted
// // version of color defined by [navigationBarUnselectedLabelSchemeColor].
// navigationBarMutedUnselectedLabel: true,
// // Set size of labels.
// navigationBarSelectedLabelSize: 12,
// navigationBarUnselectedLabelSize: 10,
// // Set the size of icons icons.
// navigationBarSelectedIconSize: 26,
// navigationBarUnselectedIconSize: 22,
);
// If true, the top part of the Android AppBar has no scrim, it then becomes
// one colored like on iOS.
const bool _transparentStatusBar = true;
// Usually the TabBar is used in an AppBar. This style themes it right for
// that, regardless of what FlexAppBarStyle you use for the `appBarStyle`.
// If you will use the TabBar on Scaffold or other background colors, then
// use the style FlexTabBarStyle.forBackground.
const FlexTabBarStyle _tabBarForAppBar = FlexTabBarStyle.forAppBar;
// If true, tooltip background brightness is same as background brightness.
// False by default, which is inverted background brightness compared to theme.
// Setting this to true is more Windows desktop like.
const bool _tooltipsMatchBackground = true;
// The visual density setting defaults to same as SDK default value,
// which is `VisualDensity.adaptivePlatformDensity`. You can define a fixed one
// or try `FlexColorScheme.comfortablePlatformDensity`.
// The `comfortablePlatformDensity` is an alternative adaptive density to the
// default `adaptivePlatformDensity`. It makes the density `comfortable` on
// desktops, instead of `compact` as the `adaptivePlatformDensity` does.
// This is useful on desktop with touch screens, since it keeps tap targets
// a bit larger but not as large as `standard` intended for phones and tablets.
final VisualDensity _visualDensity = FlexColorScheme.comfortablePlatformDensity;
// This is just standard `platform` property in `ThemeData`, handy to have as
// a direct property, you can use it to test how things changes on different
// platforms without using `copyWith` on the resulting theme data.
final TargetPlatform _platform = defaultTargetPlatform;
/// A theme Extension example with a single custom brand color property.
///
/// You can add as many colors and other theme properties as you need, and
/// you can add multiple different ThemeExtension sub classes as well.
class BrandTheme extends ThemeExtension<BrandTheme> {
const BrandTheme({
this.brandColor,
});
final Color? brandColor;
// You must override the copyWith method.
@override
BrandTheme copyWith({
Color? brandColor,
}) =>
BrandTheme(
brandColor: brandColor ?? this.brandColor,
);
// You must override the lerp method.
@override
BrandTheme lerp(ThemeExtension<BrandTheme>? other, double t) {
if (other is! BrandTheme) {
return this;
}
return BrandTheme(
brandColor: Color.lerp(brandColor, other.brandColor, t),
);
}
}
// Custom const theme with our brand color in light mode.
const BrandTheme lightBrandTheme = BrandTheme(
brandColor: Color.fromARGB(255, 8, 79, 71),
);
// Custom const theme with our brand color in dark mode.
const BrandTheme darkBrandTheme = BrandTheme(
brandColor: Color.fromARGB(255, 167, 227, 218),
);
class DemoApp extends StatefulWidget {
const DemoApp({super.key});
@override
State<DemoApp> createState() => _DemoAppState();
}
class _DemoAppState extends State<DemoApp> {
ThemeMode themeMode = ThemeMode.system;
bool useMaterial3 = true;
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Hot Reload Playground',
// Define the light theme for the app, based on defined colors and
// properties above.
theme: FlexThemeData.light(
// Use local state to toggle usage of Material 3.
useMaterial3: useMaterial3,
// Want to use a built in scheme? Don't assign any value to colors.
// We just use the _useScheme bool toggle here from above, only for easy
// switching via code params so you can try options handily.
colors: _useScheme ? null : _schemeLight,
scheme: _scheme,
swapColors: _swapColors, // If true, swap primary and secondaries.
usedColors: _usedColors,
// For an optional white look set lightIsWhite to true.
// This is the counterpart to darkIsTrueBlack mode in dark theme mode,
// which is much more useful than this feature.
lightIsWhite: false,
// If you want to use an existing fully specified `ColorScheme` that
// your designer or you yourself made, you can do so too. This is
// useful e.g. if you want the use FlexColorScheme for its component
// sub-theming with an existing `ColorScheme`. To use a`ColorScheme`
// object as color sources for your `FlexColorscheme` just pass it to
// the `colorScheme` property. The `surfaceMode` and `blendLevel` will
// still adjust surface and background colors on surfaces in passed
// `ColorScheme` if they are used. This can be demonstrated here with
// the default Flutter M2 based light ColorScheme set, if uncommented
// below.
// colorScheme: const ColorScheme.light(),
// If you provide a color value to a direct color property, the color
// value will override anything specified via the other properties.
// The order from lowest to highest color property priority, to
// determine effective colors are:
// 1. scheme 2. colors 3. colorScheme 4. individual color values.
// Normally you would make a custom scheme using the colors property,
// but if you want to override just one or two colors in a pre-existing
// scheme, this can be handy way to do it.
// Uncomment a color property below on the light theme to try it:
// primary: FlexColor.indigo.light.primary,
// primaryContainer: FlexColor.greenLightPrimaryContainer,
// secondary: FlexColor.indigo.light.secondary,
// secondaryContainer: FlexColor.indigo.light.secondaryContainer,
// surface: FlexColor.lightSurface,
// background: FlexColor.lightBackground,
// error: FlexColor.materialLightErrorHc,
// scaffoldBackground: FlexColor.lightScaffoldBackground,
// dialogBackground: FlexColor.lightSurface,
// appBarBackground: FlexColor.barossaLightPrimary,
// The default style of AppBar in Flutter SDK light mode uses scheme
// primary color as its background color. The appBarStyle
// FlexAppBarStyle.primary, results in this too, and is the default in
// light mode. You can also choose other themed styles. Like
// FlexAppBarStyle.background, that gets active color blend from used
// surfaceMode or surfaceStyle, depending on which one is being used.
// You may often want a different style on the app bar in dark and
// light theme mode, therefore it was not set via a shared value
// above in this template.
appBarStyle: null, // Try different style, e.g.FlexAppBarStyle.primary,
appBarElevation: _appBarElevation,
appBarOpacity: _appBarOpacity,
transparentStatusBar: _transparentStatusBar,
tabBarStyle: _tabBarForAppBar,
surfaceMode: _surfaceMode,
blendLevel: _blendLevel,
tooltipsMatchBackground: _tooltipsMatchBackground,
// You can try another font too.
// Prefer using fully defined TextThemes when using fonts, rather than
// just setting the fontFamily name, even with GoogleFonts. For
// quick tests this is fine if the same font style is good
// as is for all the styles in the TextTheme, then just the fontFamily
// works well too.
fontFamily: _fontFamily,
textTheme: _textTheme,
primaryTextTheme: _textTheme,
keyColors: _keyColors,
tones: _flexTonesLight,
subThemesData: _useSubThemes ? _subThemesData : null,
visualDensity: _visualDensity,
platform: _platform,
// Add all our custom theme extensions, in this case we only have one.
extensions: <ThemeExtension<dynamic>>{
lightBrandTheme,
},
),
// Define the corresponding dark theme for the app.
darkTheme: FlexThemeData.dark(
// Use local state to toggle usage of Material 3.
useMaterial3: useMaterial3,
// If you want to base the dark scheme on your light colors,
// you can also compute it from the light theme's FlexSchemeColors.
// Here you can do so by setting _computeDarkTheme above to true.
// The FlexSchemeColors class has a toDark() method that can convert
// a color scheme designed for a light theme, to corresponding colors
// suitable for a dark theme. For the built in themes there is no
// need to do so, they all have hand tuned dark scheme colors.
// Regardless, below we anyway demonstrate how you can do that too.
//
// Normally you would not do things like this complicated logic, you
// would just use the colors or scheme property based on what you want.
// This logic is just here so you can toggle the two booleans earlier
// above to try the options without commenting any code.
colors: (_useScheme && _computeDarkTheme)
// If we use predefined schemes and want to compute a dark
// theme from its light colors, we can grab the light scheme colors
// for _schemes from the FlexColor.schemes map and use toDark(),
// that takes a white blend saturation %, where 0 is same colors as
// the input light scheme colors, and 100% makes it white.
? FlexColor.schemes[_scheme]!.light.toDark(_toDarkLevel)
// If we use a predefined scheme, then pass, null so we get
// selected _scheme via the scheme property.
: _useScheme
? null
// If we compute a scheme from our custom data, then use the
// toDark() method on our custom light FlexSchemeColor data.
// New in version 5:
// For better dark mapping of the light color
// based values, set parameter swapColor to true in toDark.
: _computeDarkTheme
? _schemeLight.toDark(_toDarkLevel, true)
// And finally, use the defined custom dark colors.
: _schemeDark,
// To use a built-in scheme based on enum, don't assign colors above.
scheme: _scheme,
swapColors: _swapColors,
usedColors: _usedColors,
// For an optional ink black dark mode, set darkIsTrueBlack to true.
darkIsTrueBlack: false,
//
// The SDK default style of the AppBar in dark mode uses a fixed dark
// background color, defined via colorScheme.surface color. The
// appBarStyle FlexAppBarStyle.material results in the same color value.
// It is also the default if you do not define the style.
// You can also use other themed styles. Here we use background, that
// also gets active color blend from used SurfaceMode or SurfaceStyle.
// You may often want a different style on the AppBar in dark and light
// theme mode, therefore it was not set via a shared value value
// above in this template.
appBarStyle: null, // Try styles like: FlexAppBarStyle.background,
appBarElevation: _appBarElevation,
appBarOpacity: _appBarOpacity,
transparentStatusBar: _transparentStatusBar,
tabBarStyle: _tabBarForAppBar,
surfaceMode: _surfaceMode,
blendLevel: _blendLevel,
tooltipsMatchBackground: _tooltipsMatchBackground,
fontFamily: _fontFamily,
textTheme: _textTheme,
primaryTextTheme: _textTheme,
keyColors: _keyColors,
tones: _flexTonesDark,
subThemesData: _useSubThemes ? _subThemesData : null,
visualDensity: _visualDensity,
platform: _platform,
// Add all our custom theme extensions, in this case we only have one.
extensions: <ThemeExtension<dynamic>>{
darkBrandTheme,
},
),
themeMode: themeMode,
home: HomePage(
themeMode: themeMode,
onThemeModeChanged: (ThemeMode mode) {
setState(() {
themeMode = mode;
});
},
useMaterial3: useMaterial3,
onMaterial3Changed: (bool value) {
setState(() {
useMaterial3 = value;
});
},
),
);
}
}
// -----------------------------------------------------------------------------
// Home Page for the Default Example - Hot Reload Playground
// -----------------------------------------------------------------------------
//
// The content of HomePage below is not so relevant for using FlexColorScheme
// based application theming. The critical parts are in the MaterialApp
// theme definitions above. The HomePage contains UI to visually show what
// the defined example looks like in an application and with common Widgets.
//
// The AnnotatedRegion using FlexColorScheme.themedSystemNavigationBar demo
// is however relevant if you want to change the style of the system
// navigation bar on Android.
//
// The contents below makes it easy to see what your theme looks
// like, and the purpose of this demo app is to show that. You can use this
// example app to experiment with your own themes in code and see the results
// via this HomePage.
class HomePage extends StatefulWidget {
const HomePage({
super.key,
required this.themeMode,
required this.onThemeModeChanged,
required this.useMaterial3,
required this.onMaterial3Changed,
});
final ThemeMode themeMode;
final ValueChanged<ThemeMode> onThemeModeChanged;
final bool useMaterial3;
final ValueChanged<bool> onMaterial3Changed;
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late final ScrollController scrollController;
// Enabled state of each menuItem.
late List<bool> menuItemsEnabled;
// Active state of each menuItem.
late List<ResponsiveMenuItemIconState> menuItemsIconState;
@override
void initState() {
super.initState();
scrollController =
ScrollController(keepScrollOffset: true, initialScrollOffset: 0);
// Set enabled menu items.
menuItemsEnabled =
List<bool>.generate(App.menuItems.length, (int i) => false);
menuItemsEnabled[0] = true;
menuItemsEnabled[1] = true;
// Set menu icons states to initial states, some are a loaded from
// persisted values via the theme controller.
menuItemsIconState = List<ResponsiveMenuItemIconState>.generate(
App.menuItems.length, (int i) => ResponsiveMenuItemIconState.primary);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
final ThemeData theme = Theme.of(context);
final bool isLight = theme.brightness == Brightness.light;
menuItemsIconState[0] = isLight
? ResponsiveMenuItemIconState.primary
: ResponsiveMenuItemIconState.secondary;
menuItemsIconState[1] = theme.useMaterial3
? ResponsiveMenuItemIconState.primary
: ResponsiveMenuItemIconState.secondary;
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final Size mediaSize = MediaQuery.sizeOf(context);
final EdgeInsets mediaPadding = MediaQuery.paddingOf(context);
final double margins = App.responsiveInsets(mediaSize.width);
final double topPadding = mediaPadding.top + kToolbarHeight + margins;
final double bottomPadding = mediaPadding.bottom + margins;
final bool isPhone = mediaSize.width < App.phoneWidthBreakpoint ||
mediaSize.height < App.phoneHeightBreakpoint;
final ThemeData theme = Theme.of(context);
final TextTheme textTheme = theme.textTheme;
final TextStyle headlineMedium = textTheme.headlineSmall!;
final bool isDark = theme.brightness == Brightness.dark;
// Get our custom brand color from the BrandTheme extension, with a
// fallback to primary color.
final Color brandColor =
theme.extension<BrandTheme>()!.brandColor ?? theme.colorScheme.primary;
return AnnotatedRegion<SystemUiOverlayStyle>(
// FlexColorScheme contains a static helper that can be use to theme
// the system navigation bar using an AnnotatedRegion. Without this
// wrapper the system navigation bar in Android will not change
// theme color as we change themes for the page. This is normal Flutter
// behavior. By using an annotated region with the helper function
// FlexColorScheme.themedSystemNavigationBar, we can make the
// navigation bar follow desired background color and theme mode.
// This looks much better and as it should on Android devices.
// It also supports system navbar with opacity or fully transparent
// Android system navigation bar on Android SDK >= 29.
value: FlexColorScheme.themedSystemNavigationBar(
context,
// On Android SDK >= 29, try changing this to transparent, then on the
// sub page demo with a bottom navigation bar and some opacity set
// further below in [opacity].
// You then get one homogeneously slightly transparent area, shared
// with the bottom navigation bar and system navigation bar.
systemNavBarStyle: FlexSystemNavBarStyle.background,
// You can use a top divider on the navigation bar, but it does
// add an extra scrim, which becomes visible when using bars with
// opacity or fully transparent.
useDivider: false,
// You can set opacity on the Android system navigation bar, this will
// result in content being visible behind it if Scaffold uses
// extendBody.
opacity: 0.60,
),
child: ResponsiveScaffold(
title: Text(App.title(context)),
menuTitle: const Text(App.packageName),
menuLeadingTitle: Text(
App.title(context),
style:
theme.textTheme.titleSmall!.copyWith(fontWeight: FontWeight.bold),
),
menuLeadingSubtitle: const Text('Version ${App.versionMajor}'),
menuLeadingAvatarLabel: 'FCS',
menuItems: App.menuItems,
menuItemsEnabled: menuItemsEnabled,
menuItemsIconState: menuItemsIconState,
railWidth: isPhone ? 52 : 66,
breakpointShowFullMenu: App.desktopWidthBreakpoint,
extendBodyBehindAppBar: true,
extendBody: true,
onSelect: (int index) {
if (index == 0) {
if (isDark) {
widget.onThemeModeChanged(ThemeMode.light);
} else {
widget.onThemeModeChanged(ThemeMode.dark);
}
}
if (index == 1) {
if (widget.useMaterial3) {
widget.onMaterial3Changed(false);
} else {
widget.onMaterial3Changed(true);
}
}
},
body: ResponsiveCenter(
controller: scrollController,
constraints: const BoxConstraints(maxWidth: App.maxBodyWidth),
child: ListView(
controller: scrollController,
padding: EdgeInsets.fromLTRB(
margins, topPadding, margins, bottomPadding),
children: <Widget>[
Text('Theme Extension Colored Header',
style: headlineMedium.copyWith(color: brandColor)),
const Text(
'This is FlexColorScheme developers Hot Reload '
'Playground. It has a large number of property values '
'configured and documented, that you can modify and '
'hot reload the app to try different options and features.',
),
const SizedBox(height: 8),
ListTile(
contentPadding: EdgeInsets.zero,
title: const Text('Theme mode'),
subtitle: Text('Theme '
'${widget.themeMode.toString().dotTail}'),
trailing: ThemeModeSwitch(
themeMode: widget.themeMode,
onChanged: widget.onThemeModeChanged,
),
onTap: () {
if (isDark) {
widget.onThemeModeChanged(ThemeMode.light);
} else {
widget.onThemeModeChanged(ThemeMode.dark);
}
},
),
const SizedBox(height: 8),
SwitchListTile(
contentPadding: EdgeInsets.zero,
title: const Text('Use Material 3'),
value: widget.useMaterial3,
onChanged: (bool value) {
widget.onMaterial3Changed(value);
},
),
const SizedBox(height: 8),
const ShowColorSchemeColors(),
const SizedBox(height: 8),
const ShowThemeDataColors(),
const SizedBox(height: 8),
const ShowSubThemeColors(),
const SizedBox(height: 8),
const ShowSubPages(),
const Divider(),
Text('Widget Showcase', style: headlineMedium),
const SizedBox(height: 8),
const ShowcaseMaterial(),
],
),
),
),
);
}
}