// Copyright 2018 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 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'colors.dart'; import 'text_theme.dart'; export 'package:flutter/services.dart' show Brightness; // Values derived from https://developer.apple.com/design/resources/. const Color _kDefaultBarLightBackgroundColor = Color(0xCCF8F8F8); const Color _kDefaultBarDarkBackgroundColor = Color(0xB7212121); /// Applies a visual styling theme to descendant Cupertino widgets. /// /// Affects the color and text styles of Cupertino widgets whose styling /// are not overridden when constructing the respective widgets instances. /// /// Descendant widgets can retrieve the current [CupertinoThemeData] by calling /// [CupertinoTheme.of]. An [InheritedWidget] dependency is created when /// an ancestor [CupertinoThemeData] is retrieved via [CupertinoTheme.of]. /// /// See also: /// /// * [CupertinoThemeData], specifies the theme's visual styling. /// * [CupertinoApp], which will automatically add a [CupertinoTheme]. /// * [Theme], a Material theme which will automatically add a [CupertinoTheme] /// with a [CupertinoThemeData] derived from the Material [ThemeData]. class CupertinoTheme extends InheritedWidget { /// Creates a [CupertinoTheme] to change descendant Cupertino widgets' styling. /// /// The [data] and [child] parameters must not be null. const CupertinoTheme({ Key key, @required this.data, @required Widget child, }) : assert(child != null), assert(data != null), super(key: key, child: child); /// The [CupertinoThemeData] styling for this theme. final CupertinoThemeData data; @override bool updateShouldNotify(CupertinoTheme oldWidget) => data != oldWidget.data; /// Retrieve the [CupertinoThemeData] from an ancestor [CupertinoTheme] widget. /// /// Returns a default [CupertinoThemeData] if no [CupertinoTheme] widgets /// exist in the ancestry tree. static CupertinoThemeData of(BuildContext context) { final CupertinoTheme theme = context.inheritFromWidgetOfExactType(CupertinoTheme); return theme?.data ?? const CupertinoThemeData(); } } /// Styling specifications for a [CupertinoTheme]. /// /// All constructor parameters can be null, in which case a /// [CupertinoColors.activeBlue] based default iOS theme styling is used. /// /// Parameters can also be partially specified, in which case some parameters /// will cascade down to other dependent parameters to create a cohesive /// visual effect. For instance, if a [primaryColor] is specified, it would /// cascade down to affect some fonts in [textTheme] if [textTheme] is not /// specified. /// /// See also: /// /// * [CupertinoTheme], in which this [CupertinoThemeData] is inserted. /// * [ThemeData], a Material equivalent that also configures Cupertino /// styling via a [CupertinoThemeData] subclass [MaterialBasedCupertinoThemeData]. @immutable class CupertinoThemeData extends Diagnosticable { /// Create a [CupertinoTheme] styling specification. /// /// Unspecified parameters default to a reasonable iOS default style. const CupertinoThemeData({ Brightness brightness, Color primaryColor, Color primaryContrastingColor, CupertinoTextThemeData textTheme, Color barBackgroundColor, Color scaffoldBackgroundColor, }) : this.raw( brightness, primaryColor, primaryContrastingColor, textTheme, barBackgroundColor, scaffoldBackgroundColor, ); /// Same as the default constructor but with positional arguments to avoid /// forgetting any and to specify all arguments. /// /// Used by subclasses to get the superclass's defaulting behaviors. @protected const CupertinoThemeData.raw( this._brightness, this._primaryColor, this._primaryContrastingColor, this._textTheme, this._barBackgroundColor, this._scaffoldBackgroundColor, ); bool get _isLight => brightness == Brightness.light; /// The general brightness theme of the [CupertinoThemeData]. /// /// Affects all other theme properties when unspecified. Defaults to /// [Brightness.light]. /// /// If coming from a Material [Theme] and unspecified, [brightness] will be /// derived from the Material [ThemeData]'s `brightness`. Brightness get brightness => _brightness ?? Brightness.light; final Brightness _brightness; /// A color used on interactive elements of the theme. /// /// This color is generally used on text and icons in buttons and tappable /// elements. Defaults to [CupertinoColors.activeBlue] or /// [CupertinoColors.activeOrange] when [brightness] is light or dark. /// /// If coming from a Material [Theme] and unspecified, [primaryColor] will be /// derived from the Material [ThemeData]'s `colorScheme.primary`. However, in /// iOS styling, the [primaryColor] is more sparsely used than in Material /// Design where the [primaryColor] can appear on non-interactive surfaces like /// the [AppBar] background, [TextField] borders etc. Color get primaryColor { return _primaryColor ?? (_isLight ? CupertinoColors.activeBlue : CupertinoColors.activeOrange); } final Color _primaryColor; /// A color used for content that must contrast against a [primaryColor] background. /// /// For example, this color is used for a [CupertinoButton]'s text and icons /// when the button's background is [primaryColor]. /// /// If coming from a Material [Theme] and unspecified, [primaryContrastingColor] /// will be derived from the Material [ThemeData]'s `colorScheme.onPrimary`. Color get primaryContrastingColor { return _primaryContrastingColor ?? (_isLight ? CupertinoColors.white : CupertinoColors.black); } final Color _primaryContrastingColor; /// Text styles used by Cupertino widgets. /// /// Derived from [brightness] and [primaryColor] if unspecified, including /// [brightness] and [primaryColor] of a Material [ThemeData] if coming /// from a Material [Theme]. CupertinoTextThemeData get textTheme { return _textTheme ?? CupertinoTextThemeData( brightness: brightness, primaryColor: primaryColor, ); } final CupertinoTextThemeData _textTheme; /// Background color of the top nav bar and bottom tab bar. /// /// Defaults to a light gray or a dark gray translucent color depending /// on the [brightness]. Color get barBackgroundColor { return _barBackgroundColor ?? (_isLight ? _kDefaultBarLightBackgroundColor : _kDefaultBarDarkBackgroundColor); } final Color _barBackgroundColor; /// Background color of the scaffold. /// /// Defaults to white or black depending on the [brightness]. Color get scaffoldBackgroundColor { return _scaffoldBackgroundColor ?? (_isLight ? CupertinoColors.white : CupertinoColors.black); } final Color _scaffoldBackgroundColor; /// Return an instance of the [CupertinoThemeData] whose property getters /// only return the construction time specifications with no derived values. /// /// Used in Material themes to let unspecified properties fallback to Material /// theme properties instead of iOS defaults. CupertinoThemeData noDefault() { return _NoDefaultCupertinoThemeData( _brightness, _primaryColor, _primaryContrastingColor, _textTheme, _barBackgroundColor, _scaffoldBackgroundColor, ); } /// Create a copy of [CupertinoThemeData] with specified attributes overridden. /// /// Only the current instance's specified attributes are copied instead of /// derived values. For instance, if the current [primaryColor] is implied /// to be [CupertinoColors.activeOrange] due to the current [brightness], /// copying with a different [brightness] will also change the copy's /// implied [primaryColor]. CupertinoThemeData copyWith({ Brightness brightness, Color primaryColor, Color primaryContrastingColor, CupertinoTextThemeData textTheme, Color barBackgroundColor, Color scaffoldBackgroundColor, }) { return CupertinoThemeData( brightness: brightness ?? _brightness, primaryColor: primaryColor ?? _primaryColor, primaryContrastingColor: primaryContrastingColor ?? _primaryContrastingColor, textTheme: textTheme ?? _textTheme, barBackgroundColor: barBackgroundColor ?? _barBackgroundColor, scaffoldBackgroundColor: scaffoldBackgroundColor ?? _scaffoldBackgroundColor, ); } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); const CupertinoThemeData defaultData = CupertinoThemeData(); properties.add(EnumProperty<Brightness>('brightness', brightness, defaultValue: defaultData.brightness)); properties.add(DiagnosticsProperty<Color>('primaryColor', primaryColor, defaultValue: defaultData.primaryColor)); properties.add(DiagnosticsProperty<Color>('primaryContrastingColor', primaryContrastingColor, defaultValue: defaultData.primaryContrastingColor)); properties.add(DiagnosticsProperty<CupertinoTextThemeData>('textTheme', textTheme, defaultValue: defaultData.textTheme)); properties.add(DiagnosticsProperty<Color>('barBackgroundColor', barBackgroundColor, defaultValue: defaultData.barBackgroundColor)); properties.add(DiagnosticsProperty<Color>('scaffoldBackgroundColor', scaffoldBackgroundColor, defaultValue: defaultData.scaffoldBackgroundColor)); } } class _NoDefaultCupertinoThemeData extends CupertinoThemeData { const _NoDefaultCupertinoThemeData( this.brightness, this.primaryColor, this.primaryContrastingColor, this.textTheme, this.barBackgroundColor, this.scaffoldBackgroundColor, ) : super.raw( brightness, primaryColor, primaryContrastingColor, textTheme, barBackgroundColor, scaffoldBackgroundColor, ); @override final Brightness brightness; @override final Color primaryColor; @override final Color primaryContrastingColor; @override final CupertinoTextThemeData textTheme; @override final Color barBackgroundColor; @override final Color scaffoldBackgroundColor; }