blob: 7a144a373fc71ef0edb9e915ff314ba93432c4a7 [file] [log] [blame] [edit]
// 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);
expect(theme.applyThemeToAll, false);
});
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 originalTheme = CupertinoThemeData(brightness: Brightness.dark, applyThemeToAll: true);
final CupertinoThemeData theme = await testTheme(
tester,
originalTheme.copyWith(primaryColor: CupertinoColors.systemGreen, applyThemeToAll: false),
);
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));
expect(theme.applyThemeToAll, false);
});
testWidgets("Theme has default IconThemeData, which is derived from the theme's primary color", (
WidgetTester tester,
) async {
const CupertinoDynamicColor primaryColor = CupertinoColors.systemRed;
const 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 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',
'applyThemeToAll',
'textStyle',
'actionTextStyle',
'actionSmallTextStyle',
'tabLabelTextStyle',
'navTitleTextStyle',
'navLargeTitleTextStyle',
'navActionTextStyle',
'pickerTextStyle',
'dateTimePickerTextStyle',
'selectionHandleColor',
}),
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: CupertinoColors.transparent),
child: SizedBox(),
).toStringDeep().trimRight(),
isNot(contains('\n')),
);
});
testWidgets('CupertinoThemeData equality', (WidgetTester tester) async {
const a = CupertinoThemeData(brightness: Brightness.dark);
final CupertinoThemeData b = a.copyWith();
final CupertinoThemeData c = a.copyWith(brightness: Brightness.light);
expect(a, equals(b));
expect(b, equals(a));
expect(a, isNot(equals(c)));
expect(c, isNot(equals(a)));
expect(b, isNot(equals(c)));
expect(c, isNot(equals(b)));
});
testWidgets('NoDefaultCupertinoThemeData equality', (WidgetTester tester) async {
const a = NoDefaultCupertinoThemeData();
final NoDefaultCupertinoThemeData b = a.copyWith();
final NoDefaultCupertinoThemeData c = a.copyWith(brightness: Brightness.light);
expect(a, equals(b));
expect(a, isNot(c));
});
late Brightness currentBrightness;
void colorMatches(Color? componentColor, Color expectedDynamicColor) {
if (expectedDynamicColor is CupertinoDynamicColor) {
switch (currentBrightness) {
case Brightness.light:
expect(componentColor, isSameColorAs(expectedDynamicColor.color));
case Brightness.dark:
expect(componentColor, isSameColorAs(expectedDynamicColor.darkColor));
}
} else {
expect(componentColor, isSameColorAs(expectedDynamicColor));
}
}
void dynamicColorsTestGroup() {
testWidgets('CupertinoTheme.of resolves colors', (WidgetTester tester) async {
final 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 data = CupertinoThemeData(brightness: currentBrightness, primaryColor: primaryColor);
const barBackgroundColor = CupertinoDynamicColor.withBrightness(
color: Color(0xF0F9F9F9),
darkColor: Color(0xF01D1D1D),
);
final CupertinoThemeData theme = await testTheme(tester, data);
colorMatches(theme.primaryContrastingColor, CupertinoColors.white);
colorMatches(theme.barBackgroundColor, barBackgroundColor);
colorMatches(theme.scaffoldBackgroundColor, CupertinoColors.systemBackground);
colorMatches(theme.selectionHandleColor, CupertinoColors.systemBlue);
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);
}