blob: 4095e7d562a38de983575a7e43018e30418f50f8 [file] [log] [blame]
// 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/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
const DatePickerThemeData datePickerTheme = DatePickerThemeData(
backgroundColor: Color(0xfffffff0),
elevation: 6,
shadowColor: Color(0xfffffff1),
surfaceTintColor: Color(0xfffffff2),
shape: RoundedRectangleBorder(),
headerBackgroundColor: Color(0xfffffff3),
headerForegroundColor: Color(0xfffffff4),
headerHeadlineStyle: TextStyle(fontSize: 10),
headerHelpStyle: TextStyle(fontSize: 11),
weekdayStyle: TextStyle(fontSize: 12),
dayStyle: TextStyle(fontSize: 13),
dayForegroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffff5)),
dayBackgroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffff6)),
dayOverlayColor: MaterialStatePropertyAll<Color>(Color(0xfffffff7)),
dayShape: MaterialStatePropertyAll<OutlinedBorder>(RoundedRectangleBorder()),
todayForegroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffff8)),
todayBackgroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffff9)),
todayBorder: BorderSide(width: 3),
yearStyle: TextStyle(fontSize: 13),
yearForegroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffffa)),
yearBackgroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffffb)),
yearOverlayColor: MaterialStatePropertyAll<Color>(Color(0xfffffffc)),
rangePickerBackgroundColor: Color(0xfffffffd),
rangePickerElevation: 7,
rangePickerShadowColor: Color(0xfffffffe),
rangePickerSurfaceTintColor: Color(0xffffffff),
rangePickerShape: RoundedRectangleBorder(),
rangePickerHeaderBackgroundColor: Color(0xffffff0f),
rangePickerHeaderForegroundColor: Color(0xffffff1f),
rangePickerHeaderHeadlineStyle: TextStyle(fontSize: 14),
rangePickerHeaderHelpStyle: TextStyle(fontSize: 15),
rangeSelectionBackgroundColor: Color(0xffffff2f),
rangeSelectionOverlayColor: MaterialStatePropertyAll<Color>(Color(0xffffff3f)),
dividerColor: Color(0xffffff4f),
inputDecorationTheme: InputDecorationTheme(
fillColor: Color(0xffffff5f),
border: UnderlineInputBorder(),
),
cancelButtonStyle: ButtonStyle(foregroundColor: MaterialStatePropertyAll<Color>(Color(0xffffff6f))),
confirmButtonStyle: ButtonStyle(foregroundColor: MaterialStatePropertyAll<Color>(Color(0xffffff7f))),
);
Material findDialogMaterial(WidgetTester tester) {
return tester.widget<Material>(
find.descendant(
of: find.byType(Dialog),
matching: find.byType(Material)
).first
);
}
Material findHeaderMaterial(WidgetTester tester, String text) {
return tester.widget<Material>(
find.ancestor(
of: find.text(text),
matching: find.byType(Material)
).first,
);
}
BoxDecoration? findTextDecoration(WidgetTester tester, String date) {
final Container container = tester.widget<Container>(
find.ancestor(
of: find.text(date),
matching: find.byType(Container)
).first,
);
return container.decoration as BoxDecoration?;
}
ShapeDecoration? findDayDecoration(WidgetTester tester, String day) {
return tester.widget<DecoratedBox>(
find.ancestor(
of: find.text(day),
matching: find.byType(DecoratedBox)
),
).decoration as ShapeDecoration?;
}
ButtonStyle actionButtonStyle(WidgetTester tester, String text) {
return tester.widget<TextButton>(find.widgetWithText(TextButton, text)).style!;
}
const Size wideWindowSize = Size(1920.0, 1080.0);
const Size narrowWindowSize = Size(1070.0, 1770.0);
test('DatePickerThemeData copyWith, ==, hashCode basics', () {
expect(const DatePickerThemeData(), const DatePickerThemeData().copyWith());
expect(const DatePickerThemeData().hashCode, const DatePickerThemeData().copyWith().hashCode);
});
test('DatePickerThemeData lerp special cases', () {
const DatePickerThemeData data = DatePickerThemeData();
expect(identical(DatePickerThemeData.lerp(data, data, 0.5), data), true);
});
test('DatePickerThemeData defaults', () {
const DatePickerThemeData theme = DatePickerThemeData();
expect(theme.backgroundColor, null);
expect(theme.elevation, null);
expect(theme.shadowColor, null);
expect(theme.surfaceTintColor, null);
expect(theme.shape, null);
expect(theme.headerBackgroundColor, null);
expect(theme.headerForegroundColor, null);
expect(theme.headerHeadlineStyle, null);
expect(theme.headerHelpStyle, null);
expect(theme.weekdayStyle, null);
expect(theme.dayStyle, null);
expect(theme.dayForegroundColor, null);
expect(theme.dayBackgroundColor, null);
expect(theme.dayOverlayColor, null);
expect(theme.dayShape, null);
expect(theme.todayForegroundColor, null);
expect(theme.todayBackgroundColor, null);
expect(theme.todayBorder, null);
expect(theme.yearStyle, null);
expect(theme.yearForegroundColor, null);
expect(theme.yearBackgroundColor, null);
expect(theme.yearOverlayColor, null);
expect(theme.rangePickerBackgroundColor, null);
expect(theme.rangePickerElevation, null);
expect(theme.rangePickerShadowColor, null);
expect(theme.rangePickerSurfaceTintColor, null);
expect(theme.rangePickerShape, null);
expect(theme.rangePickerHeaderBackgroundColor, null);
expect(theme.rangePickerHeaderForegroundColor, null);
expect(theme.rangePickerHeaderHeadlineStyle, null);
expect(theme.rangePickerHeaderHelpStyle, null);
expect(theme.rangeSelectionBackgroundColor, null);
expect(theme.rangeSelectionOverlayColor, null);
expect(theme.dividerColor, null);
expect(theme.inputDecorationTheme, null);
expect(theme.cancelButtonStyle, null);
expect(theme.confirmButtonStyle, null);
});
testWidgets('DatePickerTheme.defaults M3 defaults', (WidgetTester tester) async {
late final DatePickerThemeData m3; // M3 Defaults
late final ThemeData theme;
late final ColorScheme colorScheme;
late final TextTheme textTheme;
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(useMaterial3: true),
home: Builder(
builder: (BuildContext context) {
m3 = DatePickerTheme.defaults(context);
theme = Theme.of(context);
colorScheme = theme.colorScheme;
textTheme = theme.textTheme;
return Container();
},
),
),
);
expect(m3.backgroundColor, colorScheme.surfaceContainerHigh);
expect(m3.elevation, 6);
expect(m3.shadowColor, const Color(0x00000000)); // Colors.transparent
expect(m3.surfaceTintColor, Colors.transparent);
expect(m3.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(28)));
expect(m3.headerBackgroundColor, const Color(0x00000000)); // Colors.transparent
expect(m3.headerForegroundColor, colorScheme.onSurfaceVariant);
expect(m3.headerHeadlineStyle, textTheme.headlineLarge);
expect(m3.headerHelpStyle, textTheme.labelLarge);
expect(m3.weekdayStyle, textTheme.bodyLarge?.apply(color: colorScheme.onSurface));
expect(m3.dayStyle, textTheme.bodyLarge);
expect(m3.dayForegroundColor?.resolve(<MaterialState>{}), colorScheme.onSurface);
expect(m3.dayForegroundColor?.resolve(<MaterialState>{MaterialState.selected}), colorScheme.onPrimary);
expect(m3.dayForegroundColor?.resolve(<MaterialState>{MaterialState.disabled}), colorScheme.onSurface.withOpacity(0.38));
expect(m3.dayBackgroundColor?.resolve(<MaterialState>{}), null);
expect(m3.dayBackgroundColor?.resolve(<MaterialState>{MaterialState.selected}), colorScheme.primary);
expect(m3.dayOverlayColor?.resolve(<MaterialState>{}), null);
expect(m3.dayOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.hovered}), colorScheme.onPrimary.withOpacity(0.08));
expect(m3.dayOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.focused}), colorScheme.onPrimary.withOpacity(0.1));
expect(m3.dayOverlayColor?.resolve(<MaterialState>{MaterialState.hovered}), colorScheme.onSurfaceVariant.withOpacity(0.08));
expect(m3.dayOverlayColor?.resolve(<MaterialState>{MaterialState.focused}), colorScheme.onSurfaceVariant.withOpacity(0.1));
expect(m3.dayOverlayColor?.resolve(<MaterialState>{MaterialState.pressed}), colorScheme.onSurfaceVariant.withOpacity(0.1));
expect(m3.dayOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.hovered, MaterialState.focused}), colorScheme.onPrimary.withOpacity(0.08));
expect(m3.dayOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.hovered, MaterialState.pressed}), colorScheme.onPrimary.withOpacity(0.1));
expect(m3.dayOverlayColor?.resolve(<MaterialState>{MaterialState.hovered, MaterialState.focused}), colorScheme.onSurfaceVariant.withOpacity(0.08));
expect(m3.dayOverlayColor?.resolve(<MaterialState>{MaterialState.hovered, MaterialState.pressed}), colorScheme.onSurfaceVariant.withOpacity(0.1));
expect(m3.dayShape?.resolve(<MaterialState>{}), const CircleBorder());
expect(m3.todayForegroundColor?.resolve(<MaterialState>{}), colorScheme.primary);
expect(m3.todayForegroundColor?.resolve(<MaterialState>{MaterialState.disabled}), colorScheme.primary.withOpacity(0.38));
expect(m3.todayBorder, BorderSide(color: colorScheme.primary));
expect(m3.yearStyle, textTheme.bodyLarge);
expect(m3.yearForegroundColor?.resolve(<MaterialState>{}), colorScheme.onSurfaceVariant);
expect(m3.yearForegroundColor?.resolve(<MaterialState>{MaterialState.selected}), colorScheme.onPrimary);
expect(m3.yearForegroundColor?.resolve(<MaterialState>{MaterialState.disabled}), colorScheme.onSurfaceVariant.withOpacity(0.38));
expect(m3.yearBackgroundColor?.resolve(<MaterialState>{}), null);
expect(m3.yearBackgroundColor?.resolve(<MaterialState>{MaterialState.selected}), colorScheme.primary);
expect(m3.yearOverlayColor?.resolve(<MaterialState>{}), null);
expect(m3.yearOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.hovered}), colorScheme.onPrimary.withOpacity(0.08));
expect(m3.yearOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.focused}), colorScheme.onPrimary.withOpacity(0.1));
expect(m3.yearOverlayColor?.resolve(<MaterialState>{MaterialState.hovered}), colorScheme.onSurfaceVariant.withOpacity(0.08));
expect(m3.yearOverlayColor?.resolve(<MaterialState>{MaterialState.focused}), colorScheme.onSurfaceVariant.withOpacity(0.1));
expect(m3.yearOverlayColor?.resolve(<MaterialState>{MaterialState.pressed}), colorScheme.onSurfaceVariant.withOpacity(0.1));
expect(m3.rangePickerElevation, 0);
expect(m3.rangePickerShape, const RoundedRectangleBorder());
expect(m3.rangePickerShadowColor, Colors.transparent);
expect(m3.rangePickerSurfaceTintColor, Colors.transparent);
expect(m3.rangeSelectionOverlayColor?.resolve(<MaterialState>{}), null);
expect(m3.rangePickerHeaderBackgroundColor, Colors.transparent);
expect(m3.rangePickerHeaderForegroundColor, colorScheme.onSurfaceVariant);
expect(m3.rangePickerHeaderHeadlineStyle, textTheme.titleLarge);
expect(m3.rangePickerHeaderHelpStyle, textTheme.titleSmall);
expect(m3.dividerColor, null);
expect(m3.inputDecorationTheme, null);
expect(m3.cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
expect(m3.confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
});
testWidgets('DatePickerTheme.defaults M2 defaults', (WidgetTester tester) async {
late final DatePickerThemeData m2; // M2 defaults
late final ThemeData theme;
late final ColorScheme colorScheme;
late final TextTheme textTheme;
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(useMaterial3: false),
home: Builder(
builder: (BuildContext context) {
m2 = DatePickerTheme.defaults(context);
theme = Theme.of(context);
colorScheme = theme.colorScheme;
textTheme = theme.textTheme;
return Container();
},
),
),
);
expect(m2.elevation, 24);
expect(m2.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))));
expect(m2.headerBackgroundColor, colorScheme.primary);
expect(m2.headerForegroundColor, colorScheme.onPrimary);
expect(m2.headerHeadlineStyle, textTheme.headlineSmall);
expect(m2.headerHelpStyle, textTheme.labelSmall);
expect(m2.weekdayStyle, textTheme.bodySmall?.apply(color: colorScheme.onSurface.withOpacity(0.60)));
expect(m2.dayStyle, textTheme.bodySmall);
expect(m2.dayForegroundColor?.resolve(<MaterialState>{}), colorScheme.onSurface);
expect(m2.dayForegroundColor?.resolve(<MaterialState>{MaterialState.selected}), colorScheme.onPrimary);
expect(m2.dayForegroundColor?.resolve(<MaterialState>{MaterialState.disabled}), colorScheme.onSurface.withOpacity(0.38));
expect(m2.dayBackgroundColor?.resolve(<MaterialState>{}), null);
expect(m2.dayBackgroundColor?.resolve(<MaterialState>{MaterialState.selected}), colorScheme.primary);
expect(m2.dayOverlayColor?.resolve(<MaterialState>{}), null);
expect(m2.dayOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.hovered}), colorScheme.onPrimary.withOpacity(0.08));
expect(m2.dayOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.focused}), colorScheme.onPrimary.withOpacity(0.12));
expect(m2.dayOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.pressed}), colorScheme.onPrimary.withOpacity(0.38));
expect(m2.dayOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.hovered, MaterialState.focused}), colorScheme.onPrimary.withOpacity(0.08));
expect(m2.dayOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.hovered, MaterialState.pressed}), colorScheme.onPrimary.withOpacity(0.38));
expect(m2.dayOverlayColor?.resolve(<MaterialState>{MaterialState.hovered}), colorScheme.onSurfaceVariant.withOpacity(0.08));
expect(m2.dayOverlayColor?.resolve(<MaterialState>{MaterialState.focused}), colorScheme.onSurfaceVariant.withOpacity(0.12));
expect(m2.dayOverlayColor?.resolve(<MaterialState>{MaterialState.pressed}), colorScheme.onSurfaceVariant.withOpacity(0.12));
expect(m2.dayShape?.resolve(<MaterialState>{}), const CircleBorder());
expect(m2.todayForegroundColor?.resolve(<MaterialState>{}), colorScheme.primary);
expect(m2.todayForegroundColor?.resolve(<MaterialState>{MaterialState.disabled}), colorScheme.onSurface.withOpacity(0.38));
expect(m2.todayBorder, BorderSide(color: colorScheme.primary));
expect(m2.yearStyle, textTheme.bodyLarge);
expect(m2.rangePickerBackgroundColor, colorScheme.surface);
expect(m2.rangePickerElevation, 0);
expect(m2.rangePickerShape, const RoundedRectangleBorder());
expect(m2.rangePickerShadowColor, Colors.transparent);
expect(m2.rangePickerSurfaceTintColor, Colors.transparent);
expect(m2.rangeSelectionOverlayColor?.resolve(<MaterialState>{}), null);
expect(m2.rangeSelectionOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.hovered}), colorScheme.onPrimary.withOpacity(0.08));
expect(m2.rangeSelectionOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.focused}), colorScheme.onPrimary.withOpacity(0.12));
expect(m2.rangeSelectionOverlayColor?.resolve(<MaterialState>{MaterialState.selected, MaterialState.pressed}), colorScheme.onPrimary.withOpacity(0.38));
expect(m2.rangeSelectionOverlayColor?.resolve(<MaterialState>{MaterialState.hovered}), colorScheme.onSurfaceVariant.withOpacity(0.08));
expect(m2.rangeSelectionOverlayColor?.resolve(<MaterialState>{MaterialState.focused}), colorScheme.onSurfaceVariant.withOpacity(0.12));
expect(m2.rangeSelectionOverlayColor?.resolve(<MaterialState>{MaterialState.pressed}), colorScheme.onSurfaceVariant.withOpacity(0.12));
expect(m2.rangePickerHeaderBackgroundColor, colorScheme.primary);
expect(m2.rangePickerHeaderForegroundColor, colorScheme.onPrimary);
expect(m2.rangePickerHeaderHeadlineStyle, textTheme.headlineSmall);
expect(m2.rangePickerHeaderHelpStyle, textTheme.labelSmall);
expect(m2.dividerColor, null);
expect(m2.inputDecorationTheme, null);
expect(m2.cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
expect(m2.confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
});
testWidgets('Default DatePickerThemeData debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const DatePickerThemeData().debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[]);
});
testWidgets('DatePickerThemeData implements debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
datePickerTheme.debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, equalsIgnoringHashCodes(<String>[
'backgroundColor: Color(0xfffffff0)',
'elevation: 6.0',
'shadowColor: Color(0xfffffff1)',
'surfaceTintColor: Color(0xfffffff2)',
'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)',
'headerBackgroundColor: Color(0xfffffff3)',
'headerForegroundColor: Color(0xfffffff4)',
'headerHeadlineStyle: TextStyle(inherit: true, size: 10.0)',
'headerHelpStyle: TextStyle(inherit: true, size: 11.0)',
'weekDayStyle: TextStyle(inherit: true, size: 12.0)',
'dayStyle: TextStyle(inherit: true, size: 13.0)',
'dayForegroundColor: WidgetStatePropertyAll(Color(0xfffffff5))',
'dayBackgroundColor: WidgetStatePropertyAll(Color(0xfffffff6))',
'dayOverlayColor: WidgetStatePropertyAll(Color(0xfffffff7))',
'dayShape: WidgetStatePropertyAll(RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero))',
'todayForegroundColor: WidgetStatePropertyAll(Color(0xfffffff8))',
'todayBackgroundColor: WidgetStatePropertyAll(Color(0xfffffff9))',
'todayBorder: BorderSide(width: 3.0)',
'yearStyle: TextStyle(inherit: true, size: 13.0)',
'yearForegroundColor: WidgetStatePropertyAll(Color(0xfffffffa))',
'yearBackgroundColor: WidgetStatePropertyAll(Color(0xfffffffb))',
'yearOverlayColor: WidgetStatePropertyAll(Color(0xfffffffc))',
'rangePickerBackgroundColor: Color(0xfffffffd)',
'rangePickerElevation: 7.0',
'rangePickerShadowColor: Color(0xfffffffe)',
'rangePickerSurfaceTintColor: Color(0xffffffff)',
'rangePickerShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)',
'rangePickerHeaderBackgroundColor: Color(0xffffff0f)',
'rangePickerHeaderForegroundColor: Color(0xffffff1f)',
'rangePickerHeaderHeadlineStyle: TextStyle(inherit: true, size: 14.0)',
'rangePickerHeaderHelpStyle: TextStyle(inherit: true, size: 15.0)',
'rangeSelectionBackgroundColor: Color(0xffffff2f)',
'rangeSelectionOverlayColor: WidgetStatePropertyAll(Color(0xffffff3f))',
'dividerColor: Color(0xffffff4f)',
'inputDecorationTheme: InputDecorationTheme#00000(fillColor: Color(0xffffff5f), border: UnderlineInputBorder())',
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(Color(0xffffff6f)))',
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(Color(0xffffff7f)))'
]));
});
testWidgets('DatePickerDialog uses ThemeData datePicker theme (calendar mode)', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
datePickerTheme: datePickerTheme,
useMaterial3: true,
),
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: Center(
child: DatePickerDialog(
initialDate: DateTime(2023, DateTime.january, 25),
firstDate: DateTime(2022),
lastDate: DateTime(2024, DateTime.december, 31),
currentDate: DateTime(2023, DateTime.january, 24),
),
),
),
),
),
);
final Material material = findDialogMaterial(tester);
expect(material.color, datePickerTheme.backgroundColor);
expect(material.elevation, datePickerTheme.elevation);
expect(material.shadowColor, datePickerTheme.shadowColor);
expect(material.surfaceTintColor, datePickerTheme.surfaceTintColor);
expect(material.shape, datePickerTheme.shape);
final Text selectDate = tester.widget<Text>(find.text('Select date'));
final Material headerMaterial = findHeaderMaterial(tester, 'Select date');
expect(selectDate.style?.color, datePickerTheme.headerForegroundColor);
expect(selectDate.style?.fontSize, datePickerTheme.headerHelpStyle?.fontSize);
expect(headerMaterial.color, datePickerTheme.headerBackgroundColor);
final Text weekday = tester.widget<Text>(find.text('W'));
expect(weekday.style?.color, datePickerTheme.weekdayStyle?.color);
expect(weekday.style?.fontSize, datePickerTheme.weekdayStyle?.fontSize);
final Text selectedDate = tester.widget<Text>(find.text('Wed, Jan 25'));
expect(selectedDate.style?.color, datePickerTheme.headerForegroundColor);
expect(selectedDate.style?.fontSize, datePickerTheme.headerHeadlineStyle?.fontSize);
final Text day31 = tester.widget<Text>(find.text('31'));
final ShapeDecoration day31Decoration = findDayDecoration(tester, '31')!;
expect(day31.style?.color, datePickerTheme.dayForegroundColor?.resolve(<MaterialState>{}));
expect(day31.style?.fontSize, datePickerTheme.dayStyle?.fontSize);
expect(day31Decoration.color, datePickerTheme.dayBackgroundColor?.resolve(<MaterialState>{}));
expect(day31Decoration.shape, datePickerTheme.dayShape?.resolve(<MaterialState>{}));
final Text day24 = tester.widget<Text>(find.text('24')); // DatePickerDialog.currentDate
final ShapeDecoration day24Decoration = findDayDecoration(tester, '24')!;
final OutlinedBorder day24Shape = day24Decoration.shape as OutlinedBorder;
expect(day24.style?.fontSize, datePickerTheme.dayStyle?.fontSize);
expect(day24.style?.color, datePickerTheme.todayForegroundColor?.resolve(<MaterialState>{}));
expect(day24Decoration.color, datePickerTheme.todayBackgroundColor?.resolve(<MaterialState>{}));
expect(
day24Decoration.shape,
datePickerTheme.dayShape?.resolve(<MaterialState>{})!
.copyWith(side: datePickerTheme.todayBorder?.copyWith(color: datePickerTheme.todayForegroundColor?.resolve(<MaterialState>{}))),
);
expect(day24Shape.side.width, datePickerTheme.todayBorder?.width);
// Test the day overlay color.
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
final TestGesture gesture = await tester.createGesture(
kind: PointerDeviceKind.mouse,
);
await gesture.addPointer();
await gesture.moveTo(tester.getCenter(find.text('25')));
await tester.pumpAndSettle();
expect(inkFeatures, paints..circle(color: datePickerTheme.dayOverlayColor?.resolve(<MaterialState>{})));
// Show the year selector.
await tester.tap(find.text('January 2023'));
await tester.pumpAndSettle();
final Text year2022 = tester.widget<Text>(find.text('2022'));
final BoxDecoration year2022Decoration = findTextDecoration(tester, '2022')!;
expect(year2022.style?.fontSize, datePickerTheme.yearStyle?.fontSize);
expect(year2022.style?.color, datePickerTheme.yearForegroundColor?.resolve(<MaterialState>{}));
expect(year2022Decoration.color, datePickerTheme.yearBackgroundColor?.resolve(<MaterialState>{}));
final Text year2023 = tester.widget<Text>(find.text('2023')); // DatePickerDialog.currentDate
final BoxDecoration year2023Decoration = findTextDecoration(tester, '2023')!;
expect(year2023.style?.fontSize, datePickerTheme.yearStyle?.fontSize);
expect(year2023.style?.color, datePickerTheme.todayForegroundColor?.resolve(<MaterialState>{}));
expect(year2023Decoration.color, datePickerTheme.todayBackgroundColor?.resolve(<MaterialState>{}));
expect(year2023Decoration.border?.top.width, datePickerTheme.todayBorder?.width);
expect(year2023Decoration.border?.bottom.width, datePickerTheme.todayBorder?.width);
expect(year2023Decoration.border?.top.color, datePickerTheme.todayForegroundColor?.resolve(<MaterialState>{}));
expect(year2023Decoration.border?.bottom.color, datePickerTheme.todayForegroundColor?.resolve(<MaterialState>{}));
// Test the year overlay color.
await gesture.moveTo(tester.getCenter(find.text('2024')));
await tester.pumpAndSettle();
expect(inkFeatures, paints..rect(color: datePickerTheme.yearOverlayColor?.resolve(<MaterialState>{})));
final ButtonStyle cancelButtonStyle = actionButtonStyle(tester, 'Cancel');
expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.cancelButtonStyle.toString()));
final ButtonStyle confirmButtonStyle = actionButtonStyle(tester, 'OK');
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.confirmButtonStyle.toString()));
});
testWidgets('DatePickerDialog uses ThemeData datePicker theme (input mode)', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
datePickerTheme: datePickerTheme,
useMaterial3: true,
),
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: Center(
child: DatePickerDialog(
initialEntryMode: DatePickerEntryMode.input,
initialDate: DateTime(2023, DateTime.january, 25),
firstDate: DateTime(2022),
lastDate: DateTime(2024, DateTime.december, 31),
currentDate: DateTime(2023, DateTime.january, 24),
),
),
),
),
),
);
final Material material = findDialogMaterial(tester);
expect(material.color, datePickerTheme.backgroundColor);
expect(material.elevation, datePickerTheme.elevation);
expect(material.shadowColor, datePickerTheme.shadowColor);
expect(material.surfaceTintColor, datePickerTheme.surfaceTintColor);
expect(material.shape, datePickerTheme.shape);
final Text selectDate = tester.widget<Text>(find.text('Select date'));
final Material headerMaterial = findHeaderMaterial(tester, 'Select date');
expect(selectDate.style?.color, datePickerTheme.headerForegroundColor);
expect(selectDate.style?.fontSize, datePickerTheme.headerHelpStyle?.fontSize);
expect(headerMaterial.color, datePickerTheme.headerBackgroundColor);
final InputDecoration inputDecoration = tester.widget<TextField>(find.byType(TextField)).decoration!;
expect(inputDecoration.fillColor, datePickerTheme.inputDecorationTheme?.fillColor);
final ButtonStyle cancelButtonStyle = actionButtonStyle(tester, 'Cancel');
expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.cancelButtonStyle.toString()));
final ButtonStyle confirmButtonStyle = actionButtonStyle(tester, 'OK');
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.confirmButtonStyle.toString()));
});
testWidgets('DateRangePickerDialog uses ThemeData datePicker theme', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
datePickerTheme: datePickerTheme,
useMaterial3: true,
),
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: Center(
child: DateRangePickerDialog(
firstDate: DateTime(2023),
lastDate: DateTime(2023, DateTime.january, 31),
initialDateRange: DateTimeRange(
start: DateTime(2023, DateTime.january, 17),
end: DateTime(2023, DateTime.january, 20),
),
currentDate: DateTime(2023, DateTime.january, 23),
),
),
),
),
),
);
final Material material = findDialogMaterial(tester);
expect(material.color, datePickerTheme.backgroundColor);
expect(tester.widget<Scaffold>(find.byType(Scaffold)).backgroundColor, datePickerTheme.rangePickerBackgroundColor);
expect(material.elevation, datePickerTheme.rangePickerElevation);
expect(material.shadowColor, datePickerTheme.rangePickerShadowColor);
expect(material.surfaceTintColor, datePickerTheme.rangePickerSurfaceTintColor);
expect(material.shape, datePickerTheme.rangePickerShape);
final AppBar appBar = tester.widget<AppBar>(find.byType(AppBar));
expect(appBar.backgroundColor, datePickerTheme.rangePickerHeaderBackgroundColor);
final Text selectRange = tester.widget<Text>(find.text('Select range'));
expect(selectRange.style?.color, datePickerTheme.rangePickerHeaderForegroundColor);
expect(selectRange.style?.fontSize, datePickerTheme.rangePickerHeaderHelpStyle?.fontSize);
final Text selectedDate = tester.widget<Text>(find.text('Jan 17'));
expect(selectedDate.style?.color, datePickerTheme.rangePickerHeaderForegroundColor);
expect(selectedDate.style?.fontSize, datePickerTheme.rangePickerHeaderHeadlineStyle?.fontSize);
// Test the day overlay color.
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
final TestGesture gesture = await tester.createGesture(
kind: PointerDeviceKind.mouse,
);
await gesture.addPointer();
await gesture.moveTo(tester.getCenter(find.text('16')));
await tester.pumpAndSettle();
expect(inkFeatures, paints..circle(color: datePickerTheme.dayOverlayColor?.resolve(<MaterialState>{})));
// Test the range selection overlay color.
await gesture.moveTo(tester.getCenter(find.text('18')));
await tester.pumpAndSettle();
expect(inkFeatures, paints..circle(color: datePickerTheme.rangeSelectionOverlayColor?.resolve(<MaterialState>{})));
});
testWidgets('Material2 - DateRangePickerDialog uses ThemeData datePicker theme', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
datePickerTheme: datePickerTheme,
useMaterial3: false,
),
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: Center(
child: DateRangePickerDialog(
firstDate: DateTime(2023),
lastDate: DateTime(2023, DateTime.january, 31),
initialDateRange: DateTimeRange(
start: DateTime(2023, DateTime.january, 17),
end: DateTime(2023, DateTime.january, 20),
),
currentDate: DateTime(2023, DateTime.january, 23),
),
),
),
),
),
);
final Material material = findDialogMaterial(tester);
expect(material.color, datePickerTheme.backgroundColor);
expect(tester.widget<Scaffold>(find.byType(Scaffold)).backgroundColor, datePickerTheme.rangePickerBackgroundColor);
expect(material.elevation, datePickerTheme.rangePickerElevation);
expect(material.shadowColor, datePickerTheme.rangePickerShadowColor);
expect(material.surfaceTintColor, datePickerTheme.rangePickerSurfaceTintColor);
expect(material.shape, datePickerTheme.rangePickerShape);
final AppBar appBar = tester.widget<AppBar>(find.byType(AppBar));
expect(appBar.backgroundColor, datePickerTheme.rangePickerHeaderBackgroundColor);
final Text selectRange = tester.widget<Text>(find.text('SELECT RANGE'));
expect(selectRange.style?.color, datePickerTheme.rangePickerHeaderForegroundColor);
expect(selectRange.style?.fontSize, datePickerTheme.rangePickerHeaderHelpStyle?.fontSize);
final Text selectedDate = tester.widget<Text>(find.text('Jan 17'));
expect(selectedDate.style?.color, datePickerTheme.rangePickerHeaderForegroundColor);
expect(selectedDate.style?.fontSize, datePickerTheme.rangePickerHeaderHeadlineStyle?.fontSize);
// Test the day overlay color.
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
final TestGesture gesture = await tester.createGesture(
kind: PointerDeviceKind.mouse,
);
await gesture.addPointer();
await gesture.moveTo(tester.getCenter(find.text('16')));
await tester.pumpAndSettle();
expect(inkFeatures, paints..circle(color: datePickerTheme.dayOverlayColor?.resolve(<MaterialState>{})));
// Test the range selection overlay color.
await gesture.moveTo(tester.getCenter(find.text('18')));
await tester.pumpAndSettle();
expect(inkFeatures, paints..circle(color: datePickerTheme.rangeSelectionOverlayColor?.resolve(<MaterialState>{})));
});
testWidgets('Dividers use DatePickerThemeData.dividerColor', (WidgetTester tester) async {
Future<void> showPicker(WidgetTester tester, Size size) async {
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1.0;
addTearDown(tester.view.reset);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
datePickerTheme: datePickerTheme,
useMaterial3: true,
),
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: Center(
child: DatePickerDialog(
initialDate: DateTime(2023, DateTime.january, 25),
firstDate: DateTime(2022),
lastDate: DateTime(2024, DateTime.december, 31),
currentDate: DateTime(2023, DateTime.january, 24),
),
),
),
),
),
);
}
await showPicker(tester, wideWindowSize);
// Test vertical divider.
final VerticalDivider verticalDivider = tester.widget(find.byType(VerticalDivider));
expect(verticalDivider.color, datePickerTheme.dividerColor);
// Test portrait layout.
await showPicker(tester, narrowWindowSize);
// Test horizontal divider.
final Divider horizontalDivider = tester.widget(find.byType(Divider));
expect(horizontalDivider.color, datePickerTheme.dividerColor);
});
testWidgets(
'DatePicker uses ThemeData.inputDecorationTheme properties '
'which are null in DatePickerThemeData.inputDecorationTheme',
(WidgetTester tester) async {
Widget buildWidget({
InputDecorationTheme? inputDecorationTheme,
DatePickerThemeData? datePickerTheme,
}) {
return MaterialApp(
theme: ThemeData(
useMaterial3: true,
inputDecorationTheme: inputDecorationTheme,
datePickerTheme: datePickerTheme,
),
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: Center(
child: DatePickerDialog(
initialEntryMode: DatePickerEntryMode.input,
initialDate: DateTime(2023, DateTime.january, 25),
firstDate: DateTime(2022),
lastDate: DateTime(2024, DateTime.december, 31),
currentDate: DateTime(2023, DateTime.january, 24),
),
),
),
),
);
}
// Test DatePicker with DatePickerThemeData.inputDecorationTheme.
await tester.pumpWidget(buildWidget(
inputDecorationTheme: const InputDecorationTheme(filled: true),
datePickerTheme: datePickerTheme,
));
InputDecoration inputDecoration = tester.widget<TextField>(find.byType(TextField)).decoration!;
expect(inputDecoration.fillColor, datePickerTheme.inputDecorationTheme!.fillColor);
expect(inputDecoration.border , datePickerTheme.inputDecorationTheme!.border);
// Test DatePicker with ThemeData.inputDecorationTheme.
await tester.pumpWidget(buildWidget(
inputDecorationTheme: const InputDecorationTheme(
filled: true,
fillColor: Color(0xFF00FF00),
border: OutlineInputBorder(),
),
));
await tester.pumpAndSettle();
inputDecoration = tester.widget<TextField>(find.byType(TextField)).decoration!;
expect(inputDecoration.fillColor, const Color(0xFF00FF00));
expect(inputDecoration.border , const OutlineInputBorder());
});
testWidgets('DatePickerDialog resolves DatePickerTheme.dayOverlayColor states', (WidgetTester tester) async {
final MaterialStateProperty<Color> dayOverlayColor = MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return const Color(0xff00ff00);
}
if (states.contains(MaterialState.focused)) {
return const Color(0xffff00ff);
}
if (states.contains(MaterialState.pressed)) {
return const Color(0xffffff00);
}
return Colors.transparent;
});
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
datePickerTheme: DatePickerThemeData(
dayOverlayColor: dayOverlayColor,
),
useMaterial3: true,
),
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: Center(
child: Focus(
child: DatePickerDialog(
initialDate: DateTime(2023, DateTime.january, 25),
firstDate: DateTime(2022),
lastDate: DateTime(2024, DateTime.december, 31),
currentDate: DateTime(2023, DateTime.january, 24),
),
),
),
),
),
),
);
// Test the hover overlay color.
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
final TestGesture gesture = await tester.createGesture(
kind: PointerDeviceKind.mouse,
);
await gesture.addPointer();
await gesture.moveTo(tester.getCenter(find.text('20')));
await tester.pumpAndSettle();
expect(
inkFeatures,
paints
..circle(color: dayOverlayColor.resolve(<MaterialState>{MaterialState.hovered})),
);
// Test the pressed overlay color.
await gesture.down(tester.getCenter(find.text('20')));
await tester.pumpAndSettle();
if (kIsWeb) {
// An extra circle is painted on the web for the hovered state.
expect(
inkFeatures,
paints
..circle(color: dayOverlayColor.resolve(<MaterialState>{MaterialState.hovered}))
..circle(color: dayOverlayColor.resolve(<MaterialState>{MaterialState.hovered}))
..circle(color: dayOverlayColor.resolve(<MaterialState>{MaterialState.pressed})),
);
} else {
expect(
inkFeatures,
paints
..circle(color: dayOverlayColor.resolve(<MaterialState>{MaterialState.hovered}))
..circle(color: dayOverlayColor.resolve(<MaterialState>{MaterialState.pressed})),
);
}
await gesture.removePointer();
await tester.pumpAndSettle();
// Focus day selection.
for (int i = 0; i < 5; i++) {
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.pumpAndSettle();
}
// Test the focused overlay color.
expect(
inkFeatures,
paints
..circle(color: dayOverlayColor.resolve(<MaterialState>{MaterialState.focused})),
);
});
testWidgets('DatePickerDialog resolves DatePickerTheme.yearOverlayColor states', (WidgetTester tester) async {
final MaterialStateProperty<Color> yearOverlayColor = MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return const Color(0xff00ff00);
}
if (states.contains(MaterialState.focused)) {
return const Color(0xffff00ff);
}
if (states.contains(MaterialState.pressed)) {
return const Color(0xffffff00);
}
return Colors.transparent;
});
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
datePickerTheme: DatePickerThemeData(
yearOverlayColor: yearOverlayColor,
),
useMaterial3: true,
),
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: Center(
child: Focus(
child: DatePickerDialog(
initialDate: DateTime(2023, DateTime.january, 25),
firstDate: DateTime(2022),
lastDate: DateTime(2024, DateTime.december, 31),
currentDate: DateTime(2023, DateTime.january, 24),
initialCalendarMode: DatePickerMode.year,
),
),
),
),
),
),
);
// Test the hover overlay color.
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
final TestGesture gesture = await tester.createGesture(
kind: PointerDeviceKind.mouse,
);
await gesture.addPointer();
await gesture.moveTo(tester.getCenter(find.text('2022')));
await tester.pumpAndSettle();
expect(
inkFeatures,
paints
..rect(color: yearOverlayColor.resolve(<MaterialState>{MaterialState.hovered})),
);
// Test the pressed overlay color.
await gesture.down(tester.getCenter(find.text('2022')));
await tester.pumpAndSettle();
expect(
inkFeatures,
paints
..rect(color: yearOverlayColor.resolve(<MaterialState>{MaterialState.hovered}))
..rect(color: yearOverlayColor.resolve(<MaterialState>{MaterialState.pressed})),
);
await gesture.removePointer();
await tester.pumpAndSettle();
// Focus year selection.
for (int i = 0; i < 3; i++) {
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.pumpAndSettle();
}
// Test the focused overlay color.
expect(
inkFeatures,
paints
..rect(color: yearOverlayColor.resolve(<MaterialState>{MaterialState.focused})),
);
});
testWidgets('DateRangePickerDialog resolves DatePickerTheme.rangeSelectionOverlayColor states', (WidgetTester tester) async {
final MaterialStateProperty<Color> rangeSelectionOverlayColor = MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return const Color(0xff00ff00);
}
if (states.contains(MaterialState.pressed)) {
return const Color(0xffffff00);
}
return Colors.transparent;
});
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
datePickerTheme: DatePickerThemeData(
rangeSelectionOverlayColor: rangeSelectionOverlayColor,
),
useMaterial3: true,
),
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: Center(
child: DateRangePickerDialog(
firstDate: DateTime(2023),
lastDate: DateTime(2023, DateTime.january, 31),
initialDateRange: DateTimeRange(
start: DateTime(2023, DateTime.january, 17),
end: DateTime(2023, DateTime.january, 20),
),
currentDate: DateTime(2023, DateTime.january, 23),
),
),
),
),
),
);
// Test the hover overlay color.
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
final TestGesture gesture = await tester.createGesture(
kind: PointerDeviceKind.mouse,
);
await gesture.addPointer();
await gesture.moveTo(tester.getCenter(find.text('18')));
await tester.pumpAndSettle();
expect(
inkFeatures,
paints
..circle(color: rangeSelectionOverlayColor.resolve(<MaterialState>{MaterialState.hovered})),
);
// Test the pressed overlay color.
await gesture.down(tester.getCenter(find.text('18')));
await tester.pumpAndSettle();
if (kIsWeb) {
// An extra circle is painted on the web for the hovered state.
expect(
inkFeatures,
paints
..circle(color: rangeSelectionOverlayColor.resolve(<MaterialState>{MaterialState.hovered}))
..circle(color: rangeSelectionOverlayColor.resolve(<MaterialState>{MaterialState.hovered}))
..circle(color: rangeSelectionOverlayColor.resolve(<MaterialState>{MaterialState.pressed})),
);
} else {
expect(
inkFeatures,
paints
..circle(color: rangeSelectionOverlayColor.resolve(<MaterialState>{MaterialState.hovered}))
..circle(color: rangeSelectionOverlayColor.resolve(<MaterialState>{MaterialState.pressed})),
);
}
});
}