1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'package:flutter/material.dart';
6///
7/// @docImport 'app.dart';
8/// @docImport 'button.dart';
9/// @docImport 'switch.dart';
10library;
11
12import 'package:flutter/foundation.dart';
13import 'package:flutter/widgets.dart';
14
15import 'colors.dart';
16import 'icon_theme_data.dart';
17import 'text_theme.dart';
18
19export 'package:flutter/foundation.dart' show Brightness;
20
21// Values derived from https://developer.apple.com/design/resources/.
22const _CupertinoThemeDefaults _kDefaultTheme = _CupertinoThemeDefaults(
23 null,
24 CupertinoColors.systemBlue,
25 CupertinoColors.white,
26 CupertinoDynamicColor.withBrightness(
27 color: Color(0xF0F9F9F9),
28 darkColor: Color(0xF01D1D1D),
29 // Values extracted from navigation bar. For toolbar or tabbar the dark color is 0xF0161616.
30 ),
31 CupertinoColors.systemBackground,
32 CupertinoColors.systemBlue,
33 false,
34 _CupertinoTextThemeDefaults(CupertinoColors.label, CupertinoColors.inactiveGray),
35);
36
37/// Applies a visual styling theme to descendant Cupertino widgets.
38///
39/// Affects the color and text styles of Cupertino widgets whose styling
40/// are not overridden when constructing the respective widgets instances.
41///
42/// Descendant widgets can retrieve the current [CupertinoThemeData] by calling
43/// [CupertinoTheme.of]. An [InheritedWidget] dependency is created when
44/// an ancestor [CupertinoThemeData] is retrieved via [CupertinoTheme.of].
45///
46/// The [CupertinoTheme] widget implies an [IconTheme] widget, whose
47/// [IconTheme.data] has the same color as [CupertinoThemeData.primaryColor]
48///
49/// See also:
50///
51/// * [CupertinoThemeData], specifies the theme's visual styling.
52/// * [CupertinoApp], which will automatically add a [CupertinoTheme] based on the
53/// value of [CupertinoApp.theme].
54/// * [Theme], a Material theme which will automatically add a [CupertinoTheme]
55/// with a [CupertinoThemeData] derived from the Material [ThemeData].
56class CupertinoTheme extends StatelessWidget {
57 /// Creates a [CupertinoTheme] to change descendant Cupertino widgets' styling.
58 const CupertinoTheme({super.key, required this.data, required this.child});
59
60 /// The [CupertinoThemeData] styling for this theme.
61 final CupertinoThemeData data;
62
63 /// Retrieves the [CupertinoThemeData] from the closest ancestor [CupertinoTheme]
64 /// widget, or a default [CupertinoThemeData] if no [CupertinoTheme] ancestor
65 /// exists.
66 ///
67 /// Resolves all the colors defined in that [CupertinoThemeData] against the
68 /// given [BuildContext] on a best-effort basis.
69 static CupertinoThemeData of(BuildContext context) {
70 final InheritedCupertinoTheme? inheritedTheme = context
71 .dependOnInheritedWidgetOfExactType<InheritedCupertinoTheme>();
72 return (inheritedTheme?.theme.data ?? const CupertinoThemeData()).resolveFrom(context);
73 }
74
75 /// Retrieves the [Brightness] to use for descendant Cupertino widgets, based
76 /// on the value of [CupertinoThemeData.brightness] in the given [context].
77 ///
78 /// If no [CupertinoTheme] can be found in the given [context], or its `brightness`
79 /// is null, it will fall back to [MediaQueryData.platformBrightness].
80 ///
81 /// Throws an exception if no valid [CupertinoTheme] or [MediaQuery] widgets
82 /// exist in the ancestry tree.
83 ///
84 /// See also:
85 ///
86 /// * [maybeBrightnessOf], which returns null if no valid [CupertinoTheme] or
87 /// [MediaQuery] exists, instead of throwing.
88 /// * [CupertinoThemeData.brightness], the property takes precedence over
89 /// [MediaQueryData.platformBrightness] for descendant Cupertino widgets.
90 static Brightness brightnessOf(BuildContext context) {
91 final InheritedCupertinoTheme? inheritedTheme = context
92 .dependOnInheritedWidgetOfExactType<InheritedCupertinoTheme>();
93 return inheritedTheme?.theme.data.brightness ?? MediaQuery.platformBrightnessOf(context);
94 }
95
96 /// Retrieves the [Brightness] to use for descendant Cupertino widgets, based
97 /// on the value of [CupertinoThemeData.brightness] in the given [context].
98 ///
99 /// If no [CupertinoTheme] can be found in the given [context], it will fall
100 /// back to [MediaQueryData.platformBrightness].
101 ///
102 /// Returns null if no valid [CupertinoTheme] or [MediaQuery] widgets exist in
103 /// the ancestry tree.
104 ///
105 /// See also:
106 ///
107 /// * [CupertinoThemeData.brightness], the property takes precedence over
108 /// [MediaQueryData.platformBrightness] for descendant Cupertino widgets.
109 /// * [brightnessOf], which throws if no valid [CupertinoTheme] or
110 /// [MediaQuery] exists, instead of returning null.
111 static Brightness? maybeBrightnessOf(BuildContext context) {
112 final InheritedCupertinoTheme? inheritedTheme = context
113 .dependOnInheritedWidgetOfExactType<InheritedCupertinoTheme>();
114 return inheritedTheme?.theme.data.brightness ?? MediaQuery.maybePlatformBrightnessOf(context);
115 }
116
117 /// The widget below this widget in the tree.
118 ///
119 /// {@macro flutter.widgets.ProxyWidget.child}
120 final Widget child;
121
122 @override
123 Widget build(BuildContext context) {
124 return InheritedCupertinoTheme(
125 theme: this,
126 child: IconTheme(
127 data: CupertinoIconThemeData(color: data.primaryColor),
128 child: child,
129 ),
130 );
131 }
132
133 @override
134 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
135 super.debugFillProperties(properties);
136 data.debugFillProperties(properties);
137 }
138}
139
140/// Provides a [CupertinoTheme] to all descendants.
141class InheritedCupertinoTheme extends InheritedTheme {
142 /// Creates an [InheritedTheme] that provides a [CupertinoTheme] to all
143 /// descendants.
144 const InheritedCupertinoTheme({super.key, required this.theme, required super.child});
145
146 /// The [CupertinoTheme] that is provided to widgets lower in the tree.
147 final CupertinoTheme theme;
148
149 @override
150 Widget wrap(BuildContext context, Widget child) {
151 return CupertinoTheme(data: theme.data, child: child);
152 }
153
154 @override
155 bool updateShouldNotify(InheritedCupertinoTheme oldWidget) => theme.data != oldWidget.theme.data;
156}
157
158/// Styling specifications for a [CupertinoTheme].
159///
160/// All constructor parameters can be null, in which case a
161/// [CupertinoColors.activeBlue] based default iOS theme styling is used.
162///
163/// Parameters can also be partially specified, in which case some parameters
164/// will cascade down to other dependent parameters to create a cohesive
165/// visual effect. For instance, if a [primaryColor] is specified, it would
166/// cascade down to affect some fonts in [textTheme] if [textTheme] is not
167/// specified.
168///
169/// See also:
170///
171/// * [CupertinoTheme], in which this [CupertinoThemeData] is inserted.
172/// * [ThemeData], a Material equivalent that also configures Cupertino
173/// styling via a [CupertinoThemeData] subclass [MaterialBasedCupertinoThemeData].
174@immutable
175class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable {
176 /// Creates a [CupertinoTheme] styling specification.
177 ///
178 /// Unspecified parameters default to a reasonable iOS default style.
179 const CupertinoThemeData({
180 Brightness? brightness,
181 Color? primaryColor,
182 Color? primaryContrastingColor,
183 CupertinoTextThemeData? textTheme,
184 Color? barBackgroundColor,
185 Color? scaffoldBackgroundColor,
186 Color? selectionHandleColor,
187 bool? applyThemeToAll,
188 }) : this.raw(
189 brightness,
190 primaryColor,
191 primaryContrastingColor,
192 textTheme,
193 barBackgroundColor,
194 scaffoldBackgroundColor,
195 selectionHandleColor,
196 applyThemeToAll,
197 );
198
199 /// Same as the default constructor but with positional arguments to avoid
200 /// forgetting any and to specify all arguments.
201 ///
202 /// Used by subclasses to get the superclass's defaulting behaviors.
203 @protected
204 const CupertinoThemeData.raw(
205 Brightness? brightness,
206 Color? primaryColor,
207 Color? primaryContrastingColor,
208 CupertinoTextThemeData? textTheme,
209 Color? barBackgroundColor,
210 Color? scaffoldBackgroundColor,
211 Color? selectionHandleColor,
212 bool? applyThemeToAll,
213 ) : this._rawWithDefaults(
214 brightness,
215 primaryColor,
216 primaryContrastingColor,
217 textTheme,
218 barBackgroundColor,
219 scaffoldBackgroundColor,
220 selectionHandleColor,
221 applyThemeToAll,
222 _kDefaultTheme,
223 );
224
225 const CupertinoThemeData._rawWithDefaults(
226 Brightness? brightness,
227 Color? primaryColor,
228 Color? primaryContrastingColor,
229 CupertinoTextThemeData? textTheme,
230 Color? barBackgroundColor,
231 Color? scaffoldBackgroundColor,
232 Color? selectionHandleColor,
233 bool? applyThemeToAll,
234 this._defaults,
235 ) : super(
236 brightness: brightness,
237 primaryColor: primaryColor,
238 primaryContrastingColor: primaryContrastingColor,
239 textTheme: textTheme,
240 barBackgroundColor: barBackgroundColor,
241 scaffoldBackgroundColor: scaffoldBackgroundColor,
242 selectionHandleColor: selectionHandleColor,
243 applyThemeToAll: applyThemeToAll,
244 );
245
246 final _CupertinoThemeDefaults _defaults;
247
248 @override
249 Color get primaryColor => super.primaryColor ?? _defaults.primaryColor;
250
251 @override
252 Color get primaryContrastingColor =>
253 super.primaryContrastingColor ?? _defaults.primaryContrastingColor;
254
255 @override
256 CupertinoTextThemeData get textTheme {
257 return super.textTheme ??
258 _defaults.textThemeDefaults.createDefaults(primaryColor: primaryColor);
259 }
260
261 @override
262 Color get barBackgroundColor => super.barBackgroundColor ?? _defaults.barBackgroundColor;
263
264 @override
265 Color get scaffoldBackgroundColor =>
266 super.scaffoldBackgroundColor ?? _defaults.scaffoldBackgroundColor;
267
268 @override
269 Color get selectionHandleColor => super.selectionHandleColor ?? _defaults.selectionHandleColor;
270
271 @override
272 bool get applyThemeToAll => super.applyThemeToAll ?? _defaults.applyThemeToAll;
273
274 @override
275 NoDefaultCupertinoThemeData noDefault() {
276 return NoDefaultCupertinoThemeData(
277 brightness: super.brightness,
278 primaryColor: super.primaryColor,
279 primaryContrastingColor: super.primaryContrastingColor,
280 textTheme: super.textTheme,
281 barBackgroundColor: super.barBackgroundColor,
282 scaffoldBackgroundColor: super.scaffoldBackgroundColor,
283 selectionHandleColor: super.selectionHandleColor,
284 applyThemeToAll: super.applyThemeToAll,
285 );
286 }
287
288 @override
289 CupertinoThemeData resolveFrom(BuildContext context) {
290 Color? convertColor(Color? color) => CupertinoDynamicColor.maybeResolve(color, context);
291
292 return CupertinoThemeData._rawWithDefaults(
293 brightness,
294 convertColor(super.primaryColor),
295 convertColor(super.primaryContrastingColor),
296 super.textTheme?.resolveFrom(context),
297 convertColor(super.barBackgroundColor),
298 convertColor(super.scaffoldBackgroundColor),
299 convertColor(super.selectionHandleColor),
300 applyThemeToAll,
301 _defaults.resolveFrom(context, super.textTheme == null),
302 );
303 }
304
305 @override
306 CupertinoThemeData copyWith({
307 Brightness? brightness,
308 Color? primaryColor,
309 Color? primaryContrastingColor,
310 CupertinoTextThemeData? textTheme,
311 Color? barBackgroundColor,
312 Color? scaffoldBackgroundColor,
313 Color? selectionHandleColor,
314 bool? applyThemeToAll,
315 }) {
316 return CupertinoThemeData._rawWithDefaults(
317 brightness ?? super.brightness,
318 primaryColor ?? super.primaryColor,
319 primaryContrastingColor ?? super.primaryContrastingColor,
320 textTheme ?? super.textTheme,
321 barBackgroundColor ?? super.barBackgroundColor,
322 scaffoldBackgroundColor ?? super.scaffoldBackgroundColor,
323 selectionHandleColor ?? super.selectionHandleColor,
324 applyThemeToAll ?? super.applyThemeToAll,
325 _defaults,
326 );
327 }
328
329 @override
330 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
331 super.debugFillProperties(properties);
332 const CupertinoThemeData defaultData = CupertinoThemeData();
333 properties.add(EnumProperty<Brightness>('brightness', brightness, defaultValue: null));
334 properties.add(
335 createCupertinoColorProperty(
336 'primaryColor',
337 primaryColor,
338 defaultValue: defaultData.primaryColor,
339 ),
340 );
341 properties.add(
342 createCupertinoColorProperty(
343 'primaryContrastingColor',
344 primaryContrastingColor,
345 defaultValue: defaultData.primaryContrastingColor,
346 ),
347 );
348 properties.add(
349 createCupertinoColorProperty(
350 'barBackgroundColor',
351 barBackgroundColor,
352 defaultValue: defaultData.barBackgroundColor,
353 ),
354 );
355 properties.add(
356 createCupertinoColorProperty(
357 'scaffoldBackgroundColor',
358 scaffoldBackgroundColor,
359 defaultValue: defaultData.scaffoldBackgroundColor,
360 ),
361 );
362 properties.add(
363 createCupertinoColorProperty(
364 'selectionHandleColor',
365 selectionHandleColor,
366 defaultValue: defaultData.selectionHandleColor,
367 ),
368 );
369 properties.add(
370 DiagnosticsProperty<bool>(
371 'applyThemeToAll',
372 applyThemeToAll,
373 defaultValue: defaultData.applyThemeToAll,
374 ),
375 );
376 textTheme.debugFillProperties(properties);
377 }
378
379 @override
380 bool operator ==(Object other) {
381 if (identical(this, other)) {
382 return true;
383 }
384 if (other.runtimeType != runtimeType) {
385 return false;
386 }
387 return other is CupertinoThemeData &&
388 other.brightness == brightness &&
389 other.primaryColor == primaryColor &&
390 other.primaryContrastingColor == primaryContrastingColor &&
391 other.textTheme == textTheme &&
392 other.barBackgroundColor == barBackgroundColor &&
393 other.scaffoldBackgroundColor == scaffoldBackgroundColor &&
394 other.selectionHandleColor == selectionHandleColor &&
395 other.applyThemeToAll == applyThemeToAll;
396 }
397
398 @override
399 int get hashCode => Object.hash(
400 brightness,
401 primaryColor,
402 primaryContrastingColor,
403 textTheme,
404 barBackgroundColor,
405 scaffoldBackgroundColor,
406 selectionHandleColor,
407 applyThemeToAll,
408 );
409}
410
411/// Styling specifications for a cupertino theme without default values for
412/// unspecified properties.
413///
414/// Unlike [CupertinoThemeData] instances of this class do not return default
415/// values for properties that have been left unspecified in the constructor.
416/// Instead, unspecified properties will return null. This is used by
417/// Material's [ThemeData.cupertinoOverrideTheme].
418///
419/// See also:
420///
421/// * [CupertinoThemeData], which uses reasonable default values for
422/// unspecified theme properties.
423@immutable
424class NoDefaultCupertinoThemeData {
425 /// Creates a [NoDefaultCupertinoThemeData] styling specification.
426 ///
427 /// Unspecified properties default to null.
428 const NoDefaultCupertinoThemeData({
429 this.brightness,
430 this.primaryColor,
431 this.primaryContrastingColor,
432 this.textTheme,
433 this.barBackgroundColor,
434 this.scaffoldBackgroundColor,
435 this.selectionHandleColor,
436 this.applyThemeToAll,
437 });
438
439 /// The brightness override for Cupertino descendants.
440 ///
441 /// Defaults to null. If a non-null [Brightness] is specified, the value will
442 /// take precedence over the ambient [MediaQueryData.platformBrightness], when
443 /// determining the brightness of descendant Cupertino widgets.
444 ///
445 /// If coming from a Material [Theme] and unspecified, [brightness] will be
446 /// derived from the Material [ThemeData]'s [brightness].
447 ///
448 /// See also:
449 ///
450 /// * [MaterialBasedCupertinoThemeData], a [CupertinoThemeData] that defers
451 /// [brightness] to its Material [Theme] parent if it's unspecified.
452 ///
453 /// * [CupertinoTheme.brightnessOf], a method used to retrieve the overall
454 /// [Brightness] from a [BuildContext], for Cupertino widgets.
455 final Brightness? brightness;
456
457 /// A color used on interactive elements of the theme.
458 ///
459 /// This color is generally used on text and icons in buttons and tappable
460 /// elements. Defaults to [CupertinoColors.activeBlue].
461 ///
462 /// If coming from a Material [Theme] and unspecified, [primaryColor] will be
463 /// derived from the Material [ThemeData]'s `colorScheme.primary`. However, in
464 /// iOS styling, the [primaryColor] is more sparsely used than in Material
465 /// Design where the [primaryColor] can appear on non-interactive surfaces like
466 /// the [AppBar] background, [TextField] borders etc.
467 ///
468 /// See also:
469 ///
470 /// * [MaterialBasedCupertinoThemeData], a [CupertinoThemeData] that defers
471 /// [primaryColor] to its Material [Theme] parent if it's unspecified.
472 final Color? primaryColor;
473
474 /// A color that must be easy to see when rendered on a [primaryColor] background.
475 ///
476 /// For example, this color is used for a [CupertinoButton]'s text and icons
477 /// when the button's background is [primaryColor].
478 ///
479 /// If coming from a Material [Theme] and unspecified, [primaryContrastingColor]
480 /// will be derived from the Material [ThemeData]'s `colorScheme.onPrimary`.
481 ///
482 /// See also:
483 ///
484 /// * [MaterialBasedCupertinoThemeData], a [CupertinoThemeData] that defers
485 /// [primaryContrastingColor] to its Material [Theme] parent if it's unspecified.
486 final Color? primaryContrastingColor;
487
488 /// Text styles used by Cupertino widgets.
489 ///
490 /// Derived from [primaryColor] if unspecified.
491 final CupertinoTextThemeData? textTheme;
492
493 /// Background color of the top nav bar and bottom tab bar.
494 ///
495 /// Defaults to a light gray in light mode, or a dark translucent gray color in
496 /// dark mode.
497 final Color? barBackgroundColor;
498
499 /// Background color of the scaffold.
500 ///
501 /// Defaults to [CupertinoColors.systemBackground].
502 final Color? scaffoldBackgroundColor;
503
504 /// The color of the selection handles on the text field.
505 ///
506 /// Defaults to [CupertinoColors.systemBlue].
507 final Color? selectionHandleColor;
508
509 /// Flag to apply this theme to all descendant Cupertino widgets.
510 ///
511 /// Certain Cupertino widgets previously didn't use theming, matching past
512 /// versions of iOS. For example, [CupertinoSwitch]s always used
513 /// [CupertinoColors.systemGreen] when active.
514 ///
515 /// Today, however, these widgets can indeed be themed on iOS. Moreover on
516 /// macOS, the accent color is reflected in these widgets. Turning this flag
517 /// on ensures that descendant Cupertino widgets will be themed accordingly.
518 ///
519 /// This flag currently applies to the following widgets:
520 /// - [CupertinoSwitch] & [Switch.adaptive]
521 ///
522 /// Defaults to false.
523 final bool? applyThemeToAll;
524
525 /// Returns an instance of the theme data whose property getters only return
526 /// the construction time specifications with no derived values.
527 ///
528 /// Used in Material themes to let unspecified properties fallback to Material
529 /// theme properties instead of iOS defaults.
530 NoDefaultCupertinoThemeData noDefault() => this;
531
532 /// Returns a new theme data with all its colors resolved against the
533 /// given [BuildContext].
534 ///
535 /// Called by [CupertinoTheme.of] to resolve colors defined in the retrieved
536 /// [CupertinoThemeData].
537 @protected
538 NoDefaultCupertinoThemeData resolveFrom(BuildContext context) {
539 Color? convertColor(Color? color) => CupertinoDynamicColor.maybeResolve(color, context);
540
541 return NoDefaultCupertinoThemeData(
542 brightness: brightness,
543 primaryColor: convertColor(primaryColor),
544 primaryContrastingColor: convertColor(primaryContrastingColor),
545 textTheme: textTheme?.resolveFrom(context),
546 barBackgroundColor: convertColor(barBackgroundColor),
547 scaffoldBackgroundColor: convertColor(scaffoldBackgroundColor),
548 selectionHandleColor: convertColor(selectionHandleColor),
549 applyThemeToAll: applyThemeToAll,
550 );
551 }
552
553 /// Creates a copy of the theme data with specified attributes overridden.
554 ///
555 /// Only the current instance's specified attributes are copied instead of
556 /// derived values. For instance, if the current [textTheme] is implied from
557 /// the current [primaryColor] because it was not specified, copying with a
558 /// different [primaryColor] will also change the copy's implied [textTheme].
559 NoDefaultCupertinoThemeData copyWith({
560 Brightness? brightness,
561 Color? primaryColor,
562 Color? primaryContrastingColor,
563 CupertinoTextThemeData? textTheme,
564 Color? barBackgroundColor,
565 Color? scaffoldBackgroundColor,
566 Color? selectionHandleColor,
567 bool? applyThemeToAll,
568 }) {
569 return NoDefaultCupertinoThemeData(
570 brightness: brightness ?? this.brightness,
571 primaryColor: primaryColor ?? this.primaryColor,
572 primaryContrastingColor: primaryContrastingColor ?? this.primaryContrastingColor,
573 textTheme: textTheme ?? this.textTheme,
574 barBackgroundColor: barBackgroundColor ?? this.barBackgroundColor,
575 scaffoldBackgroundColor: scaffoldBackgroundColor ?? this.scaffoldBackgroundColor,
576 selectionHandleColor: selectionHandleColor ?? this.selectionHandleColor,
577 applyThemeToAll: applyThemeToAll ?? this.applyThemeToAll,
578 );
579 }
580
581 @override
582 bool operator ==(Object other) {
583 if (identical(this, other)) {
584 return true;
585 }
586 if (other.runtimeType != runtimeType) {
587 return false;
588 }
589 return other is NoDefaultCupertinoThemeData &&
590 other.brightness == brightness &&
591 other.primaryColor == primaryColor &&
592 other.primaryContrastingColor == primaryContrastingColor &&
593 other.textTheme == textTheme &&
594 other.barBackgroundColor == barBackgroundColor &&
595 other.scaffoldBackgroundColor == scaffoldBackgroundColor &&
596 other.applyThemeToAll == applyThemeToAll;
597 }
598
599 @override
600 int get hashCode => Object.hash(
601 brightness,
602 primaryColor,
603 primaryContrastingColor,
604 textTheme,
605 barBackgroundColor,
606 scaffoldBackgroundColor,
607 applyThemeToAll,
608 );
609}
610
611@immutable
612class _CupertinoThemeDefaults {
613 const _CupertinoThemeDefaults(
614 this.brightness,
615 this.primaryColor,
616 this.primaryContrastingColor,
617 this.barBackgroundColor,
618 this.scaffoldBackgroundColor,
619 this.selectionHandleColor,
620 this.applyThemeToAll,
621 this.textThemeDefaults,
622 );
623
624 final Brightness? brightness;
625 final Color primaryColor;
626 final Color primaryContrastingColor;
627 final Color barBackgroundColor;
628 final Color scaffoldBackgroundColor;
629 final Color selectionHandleColor;
630 final bool applyThemeToAll;
631 final _CupertinoTextThemeDefaults textThemeDefaults;
632
633 _CupertinoThemeDefaults resolveFrom(BuildContext context, bool resolveTextTheme) {
634 Color convertColor(Color color) => CupertinoDynamicColor.resolve(color, context);
635
636 return _CupertinoThemeDefaults(
637 brightness,
638 convertColor(primaryColor),
639 convertColor(primaryContrastingColor),
640 convertColor(barBackgroundColor),
641 convertColor(scaffoldBackgroundColor),
642 convertColor(selectionHandleColor),
643 applyThemeToAll,
644 resolveTextTheme ? textThemeDefaults.resolveFrom(context) : textThemeDefaults,
645 );
646 }
647}
648
649@immutable
650class _CupertinoTextThemeDefaults {
651 const _CupertinoTextThemeDefaults(this.labelColor, this.inactiveGray);
652
653 final Color labelColor;
654 final Color inactiveGray;
655
656 _CupertinoTextThemeDefaults resolveFrom(BuildContext context) {
657 return _CupertinoTextThemeDefaults(
658 CupertinoDynamicColor.resolve(labelColor, context),
659 CupertinoDynamicColor.resolve(inactiveGray, context),
660 );
661 }
662
663 CupertinoTextThemeData createDefaults({required Color primaryColor}) {
664 return _DefaultCupertinoTextThemeData(
665 primaryColor: primaryColor,
666 labelColor: labelColor,
667 inactiveGray: inactiveGray,
668 );
669 }
670}
671
672// CupertinoTextThemeData with no text styles explicitly specified.
673// The implementation of this class may need to be updated when any of the default
674// text styles changes.
675class _DefaultCupertinoTextThemeData extends CupertinoTextThemeData {
676 const _DefaultCupertinoTextThemeData({
677 required this.labelColor,
678 required this.inactiveGray,
679 required super.primaryColor,
680 });
681
682 final Color labelColor;
683 final Color inactiveGray;
684
685 @override
686 TextStyle get textStyle => super.textStyle.copyWith(color: labelColor);
687
688 @override
689 TextStyle get tabLabelTextStyle => super.tabLabelTextStyle.copyWith(color: inactiveGray);
690
691 @override
692 TextStyle get navTitleTextStyle => super.navTitleTextStyle.copyWith(color: labelColor);
693
694 @override
695 TextStyle get navLargeTitleTextStyle => super.navLargeTitleTextStyle.copyWith(color: labelColor);
696
697 @override
698 TextStyle get pickerTextStyle => super.pickerTextStyle.copyWith(color: labelColor);
699
700 @override
701 TextStyle get dateTimePickerTextStyle =>
702 super.dateTimePickerTextStyle.copyWith(color: labelColor);
703}
704