| // Copyright 2014 The Flutter 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/foundation.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| int buildCount = 0; |
| CupertinoThemeData? actualTheme; |
| IconThemeData? actualIconTheme; |
| |
| final Widget singletonThemeSubtree = Builder( |
| builder: (BuildContext context) { |
| buildCount++; |
| actualTheme = CupertinoTheme.of(context); |
| actualIconTheme = IconTheme.of(context); |
| return const Placeholder(); |
| }, |
| ); |
| |
| Future<CupertinoThemeData> testTheme(WidgetTester tester, CupertinoThemeData theme) async { |
| await tester.pumpWidget( |
| CupertinoTheme( |
| data: theme, |
| child: singletonThemeSubtree, |
| ), |
| ); |
| return actualTheme!; |
| } |
| |
| Future<IconThemeData> testIconTheme(WidgetTester tester, CupertinoThemeData theme) async { |
| await tester.pumpWidget( |
| CupertinoTheme( |
| data: theme, |
| child: singletonThemeSubtree, |
| ), |
| ); |
| return actualIconTheme!; |
| } |
| |
| void main() { |
| setUp(() { |
| buildCount = 0; |
| actualTheme = null; |
| actualIconTheme = null; |
| }); |
| |
| testWidgets('Default theme has defaults', (WidgetTester tester) async { |
| final CupertinoThemeData theme = await testTheme(tester, const CupertinoThemeData()); |
| |
| expect(theme.brightness, isNull); |
| expect(theme.primaryColor, CupertinoColors.activeBlue); |
| expect(theme.textTheme.textStyle.fontSize, 17.0); |
| }); |
| |
| testWidgets('Theme attributes cascade', (WidgetTester tester) async { |
| final CupertinoThemeData theme = await testTheme(tester, const CupertinoThemeData( |
| primaryColor: CupertinoColors.systemRed, |
| )); |
| |
| expect(theme.textTheme.actionTextStyle.color, isSameColorAs(CupertinoColors.systemRed.color)); |
| }); |
| |
| testWidgets('Dependent attribute can be overridden from cascaded value', (WidgetTester tester) async { |
| final CupertinoThemeData theme = await testTheme(tester, const CupertinoThemeData( |
| brightness: Brightness.dark, |
| textTheme: CupertinoTextThemeData( |
| textStyle: TextStyle(color: CupertinoColors.black), |
| ), |
| )); |
| |
| // The brightness still cascaded down to the background color. |
| expect(theme.scaffoldBackgroundColor, isSameColorAs(CupertinoColors.black)); |
| // But not to the font color which we overrode. |
| expect(theme.textTheme.textStyle.color, isSameColorAs(CupertinoColors.black)); |
| }); |
| |
| testWidgets( |
| 'Reading themes creates dependencies', |
| (WidgetTester tester) async { |
| // Reading the theme creates a dependency. |
| CupertinoThemeData theme = await testTheme(tester, const CupertinoThemeData( |
| // Default brightness is light, |
| barBackgroundColor: Color(0x11223344), |
| textTheme: CupertinoTextThemeData( |
| textStyle: TextStyle(fontFamily: 'Skeuomorphic'), |
| ), |
| )); |
| |
| expect(buildCount, 1); |
| expect(theme.textTheme.textStyle.fontFamily, 'Skeuomorphic'); |
| |
| // Changing another property also triggers a rebuild. |
| theme = await testTheme(tester, const CupertinoThemeData( |
| brightness: Brightness.light, |
| barBackgroundColor: Color(0x11223344), |
| textTheme: CupertinoTextThemeData( |
| textStyle: TextStyle(fontFamily: 'Skeuomorphic'), |
| ), |
| )); |
| |
| expect(buildCount, 2); |
| // Re-reading the same value doesn't change anything. |
| expect(theme.textTheme.textStyle.fontFamily, 'Skeuomorphic'); |
| |
| theme = await testTheme(tester, const CupertinoThemeData( |
| brightness: Brightness.light, |
| barBackgroundColor: Color(0x11223344), |
| textTheme: CupertinoTextThemeData( |
| textStyle: TextStyle(fontFamily: 'Flat'), |
| ), |
| )); |
| |
| expect(buildCount, 3); |
| expect(theme.textTheme.textStyle.fontFamily, 'Flat'); |
| }, |
| ); |
| |
| testWidgets( |
| 'copyWith works', |
| (WidgetTester tester) async { |
| const CupertinoThemeData originalTheme = CupertinoThemeData( |
| brightness: Brightness.dark, |
| ); |
| |
| final CupertinoThemeData theme = await testTheme(tester, originalTheme.copyWith( |
| primaryColor: CupertinoColors.systemGreen, |
| )); |
| |
| expect(theme.brightness, Brightness.dark); |
| expect(theme.primaryColor, isSameColorAs(CupertinoColors.systemGreen.darkColor)); |
| // Now check calculated derivatives. |
| expect(theme.textTheme.actionTextStyle.color, isSameColorAs(CupertinoColors.systemGreen.darkColor)); |
| expect(theme.scaffoldBackgroundColor, isSameColorAs(CupertinoColors.black)); |
| }, |
| ); |
| |
| testWidgets("Theme has default IconThemeData, which is derived from the theme's primary color", (WidgetTester tester) async { |
| const CupertinoDynamicColor primaryColor = CupertinoColors.systemRed; |
| const CupertinoThemeData themeData = CupertinoThemeData(primaryColor: primaryColor); |
| |
| final IconThemeData resultingIconTheme = await testIconTheme(tester, themeData); |
| |
| expect(resultingIconTheme.color, isSameColorAs(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 { |
| IconThemeData iconTheme = await testIconTheme(tester, const CupertinoThemeData(primaryColor: CupertinoColors.destructiveRed)); |
| |
| expect(buildCount, 1); |
| expect(iconTheme.color, CupertinoColors.destructiveRed); |
| |
| iconTheme = await testIconTheme(tester, const CupertinoThemeData(primaryColor: CupertinoColors.activeOrange)); |
| expect(buildCount, 2); |
| expect(iconTheme.color, CupertinoColors.activeOrange); |
| }); |
| |
| testWidgets('CupertinoTheme diagnostics', (WidgetTester tester) async { |
| final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); |
| const CupertinoThemeData().debugFillProperties(builder); |
| |
| final Set<String> description = builder.properties |
| .map((DiagnosticsNode node) => node.name.toString()) |
| .toSet(); |
| |
| expect( |
| setEquals( |
| description, |
| <String>{ |
| 'brightness', |
| 'primaryColor', |
| 'primaryContrastingColor', |
| 'barBackgroundColor', |
| 'scaffoldBackgroundColor', |
| 'textStyle', |
| 'actionTextStyle', |
| 'tabLabelTextStyle', |
| 'navTitleTextStyle', |
| 'navLargeTitleTextStyle', |
| 'navActionTextStyle', |
| 'pickerTextStyle', |
| 'dateTimePickerTextStyle', |
| }, |
| ), |
| isTrue, |
| ); |
| }); |
| |
| testWidgets('CupertinoTheme.toStringDeep uses single-line style', (WidgetTester tester) async { |
| // Regression test for https://github.com/flutter/flutter/issues/47651. |
| expect( |
| const CupertinoTheme( |
| data: CupertinoThemeData(primaryColor: Color(0x00000000)), |
| child: SizedBox(), |
| ).toStringDeep().trimRight(), |
| isNot(contains('\n')), |
| ); |
| }); |
| |
| late 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; |
| } |
| } |
| |
| void 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)); |
| 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); |
| } |