[Discuss] Let the initial date picker mode be selectable (#11614)
* Let the initial date picker mode be selectable * Doc for enum * Add a test * Add a comment for test * actually decouple test from setup state
This commit is contained in:
parent
3b8159564f
commit
4cb3a98f2c
@ -26,7 +26,18 @@ import 'material.dart';
|
||||
import 'theme.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
enum _DatePickerMode { day, year }
|
||||
/// Date picker UI mode for either showing a list of available years or a
|
||||
/// monthly calendar.
|
||||
///
|
||||
/// Also see:
|
||||
///
|
||||
/// * <https://material.io/guidelines/components/pickers.html#pickers-date-pickers>
|
||||
enum DatePickerMode {
|
||||
/// Show a date picker UI for choosing a month and day.
|
||||
day,
|
||||
/// Show a date picker UI for choosing a year.
|
||||
year,
|
||||
}
|
||||
|
||||
const double _kDatePickerHeaderPortraitHeight = 100.0;
|
||||
const double _kDatePickerHeaderLandscapeWidth = 168.0;
|
||||
@ -57,11 +68,11 @@ class _DatePickerHeader extends StatelessWidget {
|
||||
super(key: key);
|
||||
|
||||
final DateTime selectedDate;
|
||||
final _DatePickerMode mode;
|
||||
final ValueChanged<_DatePickerMode> onModeChanged;
|
||||
final DatePickerMode mode;
|
||||
final ValueChanged<DatePickerMode> onModeChanged;
|
||||
final Orientation orientation;
|
||||
|
||||
void _handleChangeMode(_DatePickerMode value) {
|
||||
void _handleChangeMode(DatePickerMode value) {
|
||||
if (value != mode)
|
||||
onModeChanged(value);
|
||||
}
|
||||
@ -74,12 +85,12 @@ class _DatePickerHeader extends StatelessWidget {
|
||||
Color yearColor;
|
||||
switch(themeData.primaryColorBrightness) {
|
||||
case Brightness.light:
|
||||
dayColor = mode == _DatePickerMode.day ? Colors.black87 : Colors.black54;
|
||||
yearColor = mode == _DatePickerMode.year ? Colors.black87 : Colors.black54;
|
||||
dayColor = mode == DatePickerMode.day ? Colors.black87 : Colors.black54;
|
||||
yearColor = mode == DatePickerMode.year ? Colors.black87 : Colors.black54;
|
||||
break;
|
||||
case Brightness.dark:
|
||||
dayColor = mode == _DatePickerMode.day ? Colors.white : Colors.white70;
|
||||
yearColor = mode == _DatePickerMode.year ? Colors.white : Colors.white70;
|
||||
dayColor = mode == DatePickerMode.day ? Colors.white : Colors.white70;
|
||||
yearColor = mode == DatePickerMode.year ? Colors.white : Colors.white70;
|
||||
break;
|
||||
}
|
||||
final TextStyle dayStyle = headerTextTheme.display1.copyWith(color: dayColor, height: 1.4);
|
||||
@ -114,17 +125,17 @@ class _DatePickerHeader extends StatelessWidget {
|
||||
|
||||
Widget yearButton = new _DateHeaderButton(
|
||||
color: backgroundColor,
|
||||
onTap: Feedback.wrapForTap(() => _handleChangeMode(_DatePickerMode.year), context),
|
||||
onTap: Feedback.wrapForTap(() => _handleChangeMode(DatePickerMode.year), context),
|
||||
child: new Text(new DateFormat('yyyy').format(selectedDate), style: yearStyle),
|
||||
);
|
||||
Widget dayButton = new _DateHeaderButton(
|
||||
color: backgroundColor,
|
||||
onTap: Feedback.wrapForTap(() => _handleChangeMode(_DatePickerMode.day), context),
|
||||
onTap: Feedback.wrapForTap(() => _handleChangeMode(DatePickerMode.day), context),
|
||||
child: new Text(new DateFormat('E, MMM\u00a0d').format(selectedDate), style: dayStyle),
|
||||
);
|
||||
|
||||
// Disable the button for the current mode.
|
||||
if (mode == _DatePickerMode.day)
|
||||
if (mode == DatePickerMode.day)
|
||||
dayButton = new IgnorePointer(child: dayButton);
|
||||
else
|
||||
yearButton = new IgnorePointer(child: yearButton);
|
||||
@ -658,12 +669,14 @@ class _DatePickerDialog extends StatefulWidget {
|
||||
this.firstDate,
|
||||
this.lastDate,
|
||||
this.selectableDayPredicate,
|
||||
this.initialDatePickerMode,
|
||||
}) : super(key: key);
|
||||
|
||||
final DateTime initialDate;
|
||||
final DateTime firstDate;
|
||||
final DateTime lastDate;
|
||||
final SelectableDayPredicate selectableDayPredicate;
|
||||
final DatePickerMode initialDatePickerMode;
|
||||
|
||||
@override
|
||||
_DatePickerDialogState createState() => new _DatePickerDialogState();
|
||||
@ -674,10 +687,11 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
_selectedDate = widget.initialDate;
|
||||
_mode = widget.initialDatePickerMode;
|
||||
}
|
||||
|
||||
DateTime _selectedDate;
|
||||
_DatePickerMode _mode = _DatePickerMode.day;
|
||||
DatePickerMode _mode;
|
||||
final GlobalKey _pickerKey = new GlobalKey();
|
||||
|
||||
void _vibrate() {
|
||||
@ -691,7 +705,7 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
|
||||
}
|
||||
}
|
||||
|
||||
void _handleModeChanged(_DatePickerMode mode) {
|
||||
void _handleModeChanged(DatePickerMode mode) {
|
||||
_vibrate();
|
||||
setState(() {
|
||||
_mode = mode;
|
||||
@ -701,7 +715,7 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
|
||||
void _handleYearChanged(DateTime value) {
|
||||
_vibrate();
|
||||
setState(() {
|
||||
_mode = _DatePickerMode.day;
|
||||
_mode = DatePickerMode.day;
|
||||
_selectedDate = value;
|
||||
});
|
||||
}
|
||||
@ -724,7 +738,7 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
|
||||
Widget _buildPicker() {
|
||||
assert(_mode != null);
|
||||
switch (_mode) {
|
||||
case _DatePickerMode.day:
|
||||
case DatePickerMode.day:
|
||||
return new MonthPicker(
|
||||
key: _pickerKey,
|
||||
selectedDate: _selectedDate,
|
||||
@ -732,9 +746,9 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
|
||||
firstDate: widget.firstDate,
|
||||
lastDate: widget.lastDate,
|
||||
selectableDayPredicate: widget.selectableDayPredicate,
|
||||
onMonthHeaderTap: () { _handleModeChanged(_DatePickerMode.year); },
|
||||
onMonthHeaderTap: () { _handleModeChanged(DatePickerMode.year); },
|
||||
);
|
||||
case _DatePickerMode.year:
|
||||
case DatePickerMode.year:
|
||||
return new YearPicker(
|
||||
key: _pickerKey,
|
||||
selectedDate: _selectedDate,
|
||||
@ -831,6 +845,10 @@ typedef bool SelectableDayPredicate(DateTime day);
|
||||
/// the days to enable for selection. If provided, only the days that
|
||||
/// [selectableDayPredicate] returned true for will be selectable.
|
||||
///
|
||||
/// An optional [initialDatePickerMode] argument can be used to display the
|
||||
/// date picker initially in the year or month+day picker mode. It defaults
|
||||
/// to month+day, but cannot be null.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [showTimePicker]
|
||||
@ -841,6 +859,7 @@ Future<DateTime> showDatePicker({
|
||||
@required DateTime firstDate,
|
||||
@required DateTime lastDate,
|
||||
SelectableDayPredicate selectableDayPredicate,
|
||||
DatePickerMode initialDatePickerMode: DatePickerMode.day,
|
||||
}) async {
|
||||
assert(!initialDate.isBefore(firstDate), 'initialDate must be on or after firstDate');
|
||||
assert(!initialDate.isAfter(lastDate), 'initialDate must be on or before lastDate');
|
||||
@ -849,6 +868,7 @@ Future<DateTime> showDatePicker({
|
||||
selectableDayPredicate == null || selectableDayPredicate(initialDate),
|
||||
'Provided initialDate must satisfy provided selectableDayPredicate'
|
||||
);
|
||||
assert(initialDatePickerMode != null, 'initialDatePickerMode cannot be null');
|
||||
return await showDialog(
|
||||
context: context,
|
||||
child: new _DatePickerDialog(
|
||||
@ -856,6 +876,7 @@ Future<DateTime> showDatePicker({
|
||||
firstDate: firstDate,
|
||||
lastDate: lastDate,
|
||||
selectableDayPredicate: selectableDayPredicate,
|
||||
initialDatePickerMode: initialDatePickerMode,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -13,11 +13,14 @@ void main() {
|
||||
DateTime lastDate;
|
||||
DateTime initialDate;
|
||||
SelectableDayPredicate selectableDayPredicate;
|
||||
DatePickerMode initialDatePickerMode;
|
||||
|
||||
setUp(() {
|
||||
firstDate = new DateTime(2001, DateTime.JANUARY, 1);
|
||||
lastDate = new DateTime(2031, DateTime.DECEMBER, 31);
|
||||
initialDate = new DateTime(2016, DateTime.JANUARY, 15);
|
||||
selectableDayPredicate = null;
|
||||
initialDatePickerMode = null;
|
||||
});
|
||||
|
||||
testWidgets('tap-select a day', (WidgetTester tester) async {
|
||||
@ -138,13 +141,25 @@ void main() {
|
||||
await tester.tap(find.text('Go'));
|
||||
expect(buttonContext, isNotNull);
|
||||
|
||||
final Future<DateTime> date = showDatePicker(
|
||||
context: buttonContext,
|
||||
initialDate: initialDate,
|
||||
firstDate: firstDate,
|
||||
lastDate: lastDate,
|
||||
selectableDayPredicate: selectableDayPredicate
|
||||
);
|
||||
final Future<DateTime> date = initialDatePickerMode == null
|
||||
// Exercise the argument default for initialDatePickerMode.
|
||||
?
|
||||
showDatePicker(
|
||||
context: buttonContext,
|
||||
initialDate: initialDate,
|
||||
firstDate: firstDate,
|
||||
lastDate: lastDate,
|
||||
selectableDayPredicate: selectableDayPredicate,
|
||||
)
|
||||
:
|
||||
showDatePicker(
|
||||
context: buttonContext,
|
||||
initialDate: initialDate,
|
||||
firstDate: firstDate,
|
||||
lastDate: lastDate,
|
||||
selectableDayPredicate: selectableDayPredicate,
|
||||
initialDatePickerMode: initialDatePickerMode,
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle(const Duration(seconds: 1));
|
||||
await callback(date);
|
||||
@ -283,6 +298,19 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('Can select initial date picker mode', (WidgetTester tester) async {
|
||||
initialDate = new DateTime(2014, DateTime.JANUARY, 15);
|
||||
initialDatePickerMode = DatePickerMode.year;
|
||||
await preparePicker(tester, (Future<DateTime> date) async {
|
||||
await tester.pump();
|
||||
// 2018 wouldn't be available if the year picker wasn't showing.
|
||||
// The initial current year is 2014.
|
||||
await tester.tap(find.text('2018'));
|
||||
await tester.tap(find.text('OK'));
|
||||
expect(await date, equals(new DateTime(2018, DateTime.JANUARY, 15)));
|
||||
});
|
||||
});
|
||||
|
||||
group('haptic feedback', () {
|
||||
const Duration kHapticFeedbackInterval = const Duration(milliseconds: 10);
|
||||
FeedbackTester feedback;
|
||||
|
Loading…
x
Reference in New Issue
Block a user