Unverified Commit 5fa937ed authored by Darren Austin's avatar Darren Austin Committed by GitHub

Keyboard navigation fo the Material Date Range Picker (#60497)

parent 6f4c4b3c
......@@ -470,7 +470,7 @@ class _MonthPicker extends StatefulWidget {
final SelectableDayPredicate selectableDayPredicate;
@override
State<StatefulWidget> createState() => _MonthPickerState();
_MonthPickerState createState() => _MonthPickerState();
}
class _MonthPickerState extends State<_MonthPicker> {
......@@ -754,16 +754,13 @@ class _MonthPickerState extends State<_MonthPicker> {
onFocusChange: _handleGridFocusChange,
child: _FocusedDate(
date: _dayGridFocus.hasFocus ? _focusedDay : null,
child: Container(
color: _dayGridFocus.hasFocus ? Theme.of(context).focusColor : null,
child: PageView.builder(
key: _pageViewKey,
controller: _pageController,
itemBuilder: _buildItems,
itemCount: utils.monthDelta(widget.firstDate, widget.lastDate) + 1,
scrollDirection: Axis.horizontal,
onPageChanged: _handleMonthPageChanged,
),
child: PageView.builder(
key: _pageViewKey,
controller: _pageController,
itemBuilder: _buildItems,
itemCount: utils.monthDelta(widget.firstDate, widget.lastDate) + 1,
scrollDirection: Axis.horizontal,
onPageChanged: _handleMonthPageChanged,
),
),
),
......
......@@ -88,4 +88,7 @@ class DateTimeRange {
@override
int get hashCode => hashValues(start, end);
@override
String toString() => '$start - $end';
}
......@@ -5,6 +5,7 @@
// @dart = 2.8
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'feedback_tester.dart';
......@@ -49,7 +50,11 @@ void main() {
saveText = null;
});
Future<void> preparePicker(WidgetTester tester, Future<void> callback(Future<DateTimeRange> date)) async {
Future<void> preparePicker(
WidgetTester tester,
Future<void> callback(Future<DateTimeRange> date),
{ TextDirection textDirection = TextDirection.ltr }
) async {
BuildContext buttonContext;
await tester.pumpWidget(MaterialApp(
home: Material(
......@@ -86,6 +91,12 @@ void main() {
fieldEndLabelText: fieldEndLabelText,
helpText: helpText,
saveText: saveText,
builder: (BuildContext context, Widget child) {
return Directionality(
textDirection: textDirection,
child: child,
);
},
);
await tester.pumpAndSettle(const Duration(seconds: 1));
......@@ -237,6 +248,186 @@ void main() {
});
});
group('Keyboard navigation', () {
testWidgets('Can toggle to calendar entry mode', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
expect(find.byType(TextField), findsNothing);
// Navigate to the entry toggle button and activate it
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Should be in the input mode
expect(find.byType(TextField), findsNWidgets(2));
});
});
testWidgets('Can navigate date grid with arrow keys', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
// Navigate to the grid
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.pumpAndSettle();
// Navigate from Jan 15 to Jan 18 with arrow keys
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.pumpAndSettle();
// Activate it to select the beginning of the range
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate to Jan 29
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.pumpAndSettle();
// Activate it to select the end of the range
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate out of the grid and to the OK button
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
// Activate OK
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Should have selected Jan 18 - Jan 29
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.january, 18),
end: DateTime(2016, DateTime.january, 29),
));
});
});
testWidgets('Navigating with arrow keys scrolls as needed', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
// Jan and Feb headers should be showing, but no Mar
expect(find.text('January 2016'), findsOneWidget);
expect(find.text('February 2016'), findsOneWidget);
expect(find.text('Mar 2016'), findsNothing);
// Navigate to the grid
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
// Navigate from Jan 15 to Jan 18 with arrow keys
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.pumpAndSettle();
// Activate it to select the beginning of the range
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate to Mar 17
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.pumpAndSettle();
// Jan should have scrolled off, Mar should be visible
expect(find.text('January 2016'), findsNothing);
expect(find.text('February 2016'), findsOneWidget);
expect(find.text('March 2016'), findsOneWidget);
// Activate it to select the end of the range
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate out of the grid and to the OK button
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
// Activate OK
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Should have selected Jan 18 - Mar 17
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.january, 18),
end: DateTime(2016, DateTime.march, 17),
));
});
});
testWidgets('RTL text direction reverses the horizontal arrow key navigation', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
// Navigate to the grid
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
// Navigate from Jan 15 to 19 with arrow keys
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.pumpAndSettle();
// Activate it
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate to Jan 21
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.pumpAndSettle();
// Activate it
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate out of the grid and to the OK button
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
// Activate OK
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Should have selected Jan 19 - Mar 21
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.january, 19),
end: DateTime(2016, DateTime.january, 21),
));
},
textDirection: TextDirection.rtl);
});
});
group('Input mode', () {
setUp(() {
firstDate = DateTime(2015, DateTime.january, 1);
......
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