mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
This enum doesn't make sense anymore now that we can arbitrarily colorize icons. Instead, we just use a Color, which is both simpler and can be interpolated during animations. Fixes #1279
300 lines
12 KiB
Dart
300 lines
12 KiB
Dart
// Copyright 2015 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:ui' show Color, hashValues, hashList, lerpDouble;
|
|
|
|
import 'colors.dart';
|
|
import 'icon_theme_data.dart';
|
|
import 'typography.dart';
|
|
|
|
enum ThemeBrightness { dark, light }
|
|
|
|
// Deriving these values is black magic. The spec claims that pressed buttons
|
|
// have a highlight of 0x66999999, but that's clearly wrong. The videos in the
|
|
// spec show that buttons have a composited highlight of #E1E1E1 on a background
|
|
// of #FAFAFA. Assuming that the highlight really has an opacity of 0x66, we can
|
|
// solve for the actual color of the highlight:
|
|
const Color _kLightThemeHighlightColor = const Color(0x66BCBCBC);
|
|
|
|
// The same video shows the splash compositing to #D7D7D7 on a background of
|
|
// #E1E1E1. Again, assuming the splash has an opacity of 0x66, we can solve for
|
|
// the actual color of the splash:
|
|
const Color _kLightThemeSplashColor = const Color(0x66C8C8C8);
|
|
|
|
// Unfortunately, a similar video isn't available for the dark theme, which
|
|
// means we assume the values in the spec are actually correct.
|
|
const Color _kDarkThemeHighlightColor = const Color(0x40CCCCCC);
|
|
const Color _kDarkThemeSplashColor = const Color(0x40CCCCCC);
|
|
|
|
class ThemeData {
|
|
|
|
ThemeData.raw({
|
|
this.brightness,
|
|
this.primaryColor,
|
|
this.primaryColorBrightness,
|
|
this.accentColor,
|
|
this.accentColorBrightness,
|
|
this.canvasColor,
|
|
this.cardColor,
|
|
this.dividerColor,
|
|
this.highlightColor,
|
|
this.splashColor,
|
|
this.unselectedColor,
|
|
this.disabledColor,
|
|
this.buttonColor,
|
|
this.selectionColor,
|
|
this.backgroundColor,
|
|
this.indicatorColor,
|
|
this.hintColor,
|
|
this.hintOpacity,
|
|
this.errorColor,
|
|
this.text,
|
|
this.primaryTextTheme,
|
|
this.primaryIconTheme
|
|
}) {
|
|
assert(brightness != null);
|
|
assert(primaryColor != null);
|
|
assert(primaryColorBrightness != null);
|
|
assert(accentColor != null);
|
|
assert(accentColorBrightness != null);
|
|
assert(canvasColor != null);
|
|
assert(cardColor != null);
|
|
assert(dividerColor != null);
|
|
assert(highlightColor != null);
|
|
assert(splashColor != null);
|
|
assert(unselectedColor != null);
|
|
assert(disabledColor != null);
|
|
assert(buttonColor != null);
|
|
assert(selectionColor != null);
|
|
assert(disabledColor != null);
|
|
assert(indicatorColor != null);
|
|
assert(hintColor != null);
|
|
assert(hintOpacity != null);
|
|
assert(errorColor != null);
|
|
assert(text != null);
|
|
assert(primaryTextTheme != null);
|
|
assert(primaryIconTheme != null);
|
|
}
|
|
|
|
factory ThemeData({
|
|
ThemeBrightness brightness,
|
|
Map<int, Color> primarySwatch,
|
|
Color primaryColor,
|
|
ThemeBrightness primaryColorBrightness,
|
|
Color accentColor,
|
|
ThemeBrightness accentColorBrightness,
|
|
Color canvasColor,
|
|
Color cardColor,
|
|
Color dividerColor,
|
|
Color highlightColor,
|
|
Color splashColor,
|
|
Color unselectedColor,
|
|
Color disabledColor,
|
|
Color buttonColor,
|
|
Color selectionColor,
|
|
Color backgroundColor,
|
|
Color indicatorColor,
|
|
Color hintColor,
|
|
double hintOpacity,
|
|
Color errorColor,
|
|
TextTheme text,
|
|
TextTheme primaryTextTheme,
|
|
IconThemeData primaryIconTheme
|
|
}) {
|
|
brightness ??= ThemeBrightness.light;
|
|
final bool isDark = brightness == ThemeBrightness.dark;
|
|
primarySwatch ??= Colors.blue;
|
|
primaryColor ??= isDark ? Colors.grey[900] : primarySwatch[500];
|
|
primaryColorBrightness ??= ThemeBrightness.dark;
|
|
accentColor ??= primarySwatch[500];
|
|
accentColorBrightness ??= ThemeBrightness.dark;
|
|
canvasColor ??= isDark ? Colors.grey[850] : Colors.grey[50];
|
|
cardColor ??= isDark ? Colors.grey[800] : Colors.white;
|
|
dividerColor ??= isDark ? const Color(0x1FFFFFFF) : const Color(0x1F000000);
|
|
highlightColor ??= isDark ? _kDarkThemeHighlightColor : _kLightThemeHighlightColor;
|
|
splashColor ??= isDark ? _kDarkThemeSplashColor : _kLightThemeSplashColor;
|
|
unselectedColor ??= isDark ? Colors.white70 : Colors.black54;
|
|
disabledColor ??= isDark ? Colors.white30 : Colors.black26;
|
|
buttonColor ??= isDark ? primarySwatch[600] : Colors.grey[300];
|
|
selectionColor ??= isDark ? accentColor : primarySwatch[200];
|
|
backgroundColor ??= isDark ? Colors.grey[700] : primarySwatch[200];
|
|
indicatorColor ??= accentColor == primaryColor ? Colors.white : accentColor;
|
|
hintColor ??= isDark ? const Color(0x42FFFFFF) : const Color(0x4C000000);
|
|
hintOpacity ??= hintColor != null ? hintColor.alpha / 0xFF : isDark ? 0.26 : 0.30;
|
|
errorColor ??= Colors.red[700];
|
|
text ??= isDark ? Typography.white : Typography.black;
|
|
primaryTextTheme ??= primaryColorBrightness == ThemeBrightness.dark ? Typography.white : Typography.black;
|
|
primaryIconTheme ??= primaryColorBrightness == ThemeBrightness.dark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black);
|
|
return new ThemeData.raw(
|
|
brightness: brightness,
|
|
primaryColor: primaryColor,
|
|
primaryColorBrightness: primaryColorBrightness,
|
|
accentColor: accentColor,
|
|
accentColorBrightness: accentColorBrightness,
|
|
canvasColor: canvasColor,
|
|
cardColor: cardColor,
|
|
dividerColor: dividerColor,
|
|
highlightColor: highlightColor,
|
|
splashColor: splashColor,
|
|
unselectedColor: unselectedColor,
|
|
disabledColor: disabledColor,
|
|
buttonColor: buttonColor,
|
|
selectionColor: selectionColor,
|
|
backgroundColor: backgroundColor,
|
|
indicatorColor: indicatorColor,
|
|
hintColor: hintColor,
|
|
hintOpacity: hintOpacity,
|
|
errorColor: errorColor,
|
|
text: text,
|
|
primaryTextTheme: primaryTextTheme,
|
|
primaryIconTheme: primaryIconTheme
|
|
);
|
|
}
|
|
|
|
factory ThemeData.light() => new ThemeData(brightness: ThemeBrightness.light);
|
|
factory ThemeData.dark() => new ThemeData(brightness: ThemeBrightness.dark);
|
|
factory ThemeData.fallback() => new ThemeData.light();
|
|
|
|
/// The brightness of the overall theme of the application. Used by widgets
|
|
/// like buttons to determine what color to pick when not using the primary or
|
|
/// accent color.
|
|
///
|
|
/// When the ThemeBrightness is dark, the canvas, card, and primary colors are
|
|
/// all dark. When the ThemeBrightness is light, the canvas and card colors
|
|
/// are bright, and the primary color's darkness varies as described by
|
|
/// primaryColorBrightness. The primaryColor does not contrast well with the
|
|
/// card and canvas colors when the brightness is dark; when the brightness is
|
|
/// dark, use Colors.white or the accentColor for a contrasting color.
|
|
final ThemeBrightness brightness;
|
|
|
|
/// The background colour for major parts of the app (toolbars, tab bars, etc)
|
|
final Color primaryColor;
|
|
|
|
/// The brightness of the primaryColor. Used to determine the colour of text and
|
|
/// icons placed on top of the primary color (e.g. toolbar text).
|
|
final ThemeBrightness primaryColorBrightness;
|
|
|
|
/// The foreground color for widgets (knobs, text, etc)
|
|
final Color accentColor;
|
|
|
|
/// The brightness of the accentColor. Used to determine the colour of text
|
|
/// and icons placed on top of the accent color (e.g. the icons on a floating
|
|
/// action button).
|
|
final ThemeBrightness accentColorBrightness;
|
|
|
|
final Color canvasColor;
|
|
final Color cardColor;
|
|
final Color dividerColor;
|
|
final Color highlightColor;
|
|
final Color splashColor;
|
|
final Color unselectedColor;
|
|
final Color disabledColor;
|
|
final Color buttonColor;
|
|
final Color selectionColor;
|
|
final Color backgroundColor;
|
|
|
|
/// The color of the selected tab indicator in a tab strip.
|
|
final Color indicatorColor;
|
|
|
|
// Some users want the pre-multiplied color, others just want the opacity.
|
|
final Color hintColor;
|
|
final double hintOpacity;
|
|
|
|
/// The color to use for input validation errors.
|
|
final Color errorColor;
|
|
|
|
/// Text with a color that contrasts with the card and canvas colors.
|
|
final TextTheme text;
|
|
|
|
/// A text theme that contrasts with the primary color.
|
|
final TextTheme primaryTextTheme;
|
|
|
|
final IconThemeData primaryIconTheme;
|
|
|
|
static ThemeData lerp(ThemeData begin, ThemeData end, double t) {
|
|
return new ThemeData.raw(
|
|
brightness: t < 0.5 ? begin.brightness : end.brightness,
|
|
primaryColor: Color.lerp(begin.primaryColor, end.primaryColor, t),
|
|
primaryColorBrightness: t < 0.5 ? begin.primaryColorBrightness : end.primaryColorBrightness,
|
|
canvasColor: Color.lerp(begin.canvasColor, end.canvasColor, t),
|
|
cardColor: Color.lerp(begin.cardColor, end.cardColor, t),
|
|
dividerColor: Color.lerp(begin.dividerColor, end.dividerColor, t),
|
|
highlightColor: Color.lerp(begin.highlightColor, end.highlightColor, t),
|
|
splashColor: Color.lerp(begin.splashColor, end.splashColor, t),
|
|
unselectedColor: Color.lerp(begin.unselectedColor, end.unselectedColor, t),
|
|
disabledColor: Color.lerp(begin.disabledColor, end.disabledColor, t),
|
|
buttonColor: Color.lerp(begin.buttonColor, end.buttonColor, t),
|
|
selectionColor: Color.lerp(begin.selectionColor, end.selectionColor, t),
|
|
backgroundColor: Color.lerp(begin.backgroundColor, end.backgroundColor, t),
|
|
accentColor: Color.lerp(begin.accentColor, end.accentColor, t),
|
|
accentColorBrightness: t < 0.5 ? begin.accentColorBrightness : end.accentColorBrightness,
|
|
indicatorColor: Color.lerp(begin.indicatorColor, end.indicatorColor, t),
|
|
hintColor: Color.lerp(begin.hintColor, end.hintColor, t),
|
|
hintOpacity: lerpDouble(begin.hintOpacity, end.hintOpacity, t),
|
|
errorColor: Color.lerp(begin.errorColor, end.errorColor, t),
|
|
text: TextTheme.lerp(begin.text, end.text, t),
|
|
primaryTextTheme: TextTheme.lerp(begin.primaryTextTheme, end.primaryTextTheme, t),
|
|
primaryIconTheme: IconThemeData.lerp(begin.primaryIconTheme, end.primaryIconTheme, t)
|
|
);
|
|
}
|
|
|
|
bool operator==(Object other) {
|
|
if (other.runtimeType != runtimeType)
|
|
return false;
|
|
ThemeData otherData = other;
|
|
return (otherData.brightness == brightness) &&
|
|
(otherData.primaryColor == primaryColor) &&
|
|
(otherData.primaryColorBrightness == primaryColorBrightness) &&
|
|
(otherData.canvasColor == canvasColor) &&
|
|
(otherData.cardColor == cardColor) &&
|
|
(otherData.dividerColor == dividerColor) &&
|
|
(otherData.highlightColor == highlightColor) &&
|
|
(otherData.splashColor == splashColor) &&
|
|
(otherData.unselectedColor == unselectedColor) &&
|
|
(otherData.disabledColor == disabledColor) &&
|
|
(otherData.buttonColor == buttonColor) &&
|
|
(otherData.selectionColor == selectionColor) &&
|
|
(otherData.backgroundColor == backgroundColor) &&
|
|
(otherData.accentColor == accentColor) &&
|
|
(otherData.accentColorBrightness == accentColorBrightness) &&
|
|
(otherData.indicatorColor == indicatorColor) &&
|
|
(otherData.hintColor == hintColor) &&
|
|
(otherData.hintOpacity == hintOpacity) &&
|
|
(otherData.errorColor == errorColor) &&
|
|
(otherData.text == text) &&
|
|
(otherData.primaryTextTheme == primaryTextTheme) &&
|
|
(otherData.primaryIconTheme == primaryIconTheme);
|
|
}
|
|
int get hashCode {
|
|
return hashValues(
|
|
brightness,
|
|
primaryColor,
|
|
primaryColorBrightness,
|
|
canvasColor,
|
|
cardColor,
|
|
dividerColor,
|
|
highlightColor,
|
|
splashColor,
|
|
unselectedColor,
|
|
disabledColor,
|
|
buttonColor,
|
|
selectionColor,
|
|
backgroundColor,
|
|
accentColor,
|
|
accentColorBrightness,
|
|
hashValues( // Too many values.
|
|
indicatorColor,
|
|
hintColor,
|
|
hintOpacity,
|
|
errorColor,
|
|
text,
|
|
primaryTextTheme,
|
|
primaryIconTheme
|
|
)
|
|
);
|
|
}
|
|
|
|
String toString() => '$runtimeType($brightness $primaryColor etc...)';
|
|
}
|