Skip to content

Handle Cupertino back gesture interrupted by Navigator push#28756

Merged
HansMuller merged 2 commits intoflutter:masterfrom
HansMuller:cupertino_route_dismiss
Mar 4, 2019
Merged

Handle Cupertino back gesture interrupted by Navigator push#28756
HansMuller merged 2 commits intoflutter:masterfrom
HansMuller:cupertino_route_dismiss

Conversation

@HansMuller
Copy link
Contributor

Previously, if a new route was pushed before the iOS "back-swipe" dismiss animation was finished then the _CupertinoBackGestureController would mistakenly pop the new route when the animation actually did finish.

Fixes #28728
Fixes #27334

@HansMuller HansMuller requested a review from xster March 2, 2019 01:11
@required this.navigator,
@required this.controller,
@required this.onEnded,
@required this.route,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is private, we can just make it take route (and make it impossible for future maintainers to accidentally give in disjoint instances of these 3 things).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, done.

// back gesture drives this animation to the dismissed status before
// popping the navigator.
if (!isCurrent) {
// removing the route.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add that it itself is responsible for disposing the route and we don't have to do it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

gesture = await tester.startGesture(const Offset(5, 300));
await gesture.moveBy(const Offset(400, 0)); // drag halfway
await gesture.up();
await tester.pump(const Duration(milliseconds: 275)); // partially dismiss "route"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this right? Looking at droppedPageForwardAnimationTime and droppedPageBackAnimationTime, it seems like it's a bit more complicated than that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I verified that the test is doing the right thing by watching it execute and making sure that (without the fix) it failed exactly as was reported.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a big deal, I just meant this animation isn't driven by MaterialPageTransition times. It's driven by https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/cupertino/route.dart#L628. It still works. It's just not 75% as written above. I'll clean this up a bit in the next PR.

await gesture.moveBy(const Offset(400, 0)); // drag halfway
await gesture.up();
await tester.pump(const Duration(milliseconds: 275)); // partially dismiss "route"
expect(find.text('route'), findsOneWidget);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert where 'route' and 'push' are so if someone refactors the droppedPageForwardAnimationTime/droppedPageBackAnimationTime in the future, we don't accidentally just finish running the whole animation and end up not testing anything here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, added checks for this.

@goderbauer goderbauer added framework flutter/packages/flutter repository. See also f: labels. f: cupertino flutter/packages/flutter/cupertino repository labels Mar 4, 2019
@xster
Copy link
Member

xster commented Mar 4, 2019

LGTM

@HansMuller HansMuller merged commit e8b8720 into flutter:master Mar 4, 2019
@HansMuller HansMuller deleted the cupertino_route_dismiss branch March 4, 2019 19:42
_animating = false;
if (status == AnimationStatus.dismissed)
navigator.pop<T>(); // this will cause the route to get disposed, which will dispose us
route.navigator.removeRoute(route); // this will cause the route to get disposed, which will dispose us
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out this has a subtle (untested :()problem. This will dispose the route first which means by the time the controller is disposed, the route's reference to the navigator is gone already and we can't call didStopUserGesture. Breaks a few uncommon APIs on the NavigatorObserver. I'll fix it in a next pr.

Copy link

@1AlexFix1 1AlexFix1 Mar 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, I don’t understand how it all works, but this change caused this problem #29596, I added
route.navigator.pop ();
instead
route.navigator.removeRoute (route);
At first glance, everything works, but what this leads to, I cannot say) you know better,
on stable branch navigator.pop(); =)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for digging through this @1AlexFix1, I think you're right in that this would break existing NavigatorObserver.didPop.

@HansMuller, let's chat about this next week. Though I'm not sure what is the right solution. Since didPop() actually returns the route that was popped whereas pop() doesn't let you specify which route was popped, this API asymmetry might be the root of the issue.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

f: cupertino flutter/packages/flutter/cupertino repository framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Severe navigator fail on iOS (swipe back) since newest stable upgrade Cannot reuse a MaterialPageRoute<dynamic> after disposing it.

5 participants