CupertinoDynamicColor and friends (#37719)

This commit is contained in:
LongCatIsLooong 2019-08-21 20:07:42 -07:00 committed by GitHub
parent ffa3785411
commit a671b28369
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 2466 additions and 238 deletions

View File

@ -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';

View File

@ -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,
);
},
),
),
),
),
);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
// 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'
);
}
}

View File

@ -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;
}

View File

@ -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({

View File

@ -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,
);
}
}

View File

@ -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),
);
}
}

View File

@ -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'

View File

@ -0,0 +1,748 @@
// 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)*)',
],
);
});
});
}

View File

@ -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)),
);
});
}