Unverified Commit bf5e4b45 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Make sure modal BottomSheets routes are identified as dialog routes (#21075)

parent 373243bc
......@@ -4,6 +4,7 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
......@@ -141,6 +142,7 @@ class _BottomSheetState extends State<BottomSheet> {
onVerticalDragUpdate: _handleDragUpdate,
onVerticalDragEnd: _handleDragEnd,
child: bottomSheet,
excludeFromSemantics: true,
);
}
}
......@@ -190,20 +192,43 @@ class _ModalBottomSheet<T> extends StatefulWidget {
class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
@override
Widget build(BuildContext context) {
final MediaQueryData mediaQuery = MediaQuery.of(context);
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
String routeLabel;
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
routeLabel = '';
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
routeLabel = localizations.dialogLabel;
break;
}
return new GestureDetector(
excludeFromSemantics: true,
onTap: () => Navigator.pop(context),
child: new AnimatedBuilder(
animation: widget.route.animation,
builder: (BuildContext context, Widget child) {
return new ClipRect(
child: new CustomSingleChildLayout(
delegate: new _ModalBottomSheetLayout(widget.route.animation.value),
child: new BottomSheet(
animationController: widget.route._animationController,
onClosing: () => Navigator.pop(context),
builder: widget.route.builder
)
)
// Disable the initial animation when accessible navigation is on so
// that the semantics are added to the tree at the correct time.
final double animationValue = mediaQuery.accessibleNavigation ? 1.0 : widget.route.animation.value;
return new Semantics(
scopesRoute: true,
namesRoute: true,
label: routeLabel,
explicitChildNodes: true,
child: new ClipRect(
child: new CustomSingleChildLayout(
delegate: new _ModalBottomSheetLayout(animationValue),
child: new BottomSheet(
animationController: widget.route._animationController,
onClosing: () => Navigator.pop(context),
builder: widget.route.builder,
),
),
),
);
}
)
......
......@@ -7,6 +7,8 @@ import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart';
import '../widgets/semantics_tester.dart';
void main() {
testWidgets('Verify that a tap dismisses a modal BottomSheet', (WidgetTester tester) async {
BuildContext savedContext;
......@@ -203,4 +205,50 @@ void main() {
const EdgeInsets.only(left: 50.0, right: 50.0, bottom: 50.0),
);
});
testWidgets('modal BottomSheet has semantics', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
await tester.pumpWidget(new MaterialApp(
home: new Scaffold(
key: scaffoldKey,
body: const Center(child: Text('body'))
)
));
showModalBottomSheet<void>(context: scaffoldKey.currentContext, builder: (BuildContext context) {
return new Container(
child: const Text('BottomSheet')
);
});
await tester.pump(); // bottom sheet show animation starts
await tester.pump(const Duration(seconds: 1)); // animation done
expect(semantics, hasSemantics(new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
children: <TestSemantics>[
new TestSemantics(
label: 'Dialog',
textDirection: TextDirection.ltr,
flags: <SemanticsFlag>[
SemanticsFlag.scopesRoute,
SemanticsFlag.namesRoute,
],
children: <TestSemantics>[
new TestSemantics(
label: 'BottomSheet',
textDirection: TextDirection.ltr,
),
],
),
],
),
],
), ignoreTransform: true, ignoreRect: true, ignoreId: true));
semantics.dispose();
});
}
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