text_theme.dart 11.9 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
xster's avatar
xster committed
2 3 4 5 6 7 8 9 10
// 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' show Brightness;
import 'package:flutter/widgets.dart';

import 'colors.dart';

11 12 13
// Please update _TextThemeDefaultsBuilder accordingly after changing the default
// color here, as their implementation depends on the default value of the color
// field.
14
//
xster's avatar
xster committed
15
// Values derived from https://developer.apple.com/design/resources/.
16
const TextStyle _kDefaultTextStyle = TextStyle(
xster's avatar
xster committed
17 18 19 20
  inherit: false,
  fontFamily: '.SF Pro Text',
  fontSize: 17.0,
  letterSpacing: -0.41,
21
  color: CupertinoColors.label,
xster's avatar
xster committed
22 23 24
  decoration: TextDecoration.none,
);

25 26 27
// Please update _TextThemeDefaultsBuilder accordingly after changing the default
// color here, as their implementation depends on the default value of the color
// field.
28
//
xster's avatar
xster committed
29 30 31 32 33 34 35 36 37 38
// Values derived from https://developer.apple.com/design/resources/.
const TextStyle _kDefaultActionTextStyle = TextStyle(
  inherit: false,
  fontFamily: '.SF Pro Text',
  fontSize: 17.0,
  letterSpacing: -0.41,
  color: CupertinoColors.activeBlue,
  decoration: TextDecoration.none,
);

39 40 41
// Please update _TextThemeDefaultsBuilder accordingly after changing the default
// color here, as their implementation depends on the default value of the color
// field.
42
//
xster's avatar
xster committed
43 44 45 46 47
// Values derived from https://developer.apple.com/design/resources/.
const TextStyle _kDefaultTabLabelTextStyle = TextStyle(
  inherit: false,
  fontFamily: '.SF Pro Text',
  fontSize: 10.0,
48
  fontWeight: FontWeight.w500,
xster's avatar
xster committed
49 50 51 52
  letterSpacing: -0.24,
  color: CupertinoColors.inactiveGray,
);

53
const TextStyle _kDefaultMiddleTitleTextStyle = TextStyle(
xster's avatar
xster committed
54 55 56 57 58
  inherit: false,
  fontFamily: '.SF Pro Text',
  fontSize: 17.0,
  fontWeight: FontWeight.w600,
  letterSpacing: -0.41,
59
  color: CupertinoColors.label,
xster's avatar
xster committed
60 61
);

62
const TextStyle _kDefaultLargeTitleTextStyle = TextStyle(
xster's avatar
xster committed
63 64 65 66 67
  inherit: false,
  fontFamily: '.SF Pro Display',
  fontSize: 34.0,
  fontWeight: FontWeight.w700,
  letterSpacing: 0.41,
68
  color: CupertinoColors.label,
xster's avatar
xster committed
69 70
);

71 72 73
// Please update _TextThemeDefaultsBuilder accordingly after changing the default
// color here, as their implementation depends on the default value of the color
// field.
74 75 76
//
// Inspected on iOS 13 simulator with "Debug View Hierarchy".
// Value extracted from off-center labels. Centered labels have a font size of 25pt.
77 78 79 80 81
//
// The letterSpacing sourced from iOS 14 simulator screenshots for comparison.
// See also:
//
// * https://github.com/flutter/flutter/pull/65501#discussion_r486557093
82
const TextStyle _kDefaultPickerTextStyle = TextStyle(
83 84
  inherit: false,
  fontFamily: '.SF Pro Display',
85
  fontSize: 21.0,
86
  fontWeight: FontWeight.w400,
87
  letterSpacing: -0.6,
88
  color: CupertinoColors.label,
89 90
);

91 92 93
// Please update _TextThemeDefaultsBuilder accordingly after changing the default
// color here, as their implementation depends on the default value of the color
// field.
94
//
95
// Inspected on iOS 13 simulator with "Debug View Hierarchy".
96 97
// Value extracted from off-center labels. Centered labels have a font size of 25pt.
const TextStyle _kDefaultDateTimePickerTextStyle = TextStyle(
98 99 100
  inherit: false,
  fontFamily: '.SF Pro Display',
  fontSize: 21,
101
  fontWeight: FontWeight.normal,
102
  color: CupertinoColors.label,
103 104
);

105
TextStyle? _resolveTextStyle(TextStyle? style, BuildContext context) {
106 107
  // This does not resolve the shadow color, foreground, background, etc.
  return style?.copyWith(
108 109 110
    color: CupertinoDynamicColor.maybeResolve(style.color, context),
    backgroundColor: CupertinoDynamicColor.maybeResolve(style.backgroundColor, context),
    decorationColor: CupertinoDynamicColor.maybeResolve(style.decorationColor, context),
111 112
  );
}
113

xster's avatar
xster committed
114 115
/// Cupertino typography theme in a [CupertinoThemeData].
@immutable
116
class CupertinoTextThemeData with Diagnosticable {
xster's avatar
xster committed
117 118
  /// Create a [CupertinoTextThemeData].
  ///
119 120 121 122
  /// The [primaryColor] is used to derive TextStyle defaults of other attributes
  /// such as [navActionTextStyle] and [actionTextStyle], it must not be null when
  /// either [navActionTextStyle] or [actionTextStyle] is null. Defaults to
  /// [CupertinoColors.systemBlue].
xster's avatar
xster committed
123 124 125 126
  ///
  /// Other [TextStyle] parameters default to default iOS text styles when
  /// unspecified.
  const CupertinoTextThemeData({
127
    Color primaryColor = CupertinoColors.systemBlue,
128 129 130 131 132 133 134 135
    TextStyle? textStyle,
    TextStyle? actionTextStyle,
    TextStyle? tabLabelTextStyle,
    TextStyle? navTitleTextStyle,
    TextStyle? navLargeTitleTextStyle,
    TextStyle? navActionTextStyle,
    TextStyle? pickerTextStyle,
    TextStyle? dateTimePickerTextStyle,
136
  }) : this._raw(
137
         const _TextThemeDefaultsBuilder(CupertinoColors.label, CupertinoColors.inactiveGray),
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
         primaryColor,
         textStyle,
         actionTextStyle,
         tabLabelTextStyle,
         navTitleTextStyle,
         navLargeTitleTextStyle,
         navActionTextStyle,
         pickerTextStyle,
         dateTimePickerTextStyle,
       );

  const CupertinoTextThemeData._raw(
    this._defaults,
    this._primaryColor,
    this._textStyle,
    this._actionTextStyle,
    this._tabLabelTextStyle,
    this._navTitleTextStyle,
    this._navLargeTitleTextStyle,
    this._navActionTextStyle,
    this._pickerTextStyle,
    this._dateTimePickerTextStyle,
  ) : assert((_navActionTextStyle != null && _actionTextStyle != null) || _primaryColor != null);
xster's avatar
xster committed
161

162
  final _TextThemeDefaultsBuilder _defaults;
163
  final Color? _primaryColor;
xster's avatar
xster committed
164

165
  final TextStyle? _textStyle;
166 167
  /// The [TextStyle] of general text content for Cupertino widgets.
  TextStyle get textStyle => _textStyle ?? _defaults.textStyle;
xster's avatar
xster committed
168

169
  final TextStyle? _actionTextStyle;
170
  /// The [TextStyle] of interactive text content such as text in a button without background.
xster's avatar
xster committed
171
  TextStyle get actionTextStyle {
172
    return _actionTextStyle ?? _defaults.actionTextStyle(primaryColor: _primaryColor);
xster's avatar
xster committed
173 174
  }

175
  final TextStyle? _tabLabelTextStyle;
176 177
  /// The [TextStyle] of unselected tabs.
  TextStyle get tabLabelTextStyle => _tabLabelTextStyle ?? _defaults.tabLabelTextStyle;
xster's avatar
xster committed
178

179
  final TextStyle? _navTitleTextStyle;
180 181
  /// The [TextStyle] of titles in standard navigation bars.
  TextStyle get navTitleTextStyle => _navTitleTextStyle ?? _defaults.navTitleTextStyle;
xster's avatar
xster committed
182

183
  final TextStyle? _navLargeTitleTextStyle;
184 185
  /// The [TextStyle] of large titles in sliver navigation bars.
  TextStyle get navLargeTitleTextStyle => _navLargeTitleTextStyle ?? _defaults.navLargeTitleTextStyle;
xster's avatar
xster committed
186

187
  final TextStyle? _navActionTextStyle;
188
  /// The [TextStyle] of interactive text content in navigation bars.
xster's avatar
xster committed
189
  TextStyle get navActionTextStyle {
190
    return _navActionTextStyle ?? _defaults.navActionTextStyle(primaryColor: _primaryColor);
xster's avatar
xster committed
191 192
  }

193
  final TextStyle? _pickerTextStyle;
194 195
  /// The [TextStyle] of pickers.
  TextStyle get pickerTextStyle => _pickerTextStyle ?? _defaults.pickerTextStyle;
196

197
  final TextStyle? _dateTimePickerTextStyle;
198 199
  /// The [TextStyle] of date time pickers.
  TextStyle get dateTimePickerTextStyle => _dateTimePickerTextStyle ?? _defaults.dateTimePickerTextStyle;
200

201 202
  /// Returns a copy of the current [CupertinoTextThemeData] with all the colors
  /// resolved against the given [BuildContext].
203
  ///
204 205 206 207 208 209
  /// If any of the [InheritedWidget]s required to resolve this
  /// [CupertinoTextThemeData] is not found in [context], any unresolved
  /// [CupertinoDynamicColor]s will use the default trait value
  /// ([Brightness.light] platform brightness, normal contrast,
  /// [CupertinoUserInterfaceLevelData.base] elevation level).
  CupertinoTextThemeData resolveFrom(BuildContext context) {
210
    return CupertinoTextThemeData._raw(
211 212 213 214 215 216 217 218 219 220
      _defaults.resolveFrom(context),
      CupertinoDynamicColor.maybeResolve(_primaryColor, context),
      _resolveTextStyle(_textStyle, context),
      _resolveTextStyle(_actionTextStyle, context),
      _resolveTextStyle(_tabLabelTextStyle, context),
      _resolveTextStyle(_navTitleTextStyle, context),
      _resolveTextStyle(_navLargeTitleTextStyle, context),
      _resolveTextStyle(_navActionTextStyle, context),
      _resolveTextStyle(_pickerTextStyle, context),
      _resolveTextStyle(_dateTimePickerTextStyle, context),
221 222 223
    );
  }

xster's avatar
xster committed
224 225 226
  /// Returns a copy of the current [CupertinoTextThemeData] instance with
  /// specified overrides.
  CupertinoTextThemeData copyWith({
227 228 229 230 231 232 233 234 235
    Color? primaryColor,
    TextStyle? textStyle,
    TextStyle? actionTextStyle,
    TextStyle? tabLabelTextStyle,
    TextStyle? navTitleTextStyle,
    TextStyle? navLargeTitleTextStyle,
    TextStyle? navActionTextStyle,
    TextStyle? pickerTextStyle,
    TextStyle? dateTimePickerTextStyle,
xster's avatar
xster committed
236
  }) {
237 238 239 240 241 242 243 244 245 246 247
    return CupertinoTextThemeData._raw(
      _defaults,
      primaryColor ?? _primaryColor,
      textStyle ?? _textStyle,
      actionTextStyle ?? _actionTextStyle,
      tabLabelTextStyle ?? _tabLabelTextStyle,
      navTitleTextStyle ?? _navTitleTextStyle,
      navLargeTitleTextStyle ?? _navLargeTitleTextStyle,
      navActionTextStyle ?? _navActionTextStyle,
      pickerTextStyle ?? _pickerTextStyle,
      dateTimePickerTextStyle ?? _dateTimePickerTextStyle,
xster's avatar
xster committed
248 249
    );
  }
250 251 252 253 254 255 256 257 258 259 260 261 262 263

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    const CupertinoTextThemeData defaultData = CupertinoTextThemeData();
    properties.add(DiagnosticsProperty<TextStyle>('textStyle', textStyle, defaultValue: defaultData.textStyle));
    properties.add(DiagnosticsProperty<TextStyle>('actionTextStyle', actionTextStyle, defaultValue: defaultData.actionTextStyle));
    properties.add(DiagnosticsProperty<TextStyle>('tabLabelTextStyle', tabLabelTextStyle, defaultValue: defaultData.tabLabelTextStyle));
    properties.add(DiagnosticsProperty<TextStyle>('navTitleTextStyle', navTitleTextStyle, defaultValue: defaultData.navTitleTextStyle));
    properties.add(DiagnosticsProperty<TextStyle>('navLargeTitleTextStyle', navLargeTitleTextStyle, defaultValue: defaultData.navLargeTitleTextStyle));
    properties.add(DiagnosticsProperty<TextStyle>('navActionTextStyle', navActionTextStyle, defaultValue: defaultData.navActionTextStyle));
    properties.add(DiagnosticsProperty<TextStyle>('pickerTextStyle', pickerTextStyle, defaultValue: defaultData.pickerTextStyle));
    properties.add(DiagnosticsProperty<TextStyle>('dateTimePickerTextStyle', dateTimePickerTextStyle, defaultValue: defaultData.dateTimePickerTextStyle));
  }
xster's avatar
xster committed
264
}
265

266

267
@immutable
268 269 270 271 272 273
class _TextThemeDefaultsBuilder {
  const _TextThemeDefaultsBuilder(
    this.labelColor,
    this.inactiveGrayColor,
  ) : assert(labelColor != null),
      assert(inactiveGrayColor != null);
274 275 276 277 278

  final Color labelColor;
  final Color inactiveGrayColor;

  static TextStyle _applyLabelColor(TextStyle original, Color color) {
279
    return original.color == color
280
      ?  original
281
      :  original.copyWith(color: color);
282 283 284 285 286 287 288 289 290
  }

  TextStyle get textStyle => _applyLabelColor(_kDefaultTextStyle, labelColor);
  TextStyle get tabLabelTextStyle => _applyLabelColor(_kDefaultTabLabelTextStyle, inactiveGrayColor);
  TextStyle get navTitleTextStyle => _applyLabelColor(_kDefaultMiddleTitleTextStyle, labelColor);
  TextStyle get navLargeTitleTextStyle => _applyLabelColor(_kDefaultLargeTitleTextStyle, labelColor);
  TextStyle get pickerTextStyle => _applyLabelColor(_kDefaultPickerTextStyle, labelColor);
  TextStyle get dateTimePickerTextStyle => _applyLabelColor(_kDefaultDateTimePickerTextStyle, labelColor);

291 292
  TextStyle actionTextStyle({ Color? primaryColor }) => _kDefaultActionTextStyle.copyWith(color: primaryColor);
  TextStyle navActionTextStyle({ Color? primaryColor }) => actionTextStyle(primaryColor: primaryColor);
293

294 295 296
  _TextThemeDefaultsBuilder resolveFrom(BuildContext context) {
    final Color resolvedLabelColor = CupertinoDynamicColor.resolve(labelColor, context);
    final Color resolvedInactiveGray = CupertinoDynamicColor.resolve(inactiveGrayColor, context);
297 298
    return resolvedLabelColor == labelColor && resolvedInactiveGray == CupertinoColors.inactiveGray
      ? this
299
      : _TextThemeDefaultsBuilder(resolvedLabelColor, resolvedInactiveGray);
300 301
  }
}