Unverified Commit 4ac2daf3 authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

CupertinoTheme & CupertinoTextTheme dark mode updates (#41859)

parent 20e015ff
...@@ -17,6 +17,7 @@ export 'src/cupertino/button.dart'; ...@@ -17,6 +17,7 @@ export 'src/cupertino/button.dart';
export 'src/cupertino/colors.dart'; export 'src/cupertino/colors.dart';
export 'src/cupertino/date_picker.dart'; export 'src/cupertino/date_picker.dart';
export 'src/cupertino/dialog.dart'; export 'src/cupertino/dialog.dart';
export 'src/cupertino/icon_theme_data.dart';
export 'src/cupertino/icons.dart'; export 'src/cupertino/icons.dart';
export 'src/cupertino/interface_level.dart'; export 'src/cupertino/interface_level.dart';
export 'src/cupertino/localizations.dart'; export 'src/cupertino/localizations.dart';
......
// 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/widgets.dart';
import 'colors.dart';
/// An [IconThemeData] subclass that automatically resolves its [color] when retrieved
/// using [IconTheme.of].
class CupertinoIconThemeData extends IconThemeData {
/// Creates a [CupertinoIconThemeData].
///
/// The opacity applies to both explicit and default icon colors. The value
/// is clamped between 0.0 and 1.0.
const CupertinoIconThemeData({
Color color,
double opacity,
double size
}) : super(color: color, opacity: opacity, size: size);
/// Called by [IconThemeData.of] to resolve [color] against the given [BuildContext].
@override
IconThemeData resolve(BuildContext context) {
final Color resolvedColor = CupertinoDynamicColor.resolve(color, context);
return resolvedColor == color ? this : copyWith(color: resolvedColor);
}
}
...@@ -59,7 +59,7 @@ class IconTheme extends InheritedTheme { ...@@ -59,7 +59,7 @@ class IconTheme extends InheritedTheme {
/// IconThemeData theme = IconTheme.of(context); /// IconThemeData theme = IconTheme.of(context);
/// ``` /// ```
static IconThemeData of(BuildContext context) { static IconThemeData of(BuildContext context) {
final IconThemeData iconThemeData = _getInheritedIconThemeData(context); final IconThemeData iconThemeData = _getInheritedIconThemeData(context).resolve(context);
return iconThemeData.isConcrete ? iconThemeData : const IconThemeData.fallback().merge(iconThemeData); return iconThemeData.isConcrete ? iconThemeData : const IconThemeData.fallback().merge(iconThemeData);
} }
......
...@@ -8,6 +8,8 @@ import 'dart:ui' as ui show lerpDouble; ...@@ -8,6 +8,8 @@ import 'dart:ui' as ui show lerpDouble;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'framework.dart' show BuildContext;
/// Defines the color, opacity, and size of icons. /// Defines the color, opacity, and size of icons.
/// ///
/// Used by [IconTheme] to control the color, opacity, and size of icons in a /// Used by [IconTheme] to control the color, opacity, and size of icons in a
...@@ -54,6 +56,24 @@ class IconThemeData extends Diagnosticable { ...@@ -54,6 +56,24 @@ class IconThemeData extends Diagnosticable {
); );
} }
/// Called by [IconTheme.of] to convert this instance to an [IconThemeData]
/// that fits the given [BuildContext].
///
/// This method gives the ambient [IconThemeData] a chance to update itself,
/// after it's been retrieved by [IconTheme.of], and before being returned as
/// the final result. For instance, [CupertinoIconThemeData] overrides this method
/// to resolve [color], in case [color] is a [CupertinoDynamicColor] and needs
/// to be resolved against the given [BuildContext] before it can be used as a
/// regular [Color].
///
/// The default implementation returns this [IconThemeData] as-is.
///
/// See also:
///
/// * [CupertinoIconThemeData.resolve] an implementation that resolves
/// [CupertinoIconThemeData.color] before returning.
IconThemeData resolve(BuildContext context) => this;
/// Whether all the properties of this object are non-null. /// Whether all the properties of this object are non-null.
bool get isConcrete => color != null && opacity != null && size != null; bool get isConcrete => color != null && opacity != null && size != null;
......
...@@ -218,7 +218,7 @@ void main() { ...@@ -218,7 +218,7 @@ void main() {
matching: find.byType(RichText), matching: find.byType(RichText),
)); ));
expect(actualActive.text.style.color.value, CupertinoColors.activeOrange.darkColor.value); expect(actualActive.text.style.color, isSameColorAs(CupertinoColors.activeBlue.darkColor));
}); });
testWidgets('Use active icon', (WidgetTester tester) async { testWidgets('Use active icon', (WidgetTester tester) async {
......
...@@ -306,7 +306,7 @@ void main() { ...@@ -306,7 +306,7 @@ void main() {
), ),
); );
expect(textStyle.color, CupertinoColors.white); expect(textStyle.color, isSameColorAs(CupertinoColors.white));
BoxDecoration decoration = tester.widget<DecoratedBox>( BoxDecoration decoration = tester.widget<DecoratedBox>(
find.descendant( find.descendant(
of: find.byType(CupertinoButton), of: find.byType(CupertinoButton),
...@@ -327,7 +327,7 @@ void main() { ...@@ -327,7 +327,7 @@ void main() {
), ),
), ),
); );
expect(textStyle.color.value, CupertinoColors.activeOrange.darkColor.value); expect(textStyle.color, isSameColorAs(CupertinoColors.systemBlue.darkColor));
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
...@@ -341,14 +341,14 @@ void main() { ...@@ -341,14 +341,14 @@ void main() {
), ),
), ),
); );
expect(textStyle.color, CupertinoColors.black); expect(textStyle.color, isSameColorAs(CupertinoColors.black));
decoration = tester.widget<DecoratedBox>( decoration = tester.widget<DecoratedBox>(
find.descendant( find.descendant(
of: find.byType(CupertinoButton), of: find.byType(CupertinoButton),
matching: find.byType(DecoratedBox), matching: find.byType(DecoratedBox),
), ),
).decoration; ).decoration;
expect(decoration.color.value, CupertinoColors.activeOrange.darkColor.value); expect(decoration.color, isSameColorAs(CupertinoColors.systemBlue.darkColor));
}); });
} }
......
// 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_test/flutter_test.dart';
void main() {
testWidgets('IconTheme.of works', (WidgetTester tester) async {
const IconThemeData data = IconThemeData(color: Color(0xAAAAAAAA), opacity: 0.5, size: 16.0);
IconThemeData retrieved;
await tester.pumpWidget(
IconTheme(data: data, child: Builder(builder: (BuildContext context) {
retrieved = IconTheme.of(context);
return const SizedBox();
}))
);
expect(retrieved, data);
await tester.pumpWidget(
IconTheme(
data: const CupertinoIconThemeData(color: CupertinoColors.systemBlue),
child: MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark),
child: Builder(builder: (BuildContext context) {
retrieved = IconTheme.of(context);
return const SizedBox();
},
)
),
),
);
expect(retrieved.color, isSameColorAs(CupertinoColors.systemBlue.darkColor));
});
}
...@@ -133,7 +133,7 @@ void main() { ...@@ -133,7 +133,7 @@ void main() {
matching: find.byType(DecoratedBox), matching: find.byType(DecoratedBox),
)).decoration; )).decoration;
expect(tabDecoration.color, const Color(0xCCF8F8F8)); expect(tabDecoration.color, isSameColorAs(const Color(0xF0F9F9F9))); // Inherited from theme.
await tester.tap(find.text('Tab 2')); await tester.tap(find.text('Tab 2'));
await tester.pump(); await tester.pump();
...@@ -159,7 +159,7 @@ void main() { ...@@ -159,7 +159,7 @@ void main() {
matching: find.byType(DecoratedBox), matching: find.byType(DecoratedBox),
)).decoration; )).decoration;
expect(tabDecoration.color, const Color(0xB7212121)); expect(tabDecoration.color, isSameColorAs(const Color(0xF01D1D1D)));
final RichText tab1 = tester.widget(find.descendant( final RichText tab1 = tester.widget(find.descendant(
of: find.text('Tab 1'), of: find.text('Tab 1'),
......
...@@ -188,19 +188,18 @@ void main() { ...@@ -188,19 +188,18 @@ void main() {
testWidgets('Nav bar respects themes', (WidgetTester tester) async { testWidgets('Nav bar respects themes', (WidgetTester tester) async {
count = 0x000000; count = 0x000000;
const CupertinoDynamicColor orange = CupertinoColors.activeOrange;
await tester.pumpWidget( await tester.pumpWidget(
CupertinoApp( CupertinoApp(
theme: const CupertinoThemeData(brightness: Brightness.dark), theme: const CupertinoThemeData(brightness: Brightness.dark),
home: CupertinoNavigationBar( home: CupertinoNavigationBar(
leading: CupertinoButton( leading: CupertinoButton(
onPressed: () { }, onPressed: () { },
child: _ExpectStyles(color: orange.darkColor, index: 0x000001), child: _ExpectStyles(color: CupertinoColors.systemBlue.darkColor, index: 0x000001),
), ),
middle: const _ExpectStyles(color: CupertinoColors.white, index: 0x000100), middle: const _ExpectStyles(color: CupertinoColors.white, index: 0x000100),
trailing: CupertinoButton( trailing: CupertinoButton(
onPressed: () { }, onPressed: () { },
child: _ExpectStyles(color: orange.darkColor, index: 0x010000), child: _ExpectStyles(color: CupertinoColors.systemBlue.darkColor, index: 0x010000),
), ),
), ),
), ),
...@@ -1129,7 +1128,7 @@ class _ExpectStyles extends StatelessWidget { ...@@ -1129,7 +1128,7 @@ class _ExpectStyles extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final TextStyle style = DefaultTextStyle.of(context).style; final TextStyle style = DefaultTextStyle.of(context).style;
expect(style.color.value, color.value); expect(style.color, isSameColorAs(color));
expect(style.fontFamily, '.SF Pro Text'); expect(style.fontFamily, '.SF Pro Text');
expect(style.fontSize, 17.0); expect(style.fontSize, 17.0);
expect(style.letterSpacing, -0.41); expect(style.letterSpacing, -0.41);
......
...@@ -226,7 +226,7 @@ void main() { ...@@ -226,7 +226,7 @@ void main() {
// The transition's stack is ordered. The bottom middle is inserted first. // The transition's stack is ordered. The bottom middle is inserted first.
final RenderParagraph bottomMiddle = final RenderParagraph bottomMiddle =
tester.renderObject(flying(tester, find.text('Page 1')).first); tester.renderObject(flying(tester, find.text('Page 1')).first);
expect(bottomMiddle.text.style.color, const Color(0xfffffaf4)); expect(bottomMiddle.text.style.color, const Color(0xFFF4F9FF));
expect(bottomMiddle.text.style.fontWeight, FontWeight.w600); expect(bottomMiddle.text.style.fontWeight, FontWeight.w600);
expect(bottomMiddle.text.style.fontFamily, '.SF Pro Text'); expect(bottomMiddle.text.style.fontFamily, '.SF Pro Text');
expect(bottomMiddle.text.style.letterSpacing, -0.41); expect(bottomMiddle.text.style.letterSpacing, -0.41);
...@@ -237,7 +237,7 @@ void main() { ...@@ -237,7 +237,7 @@ void main() {
// are flipped. // are flipped.
final RenderParagraph topBackLabel = final RenderParagraph topBackLabel =
tester.renderObject(flying(tester, find.text('Page 1')).last); tester.renderObject(flying(tester, find.text('Page 1')).last);
expect(topBackLabel.text.style.color, const Color(0xfffffaf4)); expect(topBackLabel.text.style.color, const Color(0xFFF4F9FF));
expect(topBackLabel.text.style.fontWeight, FontWeight.w600); expect(topBackLabel.text.style.fontWeight, FontWeight.w600);
expect(topBackLabel.text.style.fontFamily, '.SF Pro Text'); expect(topBackLabel.text.style.fontFamily, '.SF Pro Text');
expect(topBackLabel.text.style.letterSpacing, -0.41); expect(topBackLabel.text.style.letterSpacing, -0.41);
...@@ -246,14 +246,14 @@ void main() { ...@@ -246,14 +246,14 @@ void main() {
// Move animation further a bit. // Move animation further a bit.
await tester.pump(const Duration(milliseconds: 200)); await tester.pump(const Duration(milliseconds: 200));
expect(bottomMiddle.text.style.color, const Color(0xffffa923)); expect(bottomMiddle.text.style.color, const Color(0xFF2390FF));
expect(bottomMiddle.text.style.fontWeight, FontWeight.w400); expect(bottomMiddle.text.style.fontWeight, FontWeight.w400);
expect(bottomMiddle.text.style.fontFamily, '.SF Pro Text'); expect(bottomMiddle.text.style.fontFamily, '.SF Pro Text');
expect(bottomMiddle.text.style.letterSpacing, -0.41); expect(bottomMiddle.text.style.letterSpacing, -0.41);
checkOpacity(tester, flying(tester, find.text('Page 1')).first, 0.0); checkOpacity(tester, flying(tester, find.text('Page 1')).first, 0.0);
expect(topBackLabel.text.style.color, const Color(0xffffa923)); expect(topBackLabel.text.style.color, const Color(0xFF2390FF));
expect(topBackLabel.text.style.fontWeight, FontWeight.w400); expect(topBackLabel.text.style.fontWeight, FontWeight.w400);
expect(topBackLabel.text.style.fontFamily, '.SF Pro Text'); expect(topBackLabel.text.style.fontFamily, '.SF Pro Text');
expect(topBackLabel.text.style.letterSpacing, -0.41); expect(topBackLabel.text.style.letterSpacing, -0.41);
......
...@@ -34,10 +34,11 @@ void main() { ...@@ -34,10 +34,11 @@ void main() {
final RenderParagraph paragraph = tester.renderObject(find.text('1')); final RenderParagraph paragraph = tester.renderObject(find.text('1'));
expect(paragraph.text.style, const TextStyle( expect(paragraph.text.style.color, isSameColorAs(CupertinoColors.black));
expect(paragraph.text.style.copyWith(color: CupertinoColors.black), const TextStyle(
inherit: false, inherit: false,
fontFamily: '.SF Pro Display', fontFamily: '.SF Pro Display',
fontSize: 25.0, fontSize: 21.0,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
letterSpacing: -0.41, letterSpacing: -0.41,
color: CupertinoColors.black, color: CupertinoColors.black,
......
...@@ -411,7 +411,7 @@ void main() { ...@@ -411,7 +411,7 @@ void main() {
expect(decoratedBox.decoration.runtimeType, BoxDecoration); expect(decoratedBox.decoration.runtimeType, BoxDecoration);
final BoxDecoration decoration = decoratedBox.decoration; final BoxDecoration decoration = decoratedBox.decoration;
expect(decoration.color, CupertinoColors.white); expect(decoration.color, isSameColorAs(CupertinoColors.white));
}); });
testWidgets('Overrides background color', (WidgetTester tester) async { testWidgets('Overrides background color', (WidgetTester tester) async {
......
...@@ -427,10 +427,9 @@ void main() { ...@@ -427,10 +427,9 @@ void main() {
), ),
); );
const CupertinoDynamicColor orange = CupertinoColors.activeOrange;
expect( expect(
find.byType(CupertinoSlider), find.byType(CupertinoSlider),
paints..rrect(color: orange.darkColor), paints..rrect(color: CupertinoColors.systemBlue.darkColor),
); );
}); });
......
...@@ -340,7 +340,7 @@ void main() { ...@@ -340,7 +340,7 @@ void main() {
matching: find.byType(DecoratedBox), matching: find.byType(DecoratedBox),
)).decoration; )).decoration;
expect(tabDecoration.color, const Color(0xCCF8F8F8)); expect(tabDecoration.color, isSameColorAs(const Color(0xF0F9F9F9))); // Inherited from theme.
await tester.tap(find.text('Tab 2')); await tester.tap(find.text('Tab 2'));
await tester.pump(); await tester.pump();
...@@ -366,7 +366,7 @@ void main() { ...@@ -366,7 +366,7 @@ void main() {
matching: find.byType(DecoratedBox), matching: find.byType(DecoratedBox),
)).decoration; )).decoration;
expect(tabDecoration.color, const Color(0xB7212121)); expect(tabDecoration.color, isSameColorAs(const Color(0xF01D1D1D)));
final RichText tab1 = tester.widget(find.descendant( final RichText tab1 = tester.widget(find.descendant(
of: find.text('Tab 1'), of: find.text('Tab 1'),
...@@ -378,7 +378,7 @@ void main() { ...@@ -378,7 +378,7 @@ void main() {
of: find.text('Tab 2'), of: find.text('Tab 2'),
matching: find.byType(RichText), matching: find.byType(RichText),
)); ));
expect(tab2.text.style.color.value, CupertinoColors.systemRed.darkColor.value); expect(tab2.text.style.color, isSameColorAs(CupertinoColors.systemRed.darkColor));
}); });
testWidgets('Tab contents are padded when there are view insets', (WidgetTester tester) async { testWidgets('Tab contents are padded when there are view insets', (WidgetTester tester) async {
......
...@@ -2749,7 +2749,7 @@ void main() { ...@@ -2749,7 +2749,7 @@ void main() {
tester.renderObject<RenderEditable>( tester.renderObject<RenderEditable>(
find.byElementPredicate((Element element) => element.renderObject is RenderEditable) find.byElementPredicate((Element element) => element.renderObject is RenderEditable)
).text.style.color, ).text.style.color,
CupertinoColors.white, isSameColorAs(CupertinoColors.white),
); );
}, },
); );
...@@ -2899,7 +2899,7 @@ void main() { ...@@ -2899,7 +2899,7 @@ void main() {
); );
await tester.pump(); await tester.pump();
expect(renderEditable.cursorColor, CupertinoColors.activeOrange.darkColor); expect(renderEditable.cursorColor, CupertinoColors.activeBlue.darkColor);
await tester.pumpWidget( await tester.pumpWidget(
const CupertinoApp( const CupertinoApp(
......
...@@ -59,7 +59,7 @@ void main() { ...@@ -59,7 +59,7 @@ void main() {
primaryColor: CupertinoColors.destructiveRed, primaryColor: CupertinoColors.destructiveRed,
)); ));
expect(theme.textTheme.actionTextStyle.color, CupertinoColors.destructiveRed); expect(theme.textTheme.actionTextStyle.color, isSameColorAs(CupertinoColors.destructiveRed));
}); });
testWidgets('Dependent attribute can be overridden from cascaded value', (WidgetTester tester) async { testWidgets('Dependent attribute can be overridden from cascaded value', (WidgetTester tester) async {
...@@ -71,9 +71,9 @@ void main() { ...@@ -71,9 +71,9 @@ void main() {
)); ));
// The brightness still cascaded down to the background color. // The brightness still cascaded down to the background color.
expect(theme.scaffoldBackgroundColor, CupertinoColors.black); expect(theme.scaffoldBackgroundColor, isSameColorAs(CupertinoColors.black));
// But not to the font color which we overrode. // But not to the font color which we overrode.
expect(theme.textTheme.textStyle.color, CupertinoColors.black); expect(theme.textTheme.textStyle.color, isSameColorAs(CupertinoColors.black));
}); });
testWidgets( testWidgets(
...@@ -125,24 +125,32 @@ void main() { ...@@ -125,24 +125,32 @@ void main() {
); );
final CupertinoThemeData theme = await testTheme(tester, originalTheme.copyWith( final CupertinoThemeData theme = await testTheme(tester, originalTheme.copyWith(
primaryColor: CupertinoColors.activeGreen, primaryColor: CupertinoColors.systemGreen,
)); ));
expect(theme.brightness, Brightness.dark); expect(theme.brightness, Brightness.dark);
expect(theme.primaryColor.value, CupertinoColors.systemGreen.darkColor.value); expect(theme.primaryColor, isSameColorAs(CupertinoColors.systemGreen.darkColor));
// Now check calculated derivatives. // Now check calculated derivatives.
expect(theme.textTheme.actionTextStyle.color.value, CupertinoColors.systemGreen.darkColor.value); expect(theme.textTheme.actionTextStyle.color, isSameColorAs(CupertinoColors.systemGreen.darkColor));
expect(theme.scaffoldBackgroundColor.value, CupertinoColors.black.value); expect(theme.scaffoldBackgroundColor, isSameColorAs(CupertinoColors.black));
}, },
); );
testWidgets("Theme has default IconThemeData, which is derived from the theme's primary color", (WidgetTester tester) async { testWidgets("Theme has default IconThemeData, which is derived from the theme's primary color", (WidgetTester tester) async {
const Color primaryColor = CupertinoColors.destructiveRed; const CupertinoDynamicColor primaryColor = CupertinoColors.destructiveRed;
const CupertinoThemeData themeData = CupertinoThemeData(primaryColor: primaryColor); const CupertinoThemeData themeData = CupertinoThemeData(primaryColor: primaryColor);
final IconThemeData resultingIconTheme = await testIconTheme(tester, themeData); final IconThemeData resultingIconTheme = await testIconTheme(tester, themeData);
expect(resultingIconTheme.color, themeData.primaryColor); expect(resultingIconTheme.color, themeData.primaryColor);
// Works in dark mode if primaryColor is a CupertinoDynamicColor.
final Color darkColor = (await testIconTheme(
tester,
themeData.copyWith(brightness: Brightness.dark),
)).color;
expect(darkColor, isSameColorAs(primaryColor.darkColor));
}); });
testWidgets('IconTheme.of creates a dependency on iconTheme', (WidgetTester tester) async { testWidgets('IconTheme.of creates a dependency on iconTheme', (WidgetTester tester) async {
...@@ -155,4 +163,56 @@ void main() { ...@@ -155,4 +163,56 @@ void main() {
expect(buildCount, 2); expect(buildCount, 2);
expect(iconTheme.color, CupertinoColors.activeOrange); expect(iconTheme.color, CupertinoColors.activeOrange);
}); });
Brightness currentBrightness;
void colorMatches(Color componentColor, CupertinoDynamicColor expectedDynamicColor) {
switch (currentBrightness) {
case Brightness.light:
expect(componentColor, isSameColorAs(expectedDynamicColor.color));
break;
case Brightness.dark:
expect(componentColor, isSameColorAs(expectedDynamicColor.darkColor));
break;
}
}
final Function dynamicColorsTestGroup = () {
testWidgets('CupertinoTheme.of resolves colors', (WidgetTester tester) async {
final CupertinoThemeData data = CupertinoThemeData(brightness: currentBrightness, primaryColor: CupertinoColors.systemRed);
final CupertinoThemeData theme = await testTheme(tester, data);
expect(data.primaryColor, isSameColorAs(CupertinoColors.systemRed.color));
colorMatches(theme.primaryColor, CupertinoColors.systemRed);
});
testWidgets('CupertinoTheme.of resolves default values', (WidgetTester tester) async {
const CupertinoDynamicColor primaryColor = CupertinoColors.systemRed;
final CupertinoThemeData data = CupertinoThemeData(brightness: currentBrightness, primaryColor: primaryColor);
const CupertinoDynamicColor barBackgroundColor = CupertinoDynamicColor.withBrightness(
color: Color(0xF0F9F9F9),
darkColor: Color(0xF01D1D1D),
);
final CupertinoThemeData theme = await testTheme(tester, data);
colorMatches(theme.primaryContrastingColor, CupertinoColors.systemBackground);
colorMatches(theme.barBackgroundColor, barBackgroundColor);
colorMatches(theme.scaffoldBackgroundColor, CupertinoColors.systemBackground);
colorMatches(theme.textTheme.textStyle.color, CupertinoColors.label);
colorMatches(theme.textTheme.actionTextStyle.color, primaryColor);
colorMatches(theme.textTheme.tabLabelTextStyle.color, CupertinoColors.inactiveGray);
colorMatches(theme.textTheme.navTitleTextStyle.color, CupertinoColors.label);
colorMatches(theme.textTheme.navLargeTitleTextStyle.color, CupertinoColors.label);
colorMatches(theme.textTheme.navActionTextStyle.color, primaryColor);
colorMatches(theme.textTheme.pickerTextStyle.color, CupertinoColors.label);
colorMatches(theme.textTheme.dateTimePickerTextStyle.color, CupertinoColors.label);
});
};
currentBrightness = Brightness.light;
group('light colors', dynamicColorsTestGroup);
currentBrightness = Brightness.dark;
group('dark colors', dynamicColorsTestGroup);
} }
...@@ -127,6 +127,12 @@ const Matcher isInCard = _IsInCard(); ...@@ -127,6 +127,12 @@ const Matcher isInCard = _IsInCard();
/// * [isInCard], the opposite. /// * [isInCard], the opposite.
const Matcher isNotInCard = _IsNotInCard(); const Matcher isNotInCard = _IsNotInCard();
/// Asserts that the object represents the same color as [color] when used to paint.
///
/// Specifically this matcher checks the object is of type [Color] and its [Color.value]
/// equals to that of the given [color].
Matcher isSameColorAs(Color color) => _ColorMatcher(targetColor: color);
/// Asserts that an object's toString() is a plausible one-line description. /// Asserts that an object's toString() is a plausible one-line description.
/// ///
/// Specifically, this matcher checks that the string does not contains newline /// Specifically, this matcher checks that the string does not contains newline
...@@ -1609,6 +1615,24 @@ class _CoversSameAreaAs extends Matcher { ...@@ -1609,6 +1615,24 @@ class _CoversSameAreaAs extends Matcher {
description.add('covers expected area and only expected area'); description.add('covers expected area and only expected area');
} }
class _ColorMatcher extends Matcher {
const _ColorMatcher({
@required this.targetColor,
}) : assert(targetColor != null);
final Color targetColor;
@override
bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
if (item is Color)
return item.value == targetColor.value;
return false;
}
@override
Description describe(Description description) => description.add('matches color $targetColor');
}
Future<ui.Image> _captureImage(Element element) { Future<ui.Image> _captureImage(Element element) {
RenderObject renderObject = element.renderObject; RenderObject renderObject = element.renderObject;
while (!renderObject.isRepaintBoundary) { while (!renderObject.isRepaintBoundary) {
......
...@@ -237,6 +237,33 @@ void main() { ...@@ -237,6 +237,33 @@ void main() {
); );
}); });
test('isSameColorAs', () {
expect(
const Color(0x87654321),
isSameColorAs(_CustomColor(0x87654321)),
);
expect(
_CustomColor(0x87654321),
isSameColorAs(const Color(0x87654321)),
);
expect(
const Color(0x12345678),
isNot(isSameColorAs(_CustomColor(0x87654321))),
);
expect(
_CustomColor(0x87654321),
isNot(isSameColorAs(const Color(0x12345678))),
);
expect(
_CustomColor(0xFF123456),
isSameColorAs(_CustomColor(0xFF123456)..isEqual = false),
);
});
group('coversSameAreaAs', () { group('coversSameAreaAs', () {
test('empty Paths', () { test('empty Paths', () {
expect( expect(
...@@ -676,3 +703,14 @@ class _FakeSemanticsNode extends SemanticsNode { ...@@ -676,3 +703,14 @@ class _FakeSemanticsNode extends SemanticsNode {
@override @override
SemanticsData getSemanticsData() => data; SemanticsData getSemanticsData() => data;
} }
class _CustomColor extends Color {
_CustomColor(int value) : super(value);
bool isEqual;
@override
bool operator ==(dynamic other) => isEqual ?? super == other;
@override
int get hashCode => hashValues(super.hashCode, isEqual);
}
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