mirror of
https://github.com/flutter/flutter
synced 2024-07-16 10:29:14 +00:00
Reland [a11y] Fix date picker cannot focus on the edit field (#144198)
reland https://github.com/flutter/flutter/pull/143117 fixes: https://github.com/flutter/flutter/issues/143116 fixes: https://github.com/flutter/flutter/issues/141992 ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat [Data Driven Fixes]: https://github.com/flutter/flutter/wiki/Data-driven-Fixes
This commit is contained in:
parent
e41ffcb742
commit
14b914ab92
|
@ -409,6 +409,7 @@ class _DatePickerModeToggleButtonState extends State<_DatePickerModeToggleButton
|
|||
label: MaterialLocalizations.of(context).selectYearSemanticsLabel,
|
||||
excludeSemantics: true,
|
||||
button: true,
|
||||
container: true,
|
||||
child: SizedBox(
|
||||
height: _subHeaderHeight,
|
||||
child: InkWell(
|
||||
|
|
|
@ -861,64 +861,76 @@ class _DatePickerHeader extends StatelessWidget {
|
|||
|
||||
switch (orientation) {
|
||||
case Orientation.portrait:
|
||||
return SizedBox(
|
||||
height: _datePickerHeaderPortraitHeight,
|
||||
child: Material(
|
||||
color: backgroundColor,
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(
|
||||
start: 24,
|
||||
end: 12,
|
||||
bottom: 12,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 16),
|
||||
help,
|
||||
const Flexible(child: SizedBox(height: 38)),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(child: title),
|
||||
if (entryModeButton != null)
|
||||
entryModeButton!,
|
||||
],
|
||||
),
|
||||
],
|
||||
return Semantics(
|
||||
container: true,
|
||||
child: SizedBox(
|
||||
height: _datePickerHeaderPortraitHeight,
|
||||
child: Material(
|
||||
color: backgroundColor,
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(
|
||||
start: 24,
|
||||
end: 12,
|
||||
bottom: 12,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 16),
|
||||
help,
|
||||
const Flexible(child: SizedBox(height: 38)),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(child: title),
|
||||
if (entryModeButton != null)
|
||||
Semantics(
|
||||
container: true,
|
||||
child: entryModeButton,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
case Orientation.landscape:
|
||||
return SizedBox(
|
||||
width: _datePickerHeaderLandscapeWidth,
|
||||
child: Material(
|
||||
color: backgroundColor,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: _headerPaddingLandscape,
|
||||
),
|
||||
child: help,
|
||||
),
|
||||
SizedBox(height: isShort ? 16 : 56),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
return Semantics(
|
||||
container: true,
|
||||
child:SizedBox(
|
||||
width: _datePickerHeaderLandscapeWidth,
|
||||
child: Material(
|
||||
color: backgroundColor,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: _headerPaddingLandscape,
|
||||
),
|
||||
child: title,
|
||||
child: help,
|
||||
),
|
||||
),
|
||||
if (entryModeButton != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: entryModeButton,
|
||||
SizedBox(height: isShort ? 16 : 56),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: _headerPaddingLandscape,
|
||||
),
|
||||
child: title,
|
||||
),
|
||||
),
|
||||
],
|
||||
if (entryModeButton != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Semantics(
|
||||
container: true,
|
||||
child: entryModeButton,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -256,21 +256,24 @@ class _InputDatePickerFormFieldState extends State<InputDatePickerFormField> {
|
|||
?? theme.inputDecorationTheme.border
|
||||
?? (useMaterial3 ? const OutlineInputBorder() : const UnderlineInputBorder());
|
||||
|
||||
return TextFormField(
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.fieldHintText ?? localizations.dateHelpText,
|
||||
labelText: widget.fieldLabelText ?? localizations.dateInputLabel,
|
||||
).applyDefaults(inputTheme
|
||||
.merge(datePickerTheme.inputDecorationTheme)
|
||||
.copyWith(border: effectiveInputBorder),
|
||||
return Semantics(
|
||||
container: true,
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.fieldHintText ?? localizations.dateHelpText,
|
||||
labelText: widget.fieldLabelText ?? localizations.dateInputLabel,
|
||||
).applyDefaults(inputTheme
|
||||
.merge(datePickerTheme.inputDecorationTheme)
|
||||
.copyWith(border: effectiveInputBorder),
|
||||
),
|
||||
validator: _validateDate,
|
||||
keyboardType: widget.keyboardType ?? TextInputType.datetime,
|
||||
onSaved: _handleSaved,
|
||||
onFieldSubmitted: _handleSubmitted,
|
||||
autofocus: widget.autofocus,
|
||||
controller: _controller,
|
||||
focusNode: widget.focusNode,
|
||||
),
|
||||
validator: _validateDate,
|
||||
keyboardType: widget.keyboardType ?? TextInputType.datetime,
|
||||
onSaved: _handleSaved,
|
||||
onFieldSubmitted: _handleSubmitted,
|
||||
autofocus: widget.autofocus,
|
||||
controller: _controller,
|
||||
focusNode: widget.focusNode,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import '../widgets/clipboard_utils.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
@ -1577,6 +1578,13 @@ void main() {
|
|||
});
|
||||
|
||||
testWidgets('input mode', (WidgetTester tester) async {
|
||||
// Fill the clipboard so that the Paste option is available in the text
|
||||
// selection menu.
|
||||
final MockClipboard mockClipboard = MockClipboard();
|
||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
|
||||
addTearDown(() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null));
|
||||
|
||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||
|
||||
initialEntryMode = DatePickerEntryMode.input;
|
||||
|
@ -1596,7 +1604,22 @@ void main() {
|
|||
isFocusable: true,
|
||||
));
|
||||
|
||||
// The semantics of the InputDatePickerFormField are tested in its tests.
|
||||
expect(tester.getSemantics(find.byType(EditableText)), matchesSemantics(
|
||||
label: 'Enter Date',
|
||||
isEnabled: true,
|
||||
hasEnabledState: true,
|
||||
isTextField: true,
|
||||
isFocused: true,
|
||||
value: '01/15/2016',
|
||||
hasTapAction: true,
|
||||
hasSetTextAction: true,
|
||||
hasSetSelectionAction: true,
|
||||
hasCopyAction: true,
|
||||
hasCutAction: true,
|
||||
hasPasteAction: true,
|
||||
hasMoveCursorBackwardByCharacterAction: true,
|
||||
hasMoveCursorBackwardByWordAction: true,
|
||||
));
|
||||
|
||||
// Ok/Cancel buttons
|
||||
expect(tester.getSemantics(find.text('OK')), matchesSemantics(
|
||||
|
|
Loading…
Reference in a new issue