diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index 16915e48742..82b21c69dd4 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -164,6 +164,7 @@ Future showDatePicker({ String? fieldLabelText, TextInputType? keyboardType, Offset? anchorPoint, + final ValueChanged? onDatePickerModeChange }) async { initialDate = DateUtils.dateOnly(initialDate); firstDate = DateUtils.dateOnly(firstDate); @@ -202,6 +203,7 @@ Future showDatePicker({ fieldHintText: fieldHintText, fieldLabelText: fieldLabelText, keyboardType: keyboardType, + onDatePickerModeChange: onDatePickerModeChange, ); if (textDirection != null) { @@ -259,6 +261,7 @@ class DatePickerDialog extends StatefulWidget { this.fieldLabelText, this.keyboardType, this.restorationId, + this.onDatePickerModeChange }) : initialDate = DateUtils.dateOnly(initialDate), firstDate = DateUtils.dateOnly(firstDate), lastDate = DateUtils.dateOnly(lastDate), @@ -356,6 +359,15 @@ class DatePickerDialog extends StatefulWidget { /// Flutter. final String? restorationId; + + /// Called when the [DatePickerDialog] is toggled between + /// [DatePickerEntryMode.calendar],[DatePickerEntryMode.input]. + /// + /// An example of how this callback might be used is an app that saves the + /// user's preferred entry mode and uses it to initialize the + /// `initialEntryMode` parameter the next time the date picker is shown. + final ValueChanged? onDatePickerModeChange; + @override State createState() => _DatePickerDialogState(); } @@ -394,16 +406,24 @@ class _DatePickerDialogState extends State with RestorationMix Navigator.pop(context); } + void _handleOnDatePickerModeChange() { + if (widget.onDatePickerModeChange != null) { + widget.onDatePickerModeChange!(_entryMode.value); + } + } + void _handleEntryModeToggle() { setState(() { switch (_entryMode.value) { case DatePickerEntryMode.calendar: _autovalidateMode.value = AutovalidateMode.disabled; _entryMode.value = DatePickerEntryMode.input; + _handleOnDatePickerModeChange(); break; case DatePickerEntryMode.input: _formKey.currentState!.save(); _entryMode.value = DatePickerEntryMode.calendar; + _handleOnDatePickerModeChange(); break; case DatePickerEntryMode.calendarOnly: case DatePickerEntryMode.inputOnly: diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index 8795ba15592..7c032f225a7 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -20,6 +20,7 @@ void main() { late SelectableDayPredicate? selectableDayPredicate; late DatePickerEntryMode initialEntryMode; late DatePickerMode initialCalendarMode; + late DatePickerEntryMode currentMode; String? cancelText; String? confirmText; @@ -56,6 +57,7 @@ void main() { fieldLabelText = null; helpText = null; keyboardType = null; + currentMode = initialEntryMode; }); Future prepareDatePicker( @@ -101,6 +103,9 @@ void main() { fieldLabelText: fieldLabelText, helpText: helpText, keyboardType: keyboardType, + onDatePickerModeChange: (DatePickerEntryMode value) { + currentMode = value; + }, builder: (BuildContext context, Widget? child) { return Directionality( textDirection: textDirection, @@ -1369,6 +1374,19 @@ void main() { expect(find.byType(TextField), findsNothing); expect(find.byIcon(Icons.edit), findsNothing); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615 + + testWidgets('Test Callback on Toggle of DatePicker Mode', (WidgetTester tester) async { + prepareDatePicker(tester, (Future date) async { + await tester.tap(find.byIcon(Icons.edit)); + expect(currentMode, DatePickerEntryMode.input); + await tester.pumpAndSettle(); + expect(find.byType(TextField), findsOneWidget); + await tester.tap(find.byIcon(Icons.calendar_today)); + expect(currentMode, DatePickerEntryMode.calendar); + await tester.pumpAndSettle(); + expect(find.byType(TextField), findsNothing); + }); + }); } class _RestorableDatePickerDialogTestWidget extends StatefulWidget {