Make time picker accessible (#13152)
* make time picker accessible
* use new CustomPaint a11y API
* flutter_localizations tests; use bigger distance delta
* fix am/pm control; selected values
* fix translations; remove @mustCallSuper in describeSemanticsConfiguration
* exclude AM/PM announcement from iOS as on iOS the label is read back automatically
diff --git a/packages/flutter_localizations/lib/src/l10n/localizations.dart b/packages/flutter_localizations/lib/src/l10n/localizations.dart
index 9e30417..9f82310 100644
--- a/packages/flutter_localizations/lib/src/l10n/localizations.dart
+++ b/packages/flutter_localizations/lib/src/l10n/localizations.dart
@@ -45,6 +45,8 @@
'viewLicensesButtonLabel': r'الاطّلاع على التراخيص',
'anteMeridiemAbbreviation': r'ص',
'postMeridiemAbbreviation': r'م',
+ 'timePickerHourModeAnnouncement': r'حدد ساعات',
+ 'timePickerMinuteModeAnnouncement': r'حدد دقائق',
},
'de': const <String, String>{
'scriptCategory': r'English-like',
@@ -77,6 +79,8 @@
'viewLicensesButtonLabel': r'LIZENZEN ANZEIGEN',
'anteMeridiemAbbreviation': r'VORM.',
'postMeridiemAbbreviation': r'NACHM.',
+ 'timePickerHourModeAnnouncement': r'Stunde auswählen',
+ 'timePickerMinuteModeAnnouncement': r'Minute auswählen',
},
'de_CH': const <String, String>{
'scriptCategory': r'English-like',
@@ -140,6 +144,8 @@
'viewLicensesButtonLabel': r'VIEW LICENSES',
'anteMeridiemAbbreviation': r'AM',
'postMeridiemAbbreviation': r'PM',
+ 'timePickerHourModeAnnouncement': r'Select hours',
+ 'timePickerMinuteModeAnnouncement': r'Select minutes',
},
'en_AU': const <String, String>{
'scriptCategory': r'English-like',
@@ -389,6 +395,8 @@
'viewLicensesButtonLabel': r'VER LICENCIAS',
'anteMeridiemAbbreviation': r'A.M.',
'postMeridiemAbbreviation': r'P.M.',
+ 'timePickerHourModeAnnouncement': r'Seleccione Horas',
+ 'timePickerMinuteModeAnnouncement': r'Seleccione Minutos',
},
'es_US': const <String, String>{
'scriptCategory': r'English-like',
@@ -426,6 +434,8 @@
'viewLicensesButtonLabel': r'مشاهده مجوزها',
'anteMeridiemAbbreviation': r'ق.ظ.',
'postMeridiemAbbreviation': r'ب.ظ.',
+ 'timePickerHourModeAnnouncement': r'ساعت ها را انتخاب کنید',
+ 'timePickerMinuteModeAnnouncement': r'دقیقه را انتخاب کنید',
},
'fr': const <String, String>{
'scriptCategory': r'English-like',
@@ -458,6 +468,8 @@
'viewLicensesButtonLabel': r'AFFICHER LES LICENCES',
'anteMeridiemAbbreviation': r'AM',
'postMeridiemAbbreviation': r'PM',
+ 'timePickerHourModeAnnouncement': r'Sélectionnez les heures',
+ 'timePickerMinuteModeAnnouncement': r'Sélectionnez les minutes',
},
'fr_CA': const <String, String>{
'scriptCategory': r'English-like',
@@ -526,6 +538,8 @@
'viewLicensesButtonLabel': r'הצגת הרישיונות',
'anteMeridiemAbbreviation': r'AM',
'postMeridiemAbbreviation': r'PM',
+ 'timePickerHourModeAnnouncement': r'בחר שעות',
+ 'timePickerMinuteModeAnnouncement': r'בחר דקות',
},
'it': const <String, String>{
'scriptCategory': r'English-like',
@@ -557,6 +571,8 @@
'viewLicensesButtonLabel': r'VISUALIZZA LICENZE',
'anteMeridiemAbbreviation': r'AM',
'postMeridiemAbbreviation': r'PM',
+ 'timePickerHourModeAnnouncement': r'Seleziona ore',
+ 'timePickerMinuteModeAnnouncement': r'Seleziona minuti',
},
'ja': const <String, String>{
'scriptCategory': r'dense',
@@ -588,6 +604,8 @@
'viewLicensesButtonLabel': r'ライセンスを表示',
'anteMeridiemAbbreviation': r'AM',
'postMeridiemAbbreviation': r'PM',
+ 'timePickerHourModeAnnouncement': r'時を選択',
+ 'timePickerMinuteModeAnnouncement': r'分を選択',
},
'ps': const <String, String>{
'scriptCategory': r'tall',
@@ -616,6 +634,8 @@
'pasteButtonLabel': r'پیټ کړئ',
'selectAllButtonLabel': r'غوره کړئ',
'viewLicensesButtonLabel': r'لیدلس وګورئ',
+ 'timePickerHourModeAnnouncement': r'وختونه وټاکئ',
+ 'timePickerMinuteModeAnnouncement': r'منې غوره کړئ',
},
'pt': const <String, String>{
'scriptCategory': r'English-like',
@@ -644,6 +664,8 @@
'pasteButtonLabel': r'COLAR',
'selectAllButtonLabel': r'SELECIONAR TUDO',
'viewLicensesButtonLabel': r'VER LICENÇAS',
+ 'timePickerHourModeAnnouncement': r'Selecione horários',
+ 'timePickerMinuteModeAnnouncement': r'Selecione Minutos',
},
'pt_PT': const <String, String>{
'scriptCategory': r'English-like',
@@ -709,6 +731,8 @@
'viewLicensesButtonLabel': r'ЛИЦЕНЗИИ',
'anteMeridiemAbbreviation': r'АМ',
'postMeridiemAbbreviation': r'PM',
+ 'timePickerHourModeAnnouncement': r'ВЫБРАТЬ ЧАСЫ',
+ 'timePickerMinuteModeAnnouncement': r'ВЫБРАТЬ МИНУТЫ',
},
'ur': const <String, String>{
'scriptCategory': r'tall',
@@ -740,6 +764,8 @@
'viewLicensesButtonLabel': r'لائسنسز دیکھیں',
'anteMeridiemAbbreviation': r'AM',
'postMeridiemAbbreviation': r'PM',
+ 'timePickerHourModeAnnouncement': r'گھنٹے منتخب کریں',
+ 'timePickerMinuteModeAnnouncement': r'منٹ منتخب کریں',
},
'zh': const <String, String>{
'scriptCategory': r'dense',
@@ -771,6 +797,8 @@
'previousMonthTooltip': r'上个月',
'anteMeridiemAbbreviation': r'上午',
'postMeridiemAbbreviation': r'下午',
+ 'timePickerHourModeAnnouncement': r'选择小时',
+ 'timePickerMinuteModeAnnouncement': r'选择分钟',
},
};
diff --git a/packages/flutter_localizations/lib/src/l10n/material_ar.arb b/packages/flutter_localizations/lib/src/l10n/material_ar.arb
index 4e284c1..069a418 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_ar.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_ar.arb
@@ -31,5 +31,7 @@
"selectAllButtonLabel": "اختيار الكل",
"viewLicensesButtonLabel": "الاطّلاع على التراخيص",
"anteMeridiemAbbreviation": "ص",
- "postMeridiemAbbreviation": "م"
+ "postMeridiemAbbreviation": "م",
+ "timePickerHourModeAnnouncement": "حدد ساعات",
+ "timePickerMinuteModeAnnouncement": "حدد دقائق"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_de.arb b/packages/flutter_localizations/lib/src/l10n/material_de.arb
index 5d248d2..4fc5d5f 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_de.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_de.arb
@@ -28,5 +28,7 @@
"selectAllButtonLabel": "ALLE AUSWÄHLEN",
"viewLicensesButtonLabel": "LIZENZEN ANZEIGEN",
"anteMeridiemAbbreviation": "VORM.",
- "postMeridiemAbbreviation": "NACHM."
+ "postMeridiemAbbreviation": "NACHM.",
+ "timePickerHourModeAnnouncement": "Stunde auswählen",
+ "timePickerMinuteModeAnnouncement": "Minute auswählen"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_en.arb b/packages/flutter_localizations/lib/src/l10n/material_en.arb
index 215f2bd..27cc940 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_en.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_en.arb
@@ -143,5 +143,15 @@
"postMeridiemAbbreviation": "PM",
"@postMeridiemAbbreviation": {
"description": "The abbreviation for post meridiem (after noon) shown in the time picker. Translations for this abbreviation will only be provided for locales that support it."
+ },
+
+ "timePickerHourModeAnnouncement": "Select hours",
+ "@timePickerHourModeAnnouncement": {
+ "description": "The audio announcement made when the time picker dialog is set to hour mode."
+ },
+
+ "timePickerMinuteModeAnnouncement": "Select minutes",
+ "@timePickerMinuteModeAnnouncement": {
+ "description": "The audio announcement made when the time picker dialog is set to minute mode."
}
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_es.arb b/packages/flutter_localizations/lib/src/l10n/material_es.arb
index aa5e6d6..cf9dc85 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_es.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_es.arb
@@ -28,5 +28,7 @@
"selectAllButtonLabel": "SELECCIONAR TODO",
"viewLicensesButtonLabel": "VER LICENCIAS",
"anteMeridiemAbbreviation": "A.M.",
- "postMeridiemAbbreviation": "P.M."
+ "postMeridiemAbbreviation": "P.M.",
+ "timePickerHourModeAnnouncement": "Seleccione Horas",
+ "timePickerMinuteModeAnnouncement": "Seleccione Minutos"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_fa.arb b/packages/flutter_localizations/lib/src/l10n/material_fa.arb
index 12d07b2..e7cbf93 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_fa.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_fa.arb
@@ -27,5 +27,7 @@
"selectAllButtonLabel": "انتخاب همه",
"viewLicensesButtonLabel": "مشاهده مجوزها",
"anteMeridiemAbbreviation": "ق.ظ.",
- "postMeridiemAbbreviation": "ب.ظ."
+ "postMeridiemAbbreviation": "ب.ظ.",
+ "timePickerHourModeAnnouncement": "ساعت ها را انتخاب کنید",
+ "timePickerMinuteModeAnnouncement": "دقیقه را انتخاب کنید"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_fr.arb b/packages/flutter_localizations/lib/src/l10n/material_fr.arb
index 69d7b29..9eb4fd2 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_fr.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_fr.arb
@@ -28,5 +28,7 @@
"selectAllButtonLabel": "TOUT SÉLECTIONNER",
"viewLicensesButtonLabel": "AFFICHER LES LICENCES",
"anteMeridiemAbbreviation": "AM",
- "postMeridiemAbbreviation": "PM"
+ "postMeridiemAbbreviation": "PM",
+ "timePickerHourModeAnnouncement": "Sélectionnez les heures",
+ "timePickerMinuteModeAnnouncement": "Sélectionnez les minutes"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_he.arb b/packages/flutter_localizations/lib/src/l10n/material_he.arb
index 39083de..b6fe9e9 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_he.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_he.arb
@@ -29,5 +29,7 @@
"selectAllButtonLabel": "בחירת הכול",
"viewLicensesButtonLabel": "הצגת הרישיונות",
"anteMeridiemAbbreviation": "AM",
- "postMeridiemAbbreviation": "PM"
+ "postMeridiemAbbreviation": "PM",
+ "timePickerHourModeAnnouncement": "בחר שעות",
+ "timePickerMinuteModeAnnouncement": "בחר דקות"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_it.arb b/packages/flutter_localizations/lib/src/l10n/material_it.arb
index a0faf2a..785e32a 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_it.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_it.arb
@@ -27,5 +27,7 @@
"selectAllButtonLabel": "SELEZIONA TUTTO",
"viewLicensesButtonLabel": "VISUALIZZA LICENZE",
"anteMeridiemAbbreviation": "AM",
- "postMeridiemAbbreviation": "PM"
+ "postMeridiemAbbreviation": "PM",
+ "timePickerHourModeAnnouncement": "Seleziona ore",
+ "timePickerMinuteModeAnnouncement": "Seleziona minuti"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_ja.arb b/packages/flutter_localizations/lib/src/l10n/material_ja.arb
index c34a6ab..3bedf74 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_ja.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_ja.arb
@@ -27,5 +27,7 @@
"selectAllButtonLabel": "すべて選択",
"viewLicensesButtonLabel": "ライセンスを表示",
"anteMeridiemAbbreviation": "AM",
- "postMeridiemAbbreviation": "PM"
+ "postMeridiemAbbreviation": "PM",
+ "timePickerHourModeAnnouncement": "時を選択",
+ "timePickerMinuteModeAnnouncement": "分を選択"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_ps.arb b/packages/flutter_localizations/lib/src/l10n/material_ps.arb
index 89a41f6..c8d3769 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_ps.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_ps.arb
@@ -26,5 +26,7 @@
"okButtonLabel": "سمه ده",
"pasteButtonLabel": "پیټ کړئ",
"selectAllButtonLabel": "غوره کړئ",
- "viewLicensesButtonLabel": "لیدلس وګورئ"
+ "viewLicensesButtonLabel": "لیدلس وګورئ",
+ "timePickerHourModeAnnouncement": "وختونه وټاکئ",
+ "timePickerMinuteModeAnnouncement": "منې غوره کړئ"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_pt.arb b/packages/flutter_localizations/lib/src/l10n/material_pt.arb
index e2b95c4..c4dd6d2 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_pt.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_pt.arb
@@ -26,5 +26,7 @@
"okButtonLabel": "OK",
"pasteButtonLabel": "COLAR",
"selectAllButtonLabel": "SELECIONAR TUDO",
- "viewLicensesButtonLabel": "VER LICENÇAS"
+ "viewLicensesButtonLabel": "VER LICENÇAS",
+ "timePickerHourModeAnnouncement": "Selecione horários",
+ "timePickerMinuteModeAnnouncement": "Selecione Minutos"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_ru.arb b/packages/flutter_localizations/lib/src/l10n/material_ru.arb
index 3b36b5f..d4c0e0b 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_ru.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_ru.arb
@@ -30,5 +30,7 @@
"selectAllButtonLabel": "ВЫБРАТЬ ВСЕ",
"viewLicensesButtonLabel": "ЛИЦЕНЗИИ",
"anteMeridiemAbbreviation": "АМ",
- "postMeridiemAbbreviation": "PM"
+ "postMeridiemAbbreviation": "PM",
+ "timePickerHourModeAnnouncement": "ВЫБРАТЬ ЧАСЫ",
+ "timePickerMinuteModeAnnouncement": "ВЫБРАТЬ МИНУТЫ"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_ur.arb b/packages/flutter_localizations/lib/src/l10n/material_ur.arb
index 1276c28..8d41993 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_ur.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_ur.arb
@@ -27,5 +27,7 @@
"selectAllButtonLabel": "سبھی منتخب کریں",
"viewLicensesButtonLabel": "لائسنسز دیکھیں",
"anteMeridiemAbbreviation": "AM",
- "postMeridiemAbbreviation": "PM"
+ "postMeridiemAbbreviation": "PM",
+ "timePickerHourModeAnnouncement": "گھنٹے منتخب کریں",
+ "timePickerMinuteModeAnnouncement": "منٹ منتخب کریں"
}
diff --git a/packages/flutter_localizations/lib/src/l10n/material_zh.arb b/packages/flutter_localizations/lib/src/l10n/material_zh.arb
index 8afe969..791a974 100644
--- a/packages/flutter_localizations/lib/src/l10n/material_zh.arb
+++ b/packages/flutter_localizations/lib/src/l10n/material_zh.arb
@@ -27,5 +27,7 @@
"nextMonthTooltip": "下个月",
"previousMonthTooltip": "上个月",
"anteMeridiemAbbreviation": "上午",
- "postMeridiemAbbreviation": "下午"
+ "postMeridiemAbbreviation": "下午",
+ "timePickerHourModeAnnouncement": "选择小时",
+ "timePickerMinuteModeAnnouncement": "选择分钟"
}
diff --git a/packages/flutter_localizations/lib/src/material_localizations.dart b/packages/flutter_localizations/lib/src/material_localizations.dart
index a1538f6..800ddfa 100644
--- a/packages/flutter_localizations/lib/src/material_localizations.dart
+++ b/packages/flutter_localizations/lib/src/material_localizations.dart
@@ -316,6 +316,12 @@
@override
String get postMeridiemAbbreviation => _nameToValue['postMeridiemAbbreviation'];
+ @override
+ String get timePickerHourModeAnnouncement => _nameToValue['timePickerHourModeAnnouncement'];
+
+ @override
+ String get timePickerMinuteModeAnnouncement => _nameToValue['timePickerMinuteModeAnnouncement'];
+
/// The [TimeOfDayFormat] corresponding to one of the following supported
/// patterns:
///
diff --git a/packages/flutter_localizations/test/time_picker_test.dart b/packages/flutter_localizations/test/time_picker_test.dart
index 8b70e49..f3c2ada 100644
--- a/packages/flutter_localizations/test/time_picker_test.dart
+++ b/packages/flutter_localizations/test/time_picker_test.dart
@@ -140,57 +140,58 @@
],
child: new MediaQuery(
data: new MediaQueryData(alwaysUse24HourFormat: alwaysUse24HourFormat),
- child: new Directionality(
- textDirection: TextDirection.ltr,
- child: new Navigator(
- onGenerateRoute: (RouteSettings settings) {
- return new MaterialPageRoute<dynamic>(builder: (BuildContext context) {
- showTimePicker(context: context, initialTime: const TimeOfDay(hour: 7, minute: 0));
- return new Container();
- });
- },
+ child: new Material(
+ child: new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Navigator(
+ onGenerateRoute: (RouteSettings settings) {
+ return new MaterialPageRoute<dynamic>(builder: (BuildContext context) {
+ return new FlatButton(
+ onPressed: () {
+ showTimePicker(context: context, initialTime: const TimeOfDay(hour: 7, minute: 0));
+ },
+ child: const Text('X'),
+ );
+ });
+ },
+ ),
),
),
),
),
);
- // Pump once, because the dialog shows up asynchronously.
- await tester.pump();
+
+ await tester.tap(find.text('X'));
+ await tester.pumpAndSettle();
}
testWidgets('respects MediaQueryData.alwaysUse24HourFormat == false', (WidgetTester tester) async {
await mediaQueryBoilerplate(tester, false);
- final CustomPaint dialPaint = tester.widget(find.descendant(
- of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_Dial'),
- matching: find.byType(CustomPaint),
- ));
+ final CustomPaint dialPaint = tester.widget(find.byKey(const ValueKey<String>('time-picker-dial')));
final dynamic dialPainter = dialPaint.painter;
- final List<TextPainter> primaryOuterLabels = dialPainter.primaryOuterLabels;
- expect(primaryOuterLabels.map((TextPainter tp) => tp.text.text), labels12To11);
+ final List<dynamic> primaryOuterLabels = dialPainter.primaryOuterLabels;
+ expect(primaryOuterLabels.map<String>((dynamic tp) => tp.painter.text.text), labels12To11);
expect(dialPainter.primaryInnerLabels, null);
- final List<TextPainter> secondaryOuterLabels = dialPainter.secondaryOuterLabels;
- expect(secondaryOuterLabels.map((TextPainter tp) => tp.text.text), labels12To11);
+ final List<dynamic> secondaryOuterLabels = dialPainter.secondaryOuterLabels;
+ expect(secondaryOuterLabels.map<String>((dynamic tp) => tp.painter.text.text), labels12To11);
expect(dialPainter.secondaryInnerLabels, null);
});
testWidgets('respects MediaQueryData.alwaysUse24HourFormat == true', (WidgetTester tester) async {
await mediaQueryBoilerplate(tester, true);
- final CustomPaint dialPaint = tester.widget(find.descendant(
- of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_Dial'),
- matching: find.byType(CustomPaint),
- ));
+ final CustomPaint dialPaint = tester.widget(find.byKey(const ValueKey<String>('time-picker-dial')));
final dynamic dialPainter = dialPaint.painter;
- final List<TextPainter> primaryOuterLabels = dialPainter.primaryOuterLabels;
- expect(primaryOuterLabels.map((TextPainter tp) => tp.text.text), labels00To23);
- final List<TextPainter> primaryInnerLabels = dialPainter.primaryInnerLabels;
- expect(primaryInnerLabels.map((TextPainter tp) => tp.text.text), labels12To11TwoDigit);
+ final List<dynamic> primaryOuterLabels = dialPainter.primaryOuterLabels;
+ expect(primaryOuterLabels.map<String>((dynamic tp) => tp.painter.text.text), labels00To23);
+ final List<dynamic> primaryInnerLabels = dialPainter.primaryInnerLabels;
+ expect(primaryInnerLabels.map<String>((dynamic tp) => tp.painter.text.text), labels12To11TwoDigit);
- final List<TextPainter> secondaryOuterLabels = dialPainter.secondaryOuterLabels;
- expect(secondaryOuterLabels.map((TextPainter tp) => tp.text.text), labels00To23);
- final List<TextPainter> secondaryInnerLabels = dialPainter.secondaryInnerLabels;
- expect(secondaryInnerLabels.map((TextPainter tp) => tp.text.text), labels12To11TwoDigit);
+ final List<dynamic> secondaryOuterLabels = dialPainter.secondaryOuterLabels;
+ expect(secondaryOuterLabels.map<String>((dynamic tp) => tp.painter.text.text), labels00To23);
+ final List<dynamic> secondaryInnerLabels = dialPainter.secondaryInnerLabels;
+ expect(secondaryInnerLabels.map<String>((dynamic tp) => tp.painter.text.text), labels12To11TwoDigit);
});
}