Unverified Commit 32fe4d7f authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Add `DatePickerTheme.inputDecorationTheme` for the DatePicker with input mode. (#128950)

parent 9c963572
...@@ -9,6 +9,7 @@ import 'package:flutter/widgets.dart'; ...@@ -9,6 +9,7 @@ import 'package:flutter/widgets.dart';
import 'color_scheme.dart'; import 'color_scheme.dart';
import 'colors.dart'; import 'colors.dart';
import 'input_decorator.dart';
import 'material_state.dart'; import 'material_state.dart';
import 'text_theme.dart'; import 'text_theme.dart';
import 'theme.dart'; import 'theme.dart';
...@@ -68,6 +69,7 @@ class DatePickerThemeData with Diagnosticable { ...@@ -68,6 +69,7 @@ class DatePickerThemeData with Diagnosticable {
this.rangeSelectionBackgroundColor, this.rangeSelectionBackgroundColor,
this.rangeSelectionOverlayColor, this.rangeSelectionOverlayColor,
this.dividerColor, this.dividerColor,
this.inputDecorationTheme,
}); });
/// Overrides the default value of [Dialog.backgroundColor]. /// Overrides the default value of [Dialog.backgroundColor].
...@@ -288,6 +290,10 @@ class DatePickerThemeData with Diagnosticable { ...@@ -288,6 +290,10 @@ class DatePickerThemeData with Diagnosticable {
/// and vertical divider when the dialog is in landscape orientation. /// and vertical divider when the dialog is in landscape orientation.
final Color? dividerColor; final Color? dividerColor;
/// Overrides the [InputDatePickerFormField]'s input decoration theme.
/// If this is null, [ThemeData.inputDecorationTheme] is used instead.
final InputDecorationTheme? inputDecorationTheme;
/// Creates a copy of this object with the given fields replaced with the /// Creates a copy of this object with the given fields replaced with the
/// new values. /// new values.
DatePickerThemeData copyWith({ DatePickerThemeData copyWith({
...@@ -324,6 +330,7 @@ class DatePickerThemeData with Diagnosticable { ...@@ -324,6 +330,7 @@ class DatePickerThemeData with Diagnosticable {
Color? rangeSelectionBackgroundColor, Color? rangeSelectionBackgroundColor,
MaterialStateProperty<Color?>? rangeSelectionOverlayColor, MaterialStateProperty<Color?>? rangeSelectionOverlayColor,
Color? dividerColor, Color? dividerColor,
InputDecorationTheme? inputDecorationTheme,
}) { }) {
return DatePickerThemeData( return DatePickerThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor, backgroundColor: backgroundColor ?? this.backgroundColor,
...@@ -359,6 +366,7 @@ class DatePickerThemeData with Diagnosticable { ...@@ -359,6 +366,7 @@ class DatePickerThemeData with Diagnosticable {
rangeSelectionBackgroundColor: rangeSelectionBackgroundColor ?? this.rangeSelectionBackgroundColor, rangeSelectionBackgroundColor: rangeSelectionBackgroundColor ?? this.rangeSelectionBackgroundColor,
rangeSelectionOverlayColor: rangeSelectionOverlayColor ?? this.rangeSelectionOverlayColor, rangeSelectionOverlayColor: rangeSelectionOverlayColor ?? this.rangeSelectionOverlayColor,
dividerColor: dividerColor ?? this.dividerColor, dividerColor: dividerColor ?? this.dividerColor,
inputDecorationTheme: inputDecorationTheme ?? this.inputDecorationTheme,
); );
} }
...@@ -401,6 +409,7 @@ class DatePickerThemeData with Diagnosticable { ...@@ -401,6 +409,7 @@ class DatePickerThemeData with Diagnosticable {
rangeSelectionBackgroundColor: Color.lerp(a?.rangeSelectionBackgroundColor, b?.rangeSelectionBackgroundColor, t), rangeSelectionBackgroundColor: Color.lerp(a?.rangeSelectionBackgroundColor, b?.rangeSelectionBackgroundColor, t),
rangeSelectionOverlayColor: MaterialStateProperty.lerp<Color?>(a?.rangeSelectionOverlayColor, b?.rangeSelectionOverlayColor, t, Color.lerp), rangeSelectionOverlayColor: MaterialStateProperty.lerp<Color?>(a?.rangeSelectionOverlayColor, b?.rangeSelectionOverlayColor, t, Color.lerp),
dividerColor: Color.lerp(a?.dividerColor, b?.dividerColor, t), dividerColor: Color.lerp(a?.dividerColor, b?.dividerColor, t),
inputDecorationTheme: t < 0.5 ? a?.inputDecorationTheme : b?.inputDecorationTheme,
); );
} }
...@@ -449,6 +458,7 @@ class DatePickerThemeData with Diagnosticable { ...@@ -449,6 +458,7 @@ class DatePickerThemeData with Diagnosticable {
rangeSelectionBackgroundColor, rangeSelectionBackgroundColor,
rangeSelectionOverlayColor, rangeSelectionOverlayColor,
dividerColor, dividerColor,
inputDecorationTheme,
]); ]);
@override @override
...@@ -489,7 +499,8 @@ class DatePickerThemeData with Diagnosticable { ...@@ -489,7 +499,8 @@ class DatePickerThemeData with Diagnosticable {
&& other.rangePickerHeaderHelpStyle == rangePickerHeaderHelpStyle && other.rangePickerHeaderHelpStyle == rangePickerHeaderHelpStyle
&& other.rangeSelectionBackgroundColor == rangeSelectionBackgroundColor && other.rangeSelectionBackgroundColor == rangeSelectionBackgroundColor
&& other.rangeSelectionOverlayColor == rangeSelectionOverlayColor && other.rangeSelectionOverlayColor == rangeSelectionOverlayColor
&& other.dividerColor == dividerColor; && other.dividerColor == dividerColor
&& other.inputDecorationTheme == inputDecorationTheme;
} }
@override @override
...@@ -528,6 +539,7 @@ class DatePickerThemeData with Diagnosticable { ...@@ -528,6 +539,7 @@ class DatePickerThemeData with Diagnosticable {
properties.add(ColorProperty('rangeSelectionBackgroundColor', rangeSelectionBackgroundColor, defaultValue: null)); properties.add(ColorProperty('rangeSelectionBackgroundColor', rangeSelectionBackgroundColor, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('rangeSelectionOverlayColor', rangeSelectionOverlayColor, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('rangeSelectionOverlayColor', rangeSelectionOverlayColor, defaultValue: null));
properties.add(ColorProperty('dividerColor', dividerColor, defaultValue: null)); properties.add(ColorProperty('dividerColor', dividerColor, defaultValue: null));
properties.add(DiagnosticsProperty<InputDecorationTheme>('inputDecorationTheme', inputDecorationTheme, defaultValue: null));
} }
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'date.dart'; import 'date.dart';
import 'date_picker_theme.dart';
import 'input_border.dart'; import 'input_border.dart';
import 'input_decorator.dart'; import 'input_decorator.dart';
import 'material_localizations.dart'; import 'material_localizations.dart';
...@@ -248,16 +249,19 @@ class _InputDatePickerFormFieldState extends State<InputDatePickerFormField> { ...@@ -248,16 +249,19 @@ class _InputDatePickerFormFieldState extends State<InputDatePickerFormField> {
final ThemeData theme = Theme.of(context); final ThemeData theme = Theme.of(context);
final bool useMaterial3 = theme.useMaterial3; final bool useMaterial3 = theme.useMaterial3;
final MaterialLocalizations localizations = MaterialLocalizations.of(context); final MaterialLocalizations localizations = MaterialLocalizations.of(context);
final DatePickerThemeData datePickerTheme = theme.datePickerTheme;
final InputDecorationTheme inputTheme = theme.inputDecorationTheme; final InputDecorationTheme inputTheme = theme.inputDecorationTheme;
final InputBorder inputBorder = inputTheme.border final InputBorder effectiveInputBorder = datePickerTheme.inputDecorationTheme?.border
?? theme.inputDecorationTheme.border
?? (useMaterial3 ? const OutlineInputBorder() : const UnderlineInputBorder()); ?? (useMaterial3 ? const OutlineInputBorder() : const UnderlineInputBorder());
return TextFormField( return TextFormField(
decoration: InputDecoration( decoration: InputDecoration(
border: inputBorder,
filled: inputTheme.filled,
hintText: widget.fieldHintText ?? localizations.dateHelpText, hintText: widget.fieldHintText ?? localizations.dateHelpText,
labelText: widget.fieldLabelText ?? localizations.dateInputLabel, labelText: widget.fieldLabelText ?? localizations.dateInputLabel,
).applyDefaults(inputTheme
.merge(datePickerTheme.inputDecorationTheme)
.copyWith(border: effectiveInputBorder),
), ),
validator: _validateDate, validator: _validateDate,
keyboardType: widget.keyboardType ?? TextInputType.datetime, keyboardType: widget.keyboardType ?? TextInputType.datetime,
......
...@@ -40,7 +40,11 @@ void main() { ...@@ -40,7 +40,11 @@ void main() {
rangePickerHeaderHelpStyle: TextStyle(fontSize: 15), rangePickerHeaderHelpStyle: TextStyle(fontSize: 15),
rangeSelectionBackgroundColor: Color(0xffffff2f), rangeSelectionBackgroundColor: Color(0xffffff2f),
rangeSelectionOverlayColor: MaterialStatePropertyAll<Color>(Color(0xffffff3f)), rangeSelectionOverlayColor: MaterialStatePropertyAll<Color>(Color(0xffffff3f)),
dividerColor: Color(0xffffff3f), dividerColor: Color(0xffffff4f),
inputDecorationTheme: InputDecorationTheme(
fillColor: Color(0xffffff5f),
border: UnderlineInputBorder(),
)
); );
Material findDialogMaterial(WidgetTester tester) { Material findDialogMaterial(WidgetTester tester) {
...@@ -119,6 +123,7 @@ void main() { ...@@ -119,6 +123,7 @@ void main() {
expect(theme.rangeSelectionBackgroundColor, null); expect(theme.rangeSelectionBackgroundColor, null);
expect(theme.rangeSelectionOverlayColor, null); expect(theme.rangeSelectionOverlayColor, null);
expect(theme.dividerColor, null); expect(theme.dividerColor, null);
expect(theme.inputDecorationTheme, null);
}); });
testWidgets('DatePickerTheme.defaults M3 defaults', (WidgetTester tester) async { testWidgets('DatePickerTheme.defaults M3 defaults', (WidgetTester tester) async {
...@@ -129,7 +134,7 @@ void main() { ...@@ -129,7 +134,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData.light(useMaterial3: true), theme: ThemeData(useMaterial3: true),
home: Builder( home: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
m3 = DatePickerTheme.defaults(context); m3 = DatePickerTheme.defaults(context);
...@@ -193,6 +198,7 @@ void main() { ...@@ -193,6 +198,7 @@ void main() {
expect(m3.rangePickerHeaderHeadlineStyle, textTheme.titleLarge); expect(m3.rangePickerHeaderHeadlineStyle, textTheme.titleLarge);
expect(m3.rangePickerHeaderHelpStyle, textTheme.titleSmall); expect(m3.rangePickerHeaderHelpStyle, textTheme.titleSmall);
expect(m3.dividerColor, null); expect(m3.dividerColor, null);
expect(m3.inputDecorationTheme, null);
}); });
testWidgets('DatePickerTheme.defaults M2 defaults', (WidgetTester tester) async { testWidgets('DatePickerTheme.defaults M2 defaults', (WidgetTester tester) async {
...@@ -203,7 +209,7 @@ void main() { ...@@ -203,7 +209,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData.light(useMaterial3: false), theme: ThemeData(useMaterial3: false),
home: Builder( home: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
m2 = DatePickerTheme.defaults(context); m2 = DatePickerTheme.defaults(context);
...@@ -258,6 +264,8 @@ void main() { ...@@ -258,6 +264,8 @@ void main() {
expect(m2.rangePickerHeaderForegroundColor, colorScheme.onPrimary); expect(m2.rangePickerHeaderForegroundColor, colorScheme.onPrimary);
expect(m2.rangePickerHeaderHeadlineStyle, textTheme.headlineSmall); expect(m2.rangePickerHeaderHeadlineStyle, textTheme.headlineSmall);
expect(m2.rangePickerHeaderHelpStyle, textTheme.labelSmall); expect(m2.rangePickerHeaderHelpStyle, textTheme.labelSmall);
expect(m2.dividerColor, null);
expect(m2.inputDecorationTheme, null);
}); });
testWidgets('Default DatePickerThemeData debugFillProperties', (WidgetTester tester) async { testWidgets('Default DatePickerThemeData debugFillProperties', (WidgetTester tester) async {
...@@ -282,7 +290,9 @@ void main() { ...@@ -282,7 +290,9 @@ void main() {
.map((DiagnosticsNode node) => node.toString()) .map((DiagnosticsNode node) => node.toString())
.toList(); .toList();
expect(description, <String>[ expect(
description,
equalsIgnoringHashCodes(<String>[
'backgroundColor: Color(0xfffffff0)', 'backgroundColor: Color(0xfffffff0)',
'elevation: 6.0', 'elevation: 6.0',
'shadowColor: Color(0xfffffff1)', 'shadowColor: Color(0xfffffff1)',
...@@ -315,15 +325,18 @@ void main() { ...@@ -315,15 +325,18 @@ void main() {
'rangePickerHeaderHelpStyle: TextStyle(inherit: true, size: 15.0)', 'rangePickerHeaderHelpStyle: TextStyle(inherit: true, size: 15.0)',
'rangeSelectionBackgroundColor: Color(0xffffff2f)', 'rangeSelectionBackgroundColor: Color(0xffffff2f)',
'rangeSelectionOverlayColor: MaterialStatePropertyAll(Color(0xffffff3f))', 'rangeSelectionOverlayColor: MaterialStatePropertyAll(Color(0xffffff3f))',
'dividerColor: Color(0xffffff3f)', 'dividerColor: Color(0xffffff4f)',
]); 'inputDecorationTheme: InputDecorationTheme#00000(fillColor: Color(0xffffff5f), border: UnderlineInputBorder())'
]),
);
}); });
testWidgets('DatePickerDialog uses ThemeData datePicker theme', (WidgetTester tester) async { testWidgets('DatePickerDialog uses ThemeData datePicker theme (calendar mode)', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData.light(useMaterial3: true).copyWith( theme: ThemeData(
datePickerTheme: datePickerTheme, datePickerTheme: datePickerTheme,
useMaterial3: true,
), ),
home: Directionality( home: Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -398,11 +411,53 @@ void main() { ...@@ -398,11 +411,53 @@ void main() {
expect(year2023Decoration.border?.bottom.color, datePickerTheme.todayForegroundColor?.resolve(<MaterialState>{})); expect(year2023Decoration.border?.bottom.color, datePickerTheme.todayForegroundColor?.resolve(<MaterialState>{}));
}); });
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);
});
testWidgets('DateRangePickerDialog uses ThemeData datePicker theme', (WidgetTester tester) async { testWidgets('DateRangePickerDialog uses ThemeData datePicker theme', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData.light(useMaterial3: true).copyWith( theme: ThemeData(
datePickerTheme: datePickerTheme, datePickerTheme: datePickerTheme,
useMaterial3: true,
), ),
home: Directionality( home: Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -450,8 +505,9 @@ void main() { ...@@ -450,8 +505,9 @@ void main() {
addTearDown(tester.view.reset); addTearDown(tester.view.reset);
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData.light(useMaterial3: true).copyWith( theme: ThemeData(
datePickerTheme: datePickerTheme, datePickerTheme: datePickerTheme,
useMaterial3: true,
), ),
home: Directionality( home: Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -482,4 +538,60 @@ void main() { ...@@ -482,4 +538,60 @@ void main() {
final Divider horizontalDivider = tester.widget(find.byType(Divider)); final Divider horizontalDivider = tester.widget(find.byType(Divider));
expect(horizontalDivider.color, datePickerTheme.dividerColor); 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());
});
} }
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