blob: 06acc54979e5fd7b30610207ed606535fdae7042 [file] [log] [blame]
// 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].
///
/// The [CupertinoTheme] widget implies an [IconTheme] widget, whose
/// [IconTheme.data] has the same color as [CupertinoThemeData.primaryColor]
///
/// 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 StatelessWidget {
/// 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 this.child,
}) : assert(child != null),
assert(data != null),
super(key: key);
/// The [CupertinoThemeData] styling for this theme.
final CupertinoThemeData 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 _InheritedCupertinoTheme inheritedTheme = context.inheritFromWidgetOfExactType(_InheritedCupertinoTheme);
return inheritedTheme?.theme?.data ?? const CupertinoThemeData();
}
/// The widget below this widget in the tree.
///
/// {@macro flutter.widgets.child}
final Widget child;
@override
Widget build(BuildContext context) {
return _InheritedCupertinoTheme(
theme: this,
child: IconTheme(
data: IconThemeData(color: data.primaryColor),
child: child,
)
);
}
}
class _InheritedCupertinoTheme extends InheritedWidget {
const _InheritedCupertinoTheme({
Key key,
@required this.theme,
@required Widget child,
}) : assert(theme != null),
super(key: key, child: child);
final CupertinoTheme theme;
@override
bool updateShouldNotify(_InheritedCupertinoTheme old) => theme.data != old.theme.data;
}
/// 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;
}