Commit d0161464 authored by rami-a's avatar rami-a Committed by Flutter GitHub Bot

Allow for cupertino modal popups to be dismissed with semantics (#48915)

parent eaa0e620
......@@ -108,6 +108,7 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
onTap: () async {
await showCupertinoModalPopup<void>(
context: context,
semanticsDismissible: true,
builder: (BuildContext context) {
return _BottomPicker(
child: CupertinoPicker(
......@@ -144,6 +145,7 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
onTap: () {
showCupertinoModalPopup<void>(
context: context,
semanticsDismissible: true,
builder: (BuildContext context) {
return _BottomPicker(
child: CupertinoTimerPicker(
......@@ -176,6 +178,7 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
onTap: () {
showCupertinoModalPopup<void>(
context: context,
semanticsDismissible: true,
builder: (BuildContext context) {
return _BottomPicker(
child: CupertinoDatePicker(
......@@ -207,6 +210,7 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
onTap: () {
showCupertinoModalPopup<void>(
context: context,
semanticsDismissible: true,
builder: (BuildContext context) {
return _BottomPicker(
child: CupertinoDatePicker(
......@@ -238,6 +242,7 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
onTap: () {
showCupertinoModalPopup<void>(
context: context,
semanticsDismissible: true,
builder: (BuildContext context) {
return _BottomPicker(
child: CupertinoDatePicker(
......
......@@ -35,7 +35,8 @@ const double _kOverAndUnderCenterOpacity = 0.447;
/// that child the initially selected child.
///
/// Can be used with [showCupertinoModalPopup] to display the picker modally at the
/// bottom of the screen.
/// bottom of the screen. When calling [showCupertinoModalPopup], be sure to set
/// `semanticsDismissible` to true to enable dismissing the modal via semantics.
///
/// Sizes itself to its parent. All children are sized to the same size based
/// on [itemExtent].
......
......@@ -792,14 +792,18 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> {
this.barrierColor,
this.barrierLabel,
this.builder,
bool semanticsDismissible,
ImageFilter filter,
RouteSettings settings,
}) : super(
filter: filter,
settings: settings,
);
) {
_semanticsDismissible = semanticsDismissible;
}
final WidgetBuilder builder;
bool _semanticsDismissible;
@override
final String barrierLabel;
......@@ -811,7 +815,7 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> {
bool get barrierDismissible => true;
@override
bool get semanticsDismissible => false;
bool get semanticsDismissible => _semanticsDismissible ?? false;
@override
Duration get transitionDuration => _kModalPopupTransitionDuration;
......@@ -871,6 +875,9 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> {
/// popup to the [Navigator] furthest from or nearest to the given `context`. It
/// is `false` by default.
///
/// The `semanticsDismissble` argument is used to determine whether the
/// semantics of the modal barrier are included in the semantics tree.
///
/// The `builder` argument typically builds a [CupertinoActionSheet] widget.
/// Content below the widget is dimmed with a [ModalBarrier]. The widget built
/// by the `builder` does not share a context with the location that
......@@ -891,6 +898,7 @@ Future<T> showCupertinoModalPopup<T>({
@required WidgetBuilder builder,
ImageFilter filter,
bool useRootNavigator = true,
bool semanticsDismissible,
}) {
assert(useRootNavigator != null);
return Navigator.of(context, rootNavigator: useRootNavigator).push(
......@@ -899,6 +907,7 @@ Future<T> showCupertinoModalPopup<T>({
barrierLabel: 'Dismiss',
builder: builder,
filter: filter,
semanticsDismissible: semanticsDismissible,
),
);
}
......
......@@ -3,11 +3,14 @@
// found in the LICENSE file.
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import '../widgets/semantics_tester.dart';
void main() {
MockNavigatorObserver navigatorObserver;
......@@ -1052,6 +1055,75 @@ void main() {
expect(rootObserver.dialogCount, 0);
expect(nestedObserver.dialogCount, 1);
});
testWidgets('showCupertinoModalPopup does not allow for semantics dismiss by default', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(CupertinoApp(
home: Navigator(
onGenerateRoute: (RouteSettings settings) {
return PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> _, Animation<double> __) {
return GestureDetector(
onTap: () async {
await showCupertinoModalPopup<void>(
context: context,
builder: (BuildContext context) => const SizedBox(),
);
},
child: const Text('tap'),
);
},
);
},
),
));
// Push the route.
await tester.tap(find.text('tap'));
await tester.pumpAndSettle();
expect(semantics, isNot(includesNodeWith(
actions: <SemanticsAction>[SemanticsAction.tap],
label: 'Dismiss',
)));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('showCupertinoModalPopup allows for semantics dismiss when set', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(CupertinoApp(
home: Navigator(
onGenerateRoute: (RouteSettings settings) {
return PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> _, Animation<double> __) {
return GestureDetector(
onTap: () async {
await showCupertinoModalPopup<void>(
context: context,
semanticsDismissible: true,
builder: (BuildContext context) => const SizedBox(),
);
},
child: const Text('tap'),
);
},
);
},
),
));
// Push the route.
await tester.tap(find.text('tap'));
await tester.pumpAndSettle();
expect(semantics, includesNodeWith(
actions: <SemanticsAction>[SemanticsAction.tap],
label: 'Dismiss',
));
debugDefaultTargetPlatformOverride = null;
});
}
class MockNavigatorObserver extends Mock implements NavigatorObserver {}
......
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