// 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; 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({ ThemeBrightness brightness: ThemeBrightness.light, Map<int, Color> primarySwatch, Color accentColor, this.accentColorBrightness: ThemeBrightness.dark, TextTheme text }): this.brightness = brightness, this.primarySwatch = primarySwatch, primaryColorBrightness = primarySwatch == null ? brightness : ThemeBrightness.dark, canvasColor = brightness == ThemeBrightness.dark ? Colors.grey[850] : Colors.grey[50], cardColor = brightness == ThemeBrightness.dark ? Colors.grey[800] : Colors.white, dividerColor = brightness == ThemeBrightness.dark ? const Color(0x1FFFFFFF) : const Color(0x1F000000), // Some users want the pre-multiplied color, others just want the opacity. hintColor = brightness == ThemeBrightness.dark ? const Color(0x42FFFFFF) : const Color(0x4C000000), hintOpacity = brightness == ThemeBrightness.dark ? 0.26 : 0.30, highlightColor = brightness == ThemeBrightness.dark ? _kDarkThemeHighlightColor : _kLightThemeHighlightColor, splashColor = brightness == ThemeBrightness.dark ? _kDarkThemeSplashColor : _kLightThemeSplashColor, text = brightness == ThemeBrightness.dark ? Typography.white : Typography.black { assert(brightness != null); if (primarySwatch == null) { if (brightness == ThemeBrightness.dark) { _primaryColor = Colors.grey[900]; } else { _primaryColor = Colors.grey[100]; } } else { _primaryColor = primarySwatch[500]; } if (accentColor == null) { _accentColor = primarySwatch == null ? Colors.blue[500] : primarySwatch[500]; } else { _accentColor = accentColor; } } factory ThemeData.light() => new ThemeData(primarySwatch: Colors.blue, 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 dask; when the birghtness is /// dark, use Colors.white or the accentColor for a contrasting color. final ThemeBrightness brightness; final Map<int, Color> primarySwatch; final Color canvasColor; final Color cardColor; final Color dividerColor; final Color hintColor; final Color highlightColor; final Color splashColor; final double hintOpacity; /// Text with a color that contrasts with the card and canvas colors. final TextTheme text; /// The background colour for major parts of the app (toolbars, tab bars, etc) Color get primaryColor => _primaryColor; 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; /// A text theme that contrasts with the primary color. TextTheme get primaryTextTheme { if (primaryColorBrightness == ThemeBrightness.dark) return Typography.white; return Typography.black; } IconThemeData get primaryIconTheme { if (primaryColorBrightness == ThemeBrightness.dark) return const IconThemeData(color: IconThemeColor.white); return const IconThemeData(color: IconThemeColor.black); } Color get unselectedColor { if (brightness == ThemeBrightness.dark) return Colors.white70; return Colors.black54; } Color get disabledColor { if (brightness == ThemeBrightness.dark) return Colors.white30; return Colors.black26; } /// The foreground color for widgets (knobs, text, etc) Color get accentColor => _accentColor; 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; bool operator==(Object other) { if (other.runtimeType != runtimeType) return false; ThemeData otherData = other; return (otherData.brightness == brightness) && (otherData.primarySwatch == primarySwatch) && (otherData.canvasColor == canvasColor) && (otherData.cardColor == cardColor) && (otherData.dividerColor == dividerColor) && (otherData.hintColor == hintColor) && (otherData.highlightColor == highlightColor) && (otherData.hintOpacity == hintOpacity) && (otherData.text == text) && (otherData.primaryColorBrightness == primaryColorBrightness) && (otherData.accentColorBrightness == accentColorBrightness); } int get hashCode { int value = 373; value = 37 * value + brightness.hashCode; value = 37 * value + primarySwatch.hashCode; value = 37 * value + canvasColor.hashCode; value = 37 * value + cardColor.hashCode; value = 37 * value + dividerColor.hashCode; value = 37 * value + hintColor.hashCode; value = 37 * value + highlightColor.hashCode; value = 37 * value + hintOpacity.hashCode; value = 37 * value + text.hashCode; value = 37 * value + primaryColorBrightness.hashCode; value = 37 * value + accentColorBrightness.hashCode; return value; } String toString() => '$primaryColor $brightness etc...'; }