Unverified Commit a671b283 authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

CupertinoDynamicColor and friends (#37719)

parent ffa37854
......@@ -18,6 +18,7 @@ export 'src/cupertino/colors.dart';
export 'src/cupertino/date_picker.dart';
export 'src/cupertino/dialog.dart';
export 'src/cupertino/icons.dart';
export 'src/cupertino/interface_level.dart';
export 'src/cupertino/localizations.dart';
export 'src/cupertino/nav_bar.dart';
export 'src/cupertino/page_scaffold.dart';
......
......@@ -8,6 +8,7 @@ import 'package:flutter/widgets.dart';
import 'button.dart';
import 'colors.dart';
import 'icons.dart';
import 'interface_level.dart';
import 'localizations.dart';
import 'route.dart';
import 'theme.dart';
......@@ -268,45 +269,51 @@ class _CupertinoAppState extends State<CupertinoApp> {
return ScrollConfiguration(
behavior: _AlwaysCupertinoScrollBehavior(),
child: CupertinoTheme(
data: effectiveThemeData,
child: WidgetsApp(
key: GlobalObjectKey(this),
navigatorKey: widget.navigatorKey,
navigatorObservers: _navigatorObservers,
pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) =>
CupertinoPageRoute<T>(settings: settings, builder: builder),
home: widget.home,
routes: widget.routes,
initialRoute: widget.initialRoute,
onGenerateRoute: widget.onGenerateRoute,
onUnknownRoute: widget.onUnknownRoute,
builder: widget.builder,
title: widget.title,
onGenerateTitle: widget.onGenerateTitle,
textStyle: effectiveThemeData.textTheme.textStyle,
color: widget.color ?? CupertinoColors.activeBlue,
locale: widget.locale,
localizationsDelegates: _localizationsDelegates,
localeResolutionCallback: widget.localeResolutionCallback,
localeListResolutionCallback: widget.localeListResolutionCallback,
supportedLocales: widget.supportedLocales,
showPerformanceOverlay: widget.showPerformanceOverlay,
checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages,
checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers,
showSemanticsDebugger: widget.showSemanticsDebugger,
debugShowCheckedModeBanner: widget.debugShowCheckedModeBanner,
inspectorSelectButtonBuilder: (BuildContext context, VoidCallback onPressed) {
return CupertinoButton.filled(
child: const Icon(
CupertinoIcons.search,
size: 28.0,
color: CupertinoColors.white,
),
padding: EdgeInsets.zero,
onPressed: onPressed,
);
},
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.base,
child: CupertinoTheme(
data: effectiveThemeData,
child: CupertinoSystemColors(
data: CupertinoSystemColors.of(context, useFallbackValues: true),
child: WidgetsApp(
key: GlobalObjectKey(this),
navigatorKey: widget.navigatorKey,
navigatorObservers: _navigatorObservers,
pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) =>
CupertinoPageRoute<T>(settings: settings, builder: builder),
home: widget.home,
routes: widget.routes,
initialRoute: widget.initialRoute,
onGenerateRoute: widget.onGenerateRoute,
onUnknownRoute: widget.onUnknownRoute,
builder: widget.builder,
title: widget.title,
onGenerateTitle: widget.onGenerateTitle,
textStyle: effectiveThemeData.textTheme.textStyle,
color: widget.color ?? CupertinoColors.activeBlue,
locale: widget.locale,
localizationsDelegates: _localizationsDelegates,
localeResolutionCallback: widget.localeResolutionCallback,
localeListResolutionCallback: widget.localeListResolutionCallback,
supportedLocales: widget.supportedLocales,
showPerformanceOverlay: widget.showPerformanceOverlay,
checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages,
checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers,
showSemanticsDebugger: widget.showSemanticsDebugger,
debugShowCheckedModeBanner: widget.debugShowCheckedModeBanner,
inspectorSelectButtonBuilder: (BuildContext context, VoidCallback onPressed) {
return CupertinoButton.filled(
child: const Icon(
CupertinoIcons.search,
size: 28.0,
color: CupertinoColors.white,
),
padding: EdgeInsets.zero,
onPressed: onPressed,
);
},
),
),
),
),
);
......
......@@ -3,6 +3,19 @@
// found in the LICENSE file.
import 'dart:ui' show Color;
import 'package:collection/collection.dart' show DeepCollectionEquality;
import '../../foundation.dart';
import '../widgets/basic.dart';
import '../widgets/framework.dart';
import '../widgets/media_query.dart';
import 'interface_level.dart';
import 'theme.dart';
// Examples can assume:
// Widget child;
// Color lightModeColor;
// Color darkModeColor;
/// A palette of [Color] constants that describe colors commonly used when
/// matching the iOS platform aesthetics.
......@@ -80,3 +93,1116 @@ class CupertinoColors {
/// This is SystemRed in the iOS palette.
static const Color destructiveRed = Color(0xFFFF3B30);
}
/// A [Color] subclass that represents a family of colors, and the currect effective
/// color in the color family.
///
/// When used as a regular color, `CupertinoDynamicColor` is equivalent to the
/// effective color (i.e. [CupertinoDynamicColor.value] will come from the effective
/// color), which is determined by the [BuildContext] it is last resolved against.
/// If it has never been resolved, the light, normal contrast, base elevation variant
/// [CupertinoDynamicColor.color] will be the effective color.
// TODO(LongCatIsLooong): publicize once all Cupertino components have adopted this.
// {@tool sample}
//
// The following snippet will create a [CupertinoButton] whose background color
// is _lightModeColor_ in light mode but _darkModeColor_ in dark mode.
//
//
// ```dart
// CupertinoButton(
// child: child,
// color: CupertinoDynamicColor.withVibrancy(
// color: lightModeColor,
// darkColor: darkModeColor,
// ),
// onTap: () => null,
// )
// ```
// {@end-tool}
//
// When a Cupertino component is provided with a `CupertinoDynamicColor`, either
// directly in its constructor, or from an [InheritedWidget] it depends on (for example,
// [DefaultTextStyle]), the component will automatically resolve the color by calling
// [CupertinoDynamicColor.resolve], using their own [BuildContext].
//
// When used outside of a Cupertino component, such color resolution will not happen
// automatically. It's essential to call [CupertinoDynamicColor.resolve] with the
// correct [BuildContext] before using the color to paint, in order to get the
// desired effect.
///
/// See also:
///
/// * [CupertinoUserInterfaceLevel], an [InheritedWidget] that may affect color
/// resolution of a `CupertinoDynamicColor`.
/// * [CupertinoSystemColors], an [InheritedWidget] that exposes system colors
/// of iOS 13+.
/// * https://developer.apple.com/documentation/uikit/uicolor/3238042-resolvedcolor.
@immutable
class CupertinoDynamicColor extends Color {
/// Creates an adaptive [Color] that changes its effective color based on the
/// [BuildContext] given. The default effective color is [color].
///
/// All the colors must not be null.
CupertinoDynamicColor({
@required Color color,
@required Color darkColor,
@required Color highContrastColor,
@required Color darkHighContrastColor,
@required Color elevatedColor,
@required Color darkElevatedColor,
@required Color highContrastElevatedColor,
@required Color darkHighContrastElevatedColor,
}) : this._(
color,
<List<List<Color>>>[
<List<Color>>[
<Color>[darkColor, darkElevatedColor],
<Color>[darkHighContrastColor, darkHighContrastElevatedColor],
],
<List<Color>>[
<Color>[color, elevatedColor],
<Color>[highContrastColor, highContrastElevatedColor],
],
],
);
/// Creates an adaptive [Color] that changes its effective color based on the
/// given [BuildContext]'s brightness (from [MediaQueryData.platformBrightness]
/// or [CupertinoThemeData.brightness]) and accessibility contrast setting
/// ([MediaQueryData.highContrast]). The default effective color is [color].
///
/// All the colors must not be null.
CupertinoDynamicColor.withBrightnessAndContrast({
@required Color color,
@required Color darkColor,
@required Color highContrastColor,
@required Color darkHighContrastColor,
}) : this(
color: color,
darkColor: darkColor,
highContrastColor: highContrastColor,
darkHighContrastColor: darkHighContrastColor,
elevatedColor: color,
darkElevatedColor: darkColor,
highContrastElevatedColor: highContrastColor,
darkHighContrastElevatedColor: darkHighContrastColor,
);
/// Creates an adaptive [Color] that changes its effective color based on the given
/// [BuildContext]'s brightness (from [MediaQueryData.platformBrightness] or
/// [CupertinoThemeData.brightness]). The default effective color is [color].
///
/// All the colors must not be null.
CupertinoDynamicColor.withBrightness({
@required Color color,
@required Color darkColor,
}) : this(
color: color,
darkColor: darkColor,
highContrastColor: color,
darkHighContrastColor: darkColor,
elevatedColor: color,
darkElevatedColor: darkColor,
highContrastElevatedColor: color,
darkHighContrastElevatedColor: darkColor,
);
CupertinoDynamicColor._(
Color value,
this._colorMap,
) : assert(() {
Iterable<Object> expand(Object a) {
return (a is Iterable<Object>) ? a.expand<Object>(expand) : <Object>[a];
}
final Iterable<Object> expanded = expand(_colorMap);
assert(expanded.contains(value), '$value is not one of $_colorMap');
return !expanded.contains(null) && expanded.length == 8;
}(), 'The colorMap provided is invalid: $_colorMap'),
super(value.value);
/// The color to use when the [BuildContext] implies a combination of light mode,
/// normal contrast, and base interface elevation.
///
/// In other words, this color will be the effective color of the `CupertinoDynamicColor`
/// after it is resolved against a [BuildContext] that:
/// - has a [CupertinoTheme] whose [brightness] is [PlatformBrightness.light],
/// or a [MediaQuery] whose [MediaQueryData.platformBrightness] is [PlatformBrightness.light].
/// - has a [MediaQuery] whose [MediaQueryData.highContrast] is `false`.
/// - has a [CupertinoUserInterfaceLevel] that indicates [CupertinoUserInterfaceLevelData.base].
Color get color => _colorMap[Brightness.light.index]
[0] // 0 for normal contrast.
[CupertinoUserInterfaceLevelData.base.index];
/// The color to use when the [BuildContext] implies a combination of dark mode,
/// normal contrast, and base interface elevation.
///
/// In other words, this color will be the effective color of the `CupertinoDynamicColor`
/// after it is resolved against a [BuildContext] that:
/// - has a [CupertinoTheme] whose [brightness] is [PlatformBrightness.dark],
/// or a [MediaQuery] whose [MediaQueryData.platformBrightness] is [PlatformBrightness.dark].
/// - has a [MediaQuery] whose [MediaQueryData.highContrast] is `false`.
/// - has a [CupertinoUserInterfaceLevel] that indicates [CupertinoUserInterfaceLevelData.base].
Color get darkColor => _colorMap[Brightness.dark.index]
[0] // 0 for normal contrast.
[CupertinoUserInterfaceLevelData.base.index];
/// The color to use when the [BuildContext] implies a combination of light mode,
/// high contrast, and base interface elevation.
///
/// In other words, this color will be the effective color of the `CupertinoDynamicColor`
/// after it is resolved against a [BuildContext] that:
/// - has a [CupertinoTheme] whose [brightness] is [PlatformBrightness.light],
/// or a [MediaQuery] whose [MediaQueryData.platformBrightness] is [PlatformBrightness.light].
/// - has a [MediaQuery] whose [MediaQueryData.highContrast] is `true`.
/// - has a [CupertinoUserInterfaceLevel] that indicates [CupertinoUserInterfaceLevelData.base].
Color get highContrastColor => _colorMap[Brightness.light.index]
[1] // 1 for high contrast.
[CupertinoUserInterfaceLevelData.base.index];
/// The color to use when the [BuildContext] implies a combination of dark mode,
/// high contrast, and base interface elevation.
///
/// In other words, this color will be the effective color of the `CupertinoDynamicColor`
/// after it is resolved against a [BuildContext] that:
/// - has a [CupertinoTheme] whose [brightness] is [PlatformBrightness.dark],
/// or a [MediaQuery] whose [MediaQueryData.platformBrightness] is [PlatformBrightness.dark].
/// - has a [MediaQuery] whose [MediaQueryData.highContrast] is `true`.
/// - has a [CupertinoUserInterfaceLevel] that indicates [CupertinoUserInterfaceLevelData.base].
Color get darkHighContrastColor => _colorMap[Brightness.dark.index]
[1] // 1 for high contrast.
[CupertinoUserInterfaceLevelData.base.index];
/// The color to use when the [BuildContext] implies a combination of light mode,
/// normal contrast, and elevated interface elevation.
///
/// In other words, this color will be the effective color of the `CupertinoDynamicColor`
/// after it is resolved against a [BuildContext] that:
/// - has a [CupertinoTheme] whose [brightness] is [PlatformBrightness.light],
/// or a [MediaQuery] whose [MediaQueryData.platformBrightness] is [PlatformBrightness.light].
/// - has a [MediaQuery] whose [MediaQueryData.highContrast] is `false`.
/// - has a [CupertinoUserInterfaceLevel] that indicates [CupertinoUserInterfaceLevelData.elevated].
Color get elevatedColor => _colorMap [Brightness.light.index]
[0] // 0 for normal contrast.
[CupertinoUserInterfaceLevelData.elevated.index];
/// The color to use when the [BuildContext] implies a combination of dark mode,
/// normal contrast, and elevated interface elevation.
///
/// In other words, this color will be the effective color of the `CupertinoDynamicColor`
/// after it is resolved against a [BuildContext] that:
/// - has a [CupertinoTheme] whose [brightness] is [PlatformBrightness.dark],
/// or a [MediaQuery] whose [MediaQueryData.platformBrightness] is [PlatformBrightness.dark].
/// - has a [MediaQuery] whose [MediaQueryData.highContrast] is `false`.
/// - has a [CupertinoUserInterfaceLevel] that indicates [CupertinoUserInterfaceLevelData.elevated].
Color get darkElevatedColor => _colorMap[Brightness.dark.index]
[0] // 0 for normal contrast.
[CupertinoUserInterfaceLevelData.elevated.index];
/// The color to use when the [BuildContext] implies a combination of light mode,
/// high contrast, and elevated interface elevation.
///
/// In other words, this color will be the effective color of the `CupertinoDynamicColor`
/// after it is resolved against a [BuildContext] that:
/// - has a [CupertinoTheme] whose [brightness] is [PlatformBrightness.light],
/// or a [MediaQuery] whose [MediaQueryData.platformBrightness] is [PlatformBrightness.light].
/// - has a [MediaQuery] whose [MediaQueryData.highContrast] is `true`.
/// - has a [CupertinoUserInterfaceLevel] that indicates [CupertinoUserInterfaceLevelData.elevated].
Color get highContrastElevatedColor => _colorMap[Brightness.light.index]
[1] // 1 for high contrast.
[CupertinoUserInterfaceLevelData.elevated.index];
/// The color to use when the [BuildContext] implies a combination of dark mode,
/// high contrast, and elevated interface elevation.
///
/// In other words, this color will be the effective color of the `CupertinoDynamicColor`
/// after it is resolved against a [BuildContext] that:
/// - has a [CupertinoTheme] whose [brightness] is [PlatformBrightness.dark],
/// or a [MediaQuery] whose [MediaQueryData.platformBrightness] is [PlatformBrightness.dark].
/// - has a [MediaQuery] whose [MediaQueryData.highContrast] is `true`.
/// - has a [CupertinoUserInterfaceLevel] that indicates [CupertinoUserInterfaceLevelData.elevated].
Color get darkHighContrastElevatedColor => _colorMap[Brightness.dark.index]
[1] // 1 for high contrast.
[CupertinoUserInterfaceLevelData.elevated.index];
final List<List<List<Color>>> _colorMap;
/// Resolves the given [Color] by calling [resolveFrom].
///
/// If the given color is already a concrete [Color], it will be returned as is.
/// If the given color is a [CupertinoDynamicColor], but the given [BuildContext]
/// lacks the dependencies essential to the color resolution, an exception will
/// be thrown, unless [nullOk] is set to true.
static Color resolve(Color resolvable, BuildContext context, { bool nullOk = false }) {
assert(resolvable != null);
assert(context != null);
return (resolvable is CupertinoDynamicColor)
? resolvable.resolveFrom(context, nullOk: nullOk)
: resolvable;
}
bool get _isPlatformBrightnessDependent {
return color != darkColor
|| elevatedColor != darkElevatedColor
|| highContrastColor != darkHighContrastColor
|| highContrastElevatedColor != darkHighContrastElevatedColor;
}
bool get _isHighContrastDependent {
return color != highContrastColor
|| darkColor != darkHighContrastColor
|| elevatedColor != highContrastElevatedColor
|| darkElevatedColor != darkHighContrastElevatedColor;
}
bool get _isInterfaceElevationDependent {
return color != elevatedColor
|| darkColor != darkElevatedColor
|| highContrastColor != highContrastElevatedColor
|| darkHighContrastColor != darkHighContrastElevatedColor;
}
/// Resolves this `CupertinoDynamicColor` using the provided [BuildContext].
///
/// Calling this method will create a new `CupertinoDynamicColor` that is almost
/// identical to this `CupertinoDynamicColor`, except the effective color is
/// changed to adapt to the given [BuildContext].
///
/// For example, if the given [BuildContext] indicates the widgets in the subtree
/// should be displayed in dark mode (the surrounding [CupertinoTheme]'s [CupertinoThemeData.brightness]
/// or [MediaQuery]'s [MediaQueryData.platformBrightness] is [PlatformBrightness.dark]),
/// with a high accessibility contrast (the surrounding [MediaQuery]'s [MediaQueryData.highContrast]
/// is `true`), and an elevated interface elevation (the surrounding [CupertinoUserInterfaceLevel]'s
/// `data` is [CupertinoUserInterfaceLevelData.elevated]), the resolved
/// `CupertinoDynamicColor` will be the same as this [CupertinoDynamicColor],
/// except its effective color will be the `darkHighContrastElevatedColor` variant
/// from the orignal `CupertinoDynamicColor`.
///
/// Calling this function may create dependencies on the closest instance of some
/// [InheritedWidget]s that enclose the given [BuildContext]. E.g., if [darkColor]
/// is different from [color], this method will call [CupertinoTheme.of], and
/// then [MediaQuery.of] if brightness wasn't specified in the theme data retrived
/// from the previous [CupertinoTheme.of] call, in an effort to determine the
/// brightness value.
///
/// If any of the required dependecies are missing from the given context, an exception
/// will be thrown unless [nullOk] is set to `true`.
CupertinoDynamicColor resolveFrom(BuildContext context, { bool nullOk = false }) {
int brightnessNumber = 0;
int highContrastNumber = 0;
int interfaceElevationNumber = 0;
// If this CupertinoDynamicColor cares about brightness.
if (_isPlatformBrightnessDependent) {
final Brightness brightness = CupertinoTheme.brightnessOf(context, nullOk: nullOk) ?? Brightness.light;
brightnessNumber = brightness.index;
}
// If this CupertinoDynamicColor cares about accessibility contrast.
if (_isHighContrastDependent) {
final bool isHighContrastEnabled = MediaQuery.of(context, nullOk: nullOk)?.highContrast
?? false;
highContrastNumber = isHighContrastEnabled ? 1 : 0;
}
// If this CupertinoDynamicColor cares about user interface elevation.
if (_isInterfaceElevationDependent) {
final CupertinoUserInterfaceLevelData level = CupertinoUserInterfaceLevel.of(context, nullOk: nullOk)
?? CupertinoUserInterfaceLevelData.base;
interfaceElevationNumber = level.index;
}
final Color resolved = _colorMap[brightnessNumber][highContrastNumber][interfaceElevationNumber];
return resolved.value == value ? this : CupertinoDynamicColor._(resolved, _colorMap);
}
@override
bool operator ==(dynamic other) {
if (identical(this, other))
return true;
return other.runtimeType == runtimeType
&& value == other.value
&& (identical(_colorMap, other._colorMap) || const DeepCollectionEquality().equals(_colorMap, other._colorMap));
}
@override
int get hashCode {
return hashValues(
value,
color,
darkColor,
highContrastColor,
elevatedColor,
darkElevatedColor,
darkHighContrastColor,
darkHighContrastElevatedColor,
highContrastElevatedColor,
);
}
@override
String toString() {
String toString(String name, Color color) {
final String marker = color.value == value ? '*' : '';
return '$marker$name = $color$marker';
}
final List<String> xs = <String>[toString('color', color),
if (_isPlatformBrightnessDependent) toString('darkColor', darkColor),
if (_isHighContrastDependent) toString('highContrastColor', highContrastColor),
if (_isPlatformBrightnessDependent && _isHighContrastDependent) toString('darkHighContrastColor', darkHighContrastColor),
if (_isInterfaceElevationDependent) toString('elevatedColor', elevatedColor),
if (_isPlatformBrightnessDependent && _isInterfaceElevationDependent) toString('darkElevatedColor', darkElevatedColor),
if (_isHighContrastDependent && _isInterfaceElevationDependent) toString('highContrastElevatedColor', highContrastElevatedColor),
if (_isPlatformBrightnessDependent && _isHighContrastDependent && _isInterfaceElevationDependent) toString('darkHighContrastElevatedColor', darkHighContrastElevatedColor),
];
return '$runtimeType(${xs.join(', ')})';
}
}
/// A color palette that typically matches iOS 13+ system colors.
///
/// Generally you should not create a [CupertinoSystemColorsData] yourself.
/// Use [CupertinoSystemColors.of] to get the [CupertinoSystemColorsData] from the
/// current [BuildContext] if possible, or [CupertinoSystemColors.fromSystem]
/// when the current [BuildContext] is not available (e.g., in [CupertinoApp]'s
/// constructor).
@immutable
class CupertinoSystemColorsData extends Diagnosticable {
/// Creates a color palette.
///
/// Generally you should not create your own `CupertinoSystemColorsData`.
/// Use [CupertinoSystemColors.of] to get the [CupertinoSystemColorsData] from the
/// current [BuildContext] if possible, or [CupertinoSystemColors.fromSystem]
/// when the current [BuildContext] is not available (e.g., in [CupertinoApp]'s
/// constructor).
const CupertinoSystemColorsData({
@required this.label,
@required this.secondaryLabel,
@required this.tertiaryLabel,
@required this.quaternaryLabel,
@required this.systemFill,
@required this.secondarySystemFill,
@required this.tertiarySystemFill,
@required this.quaternarySystemFill,
@required this.placeholderText,
@required this.systemBackground,
@required this.secondarySystemBackground,
@required this.tertiarySystemBackground,
@required this.systemGroupedBackground,
@required this.secondarySystemGroupedBackground,
@required this.tertiarySystemGroupedBackground,
@required this.separator,
@required this.opaqueSeparator,
@required this.link,
@required this.systemBlue,
@required this.systemGreen,
@required this.systemIndigo,
@required this.systemOrange,
@required this.systemPink,
@required this.systemPurple,
@required this.systemRed,
@required this.systemTeal,
@required this.systemYellow,
@required this.systemGray,
@required this.systemGray2,
@required this.systemGray3,
@required this.systemGray4,
@required this.systemGray5,
@required this.systemGray6,
}) : assert(label != null),
assert(secondaryLabel != null),
assert(tertiaryLabel != null),
assert(quaternaryLabel != null),
assert(systemFill != null),
assert(secondarySystemFill != null),
assert(tertiarySystemFill != null),
assert(quaternarySystemFill != null),
assert(placeholderText != null),
assert(systemBackground != null),
assert(secondarySystemBackground != null),
assert(tertiarySystemBackground != null),
assert(systemGroupedBackground != null),
assert(secondarySystemGroupedBackground != null),
assert(tertiarySystemGroupedBackground != null),
assert(separator != null),
assert(opaqueSeparator != null),
assert(link != null),
assert(systemBlue != null),
assert(systemGreen != null),
assert(systemIndigo != null),
assert(systemOrange != null),
assert(systemPink != null),
assert(systemPurple != null),
assert(systemRed != null),
assert(systemTeal != null),
assert(systemYellow != null),
assert(systemGray != null),
assert(systemGray2 != null),
assert(systemGray3 != null),
assert(systemGray4 != null),
assert(systemGray5 != null),
assert(systemGray6 != null),
super();
/// The color for text labels containing primary content.
final CupertinoDynamicColor label;
/// The color for text labels containing secondary content.
final CupertinoDynamicColor secondaryLabel;
/// The color for text labels containing tertiary content.
final CupertinoDynamicColor tertiaryLabel;
/// The color for text labels containing quaternary content.
final CupertinoDynamicColor quaternaryLabel;
/// An overlay fill color for thin and small shapes.
final CupertinoDynamicColor systemFill;
/// An overlay fill color for medium-size shapes.
final CupertinoDynamicColor secondarySystemFill;
/// An overlay fill color for large shapes.
final CupertinoDynamicColor tertiarySystemFill;
/// An overlay fill color for large areas containing complex content.
final CupertinoDynamicColor quaternarySystemFill;
/// The color for placeholder text in controls or text views.
final CupertinoDynamicColor placeholderText;
/// The color for the main background of your interface.
///
/// Typically used for designs that have a white primary background in a light environment.
final CupertinoDynamicColor systemBackground;
/// The color for content layered on top of the main background.
///
/// Typically used for designs that have a white primary background in a light environment.
final CupertinoDynamicColor secondarySystemBackground;
/// The color for content layered on top of secondary backgrounds.
///
/// Typically used for designs that have a white primary background in a light environment.
final CupertinoDynamicColor tertiarySystemBackground;
/// The color for the main background of your grouped interface.
///
/// Typically used for grouped content, including table views and platter-based designs.
final CupertinoDynamicColor systemGroupedBackground;
/// The color for content layered on top of the main background of your grouped interface.
///
/// Typically used for grouped content, including table views and platter-based designs.
final CupertinoDynamicColor secondarySystemGroupedBackground;
/// The color for content layered on top of secondary backgrounds of your grouped interface.
///
/// Typically used for grouped content, including table views and platter-based designs.
final CupertinoDynamicColor tertiarySystemGroupedBackground;
/// The color for thin borders or divider lines that allows some underlying content to be visible.
final CupertinoDynamicColor separator;
/// The color for borders or divider lines that hide any underlying content.
final CupertinoDynamicColor opaqueSeparator;
/// The color for links.
final CupertinoDynamicColor link;
/// A blue color that can adapt to the given [BuildContext].
final CupertinoDynamicColor systemBlue;
/// A green color that can adapt to the given [BuildContext].
final CupertinoDynamicColor systemGreen;
/// An indigo color that can adapt to the given [BuildContext].
final CupertinoDynamicColor systemIndigo;
/// An orange color that can adapt to the given [BuildContext].
final CupertinoDynamicColor systemOrange;
/// A pink color that can adapt to the given [BuildContext].
final CupertinoDynamicColor systemPink;
/// A purple color that can adapt to the given [BuildContext].
final CupertinoDynamicColor systemPurple;
/// A red color that can adapt to the given [BuildContext].
final CupertinoDynamicColor systemRed;
/// A teal color that can adapt to the given [BuildContext].
final CupertinoDynamicColor systemTeal;
/// A yellow color that can adapt to the given [BuildContext].
final CupertinoDynamicColor systemYellow;
/// The base gray color.
final CupertinoDynamicColor systemGray;
/// A second-level shade of grey.
final CupertinoDynamicColor systemGray2;
/// A third-level shade of grey.
final CupertinoDynamicColor systemGray3;
/// A fourth-level shade of grey.
final CupertinoDynamicColor systemGray4;
/// A fifth-level shade of grey.
final CupertinoDynamicColor systemGray5;
/// A sixth-level shade of grey.
final CupertinoDynamicColor systemGray6;
/// Resolve every color in the palette using the given [BuildContext], by calling
/// [CupertinoDynamicColor.resolve], and return a new [CupertinoSystemColorsData]
/// with all the resolved colors.
CupertinoSystemColorsData resolveColors(BuildContext context) {
return CupertinoSystemColorsData(
label: CupertinoDynamicColor.resolve(label, context),
secondaryLabel: CupertinoDynamicColor.resolve(secondaryLabel, context),
tertiaryLabel: CupertinoDynamicColor.resolve(tertiaryLabel, context),
quaternaryLabel: CupertinoDynamicColor.resolve(quaternaryLabel, context),
systemFill: CupertinoDynamicColor.resolve(systemFill, context),
secondarySystemFill: CupertinoDynamicColor.resolve(secondarySystemFill, context),
tertiarySystemFill: CupertinoDynamicColor.resolve(tertiarySystemFill, context),
quaternarySystemFill: CupertinoDynamicColor.resolve(quaternarySystemFill, context),
placeholderText: CupertinoDynamicColor.resolve(placeholderText, context),
systemBackground: CupertinoDynamicColor.resolve(systemBackground, context),
secondarySystemBackground: CupertinoDynamicColor.resolve(secondarySystemBackground, context),
tertiarySystemBackground: CupertinoDynamicColor.resolve(tertiarySystemBackground, context),
systemGroupedBackground: CupertinoDynamicColor.resolve(systemGroupedBackground, context),
secondarySystemGroupedBackground: CupertinoDynamicColor.resolve(secondarySystemGroupedBackground, context),
tertiarySystemGroupedBackground: CupertinoDynamicColor.resolve(tertiarySystemGroupedBackground, context),
separator: CupertinoDynamicColor.resolve(separator, context),
opaqueSeparator: CupertinoDynamicColor.resolve(opaqueSeparator, context),
link: CupertinoDynamicColor.resolve(link, context),
systemBlue: CupertinoDynamicColor.resolve(systemBlue, context),
systemGreen: CupertinoDynamicColor.resolve(systemGreen, context),
systemIndigo: CupertinoDynamicColor.resolve(systemIndigo, context),
systemOrange: CupertinoDynamicColor.resolve(systemOrange, context),
systemPink: CupertinoDynamicColor.resolve(systemPink, context),
systemPurple: CupertinoDynamicColor.resolve(systemPurple, context),
systemRed: CupertinoDynamicColor.resolve(systemRed, context),
systemTeal: CupertinoDynamicColor.resolve(systemTeal, context),
systemYellow: CupertinoDynamicColor.resolve(systemYellow, context),
systemGray: CupertinoDynamicColor.resolve(systemGray, context),
systemGray2: CupertinoDynamicColor.resolve(systemGray2, context),
systemGray3: CupertinoDynamicColor.resolve(systemGray3, context),
systemGray4: CupertinoDynamicColor.resolve(systemGray4, context),
systemGray5: CupertinoDynamicColor.resolve(systemGray5, context),
systemGray6: CupertinoDynamicColor.resolve(systemGray6, context),
);
}
@override
bool operator ==(dynamic other) {
if (identical(this, other))
return true;
return other.runtimeType == runtimeType
&& other.label == label
&& other.secondaryLabel == secondaryLabel
&& other.tertiaryLabel == tertiaryLabel
&& other.quaternaryLabel == quaternaryLabel
&& other.systemFill == systemFill
&& other.secondarySystemFill == secondarySystemFill
&& other.tertiarySystemFill == tertiarySystemFill
&& other.quaternarySystemFill == quaternarySystemFill
&& other.placeholderText == placeholderText
&& other.systemBackground == systemBackground
&& other.secondarySystemBackground == secondarySystemBackground
&& other.tertiarySystemBackground == tertiarySystemBackground
&& other.systemGroupedBackground == systemGroupedBackground
&& other.secondarySystemGroupedBackground == secondarySystemGroupedBackground
&& other.tertiarySystemGroupedBackground == tertiarySystemGroupedBackground
&& other.separator == separator
&& other.opaqueSeparator== opaqueSeparator
&& other.link == link
&& other.systemBlue == systemBlue
&& other.systemGreen == systemGreen
&& other.systemIndigo == systemIndigo
&& other.systemOrange == systemOrange
&& other.systemPink == systemPink
&& other.systemPurple == systemPurple
&& other.systemRed == systemRed
&& other.systemTeal == systemTeal
&& other.systemYellow == systemYellow
&& other.systemGray == systemGray
&& other.systemGray2 == systemGray2
&& other.systemGray3 == systemGray3
&& other.systemGray4 == systemGray4
&& other.systemGray5 == systemGray5
&& other.systemGray6 == systemGray6;
}
@override
int get hashCode {
return hashList(
<Color>[
label,
secondaryLabel,
tertiaryLabel,
quaternaryLabel,
systemFill,
secondarySystemFill,
tertiarySystemFill,
quaternarySystemFill,
placeholderText,
systemBackground,
secondarySystemBackground,
tertiarySystemBackground,
systemGroupedBackground,
secondarySystemGroupedBackground,
tertiarySystemGroupedBackground,
separator,
opaqueSeparator,
link,
systemBlue,
systemGreen,
systemIndigo,
systemOrange,
systemPink,
systemPurple,
systemRed,
systemTeal,
systemYellow,
systemGray,
systemGray2,
systemGray3,
systemGray4,
systemGray5,
systemGray6,
]);
}
/// Creates a copy of this CupertinoSystemColorsData but with the given fields
/// replace with the new values.
CupertinoSystemColorsData copyWith({
CupertinoDynamicColor label,
CupertinoDynamicColor secondaryLabel,
CupertinoDynamicColor tertiaryLabel,
CupertinoDynamicColor quaternaryLabel,
CupertinoDynamicColor systemFill,
CupertinoDynamicColor secondarySystemFill,
CupertinoDynamicColor tertiarySystemFill,
CupertinoDynamicColor quaternarySystemFill,
CupertinoDynamicColor placeholderText,
CupertinoDynamicColor systemBackground,
CupertinoDynamicColor secondarySystemBackground,
CupertinoDynamicColor tertiarySystemBackground,
CupertinoDynamicColor systemGroupedBackground,
CupertinoDynamicColor secondarySystemGroupedBackground,
CupertinoDynamicColor tertiarySystemGroupedBackground,
CupertinoDynamicColor separator,
CupertinoDynamicColor opaqueSeparator,
CupertinoDynamicColor link,
CupertinoDynamicColor systemBlue,
CupertinoDynamicColor systemGreen,
CupertinoDynamicColor systemIndigo,
CupertinoDynamicColor systemOrange,
CupertinoDynamicColor systemPink,
CupertinoDynamicColor systemPurple,
CupertinoDynamicColor systemRed,
CupertinoDynamicColor systemTeal,
CupertinoDynamicColor systemYellow,
CupertinoDynamicColor systemGray,
CupertinoDynamicColor systemGray2,
CupertinoDynamicColor systemGray3,
CupertinoDynamicColor systemGray4,
CupertinoDynamicColor systemGray5,
CupertinoDynamicColor systemGray6,
}) {
return CupertinoSystemColorsData(
label: label ?? this.label,
secondaryLabel: secondaryLabel ?? this.secondaryLabel,
tertiaryLabel: tertiaryLabel ?? this.tertiaryLabel,
quaternaryLabel: quaternaryLabel ?? this.quaternaryLabel,
systemFill: systemFill ?? this.systemFill,
secondarySystemFill: secondarySystemFill ?? this.secondarySystemFill,
tertiarySystemFill: tertiarySystemFill ?? this.tertiarySystemFill,
quaternarySystemFill: quaternarySystemFill ?? this.quaternarySystemFill,
placeholderText: placeholderText ?? this.placeholderText,
systemBackground: systemBackground ?? this.systemBackground,
secondarySystemBackground: secondarySystemBackground ?? this.secondarySystemBackground,
tertiarySystemBackground: tertiarySystemBackground ?? this.tertiarySystemBackground,
systemGroupedBackground: systemGroupedBackground ?? this.systemGroupedBackground,
secondarySystemGroupedBackground: secondarySystemGroupedBackground ?? this.secondarySystemGroupedBackground,
tertiarySystemGroupedBackground: tertiarySystemGroupedBackground ?? this.tertiarySystemGroupedBackground,
separator: separator ?? this.separator,
opaqueSeparator: opaqueSeparator ?? this.opaqueSeparator,
link: link ?? this.link,
systemBlue: systemBlue ?? this.systemBlue,
systemGreen: systemGreen ?? this.systemGreen,
systemIndigo: systemIndigo ?? this.systemIndigo,
systemOrange: systemOrange ?? this.systemOrange,
systemPink: systemPink ?? this.systemPink,
systemPurple: systemPurple ?? this.systemPurple,
systemRed: systemRed ?? this.systemRed,
systemTeal: systemTeal ?? this.systemTeal,
systemYellow: systemYellow ?? this.systemYellow,
systemGray: systemGray ?? this.systemGray,
systemGray2: systemGray2 ?? this.systemGray2,
systemGray3: systemGray3 ?? this.systemGray3,
systemGray4: systemGray4 ?? this.systemGray4,
systemGray5: systemGray5 ?? this.systemGray5,
systemGray6: systemGray6 ?? this.systemGray6,
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(ColorProperty('label', label));
properties.add(ColorProperty('secondaryLabel', secondaryLabel));
properties.add(ColorProperty('tertiaryLabel', tertiaryLabel));
properties.add(ColorProperty('quaternaryLabel', quaternaryLabel));
properties.add(ColorProperty('systemFill', systemFill));
properties.add(ColorProperty('secondarySystemFill', secondarySystemFill));
properties.add(ColorProperty('tertiarySystemFill', tertiarySystemFill));
properties.add(ColorProperty('quaternarySystemFill', quaternarySystemFill));
properties.add(ColorProperty('placeholderText', placeholderText));
properties.add(ColorProperty('systemBackground', systemBackground));
properties.add(ColorProperty('secondarySystemBackground', secondarySystemBackground));
properties.add(ColorProperty('tertiarySystemBackground', tertiarySystemBackground));
properties.add(ColorProperty('systemGroupedBackground', systemGroupedBackground));
properties.add(ColorProperty('secondarySystemGroupedBackground', secondarySystemGroupedBackground));
properties.add(ColorProperty('tertiarySystemGroupedBackground', tertiarySystemGroupedBackground));
properties.add(ColorProperty('separator', separator));
properties.add(ColorProperty('opaqueSeparator', opaqueSeparator));
properties.add(ColorProperty('link', link));
properties.add(ColorProperty('systemBlue', systemBlue));
properties.add(ColorProperty('systemGreen', systemGreen));
properties.add(ColorProperty('systemIndigo', systemIndigo));
properties.add(ColorProperty('systemOrange', systemOrange));
properties.add(ColorProperty('systemPink', systemPink));
properties.add(ColorProperty('systemPurple', systemPurple));
properties.add(ColorProperty('systemRed', systemRed));
properties.add(ColorProperty('systemTeal', systemTeal));
properties.add(ColorProperty('systemYellow', systemYellow));
properties.add(ColorProperty('systemGray', systemGray));
properties.add(ColorProperty('systemGray2', systemGray2));
properties.add(ColorProperty('systemGray3', systemGray3));
properties.add(ColorProperty('systemGray4', systemGray4));
properties.add(ColorProperty('systemGray5', systemGray5));
properties.add(ColorProperty('systemGray6', systemGray6));
}
}
/// Establishes a subtree where iOS system colors resolve to the given data.
///
/// Typically the given [CupertinoSystemColorsData] is resolved against its own
/// [BuildContext] using [CupertinoSystemColorsData.resolveColors].
class CupertinoSystemColors extends InheritedWidget {
/// Creates a widget that provides a given [CupertinoSystemColorsData] to its
/// descendants.
const CupertinoSystemColors({
Key key,
@required CupertinoSystemColorsData data,
Widget child,
}) : _data = data,
assert(data != null),
super(key: key, child: child);
final CupertinoSystemColorsData _data;
@override
bool updateShouldNotify(CupertinoSystemColors oldWidget) => oldWidget._data != _data;
/// Retrieves the iOS system colors from the given [BuildContext].
///
/// Falls back to [fromSystem] if a [CupertinoSystemColors] widget couldn't be
/// found in the ancestry tree. When [fromSystem] returns null, setting [useFallbackValues]
/// to true will make the method return a set of default system colors extracted
/// from iOS 13 beta.
static CupertinoSystemColorsData of(BuildContext context, { bool useFallbackValues = true }) {
assert(context != null);
assert(useFallbackValues != null);
final CupertinoSystemColors widget = context.inheritFromWidgetOfExactType(CupertinoSystemColors);
return widget?._data ?? (useFallbackValues ? fallbackValues : null);
}
/// Fallback System Colors, extracted from:
/// https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color/#dynamic-system-colors
/// and iOS 13 beta.
@visibleForTesting
static CupertinoSystemColorsData get fallbackValues {
return CupertinoSystemColorsData(
label: CupertinoDynamicColor(
color: const Color.fromARGB(255, 0, 0, 0),
darkColor: const Color.fromARGB(255, 255, 255, 255),
highContrastColor: const Color.fromARGB(255, 0, 0, 0),
darkHighContrastColor: const Color.fromARGB(255, 255, 255, 255),
elevatedColor: const Color.fromARGB(255, 0, 0, 0),
darkElevatedColor: const Color.fromARGB(255, 255, 255, 255),
highContrastElevatedColor: const Color.fromARGB(255, 0, 0, 0),
darkHighContrastElevatedColor: const Color.fromARGB(255, 255, 255, 255),
),
secondaryLabel: CupertinoDynamicColor(
color: const Color.fromARGB(255, 0, 0, 0),
darkColor: const Color.fromARGB(255, 255, 255, 255),
highContrastColor: const Color.fromARGB(255, 0, 0, 0),
darkHighContrastColor: const Color.fromARGB(255, 255, 255, 255),
elevatedColor: const Color.fromARGB(255, 0, 0, 0),
darkElevatedColor: const Color.fromARGB(255, 255, 255, 255),
highContrastElevatedColor: const Color.fromARGB(255, 0, 0, 0),
darkHighContrastElevatedColor: const Color.fromARGB(255, 255, 255, 255),
),
tertiaryLabel: CupertinoDynamicColor(
color: const Color.fromARGB(76, 60, 60, 67),
darkColor: const Color.fromARGB(76, 235, 235, 245),
highContrastColor: const Color.fromARGB(96, 60, 60, 67),
darkHighContrastColor: const Color.fromARGB(96, 235, 235, 245),
elevatedColor: const Color.fromARGB(76, 60, 60, 67),
darkElevatedColor: const Color.fromARGB(76, 235, 235, 245),
highContrastElevatedColor: const Color.fromARGB(96, 60, 60, 67),
darkHighContrastElevatedColor: const Color.fromARGB(96, 235, 235, 245),
),
quaternaryLabel: CupertinoDynamicColor(
color: const Color.fromARGB(45, 60, 60, 67),
darkColor: const Color.fromARGB(40, 235, 235, 245),
highContrastColor: const Color.fromARGB(66, 60, 60, 67),
darkHighContrastColor: const Color.fromARGB(61, 235, 235, 245),
elevatedColor: const Color.fromARGB(45, 60, 60, 67),
darkElevatedColor: const Color.fromARGB(40, 235, 235, 245),
highContrastElevatedColor: const Color.fromARGB(66, 60, 60, 67),
darkHighContrastElevatedColor: const Color.fromARGB(61, 235, 235, 245),
),
systemFill: CupertinoDynamicColor(
color: const Color.fromARGB(51, 120, 120, 128),
darkColor: const Color.fromARGB(91, 120, 120, 128),
highContrastColor: const Color.fromARGB(71, 120, 120, 128),
darkHighContrastColor: const Color.fromARGB(112, 120, 120, 128),
elevatedColor: const Color.fromARGB(51, 120, 120, 128),
darkElevatedColor: const Color.fromARGB(91, 120, 120, 128),
highContrastElevatedColor: const Color.fromARGB(71, 120, 120, 128),
darkHighContrastElevatedColor: const Color.fromARGB(112, 120, 120, 128),
),
secondarySystemFill: CupertinoDynamicColor(
color: const Color.fromARGB(153, 60, 60, 67),
darkColor: const Color.fromARGB(153, 235, 235, 245),
highContrastColor: const Color.fromARGB(173, 60, 60, 67),
darkHighContrastColor: const Color.fromARGB(173, 235, 235, 245),
elevatedColor: const Color.fromARGB(153, 60, 60, 67),
darkElevatedColor: const Color.fromARGB(153, 235, 235, 245),
highContrastElevatedColor: const Color.fromARGB(173, 60, 60, 67),
darkHighContrastElevatedColor: const Color.fromARGB(173, 235, 235, 245),
),
tertiarySystemFill: CupertinoDynamicColor(
color: const Color.fromARGB(30, 118, 118, 128),
darkColor: const Color.fromARGB(61, 118, 118, 128),
highContrastColor: const Color.fromARGB(51, 118, 118, 128),
darkHighContrastColor: const Color.fromARGB(81, 118, 118, 128),
elevatedColor: const Color.fromARGB(30, 118, 118, 128),
darkElevatedColor: const Color.fromARGB(61, 118, 118, 128),
highContrastElevatedColor: const Color.fromARGB(51, 118, 118, 128),
darkHighContrastElevatedColor: const Color.fromARGB(81, 118, 118, 128),
),
quaternarySystemFill: CupertinoDynamicColor(
color: const Color.fromARGB(20, 116, 116, 128),
darkColor: const Color.fromARGB(45, 118, 118, 128),
highContrastColor: const Color.fromARGB(40, 116, 116, 128),
darkHighContrastColor: const Color.fromARGB(66, 118, 118, 128),
elevatedColor: const Color.fromARGB(20, 116, 116, 128),
darkElevatedColor: const Color.fromARGB(45, 118, 118, 128),
highContrastElevatedColor: const Color.fromARGB(40, 116, 116, 128),
darkHighContrastElevatedColor: const Color.fromARGB(66, 118, 118, 128),
),
placeholderText: CupertinoDynamicColor(
color: const Color.fromARGB(76, 60, 60, 67),
darkColor: const Color.fromARGB(76, 235, 235, 245),
highContrastColor: const Color.fromARGB(96, 60, 60, 67),
darkHighContrastColor: const Color.fromARGB(96, 235, 235, 245),
elevatedColor: const Color.fromARGB(76, 60, 60, 67),
darkElevatedColor: const Color.fromARGB(76, 235, 235, 245),
highContrastElevatedColor: const Color.fromARGB(96, 60, 60, 67),
darkHighContrastElevatedColor: const Color.fromARGB(96, 235, 235, 245),
),
systemBackground: CupertinoDynamicColor(
color: const Color.fromARGB(255, 255, 255, 255),
darkColor: const Color.fromARGB(255, 0, 0, 0),
highContrastColor: const Color.fromARGB(255, 255, 255, 255),
darkHighContrastColor: const Color.fromARGB(255, 0, 0, 0),
elevatedColor: const Color.fromARGB(255, 255, 255, 255),
darkElevatedColor: const Color.fromARGB(255, 28, 28, 30),
highContrastElevatedColor: const Color.fromARGB(255, 255, 255, 255),
darkHighContrastElevatedColor: const Color.fromARGB(255, 36, 36, 38),
),
secondarySystemBackground: CupertinoDynamicColor(
color: const Color.fromARGB(255, 242, 242, 247),
darkColor: const Color.fromARGB(255, 28, 28, 30),
highContrastColor: const Color.fromARGB(255, 235, 235, 240),
darkHighContrastColor: const Color.fromARGB(255, 36, 36, 38),
elevatedColor: const Color.fromARGB(255, 242, 242, 247),
darkElevatedColor: const Color.fromARGB(255, 44, 44, 46),
highContrastElevatedColor: const Color.fromARGB(255, 235, 235, 240),
darkHighContrastElevatedColor: const Color.fromARGB(255, 54, 54, 56),
),
tertiarySystemBackground: CupertinoDynamicColor(
color: const Color.fromARGB(255, 255, 255, 255),
darkColor: const Color.fromARGB(255, 44, 44, 46),
highContrastColor: const Color.fromARGB(255, 255, 255, 255),
darkHighContrastColor: const Color.fromARGB(255, 54, 54, 56),
elevatedColor: const Color.fromARGB(255, 255, 255, 255),
darkElevatedColor: const Color.fromARGB(255, 58, 58, 60),
highContrastElevatedColor: const Color.fromARGB(255, 255, 255, 255),
darkHighContrastElevatedColor: const Color.fromARGB(255, 68, 68, 70),
),
systemGroupedBackground: CupertinoDynamicColor(
color: const Color.fromARGB(255, 242, 242, 247),
darkColor: const Color.fromARGB(255, 0, 0, 0),
highContrastColor: const Color.fromARGB(255, 235, 235, 240),
darkHighContrastColor: const Color.fromARGB(255, 0, 0, 0),
elevatedColor: const Color.fromARGB(255, 242, 242, 247),
darkElevatedColor: const Color.fromARGB(255, 28, 28, 30),
highContrastElevatedColor: const Color.fromARGB(255, 235, 235, 240),
darkHighContrastElevatedColor: const Color.fromARGB(255, 36, 36, 38),
),
secondarySystemGroupedBackground: CupertinoDynamicColor(
color: const Color.fromARGB(255, 242, 242, 247),
darkColor: const Color.fromARGB(255, 0, 0, 0),
highContrastColor: const Color.fromARGB(255, 235, 235, 240),
darkHighContrastColor: const Color.fromARGB(255, 0, 0, 0),
elevatedColor: const Color.fromARGB(255, 242, 242, 247),
darkElevatedColor: const Color.fromARGB(255, 28, 28, 30),
highContrastElevatedColor: const Color.fromARGB(255, 235, 235, 240),
darkHighContrastElevatedColor: const Color.fromARGB(255, 36, 36, 38),
),
tertiarySystemGroupedBackground: CupertinoDynamicColor(
color: const Color.fromARGB(255, 242, 242, 247),
darkColor: const Color.fromARGB(255, 44, 44, 46),
highContrastColor: const Color.fromARGB(255, 235, 235, 240),
darkHighContrastColor: const Color.fromARGB(255, 54, 54, 56),
elevatedColor: const Color.fromARGB(255, 242, 242, 247),
darkElevatedColor: const Color.fromARGB(255, 58, 58, 60),
highContrastElevatedColor: const Color.fromARGB(255, 235, 235, 240),
darkHighContrastElevatedColor: const Color.fromARGB(255, 68, 68, 70),
),
separator: CupertinoDynamicColor(
color: const Color.fromARGB(73, 60, 60, 67),
darkColor: const Color.fromARGB(153, 84, 84, 88),
highContrastColor: const Color.fromARGB(94, 60, 60, 67),
darkHighContrastColor: const Color.fromARGB(173, 84, 84, 88),
elevatedColor: const Color.fromARGB(73, 60, 60, 67),
darkElevatedColor: const Color.fromARGB(153, 84, 84, 88),
highContrastElevatedColor: const Color.fromARGB(94, 60, 60, 67),
darkHighContrastElevatedColor: const Color.fromARGB(173, 84, 84, 88),
),
opaqueSeparator: CupertinoDynamicColor(
color: const Color.fromARGB(255, 198, 198, 200),
darkColor: const Color.fromARGB(255, 56, 56, 58),
highContrastColor: const Color.fromARGB(255, 198, 198, 200),
darkHighContrastColor: const Color.fromARGB(255, 56, 56, 58),
elevatedColor: const Color.fromARGB(255, 198, 198, 200),
darkElevatedColor: const Color.fromARGB(255, 56, 56, 58),
highContrastElevatedColor: const Color.fromARGB(255, 198, 198, 200),
darkHighContrastElevatedColor: const Color.fromARGB(255, 56, 56, 58),
),
link: CupertinoDynamicColor(
color: const Color.fromARGB(255, 0, 122, 255),
darkColor: const Color.fromARGB(255, 9, 132, 255),
highContrastColor: const Color.fromARGB(255, 0, 122, 255),
darkHighContrastColor: const Color.fromARGB(255, 9, 132, 255),
elevatedColor: const Color.fromARGB(255, 0, 122, 255),
darkElevatedColor: const Color.fromARGB(255, 9, 132, 255),
highContrastElevatedColor: const Color.fromARGB(255, 0, 122, 255),
darkHighContrastElevatedColor: const Color.fromARGB(255, 9, 132, 255),
),
systemBlue: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 0, 122, 255),
darkColor: const Color.fromARGB(255, 10, 132, 255),
highContrastColor: const Color.fromARGB(255, 0, 64, 221),
darkHighContrastColor: const Color.fromARGB(255, 64, 156, 255),
),
systemGreen: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 52, 199, 89),
darkColor: const Color.fromARGB(255, 48, 209, 88),
highContrastColor: const Color.fromARGB(255, 36, 138, 61),
darkHighContrastColor: const Color.fromARGB(255, 48, 219, 91),
),
systemIndigo: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 88, 86, 214),
darkColor: const Color.fromARGB(255, 94, 92, 230),
highContrastColor: const Color.fromARGB(255, 54, 52, 163),
darkHighContrastColor: const Color.fromARGB(255, 125, 122, 255),
),
systemOrange: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 255, 149, 0),
darkColor: const Color.fromARGB(255, 255, 159, 10),
highContrastColor: const Color.fromARGB(255, 201, 52, 0),
darkHighContrastColor: const Color.fromARGB(255, 255, 179, 64),
),
systemPink: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 255, 45, 85),
darkColor: const Color.fromARGB(255, 255, 55, 95),
highContrastColor: const Color.fromARGB(255, 211, 15, 69),
darkHighContrastColor: const Color.fromARGB(255, 255, 100, 130),
),
systemPurple: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 175, 82, 222),
darkColor: const Color.fromARGB(255, 191, 90, 242),
highContrastColor: const Color.fromARGB(255, 137, 68, 171),
darkHighContrastColor: const Color.fromARGB(255, 218, 143, 255),
),
systemRed: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 255, 59, 48),
darkColor: const Color.fromARGB(255, 255, 69, 58),
highContrastColor: const Color.fromARGB(255, 215, 0, 21),
darkHighContrastColor: const Color.fromARGB(255, 255, 105, 97),
),
systemTeal: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 90, 200, 250),
darkColor: const Color.fromARGB(255, 100, 210, 255),
highContrastColor: const Color.fromARGB(255, 0, 113, 164),
darkHighContrastColor: const Color.fromARGB(255, 112, 215, 255),
),
systemYellow: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 255, 204, 0),
darkColor: const Color.fromARGB(255, 255, 214, 10),
highContrastColor: const Color.fromARGB(255, 160, 90, 0),
darkHighContrastColor: const Color.fromARGB(255, 255, 212, 38),
),
systemGray: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 142, 142, 147),
darkColor: const Color.fromARGB(255, 142, 142, 147),
highContrastColor: const Color.fromARGB(255, 108, 108, 112),
darkHighContrastColor: const Color.fromARGB(255, 174, 174, 178),
),
systemGray2: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 174, 174, 178),
darkColor: const Color.fromARGB(255, 99, 99, 102),
highContrastColor: const Color.fromARGB(255, 142, 142, 147),
darkHighContrastColor: const Color.fromARGB(255, 124, 124, 128),
),
systemGray3: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 199, 199, 204),
darkColor: const Color.fromARGB(255, 72, 72, 74),
highContrastColor: const Color.fromARGB(255, 174, 174, 178),
darkHighContrastColor: const Color.fromARGB(255, 84, 84, 86),
),
systemGray4: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 209, 209, 214),
darkColor: const Color.fromARGB(255, 58, 58, 60),
highContrastColor: const Color.fromARGB(255, 188, 188, 192),
darkHighContrastColor: const Color.fromARGB(255, 68, 68, 70),
),
systemGray5: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 229, 229, 234),
darkColor: const Color.fromARGB(255, 44, 44, 46),
highContrastColor: const Color.fromARGB(255, 216, 216, 220),
darkHighContrastColor: const Color.fromARGB(255, 54, 54, 56),
),
systemGray6: CupertinoDynamicColor.withBrightnessAndContrast(
color: const Color.fromARGB(255, 242, 242, 247),
darkColor: const Color.fromARGB(255, 28, 28, 30),
highContrastColor: const Color.fromARGB(255, 235, 235, 240),
darkHighContrastColor: const Color.fromARGB(255, 36, 36, 38),
),
);
}
}
// Copyright 2019 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 '../widgets/framework.dart';
/// Indicates the visual level for a piece of content. Equivalent to `UIUserInterfaceLevel`
/// from `UIKit`.
///
/// See also:
///
/// * `UIUserInterfaceLevel`, the UIKit equivalent: https://developer.apple.com/documentation/uikit/uiuserinterfacelevel.
enum CupertinoUserInterfaceLevelData {
/// The level for your window's main content.
base,
/// The level for content visually above [base].
elevated,
}
/// Establishes a subtree in which [CupertinoUserInterfaceLevel.of] resolves to
/// the given data.
///
/// Querying the current elevation status using [CupertinoUserInterfaceLevel.of]
/// will cause your widget to rebuild automatically whenever the [CupertinoUserInterfaceLevelData]
/// changes.
///
/// If no [CupertinoUserInterfaceLevel] is in scope then the [CupertinoUserInterfaceLevel.of]
/// method will throw an exception, unless the `nullOk` argument is set to true,
/// in which case it returns null.
///
/// See also:
///
/// * [CupertinoUserInterfaceLevelData], specifies the visual level for the content
/// in the subtree [CupertinoUserInterfaceLevel] established.
class CupertinoUserInterfaceLevel extends InheritedWidget {
/// Creates a [CupertinoUserInterfaceLevel] to change descendant Cupertino widget's
/// visual level.
const CupertinoUserInterfaceLevel({
Key key,
@required CupertinoUserInterfaceLevelData data,
Widget child,
}) : assert(data != null),
_data = data,
super(key: key, child: child);
final CupertinoUserInterfaceLevelData _data;
@override
bool updateShouldNotify(CupertinoUserInterfaceLevel oldWidget) => oldWidget._data != _data;
/// The data from the closest instance of this class that encloses the given
/// context.
///
/// You can use this function to query the user interface elevation level within
/// the given [BuildContext]. When that information changes, your widget will
/// be scheduled to be rebuilt, keeping your widget up-to-date.
static CupertinoUserInterfaceLevelData of(BuildContext context, { bool nullOk = false }) {
assert(context != null);
assert(nullOk != null);
final CupertinoUserInterfaceLevel query = context.inheritFromWidgetOfExactType(CupertinoUserInterfaceLevel);
if (query != null)
return query._data;
if (nullOk)
return null;
throw FlutterError(
'CupertinoUserInterfaceLevel.of() called with a context that does not contain a CupertinoUserInterfaceLevel.\n'
'No CupertinoUserInterfaceLevel ancestor could be found starting from the context that was passed '
'to CupertinoUserInterfaceLevel.of(). This can happen because you do not have a WidgetsApp or '
'MaterialApp widget (those widgets introduce a CupertinoUserInterfaceLevel), or it can happen '
'if the context you use comes from a widget above those widgets.\n'
'The context used was:\n'
' $context'
);
}
}
......@@ -9,6 +9,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
import 'theme.dart';
import 'thumb_painter.dart';
......@@ -228,7 +229,10 @@ class _CupertinoSliderState extends State<CupertinoSlider> with TickerProviderSt
return _CupertinoSliderRenderObjectWidget(
value: (widget.value - widget.min) / (widget.max - widget.min),
divisions: widget.divisions,
activeColor: widget.activeColor ?? CupertinoTheme.of(context).primaryColor,
activeColor: CupertinoDynamicColor.resolve(
widget.activeColor ?? CupertinoTheme.of(context).primaryColor,
context
),
onChanged: widget.onChanged != null ? _handleChanged : null,
onChangeStart: widget.onChangeStart != null ? _handleDragStart : null,
onChangeEnd: widget.onChangeEnd != null ? _handleDragEnd : null,
......@@ -257,12 +261,14 @@ class _CupertinoSliderRenderObjectWidget extends LeafRenderObjectWidget {
final ValueChanged<double> onChangeEnd;
final TickerProvider vsync;
@override
_RenderCupertinoSlider createRenderObject(BuildContext context) {
return _RenderCupertinoSlider(
value: value,
divisions: divisions,
activeColor: activeColor,
trackColor: CupertinoDynamicColor.resolve(CupertinoSystemColors.of(context).systemFill, context),
onChanged: onChanged,
onChangeStart: onChangeStart,
onChangeEnd: onChangeEnd,
......@@ -277,6 +283,7 @@ class _CupertinoSliderRenderObjectWidget extends LeafRenderObjectWidget {
..value = value
..divisions = divisions
..activeColor = activeColor
..trackColor = CupertinoDynamicColor.resolve(CupertinoSystemColors.of(context).systemFill, context)
..onChanged = onChanged
..onChangeStart = onChangeStart
..onChangeEnd = onChangeEnd
......@@ -287,7 +294,6 @@ class _CupertinoSliderRenderObjectWidget extends LeafRenderObjectWidget {
}
const double _kPadding = 8.0;
const Color _kTrackColor = Color(0xFFB5B5B5);
const double _kSliderHeight = 2.0 * (CupertinoThumbPainter.radius + _kPadding);
const double _kSliderWidth = 176.0; // Matches Material Design slider.
const Duration _kDiscreteTransitionDuration = Duration(milliseconds: 500);
......@@ -299,6 +305,7 @@ class _RenderCupertinoSlider extends RenderConstrainedBox {
@required double value,
int divisions,
Color activeColor,
Color trackColor,
ValueChanged<double> onChanged,
this.onChangeStart,
this.onChangeEnd,
......@@ -309,6 +316,7 @@ class _RenderCupertinoSlider extends RenderConstrainedBox {
_value = value,
_divisions = divisions,
_activeColor = activeColor,
_trackColor = trackColor,
_onChanged = onChanged,
_textDirection = textDirection,
super(additionalConstraints: const BoxConstraints.tightFor(width: _kSliderWidth, height: _kSliderHeight)) {
......@@ -355,6 +363,15 @@ class _RenderCupertinoSlider extends RenderConstrainedBox {
markNeedsPaint();
}
Color get trackColor => _trackColor;
Color _trackColor;
set trackColor(Color value) {
if (value == _trackColor)
return;
_trackColor = value;
markNeedsPaint();
}
ValueChanged<double> get onChanged => _onChanged;
ValueChanged<double> _onChanged;
set onChanged(ValueChanged<double> value) {
......@@ -468,11 +485,11 @@ class _RenderCupertinoSlider extends RenderConstrainedBox {
case TextDirection.rtl:
visualPosition = 1.0 - _position.value;
leftColor = _activeColor;
rightColor = _kTrackColor;
rightColor = trackColor;
break;
case TextDirection.ltr:
visualPosition = _position.value;
leftColor = _kTrackColor;
leftColor = trackColor;
rightColor = _activeColor;
break;
}
......
......@@ -213,6 +213,32 @@ class CupertinoTextThemeData extends Diagnosticable {
(_isLight ? _kDefaultDateTimePickerLightTextStyle : _kDefaultDateTimePickerDarkTextStyle);
}
/// Returns a copy of the current [CupertinoTextThemeData] with all the colors
/// resolved against the given [BuildContext].
CupertinoTextThemeData resolveFrom(BuildContext context, { bool nullOk = false }) {
Color convertColor(Color color) => color == null ? null : CupertinoDynamicColor.resolve(color, context, nullOk: nullOk);
TextStyle resolveTextStyle(TextStyle textStyle) {
return textStyle?.copyWith(
color: convertColor(textStyle.color),
backgroundColor: convertColor(textStyle.backgroundColor),
decorationColor: convertColor(textStyle.decorationColor),
);
}
return copyWith(
primaryColor: convertColor(_primaryColor),
textStyle: resolveTextStyle(_textStyle),
actionTextStyle: resolveTextStyle(_actionTextStyle),
tabLabelTextStyle: resolveTextStyle(_tabLabelTextStyle),
navTitleTextStyle : resolveTextStyle(_navTitleTextStyle),
navLargeTitleTextStyle: resolveTextStyle(_navLargeTitleTextStyle),
navActionTextStyle: resolveTextStyle(_navActionTextStyle),
pickerTextStyle: resolveTextStyle(_pickerTextStyle),
dateTimePickerTextStyle: resolveTextStyle(_dateTimePickerTextStyle),
);
}
/// Returns a copy of the current [CupertinoTextThemeData] instance with
/// specified overrides.
CupertinoTextThemeData copyWith({
......
......@@ -54,7 +54,20 @@ class CupertinoTheme extends StatelessWidget {
/// exist in the ancestry tree.
static CupertinoThemeData of(BuildContext context) {
final _InheritedCupertinoTheme inheritedTheme = context.inheritFromWidgetOfExactType(_InheritedCupertinoTheme);
return inheritedTheme?.theme?.data ?? const CupertinoThemeData();
return (inheritedTheme?.theme?.data ?? const CupertinoThemeData()).resolveFrom(context, nullOk: true);
}
/// Retrieve the [Brightness] value from the closest ancestor [CupertinoTheme]
/// widget.
///
/// If no ancestral [CupertinoTheme] widget with explicit brightness value could
/// be found, the method will resort to the closest ancestor [MediaQuery] widget.
///
/// Throws an exception if no such [CupertinoTheme] or [MediaQuery] widgets exist
/// in the ancestry tree, unless [nullOk] is set to true.
static Brightness brightnessOf(BuildContext context, { bool nullOk = false }) {
final _InheritedCupertinoTheme inheritedTheme = context.inheritFromWidgetOfExactType(_InheritedCupertinoTheme);
return inheritedTheme?.theme?.data?._brightness ?? MediaQuery.of(context, nullOk: nullOk)?.platformBrightness;
}
/// The widget below this widget in the tree.
......@@ -229,6 +242,23 @@ class CupertinoThemeData extends Diagnosticable {
);
}
/// Return a new `CupertinoThemeData` whose colors are from this `CupertinoThemeData`,
/// but resolved aginst the given [BuildContext].
///
/// It will be called in [CupertinoTheme.of].
@protected
CupertinoThemeData resolveFrom(BuildContext context, { bool nullOk = false }) {
Color convertColor(Color color) => color == null ? null : CupertinoDynamicColor.resolve(color, context, nullOk: nullOk);
return copyWith(
primaryColor: convertColor(primaryColor),
primaryContrastingColor: convertColor(primaryContrastingColor),
textTheme: textTheme?.resolveFrom(context, nullOk: nullOk),
barBackgroundColor: convertColor(barBackgroundColor),
scaffoldBackgroundColor: convertColor(scaffoldBackgroundColor),
);
}
/// Create a copy of [CupertinoThemeData] with specified attributes overridden.
///
/// Only the current instance's specified attributes are copied instead of
......@@ -296,4 +326,39 @@ class _NoDefaultCupertinoThemeData extends CupertinoThemeData {
final Color barBackgroundColor;
@override
final Color scaffoldBackgroundColor;
@override
_NoDefaultCupertinoThemeData resolveFrom(BuildContext context, { bool nullOk = false }) {
Color convertColor(Color color) => color == null
? null
: CupertinoDynamicColor.resolve(color, context, nullOk: nullOk);
return _NoDefaultCupertinoThemeData(
brightness,
convertColor(primaryColor),
convertColor(primaryContrastingColor),
textTheme?.resolveFrom(context, nullOk: nullOk),
convertColor(barBackgroundColor),
convertColor(scaffoldBackgroundColor),
);
}
@override
CupertinoThemeData copyWith({
Brightness brightness,
Color primaryColor,
Color primaryContrastingColor,
CupertinoTextThemeData textTheme,
Color barBackgroundColor ,
Color scaffoldBackgroundColor
}) {
return _NoDefaultCupertinoThemeData(
brightness ?? this.brightness,
primaryColor ?? this.primaryColor,
primaryContrastingColor ?? this.primaryContrastingColor,
textTheme ?? this.textTheme,
barBackgroundColor ?? this.barBackgroundColor,
scaffoldBackgroundColor ?? this.scaffoldBackgroundColor,
);
}
}
......@@ -1416,34 +1416,43 @@ class MaterialBasedCupertinoThemeData extends CupertinoThemeData {
///
/// The [materialTheme] parameter must not be null.
MaterialBasedCupertinoThemeData({
@required ThemeData materialTheme,
}) : assert(materialTheme != null),
_materialTheme = materialTheme,
// Pass all values to the superclass so Material-agnostic properties
// like barBackgroundColor can still behave like a normal
// CupertinoThemeData.
super.raw(
materialTheme.cupertinoOverrideTheme?.brightness,
materialTheme.cupertinoOverrideTheme?.primaryColor,
materialTheme.cupertinoOverrideTheme?.primaryContrastingColor,
materialTheme.cupertinoOverrideTheme?.textTheme,
materialTheme.cupertinoOverrideTheme?.barBackgroundColor,
materialTheme.cupertinoOverrideTheme?.scaffoldBackgroundColor,
);
@required ThemeData materialTheme,
}) : this._(
materialTheme,
(materialTheme.cupertinoOverrideTheme ?? const CupertinoThemeData()).noDefault(),
);
MaterialBasedCupertinoThemeData._(
this._materialTheme,
this._cupertinoOverrideTheme,
) : assert(_materialTheme != null),
assert(_cupertinoOverrideTheme != null),
// Pass all values to the superclass so Material-agnostic properties
// like barBackgroundColor can still behave like a normal
// CupertinoThemeData.
super.raw(
_cupertinoOverrideTheme.brightness,
_cupertinoOverrideTheme.primaryColor,
_cupertinoOverrideTheme.primaryContrastingColor,
_cupertinoOverrideTheme.textTheme,
_cupertinoOverrideTheme.barBackgroundColor,
_cupertinoOverrideTheme.scaffoldBackgroundColor,
);
final ThemeData _materialTheme;
final CupertinoThemeData _cupertinoOverrideTheme;
@override
Brightness get brightness => _materialTheme.cupertinoOverrideTheme?.brightness ?? _materialTheme.brightness;
Brightness get brightness => _cupertinoOverrideTheme.brightness ?? _materialTheme.brightness;
@override
Color get primaryColor => _materialTheme.cupertinoOverrideTheme?.primaryColor ?? _materialTheme.colorScheme.primary;
Color get primaryColor => _cupertinoOverrideTheme.primaryColor ?? _materialTheme.colorScheme.primary;
@override
Color get primaryContrastingColor => _materialTheme.cupertinoOverrideTheme?.primaryContrastingColor ?? _materialTheme.colorScheme.onPrimary;
Color get primaryContrastingColor => _cupertinoOverrideTheme.primaryContrastingColor ?? _materialTheme.colorScheme.onPrimary;
@override
Color get scaffoldBackgroundColor => _materialTheme.cupertinoOverrideTheme?.scaffoldBackgroundColor ?? _materialTheme.scaffoldBackgroundColor;
Color get scaffoldBackgroundColor => _cupertinoOverrideTheme.scaffoldBackgroundColor ?? _materialTheme.scaffoldBackgroundColor;
/// Copies the [ThemeData]'s `cupertinoOverrideTheme`.
///
......@@ -1457,7 +1466,7 @@ class MaterialBasedCupertinoThemeData extends CupertinoThemeData {
/// new Material [Theme] and use `copyWith` on the Material [ThemeData]
/// instead.
@override
CupertinoThemeData copyWith({
MaterialBasedCupertinoThemeData copyWith({
Brightness brightness,
Color primaryColor,
Color primaryContrastingColor,
......@@ -1465,20 +1474,26 @@ class MaterialBasedCupertinoThemeData extends CupertinoThemeData {
Color barBackgroundColor,
Color scaffoldBackgroundColor,
}) {
return _materialTheme.cupertinoOverrideTheme?.copyWith(
brightness: brightness,
primaryColor: primaryColor,
primaryContrastingColor: primaryContrastingColor,
textTheme: textTheme,
barBackgroundColor: barBackgroundColor,
scaffoldBackgroundColor: scaffoldBackgroundColor,
) ?? CupertinoThemeData(
brightness: brightness,
primaryColor: primaryColor,
primaryContrastingColor: primaryContrastingColor,
textTheme: textTheme,
barBackgroundColor: barBackgroundColor,
scaffoldBackgroundColor: scaffoldBackgroundColor,
return MaterialBasedCupertinoThemeData._(
_materialTheme,
_cupertinoOverrideTheme.copyWith(
brightness: brightness,
primaryColor: primaryColor,
primaryContrastingColor: primaryContrastingColor,
textTheme: textTheme,
barBackgroundColor: barBackgroundColor,
scaffoldBackgroundColor: scaffoldBackgroundColor,
),
);
}
@override
CupertinoThemeData resolveFrom(BuildContext context, { bool nullOk = false }) {
// Only the cupertino override theme part will be resolved.
// If the color comes from the material theme it's not resolved.
return MaterialBasedCupertinoThemeData._(
_materialTheme,
_cupertinoOverrideTheme.resolveFrom(context, nullOk: nullOk),
);
}
}
......
......@@ -98,6 +98,7 @@ class MediaQueryData {
this.alwaysUse24HourFormat = false,
this.accessibleNavigation = false,
this.invertColors = false,
this.highContrast = false,
this.disableAnimations = false,
this.boldText = false,
});
......@@ -121,6 +122,7 @@ class MediaQueryData {
invertColors = window.accessibilityFeatures.invertColors,
disableAnimations = window.accessibilityFeatures.disableAnimations,
boldText = window.accessibilityFeatures.boldText,
highContrast = false,
alwaysUse24HourFormat = window.alwaysUse24HourFormat;
/// The size of the media in logical pixels (e.g, the size of the screen).
......@@ -259,6 +261,13 @@ class MediaQueryData {
/// * [Window.AccessibilityFeatures], where the setting originates.
final bool invertColors;
/// Whether the user requested a high contrast between foreground and background
/// content on iOS, via Settings -> Accessibility -> Increase Contrast.
///
/// This flag is currently only updated on iOS devices that are running iOS 13
/// or above.
final bool highContrast;
/// Whether the platform is requesting that animations be disabled or reduced
/// as much as possible.
///
......@@ -293,6 +302,7 @@ class MediaQueryData {
EdgeInsets viewInsets,
double physicalDepth,
bool alwaysUse24HourFormat,
bool highContrast,
bool disableAnimations,
bool invertColors,
bool accessibleNavigation,
......@@ -309,6 +319,7 @@ class MediaQueryData {
physicalDepth: physicalDepth ?? this.physicalDepth,
alwaysUse24HourFormat: alwaysUse24HourFormat ?? this.alwaysUse24HourFormat,
invertColors: invertColors ?? this.invertColors,
highContrast: highContrast ?? this.highContrast,
disableAnimations: disableAnimations ?? this.disableAnimations,
accessibleNavigation: accessibleNavigation ?? this.accessibleNavigation,
boldText: boldText ?? this.boldText,
......@@ -357,6 +368,7 @@ class MediaQueryData {
),
viewInsets: viewInsets,
alwaysUse24HourFormat: alwaysUse24HourFormat,
highContrast: highContrast,
disableAnimations: disableAnimations,
invertColors: invertColors,
accessibleNavigation: accessibleNavigation,
......@@ -404,6 +416,7 @@ class MediaQueryData {
bottom: removeBottom ? 0.0 : null,
),
alwaysUse24HourFormat: alwaysUse24HourFormat,
highContrast: highContrast,
disableAnimations: disableAnimations,
invertColors: invertColors,
accessibleNavigation: accessibleNavigation,
......@@ -451,6 +464,7 @@ class MediaQueryData {
bottom: removeBottom ? 0.0 : null,
),
alwaysUse24HourFormat: alwaysUse24HourFormat,
highContrast: highContrast,
disableAnimations: disableAnimations,
invertColors: invertColors,
accessibleNavigation: accessibleNavigation,
......@@ -472,6 +486,7 @@ class MediaQueryData {
&& typedOther.viewInsets == viewInsets
&& typedOther.physicalDepth == physicalDepth
&& typedOther.alwaysUse24HourFormat == alwaysUse24HourFormat
&& typedOther.highContrast == highContrast
&& typedOther.disableAnimations == disableAnimations
&& typedOther.invertColors == invertColors
&& typedOther.accessibleNavigation == accessibleNavigation
......@@ -490,6 +505,7 @@ class MediaQueryData {
viewInsets,
physicalDepth,
alwaysUse24HourFormat,
highContrast,
disableAnimations,
invertColors,
accessibleNavigation,
......@@ -510,6 +526,7 @@ class MediaQueryData {
'physicalDepth: $physicalDepth, '
'alwaysUse24HourFormat: $alwaysUse24HourFormat, '
'accessibleNavigation: $accessibleNavigation, '
'highContrast: $highContrast,'
'disableAnimations: $disableAnimations, '
'invertColors: $invertColors, '
'boldText: $boldText'
......
// Copyright 2019 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/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart';
import '../rendering/mock_canvas.dart';
class DependentWidget extends StatelessWidget {
const DependentWidget({
Key key,
this.color
}) : super(key: key);
final Color color;
@override
Widget build(BuildContext context) {
final Color resolved = CupertinoDynamicColor.resolve(color, context);
return DecoratedBox(
decoration: BoxDecoration(color: resolved),
child: const SizedBox.expand(),
);
}
}
const Color color0 = Color(0xFF000000);
const Color color1 = Color(0xFF000001);
const Color color2 = Color(0xFF000002);
const Color color3 = Color(0xFF000003);
const Color color4 = Color(0xFF000004);
const Color color5 = Color(0xFF000005);
const Color color6 = Color(0xFF000006);
const Color color7 = Color(0xFF000007);
// A color that depends on color vibrancy, accessibility contrast, as well as user
// interface elevation.
final CupertinoDynamicColor dynamicColor = CupertinoDynamicColor(
color: color0,
darkColor: color1,
elevatedColor: color2,
highContrastColor: color3,
darkElevatedColor: color4,
darkHighContrastColor: color5,
highContrastElevatedColor: color6,
darkHighContrastElevatedColor: color7,
);
// A color that uses [color0] in every circumstance.
final Color notSoDynamicColor1 = CupertinoDynamicColor(
color: color0,
darkColor: color0,
darkHighContrastColor: color0,
darkElevatedColor: color0,
darkHighContrastElevatedColor: color0,
highContrastColor: color0,
highContrastElevatedColor: color0,
elevatedColor: color0,
);
// A color that uses [color1] for light mode, and [color0] for dark mode.
final Color vibrancyDependentColor1 = CupertinoDynamicColor(
color: color1,
elevatedColor: color1,
highContrastColor: color1,
highContrastElevatedColor: color1,
darkColor: color0,
darkHighContrastColor: color0,
darkElevatedColor: color0,
darkHighContrastElevatedColor: color0,
);
// A color that uses [color1] for normal contrast mode, and [color0] for high
// contrast mode.
final Color contrastDependentColor1 = CupertinoDynamicColor(
color: color1,
darkColor: color1,
elevatedColor: color1,
darkElevatedColor: color1,
highContrastColor: color0,
darkHighContrastColor: color0,
highContrastElevatedColor: color0,
darkHighContrastElevatedColor: color0,
);
// A color that uses [color1] for base interface elevation, and [color0] for elevated
// interface elevation.
final Color elevationDependentColor1 = CupertinoDynamicColor(
color: color1,
darkColor: color1,
highContrastColor: color1,
darkHighContrastColor: color1,
elevatedColor: color0,
darkElevatedColor: color0,
highContrastElevatedColor: color0,
darkHighContrastElevatedColor: color0,
);
void main() {
test('== works as expected', () {
expect(dynamicColor, CupertinoDynamicColor(
color: color0,
darkColor: color1,
elevatedColor: color2,
highContrastColor: color3,
darkElevatedColor: color4,
darkHighContrastColor: color5,
highContrastElevatedColor: color6,
darkHighContrastElevatedColor: color7,
)
);
expect(notSoDynamicColor1, isNot(vibrancyDependentColor1));
expect(notSoDynamicColor1, isNot(contrastDependentColor1));
expect(vibrancyDependentColor1, isNot(CupertinoDynamicColor(
color: color0,
elevatedColor: color0,
highContrastColor: color0,
highContrastElevatedColor: color0,
darkColor: color0,
darkHighContrastColor: color0,
darkElevatedColor: color0,
darkHighContrastElevatedColor: color0,
)));
});
test('CupertinoDynamicColor.toString() works', () {
expect(
dynamicColor.toString(),
'CupertinoDynamicColor(*color = Color(0xff000000)*, '
'darkColor = Color(0xff000001), '
'highContrastColor = Color(0xff000003), '
'darkHighContrastColor = Color(0xff000005), '
'elevatedColor = Color(0xff000002), '
'darkElevatedColor = Color(0xff000004), '
'highContrastElevatedColor = Color(0xff000006), '
'darkHighContrastElevatedColor = Color(0xff000007))'
);
expect(notSoDynamicColor1.toString(), 'CupertinoDynamicColor(*color = Color(0xff000000)*)');
expect(vibrancyDependentColor1.toString(), 'CupertinoDynamicColor(*color = Color(0xff000001)*, darkColor = Color(0xff000000))');
expect(contrastDependentColor1.toString(), 'CupertinoDynamicColor(*color = Color(0xff000001)*, highContrastColor = Color(0xff000000))');
expect(elevationDependentColor1.toString(), 'CupertinoDynamicColor(*color = Color(0xff000001)*, elevatedColor = Color(0xff000000))');
expect(
CupertinoDynamicColor.withBrightnessAndContrast(
color: color0,
darkColor: color1,
highContrastColor: color2,
darkHighContrastColor: color3,
).toString(),
'CupertinoDynamicColor(*color = Color(0xff000000)*, '
'darkColor = Color(0xff000001), '
'highContrastColor = Color(0xff000002), '
'darkHighContrastColor = Color(0xff000003))',
);
});
test('withVibrancy constructor creates colors that may depend on vibrancy', () {
expect(vibrancyDependentColor1, CupertinoDynamicColor.withBrightness(
color: color1,
darkColor: color0,
));
});
test('withVibrancyAndContrast constructor creates colors that may depend on contrast and vibrancy', () {
expect(contrastDependentColor1, CupertinoDynamicColor.withBrightnessAndContrast(
color: color1,
darkColor: color1,
highContrastColor: color0,
darkHighContrastColor: color0,
));
expect(CupertinoDynamicColor(
color: color0,
darkColor: color1,
highContrastColor: color2,
darkHighContrastColor: color3,
elevatedColor: color0,
darkElevatedColor: color1,
highContrastElevatedColor: color2,
darkHighContrastElevatedColor: color3,
),
CupertinoDynamicColor.withBrightnessAndContrast(
color: color0,
darkColor: color1,
highContrastColor: color2,
darkHighContrastColor: color3,
));
});
testWidgets('Dynamic colors that are not actually dynamic should not claim dependencies',
(WidgetTester tester) async {
await tester.pumpWidget(DependentWidget(color: notSoDynamicColor1));
expect(tester.takeException(), null);
expect(find.byType(DependentWidget), paints..rect(color: color0));
});
testWidgets(
'Dynamic colors that are only dependent on vibrancy should not claim unnecessary dependencies, '
'and its resolved color should change when its dependency changes',
(WidgetTester tester) async {
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.light),
child: DependentWidget(color: vibrancyDependentColor1),
),
);
expect(tester.takeException(), null);
expect(find.byType(DependentWidget), paints..rect(color: color1));
expect(find.byType(DependentWidget), isNot(paints..rect(color: color0)));
// Changing color vibrancy works.
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark),
child: DependentWidget(color: vibrancyDependentColor1),
),
);
expect(tester.takeException(), null);
expect(find.byType(DependentWidget), paints..rect(color: color0));
expect(find.byType(DependentWidget), isNot(paints..rect(color: color1)));
// CupertinoTheme should take percedence over MediaQuery.
await tester.pumpWidget(
CupertinoTheme(
data: const CupertinoThemeData(brightness: Brightness.light),
child: MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark),
child: DependentWidget(color: vibrancyDependentColor1),
),
),
);
expect(tester.takeException(), null);
expect(find.byType(DependentWidget), paints..rect(color: color1));
expect(find.byType(DependentWidget), isNot(paints..rect(color: color0)));
});
testWidgets(
'Dynamic colors that are only dependent on accessibility contrast should not claim unnecessary dependencies, '
'and its resolved color should change when its dependency changes',
(WidgetTester tester) async {
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(highContrast: false),
child: DependentWidget(color: contrastDependentColor1),
),
);
expect(tester.takeException(), null);
expect(find.byType(DependentWidget), paints..rect(color: color1));
expect(find.byType(DependentWidget), isNot(paints..rect(color: color0)));
// Changing accessibility contrast works.
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(highContrast: true),
child: DependentWidget(color: contrastDependentColor1),
),
);
expect(tester.takeException(), null);
expect(find.byType(DependentWidget), paints..rect(color: color0));
expect(find.byType(DependentWidget), isNot(paints..rect(color: color1)));
// Asserts when the required dependency is missing.
await tester.pumpWidget(DependentWidget(color: contrastDependentColor1));
expect(tester.takeException()?.toString(), contains('does not contain a MediaQuery'));
});
testWidgets(
'Dynamic colors that are only dependent on elevation level should not claim unnecessary dependencies, '
'and its resolved color should change when its dependency changes',
(WidgetTester tester) async {
await tester.pumpWidget(
CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.base,
child: DependentWidget(color: elevationDependentColor1),
),
);
expect(tester.takeException(), null);
expect(find.byType(DependentWidget), paints..rect(color: color1));
expect(find.byType(DependentWidget), isNot(paints..rect(color: color0)));
// Changing UI elevation works.
await tester.pumpWidget(
CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.elevated,
child: DependentWidget(color: elevationDependentColor1),
),
);
expect(tester.takeException(), null);
expect(find.byType(DependentWidget), paints..rect(color: color0));
expect(find.byType(DependentWidget), isNot(paints..rect(color: color1)));
// Asserts when the required dependency is missing.
await tester.pumpWidget(DependentWidget(color: elevationDependentColor1));
expect(tester.takeException()?.toString(), contains('does not contain a CupertinoUserInterfaceLevel'));
});
testWidgets('Dynamic color with all 3 depedencies works', (WidgetTester tester) async {
final Color dynamicRainbowColor1 = CupertinoDynamicColor(
color: color0,
darkColor: color1,
highContrastColor: color2,
darkHighContrastColor: color3,
darkElevatedColor: color4,
highContrastElevatedColor: color5,
darkHighContrastElevatedColor: color6,
elevatedColor: color7,
);
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.light, highContrast: false),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.base,
child: DependentWidget(color: dynamicRainbowColor1),
),
),
);
expect(find.byType(DependentWidget), paints..rect(color: color0));
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark, highContrast: false),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.base,
child: DependentWidget(color: dynamicRainbowColor1),
),
),
);
expect(find.byType(DependentWidget), paints..rect(color: color1));
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.light, highContrast: true),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.base,
child: DependentWidget(color: dynamicRainbowColor1),
),
),
);
expect(find.byType(DependentWidget), paints..rect(color: color2));
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark, highContrast: true),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.base,
child: DependentWidget(color: dynamicRainbowColor1),
),
),
);
expect(find.byType(DependentWidget), paints..rect(color: color3));
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark, highContrast: false),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.elevated,
child: DependentWidget(color: dynamicRainbowColor1),
),
),
);
expect(find.byType(DependentWidget), paints..rect(color: color4));
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.light, highContrast: true),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.elevated,
child: DependentWidget(color: dynamicRainbowColor1),
),
),
);
expect(find.byType(DependentWidget), paints..rect(color: color5));
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark, highContrast: true),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.elevated,
child: DependentWidget(color: dynamicRainbowColor1),
),
),
);
expect(find.byType(DependentWidget), paints..rect(color: color6));
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.light, highContrast: false),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.elevated,
child: DependentWidget(color: dynamicRainbowColor1),
),
),
);
expect(find.byType(DependentWidget), paints..rect(color: color7));
});
group('CupertinoSystemColors widget', () {
CupertinoSystemColorsData colors;
setUp(() { colors = null; });
Widget systemColorGetter(BuildContext context) {
colors = CupertinoSystemColors.of(context);
return const Placeholder();
}
testWidgets('exists in CupertinoApp', (WidgetTester tester) async {
await tester.pumpWidget(CupertinoApp(home: Builder(builder: systemColorGetter)));
expect(colors.systemBackground, CupertinoSystemColors.fallbackValues.systemBackground);
});
testWidgets('resolves against its own BuildContext', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
theme: const CupertinoThemeData(brightness: Brightness.dark),
home: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.elevated,
child: Builder(
builder: (BuildContext context) {
return CupertinoSystemColors(
child: Builder(builder: systemColorGetter),
data: CupertinoSystemColors.of(context).resolveColors(context),
);
},
),
),
),
);
// In widget tests the OS colors should fallback to `fallbackValues`.
expect(colors.systemBackground, isNot(CupertinoSystemColors.fallbackValues.systemBackground));
expect(colors.systemBackground.value, CupertinoSystemColors.fallbackValues.systemBackground.darkElevatedColor.value);
colors = null;
// Changing dependencies works.
await tester.pumpWidget(
CupertinoApp(
theme: const CupertinoThemeData(brightness: Brightness.light),
home: Builder(
builder: (BuildContext context) {
return CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.elevated,
child: CupertinoSystemColors(
child: Builder(builder: systemColorGetter),
data: CupertinoSystemColors.of(context).resolveColors(context),
),
);
},
),
),
);
expect(colors.systemBackground.value, CupertinoSystemColors.fallbackValues.systemBackground.elevatedColor.value);
});
});
testWidgets('CupertinoDynamicColor used in a CupertinoTheme', (WidgetTester tester) async {
CupertinoDynamicColor color;
await tester.pumpWidget(
CupertinoApp(
theme: CupertinoThemeData(
brightness: Brightness.dark,
primaryColor: dynamicColor,
),
home: Builder(
builder: (BuildContext context) {
color = CupertinoTheme.of(context).primaryColor;
return const Placeholder();
}
),
),
);
expect(color.value, dynamicColor.darkColor.value);
// Changing dependencies works.
await tester.pumpWidget(
CupertinoApp(
theme: CupertinoThemeData(
brightness: Brightness.light,
primaryColor: dynamicColor,
),
home: Builder(
builder: (BuildContext context) {
color = CupertinoTheme.of(context).primaryColor;
return const Placeholder();
}
),
),
);
expect(color.value, dynamicColor.color.value);
// Having a dependency below the CupertinoTheme widget works.
await tester.pumpWidget(
CupertinoApp(
theme: CupertinoThemeData(primaryColor: dynamicColor),
home: MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.light, highContrast: false),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.base,
child: Builder(
builder: (BuildContext context) {
color = CupertinoTheme.of(context).primaryColor;
return const Placeholder();
}
),
),
),
),
);
expect(color.value, dynamicColor.color.value);
// Changing dependencies works.
await tester.pumpWidget(
CupertinoApp(
// No brightness is explicitly specified here so it should defer to MediaQuery.
theme: CupertinoThemeData(primaryColor: dynamicColor),
home: MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark, highContrast: true),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.elevated,
child: Builder(
builder: (BuildContext context) {
color = CupertinoTheme.of(context).primaryColor;
return const Placeholder();
}
),
),
),
),
);
expect(color.value, dynamicColor.darkHighContrastElevatedColor.value);
});
group('MaterialApp:', () {
Color color;
setUp(() { color = null; });
testWidgets('dynamic color works in cupertino override theme', (WidgetTester tester) async {
final CupertinoDynamicColor Function() typedColor = () => color;
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
cupertinoOverrideTheme: CupertinoThemeData(
brightness: Brightness.dark,
primaryColor: dynamicColor,
),
),
home: MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.light, highContrast: false),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.base,
child: Builder(
builder: (BuildContext context) {
color = CupertinoTheme.of(context).primaryColor;
return const Placeholder();
}
),
),
),
),
);
// Explicit brightness is respected.
expect(typedColor().value, dynamicColor.darkColor.value);
color = null;
// Changing dependencies works.
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
cupertinoOverrideTheme: CupertinoThemeData(
brightness: Brightness.dark,
primaryColor: dynamicColor,
),
),
home: MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark, highContrast: true),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.elevated,
child: Builder(
builder: (BuildContext context) {
color = CupertinoTheme.of(context).primaryColor;
return const Placeholder();
}
),
),
),
),
);
expect(typedColor().value, dynamicColor.darkHighContrastElevatedColor.value);
});
testWidgets('dynamic color does not work in a material theme', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
// This will create a MaterialBasedCupertinoThemeData with primaryColor set to `dynamicColor`.
theme: ThemeData(colorScheme: ColorScheme.dark(primary: dynamicColor)),
home: MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark, highContrast: true),
child: CupertinoUserInterfaceLevel(
data: CupertinoUserInterfaceLevelData.elevated,
child: Builder(
builder: (BuildContext context) {
color = CupertinoTheme.of(context).primaryColor;
return const Placeholder();
}
),
),
),
),
);
// The color is not resolved.
expect(color, dynamicColor);
expect(color, isNot(dynamicColor.darkHighContrastElevatedColor));
});
});
group('CupertinoSystemColors', () {
final Color dynamicColor0 = CupertinoDynamicColor.withBrightness(
color: const Color(0x00000000),
darkColor: const Color(0x00000000)
);
final Color dynamicColor1 = CupertinoDynamicColor.withBrightness(
color: const Color(0x00000001),
darkColor: const Color(0x00000000)
);
final CupertinoSystemColorsData system0 = CupertinoSystemColorsData(
label: dynamicColor0,
secondaryLabel: dynamicColor0,
tertiaryLabel: dynamicColor0,
quaternaryLabel: dynamicColor0,
systemFill: dynamicColor0,
secondarySystemFill: dynamicColor0,
tertiarySystemFill: dynamicColor0,
quaternarySystemFill: dynamicColor0,
placeholderText: dynamicColor0,
systemBackground: dynamicColor0,
secondarySystemBackground: dynamicColor0,
tertiarySystemBackground: dynamicColor0,
systemGroupedBackground: dynamicColor0,
secondarySystemGroupedBackground: dynamicColor0,
tertiarySystemGroupedBackground: dynamicColor0,
separator: dynamicColor0,
opaqueSeparator: dynamicColor0,
link: dynamicColor0,
systemBlue: dynamicColor0,
systemGreen: dynamicColor0,
systemIndigo: dynamicColor0,
systemOrange: dynamicColor0,
systemPink: dynamicColor0,
systemPurple: dynamicColor0,
systemRed: dynamicColor0,
systemTeal: dynamicColor0,
systemYellow: dynamicColor0,
systemGray: dynamicColor0,
systemGray2: dynamicColor0,
systemGray3: dynamicColor0,
systemGray4: dynamicColor0,
systemGray5: dynamicColor0,
systemGray6: dynamicColor0,
);
test('CupertinoSystemColorsData.== and CupertinoSystemColorsData.copyWith', () {
expect(system0, system0);
expect(system0, system0.copyWith());
expect(system0, system0.copyWith(link: dynamicColor0));
final CupertinoSystemColorsData withDifferentLink = system0.copyWith(link: dynamicColor1);
expect(withDifferentLink.link, dynamicColor1);
expect(system0, isNot(withDifferentLink));
});
test('CupertinoSystemColorsData.hashCode', () {
expect(system0.hashCode, system0.hashCode);
expect(system0.hashCode, system0.copyWith().hashCode);
expect(system0.hashCode, system0.copyWith(link: dynamicColor0).hashCode);
expect(system0.hashCode, isNot(system0.copyWith(link: dynamicColor1).hashCode));
});
test('CupertinoSystemColorsData.debugFillProperties', () {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
system0.debugFillProperties(builder);
expect(
builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList(),
<String>[
'label: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'secondaryLabel: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'tertiaryLabel: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'quaternaryLabel: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemFill: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'secondarySystemFill: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'tertiarySystemFill: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'quaternarySystemFill: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'placeholderText: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemBackground: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'secondarySystemBackground: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'tertiarySystemBackground: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemGroupedBackground: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'secondarySystemGroupedBackground: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'tertiarySystemGroupedBackground: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'separator: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'opaqueSeparator: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'link: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemBlue: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemGreen: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemIndigo: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemOrange: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemPink: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemPurple: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemRed: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemTeal: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemYellow: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemGray: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemGray2: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemGray3: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemGray4: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemGray5: CupertinoDynamicColor(*color = Color(0x00000000)*)',
'systemGray6: CupertinoDynamicColor(*color = Color(0x00000000)*)',
],
);
});
});
}
......@@ -24,26 +24,28 @@ void main() {
final Key sliderKey = UniqueKey();
double value = 0.0;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
),
),
);
},
await tester.pumpWidget(
CupertinoApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() { value = newValue; });
},
),
),
);
},
),
),
),
));
);
expect(value, equals(0.0));
await tester.tap(find.byKey(sliderKey));
......@@ -58,26 +60,28 @@ void main() {
final Key sliderKey = UniqueKey();
double value = 0.0;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.rtl,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
),
),
);
},
await tester.pumpWidget(
CupertinoApp(
home: Directionality(
textDirection: TextDirection.rtl,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() { value = newValue; });
},
),
),
);
},
),
),
),
));
);
expect(value, equals(0.0));
await tester.tap(find.byKey(sliderKey));
......@@ -93,29 +97,31 @@ void main() {
double value = 0.0;
int numberOfTimesOnChangeStartIsCalled = 0;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
onChangeStart: (double value) {
numberOfTimesOnChangeStartIsCalled++;
},
),
),
);
},
await tester.pumpWidget(
CupertinoApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() { value = newValue; });
},
onChangeStart: (double value) {
numberOfTimesOnChangeStartIsCalled++;
},
),
),
);
},
),
),
),
));
);
await _dragSlider(tester, sliderKey);
......@@ -132,29 +138,31 @@ void main() {
double value = 0.0;
int numberOfTimesOnChangeEndIsCalled = 0;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
onChangeEnd: (double value) {
numberOfTimesOnChangeEndIsCalled++;
},
),
),
);
},
await tester.pumpWidget(
CupertinoApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() { value = newValue; });
},
onChangeEnd: (double value) {
numberOfTimesOnChangeEndIsCalled++;
},
),
),
);
},
),
),
),
));
);
await _dragSlider(tester, sliderKey);
......@@ -172,32 +180,34 @@ void main() {
double startValue;
double endValue;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
onChangeStart: (double value) {
startValue = value;
},
onChangeEnd: (double value) {
endValue = value;
},
),
),
);
},
await tester.pumpWidget(
CupertinoApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() { value = newValue; });
},
onChangeStart: (double value) {
startValue = value;
},
onChangeEnd: (double value) {
endValue = value;
},
),
),
);
},
),
),
),
));
);
expect(value, equals(0.0));
......@@ -224,36 +234,34 @@ void main() {
double startValue;
double endValue;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.rtl,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
onChangeStart: (double value) {
setState(() {
startValue = value;
});
},
onChangeEnd: (double value) {
setState(() {
endValue = value;
});
},
),
),
);
},
await tester.pumpWidget(
CupertinoApp(
home: Directionality(
textDirection: TextDirection.rtl,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() { value = newValue; });
},
onChangeStart: (double value) {
setState(() { startValue = value; });
},
onChangeEnd: (double value) {
setState(() { endValue = value; });
},
),
),
);
},
),
),
),
));
);
expect(value, equals(0.0));
......@@ -277,13 +285,18 @@ void main() {
testWidgets('Slider Semantics', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: CupertinoSlider(
value: 0.5,
onChanged: (double v) { },
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(),
child: Directionality(
textDirection: TextDirection.ltr,
child: CupertinoSlider(
value: 0.5,
onChanged: (double v) { },
),
),
),
));
);
expect(semantics, hasSemantics(
TestSemantics.root(
......@@ -296,20 +309,25 @@ void main() {
textDirection: TextDirection.ltr,
actions: SemanticsAction.decrease.index | SemanticsAction.increase.index,
),
]
],
),
ignoreRect: true,
ignoreTransform: true,
));
// Disable slider
await tester.pumpWidget(const Directionality(
textDirection: TextDirection.ltr,
child: CupertinoSlider(
value: 0.5,
onChanged: null,
await tester.pumpWidget(
const MediaQuery(
data: MediaQueryData(),
child: Directionality(
textDirection: TextDirection.ltr,
child: CupertinoSlider(
value: 0.5,
onChanged: null,
),
),
),
));
);
expect(semantics, hasSemantics(
TestSemantics.root(),
......@@ -323,13 +341,17 @@ void main() {
testWidgets('Slider Semantics can be updated', (WidgetTester tester) async {
final SemanticsHandle handle = tester.ensureSemantics();
double value = 0.5;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: CupertinoSlider(
value: value,
onChanged: (double v) { },
await tester.pumpWidget(
CupertinoApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: CupertinoSlider(
value: value,
onChanged: (double v) { },
),
),
),
));
);
expect(tester.getSemantics(find.byType(CupertinoSlider)), matchesSemantics(
hasIncreaseAction: true,
......@@ -341,13 +363,17 @@ void main() {
));
value = 0.6;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: CupertinoSlider(
value: value,
onChanged: (double v) { },
await tester.pumpWidget(
CupertinoApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: CupertinoSlider(
value: value,
onChanged: (double v) { },
),
),
),
));
);
expect(tester.getSemantics(find.byType(CupertinoSlider)), matchesSemantics(
hasIncreaseAction: true,
......@@ -413,4 +439,108 @@ void main() {
paints..rrect(color: CupertinoColors.activeGreen),
);
});
testWidgets('Themes can be overridden by dynamic colors', (WidgetTester tester) async {
final CupertinoDynamicColor activeColor = CupertinoDynamicColor(
color: const Color(0x00000001),
darkColor: const Color(0x00000002),
elevatedColor: const Color(0x00000003),
highContrastColor: const Color(0x00000004),
darkElevatedColor: const Color(0x00000005),
darkHighContrastColor: const Color(0x00000006),
highContrastElevatedColor: const Color(0x00000007),
darkHighContrastElevatedColor: const Color(0x00000008),
);
Widget withTraits(Brightness brightness, CupertinoUserInterfaceLevelData level, bool highContrast) {
return CupertinoTheme(
data: CupertinoThemeData(brightness: brightness),
child: CupertinoUserInterfaceLevel(
data: level,
child: MediaQuery(
data: MediaQueryData(highContrast: highContrast),
child: Center(
child: CupertinoSlider(
activeColor: activeColor,
onChanged: (double value) { },
value: 0.5,
),
),
),
),
);
}
await tester.pumpWidget(CupertinoApp(home: withTraits(Brightness.light, CupertinoUserInterfaceLevelData.base, false)));
expect(find.byType(CupertinoSlider), paints..rrect(color: activeColor.color));
await tester.pumpWidget(CupertinoApp(home: withTraits(Brightness.dark, CupertinoUserInterfaceLevelData.base, false)));
expect(find.byType(CupertinoSlider), paints..rrect(color: activeColor.darkColor));
await tester.pumpWidget(CupertinoApp(home: withTraits(Brightness.dark, CupertinoUserInterfaceLevelData.elevated, false)));
expect(find.byType(CupertinoSlider), paints..rrect(color: activeColor.darkElevatedColor));
await tester.pumpWidget(CupertinoApp(home: withTraits(Brightness.dark, CupertinoUserInterfaceLevelData.base, true)));
expect(find.byType(CupertinoSlider), paints..rrect(color: activeColor.darkHighContrastColor));
await tester.pumpWidget(CupertinoApp(home: withTraits(Brightness.dark, CupertinoUserInterfaceLevelData.elevated, true)));
expect(find.byType(CupertinoSlider), paints..rrect(color: activeColor.darkHighContrastElevatedColor));
await tester.pumpWidget(CupertinoApp(home: withTraits(Brightness.light, CupertinoUserInterfaceLevelData.base, true)));
expect(find.byType(CupertinoSlider), paints..rrect(color: activeColor.highContrastColor));
await tester.pumpWidget(CupertinoApp(home: withTraits(Brightness.light, CupertinoUserInterfaceLevelData.elevated, false)));
expect(find.byType(CupertinoSlider), paints..rrect(color: activeColor.elevatedColor));
await tester.pumpWidget(CupertinoApp(home: withTraits(Brightness.light, CupertinoUserInterfaceLevelData.elevated, true)));
expect(find.byType(CupertinoSlider), paints..rrect(color: activeColor.highContrastElevatedColor));
});
testWidgets('track color is dynamic', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
theme: const CupertinoThemeData(brightness: Brightness.light),
home: Center(
child: CupertinoSlider(
activeColor: CupertinoColors.activeGreen,
onChanged: (double value) { },
value: 0,
),
),
),
);
expect(
find.byType(CupertinoSlider),
paints..rrect(color: CupertinoSystemColors.fallbackValues.systemFill.color),
);
expect(
find.byType(CupertinoSlider),
isNot(paints..rrect(color: CupertinoSystemColors.fallbackValues.systemFill.darkColor)),
);
await tester.pumpWidget(
CupertinoApp(
theme: const CupertinoThemeData(brightness: Brightness.dark),
home: Center(
child: CupertinoSlider(
activeColor: CupertinoColors.activeGreen,
onChanged: (double value) { },
value: 0,
),
),
),
);
expect(
find.byType(CupertinoSlider),
paints..rrect(color: CupertinoSystemColors.fallbackValues.systemFill.darkColor),
);
expect(
find.byType(CupertinoSlider),
isNot(paints..rrect(color: CupertinoSystemColors.fallbackValues.systemFill.color)),
);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment