Commit d17e80ce authored by Matt Perry's avatar Matt Perry Committed by GitHub

Fix bug with back gesture with a persistent bottom sheet showing. (#6498)

Fixes https://github.com/flutter/flutter/issues/6451
parent d4c2481e
......@@ -131,7 +131,7 @@ class _CupertinoBackGestureController extends NavigationGestureController {
}
@override
void dragEnd(double velocity) {
bool dragEnd(double velocity) {
if (velocity.abs() >= _kMinFlingVelocity) {
controller.fling(velocity: -velocity);
} else if (controller.value <= 0.5) {
......@@ -141,8 +141,11 @@ class _CupertinoBackGestureController extends NavigationGestureController {
}
// Don't end the gesture until the transition completes.
final AnimationStatus status = controller.status;
handleStatusChanged(controller.status);
controller?.addStatusListener(handleStatusChanged);
return (status == AnimationStatus.reverse || status == AnimationStatus.dismissed);
}
void handleStatusChanged(AnimationStatus status) {
......
......@@ -820,12 +820,16 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
}
void _handleDragEnd(DragEndDetails details) {
_backGestureController?.dragEnd(details.velocity.pixelsPerSecond.dx / context.size.width);
final bool willPop = _backGestureController?.dragEnd(details.velocity.pixelsPerSecond.dx / context.size.width) ?? false;
if (willPop)
_currentBottomSheet?.close();
_backGestureController = null;
}
void _handleDragCancel() {
_backGestureController?.dragEnd(0.0);
final bool willPop = _backGestureController?.dragEnd(0.0) ?? false;
if (willPop)
_currentBottomSheet?.close();
_backGestureController = null;
}
......
......@@ -218,7 +218,10 @@ abstract class NavigationGestureController {
/// The drag gesture has ended with a horizontal motion of
/// [fractionalVelocity] as a fraction of screen width per second.
void dragEnd(double fractionalVelocity);
///
/// Returns true if the gesture will complete (i.e. a back gesture will
/// result in a pop).
bool dragEnd(double fractionalVelocity);
}
/// Signature for the [Navigator.popUntil] predicate argument.
......
......@@ -13,6 +13,38 @@ class TestOverlayRoute extends OverlayRoute<Null> {
Widget _build(BuildContext context) => new Text('Overlay');
}
class PersistentBottomSheetTest extends StatefulWidget {
PersistentBottomSheetTest({ Key key }) : super(key: key);
@override
PersistentBottomSheetTestState createState() => new PersistentBottomSheetTestState();
}
class PersistentBottomSheetTestState extends State<PersistentBottomSheetTest> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
bool setStateCalled = false;
void showBottomSheet() {
_scaffoldKey.currentState.showBottomSheet/*<Null>*/((BuildContext context) {
return new Text('bottomSheet');
})
.closed.then((_) {
setState(() {
setStateCalled = true;
});
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
body: new Text('Sheet')
);
}
}
void main() {
testWidgets('Check onstage/offstage handling around transitions', (WidgetTester tester) async {
GlobalKey containerKey1 = new GlobalKey();
......@@ -332,4 +364,46 @@ void main() {
expect(find.text('Home'), isOnstage);
expect(find.text('Settings'), findsNothing);
});
// Tests bug https://github.com/flutter/flutter/issues/6451
testWidgets('Check back gesture with a persistent bottom sheet showing', (WidgetTester tester) async {
GlobalKey containerKey1 = new GlobalKey();
GlobalKey containerKey2 = new GlobalKey();
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (_) => new Scaffold(key: containerKey1, body: new Text('Home')),
'/sheet': (_) => new PersistentBottomSheetTest(key: containerKey2),
};
await tester.pumpWidget(new MaterialApp(
routes: routes,
theme: new ThemeData(platform: TargetPlatform.iOS),
));
Navigator.pushNamed(containerKey1.currentContext, '/sheet');
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(find.text('Home'), findsNothing);
expect(find.text('Sheet'), isOnstage);
// Show the bottom sheet.
PersistentBottomSheetTestState sheet = containerKey2.currentState;
sheet.showBottomSheet();
await tester.pump(const Duration(seconds: 1));
// Drag from left edge to invoke the gesture.
TestGesture gesture = await tester.startGesture(new Point(5.0, 100.0));
await gesture.moveBy(new Offset(500.0, 0.0));
await gesture.up();
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(find.text('Home'), isOnstage);
expect(find.text('Sheet'), findsNothing);
// Sheet called setState and didn't crash.
expect(sheet.setStateCalled, isTrue);
});
}
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