Commit 44f957d6 authored by Hans Muller's avatar Hans Muller Committed by GitHub

Prevent overlapping hero transitions from starting (#7568)

parent a34ae0f9
...@@ -493,7 +493,7 @@ class HeroController extends NavigatorObserver { ...@@ -493,7 +493,7 @@ class HeroController extends NavigatorObserver {
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) { void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
assert(navigator != null); assert(navigator != null);
assert(route != null); assert(route != null);
if (route is PageRoute<dynamic>) { if (_questsEnabled && route is PageRoute<dynamic>) {
assert(route.animation != null); assert(route.animation != null);
if (previousRoute is PageRoute<dynamic>) // could be null if (previousRoute is PageRoute<dynamic>) // could be null
_from = previousRoute; _from = previousRoute;
...@@ -507,7 +507,7 @@ class HeroController extends NavigatorObserver { ...@@ -507,7 +507,7 @@ class HeroController extends NavigatorObserver {
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
assert(navigator != null); assert(navigator != null);
assert(route != null); assert(route != null);
if (route is PageRoute<dynamic>) { if (_questsEnabled && route is PageRoute<dynamic>) {
assert(route.animation != null); assert(route.animation != null);
if (route.animation.status != AnimationStatus.dismissed && previousRoute is PageRoute<dynamic>) { if (route.animation.status != AnimationStatus.dismissed && previousRoute is PageRoute<dynamic>) {
_from = route; _from = route;
...@@ -532,9 +532,11 @@ class HeroController extends NavigatorObserver { ...@@ -532,9 +532,11 @@ class HeroController extends NavigatorObserver {
} }
void _checkForHeroQuest() { void _checkForHeroQuest() {
if (_from != null && _to != null && _from != _to && _questsEnabled) { assert(_questsEnabled);
if (_from != null && _to != null && _from != _to) {
assert(_animation != null); assert(_animation != null);
_to.offstage = _to.animation.status != AnimationStatus.completed; _to.offstage = _to.animation.status != AnimationStatus.completed;
_questsEnabled = false;
WidgetsBinding.instance.addPostFrameCallback(_updateQuest); WidgetsBinding.instance.addPostFrameCallback(_updateQuest);
} else { } else {
// this isn't a valid quest // this isn't a valid quest
...@@ -571,6 +573,7 @@ class HeroController extends NavigatorObserver { ...@@ -571,6 +573,7 @@ class HeroController extends NavigatorObserver {
} }
void _updateQuest(Duration timeStamp) { void _updateQuest(Duration timeStamp) {
assert(!_questsEnabled);
if (navigator == null) { if (navigator == null) {
// The navigator was removed before this end-of-frame callback was called. // The navigator was removed before this end-of-frame callback was called.
_clearPendingHeroQuest(); _clearPendingHeroQuest();
...@@ -611,5 +614,6 @@ class HeroController extends NavigatorObserver { ...@@ -611,5 +614,6 @@ class HeroController extends NavigatorObserver {
_from = null; _from = null;
_to = null; _to = null;
_animation = null; _animation = null;
_questsEnabled = true;
} }
} }
...@@ -66,6 +66,29 @@ class ThirdWidget extends StatelessWidget { ...@@ -66,6 +66,29 @@ class ThirdWidget extends StatelessWidget {
} }
} }
class OnTapPage extends StatelessWidget {
OnTapPage({ Key key, this.id, this.onTap }) : super(key: key);
final String id;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text('Page $id')),
body: new GestureDetector(
onTap: onTap,
behavior: HitTestBehavior.opaque,
child: new Container(
child: new Center(
child: new Text(id, style: Theme.of(context).textTheme.display2),
),
),
),
);
}
}
void main() { void main() {
testWidgets('Can navigator navigate to and from a stateful widget', (WidgetTester tester) async { testWidgets('Can navigator navigate to and from a stateful widget', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
...@@ -209,4 +232,32 @@ void main() { ...@@ -209,4 +232,32 @@ void main() {
// await gesture.up(); // await gesture.up();
// expect(log, equals(<String>['left'])); // expect(log, equals(<String>['left']));
// }); // });
testWidgets('popAndPushNamed', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (BuildContext context) => new OnTapPage(id: '/', onTap: () { Navigator.pushNamed(context, '/A'); }),
'/A': (BuildContext context) => new OnTapPage(id: 'A', onTap: () { Navigator.popAndPushNamed(context, '/B'); }),
'/B': (BuildContext context) => new OnTapPage(id: 'B', onTap: () { Navigator.pop(context); }),
};
await tester.pumpWidget(new MaterialApp(routes: routes));
expect(find.text('/'), findsOneWidget);
expect(find.text('A', skipOffstage: false), findsNothing);
expect(find.text('B', skipOffstage: false), findsNothing);
await tester.tap(find.text('/'));
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(find.text('/'), findsNothing);
expect(find.text('A'), findsOneWidget);
expect(find.text('B'), findsNothing);
await tester.tap(find.text('A'));
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(find.text('/'), findsNothing);
expect(find.text('A'), findsNothing);
expect(find.text('B'), findsOneWidget);
});
} }
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