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 {
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
assert(navigator != null);
assert(route != null);
if (route is PageRoute<dynamic>) {
if (_questsEnabled && route is PageRoute<dynamic>) {
assert(route.animation != null);
if (previousRoute is PageRoute<dynamic>) // could be null
_from = previousRoute;
......@@ -507,7 +507,7 @@ class HeroController extends NavigatorObserver {
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
assert(navigator != null);
assert(route != null);
if (route is PageRoute<dynamic>) {
if (_questsEnabled && route is PageRoute<dynamic>) {
assert(route.animation != null);
if (route.animation.status != AnimationStatus.dismissed && previousRoute is PageRoute<dynamic>) {
_from = route;
......@@ -532,9 +532,11 @@ class HeroController extends NavigatorObserver {
}
void _checkForHeroQuest() {
if (_from != null && _to != null && _from != _to && _questsEnabled) {
assert(_questsEnabled);
if (_from != null && _to != null && _from != _to) {
assert(_animation != null);
_to.offstage = _to.animation.status != AnimationStatus.completed;
_questsEnabled = false;
WidgetsBinding.instance.addPostFrameCallback(_updateQuest);
} else {
// this isn't a valid quest
......@@ -571,6 +573,7 @@ class HeroController extends NavigatorObserver {
}
void _updateQuest(Duration timeStamp) {
assert(!_questsEnabled);
if (navigator == null) {
// The navigator was removed before this end-of-frame callback was called.
_clearPendingHeroQuest();
......@@ -611,5 +614,6 @@ class HeroController extends NavigatorObserver {
_from = null;
_to = null;
_animation = null;
_questsEnabled = true;
}
}
......@@ -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() {
testWidgets('Can navigator navigate to and from a stateful widget', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
......@@ -209,4 +232,32 @@ void main() {
// await gesture.up();
// 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