Commit 18d5c5e7 authored by Hixie's avatar Hixie

didChangeNext()

Replace didPushNext() and didReplaceNext() with didChangeNext(), and
call it in more cases, so that a route can easily track the next route.

Use this to make TransitionRoute properly track its next route so that
you can do next-route-driven animations that work even with removes,
replaces, and other crazy manipulations of the navigator stack.
parent 1e1761d1
...@@ -40,16 +40,15 @@ abstract class Route<T> { ...@@ -40,16 +40,15 @@ abstract class Route<T> {
/// Whether calling didPop() would return false. /// Whether calling didPop() would return false.
bool get willHandlePopInternally => false; bool get willHandlePopInternally => false;
/// The given route has been pushed onto the navigator after this route.
void didPushNext(Route nextRoute) { }
/// The given route, which came after this one, has been popped off the /// The given route, which came after this one, has been popped off the
/// navigator. /// navigator.
void didPopNext(Route nextRoute) { } void didPopNext(Route nextRoute) { }
/// The given old route, which was the route that came after this one, has /// This route's next route has changed to the given new route. This is called
/// been replaced with the given new route. /// on a route whenever the next route changes for any reason, except for
void didReplaceNext(Route oldNextRoute, Route newNextRoute) { } /// cases when didPopNext() would be called, so long as it is in the history.
/// nextRoute will be null if there's no next route.
void didChangeNext(Route nextRoute) { }
/// The route should remove its overlays and free any other resources. /// The route should remove its overlays and free any other resources.
/// ///
...@@ -238,8 +237,9 @@ class NavigatorState extends State<Navigator> { ...@@ -238,8 +237,9 @@ class NavigatorState extends State<Navigator> {
route.install(_currentOverlayEntry); route.install(_currentOverlayEntry);
_history.add(route); _history.add(route);
route.didPush(); route.didPush();
route.didChangeNext(null);
if (oldRoute != null) if (oldRoute != null)
oldRoute.didPushNext(route); oldRoute.didChangeNext(route);
config.observer?.didPush(route, oldRoute); config.observer?.didPush(route, oldRoute);
}); });
assert(() { _debugLocked = false; return true; }); assert(() { _debugLocked = false; return true; });
...@@ -264,8 +264,12 @@ class NavigatorState extends State<Navigator> { ...@@ -264,8 +264,12 @@ class NavigatorState extends State<Navigator> {
newRoute.install(oldRoute.overlayEntries.last); newRoute.install(oldRoute.overlayEntries.last);
_history[index] = newRoute; _history[index] = newRoute;
newRoute.didReplace(oldRoute); newRoute.didReplace(oldRoute);
if (index + 1 < _history.length)
newRoute.didChangeNext(_history[index + 1]);
else
newRoute.didChangeNext(null);
if (index > 0) if (index > 0)
_history[index - 1].didReplaceNext(oldRoute, newRoute); _history[index - 1].didChangeNext(newRoute);
oldRoute.dispose(); oldRoute.dispose();
oldRoute._navigator = null; oldRoute._navigator = null;
}); });
...@@ -290,6 +294,9 @@ class NavigatorState extends State<Navigator> { ...@@ -290,6 +294,9 @@ class NavigatorState extends State<Navigator> {
assert(targetRoute.overlayEntries.isEmpty || !overlay.debugIsVisible(targetRoute.overlayEntries.last)); assert(targetRoute.overlayEntries.isEmpty || !overlay.debugIsVisible(targetRoute.overlayEntries.last));
setState(() { setState(() {
_history.removeAt(index); _history.removeAt(index);
Route newRoute = index < _history.length ? _history[index] : null;
if (index > 0)
_history[index - 1].didChangeNext(newRoute);
targetRoute.dispose(); targetRoute.dispose();
targetRoute._navigator = null; targetRoute._navigator = null;
}); });
...@@ -378,17 +385,16 @@ class NavigatorTransaction { ...@@ -378,17 +385,16 @@ class NavigatorTransaction {
} }
/// Adds the given route to the Navigator's history, and transitions to it. /// Adds the given route to the Navigator's history, and transitions to it.
/// The route will have didPush() called on it; the previous route, if any, /// The route will have didPush() and didChangeNext() called on it; the
/// will have didPushNext() called on it; and the Navigator observer, if any, /// previous route, if any, will have didChangeNext() called on it; and the
/// will have didPush() called on it. /// Navigator observer, if any, will have didPush() called on it.
void push(Route route, { Set<Key> mostValuableKeys }) { void push(Route route, { Set<Key> mostValuableKeys }) {
assert(_debugOpen); assert(_debugOpen);
_navigator._push(route, mostValuableKeys: mostValuableKeys); _navigator._push(route, mostValuableKeys: mostValuableKeys);
} }
/// Replaces one given route with another, but does not call didPush/didPop. /// Replaces one given route with another. Calls install(), didReplace(), and
/// Instead, this calls install() on the new route, then didReplace() on the /// didChangeNext() on the new route, then dispose() on the old route. The
/// new route passing the old route, then dispose() on the old route. The
/// navigator is not informed of the replacement. /// navigator is not informed of the replacement.
/// ///
/// The old route must have overlay entries, otherwise we won't know where to /// The old route must have overlay entries, otherwise we won't know where to
...@@ -416,8 +422,8 @@ class NavigatorTransaction { ...@@ -416,8 +422,8 @@ class NavigatorTransaction {
_navigator._replaceRouteBefore(anchorRoute: anchorRoute, newRoute: newRoute); _navigator._replaceRouteBefore(anchorRoute: anchorRoute, newRoute: newRoute);
} }
/// Removes the route prior to the given anchorRoute without notifying /// Removes the route prior to the given anchorRoute, and calls didChangeNext
/// neighbouring routes or the navigator observer, if any. /// on the route prior to that one, if any. The observer is not notified.
void removeRouteBefore(Route anchorRoute) { void removeRouteBefore(Route anchorRoute) {
assert(_debugOpen); assert(_debugOpen);
_navigator._removeRouteBefore(anchorRoute); _navigator._removeRouteBefore(anchorRoute);
...@@ -426,7 +432,7 @@ class NavigatorTransaction { ...@@ -426,7 +432,7 @@ class NavigatorTransaction {
/// Tries to removes the current route, calling its didPop() method. If that /// Tries to removes the current route, calling its didPop() method. If that
/// method returns false, then nothing else happens. Otherwise, the observer /// method returns false, then nothing else happens. Otherwise, the observer
/// (if any) is notified using its didPop() method, and the previous route is /// (if any) is notified using its didPop() method, and the previous route is
/// notified using [Route.didPopNext]. /// notified using [Route.didChangeNext].
/// ///
/// The type of the result argument, if provided, must match the type argument /// The type of the result argument, if provided, must match the type argument
/// of the class of the current route. (In practice, this is usually /// of the class of the current route. (In practice, this is usually
......
...@@ -123,6 +123,9 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -123,6 +123,9 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
} }
} }
PerformanceView get forwardPerformance => _forwardPerformance;
final ProxyPerformance _forwardPerformance = new ProxyPerformance(alwaysDismissedPerformance);
void install(OverlayEntry insertionPoint) { void install(OverlayEntry insertionPoint) {
_performanceController = createPerformanceController(); _performanceController = createPerformanceController();
assert(_performanceController != null); assert(_performanceController != null);
...@@ -151,21 +154,17 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -151,21 +154,17 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
return true; return true;
} }
void finished() { void didPopNext(Route nextRoute) {
super.finished(); _updateForwardPerformance(nextRoute);
_transitionCompleter?.complete(_result); super.didPopNext(nextRoute);
} }
void dispose() { void didChangeNext(Route nextRoute) {
_performanceController.stop(); _updateForwardPerformance(nextRoute);
super.dispose(); super.didChangeNext(nextRoute);
} }
void _updateForwardPerformance(Route nextRoute) {
PerformanceView get forwardPerformance => _forwardPerformance;
final ProxyPerformance _forwardPerformance = new ProxyPerformance();
void didPushNext(Route nextRoute) {
if (nextRoute is TransitionRoute && canTransitionTo(nextRoute) && nextRoute.canTransitionFrom(this)) { if (nextRoute is TransitionRoute && canTransitionTo(nextRoute) && nextRoute.canTransitionFrom(this)) {
PerformanceView current = _forwardPerformance.masterPerformance; PerformanceView current = _forwardPerformance.masterPerformance;
if (current != null) { if (current != null) {
...@@ -189,13 +188,24 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -189,13 +188,24 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
} else { } else {
_forwardPerformance.masterPerformance = nextRoute.performance; _forwardPerformance.masterPerformance = nextRoute.performance;
} }
} else {
_forwardPerformance.masterPerformance = alwaysDismissedPerformance;
} }
super.didPushNext(nextRoute);
} }
bool canTransitionTo(TransitionRoute nextRoute) => true; bool canTransitionTo(TransitionRoute nextRoute) => true;
bool canTransitionFrom(TransitionRoute nextRoute) => true; bool canTransitionFrom(TransitionRoute nextRoute) => true;
void finished() {
super.finished();
_transitionCompleter?.complete(_result);
}
void dispose() {
_performanceController.stop();
super.dispose();
}
String get debugLabel => '$runtimeType'; String get debugLabel => '$runtimeType';
String toString() => '$runtimeType(performance: $_performanceController)'; String toString() => '$runtimeType(performance: $_performanceController)';
} }
...@@ -469,8 +479,8 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -469,8 +479,8 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
abstract class PopupRoute<T> extends ModalRoute<T> { abstract class PopupRoute<T> extends ModalRoute<T> {
PopupRoute({ Completer<T> completer }) : super(completer: completer); PopupRoute({ Completer<T> completer }) : super(completer: completer);
bool get opaque => false; bool get opaque => false;
void didPushNext(Route nextRoute) { void didChangeNext(Route nextRoute) {
assert(nextRoute is! PageRoute); assert(nextRoute is! PageRoute);
super.didPushNext(nextRoute); super.didChangeNext(nextRoute);
} }
} }
...@@ -49,16 +49,12 @@ class TestRoute extends Route<String> { ...@@ -49,16 +49,12 @@ class TestRoute extends Route<String> {
return returnValue; return returnValue;
} }
void didPushNext(TestRoute nextRoute) {
log('didPushNext ${nextRoute.name}');
}
void didPopNext(TestRoute nextRoute) { void didPopNext(TestRoute nextRoute) {
log('didPopNext ${nextRoute.name}'); log('didPopNext ${nextRoute.name}');
} }
void didReplaceNext(TestRoute oldNextRoute, TestRoute newNextRoute) { void didChangeNext(TestRoute nextRoute) {
log('didReplaceNext ${oldNextRoute.name} ${newNextRoute.name}'); log('didChangeNext ${nextRoute?.name}');
} }
void dispose() { void dispose() {
...@@ -100,6 +96,7 @@ void main() { ...@@ -100,6 +96,7 @@ void main() {
[ [
'initial: install', 'initial: install',
'initial: didPush', 'initial: didPush',
'initial: didChangeNext null',
] ]
); );
TestRoute second; TestRoute second;
...@@ -112,7 +109,8 @@ void main() { ...@@ -112,7 +109,8 @@ void main() {
[ [
'second: install', 'second: install',
'second: didPush', 'second: didPush',
'initial: didPushNext second', 'second: didChangeNext null',
'initial: didChangeNext second',
] ]
); );
runNavigatorTest( runNavigatorTest(
...@@ -124,7 +122,8 @@ void main() { ...@@ -124,7 +122,8 @@ void main() {
[ [
'third: install', 'third: install',
'third: didPush', 'third: didPush',
'second: didPushNext third', 'third: didChangeNext null',
'second: didChangeNext third',
] ]
); );
runNavigatorTest( runNavigatorTest(
...@@ -136,7 +135,8 @@ void main() { ...@@ -136,7 +135,8 @@ void main() {
[ [
'two: install', 'two: install',
'two: didReplace second', 'two: didReplace second',
'initial: didReplaceNext second two', 'two: didChangeNext third',
'initial: didChangeNext two',
'second: dispose', 'second: dispose',
] ]
); );
...@@ -187,6 +187,7 @@ void main() { ...@@ -187,6 +187,7 @@ void main() {
[ [
'first: install', 'first: install',
'first: didPush', 'first: didPush',
'first: didChangeNext null',
] ]
); );
TestRoute second; TestRoute second;
...@@ -199,7 +200,8 @@ void main() { ...@@ -199,7 +200,8 @@ void main() {
[ [
'second: install', 'second: install',
'second: didPush', 'second: didPush',
'first: didPushNext second', 'second: didChangeNext null',
'first: didChangeNext second',
] ]
); );
runNavigatorTest( runNavigatorTest(
...@@ -211,7 +213,8 @@ void main() { ...@@ -211,7 +213,8 @@ void main() {
[ [
'third: install', 'third: install',
'third: didPush', 'third: didPush',
'second: didPushNext third', 'third: didChangeNext null',
'second: didChangeNext third',
] ]
); );
runNavigatorTest( runNavigatorTest(
...@@ -245,7 +248,8 @@ void main() { ...@@ -245,7 +248,8 @@ void main() {
[ [
'three: install', 'three: install',
'three: didPush', 'three: didPush',
'second: didPushNext three', 'three: didChangeNext null',
'second: didChangeNext three',
] ]
); );
TestRoute four; TestRoute four;
...@@ -258,7 +262,8 @@ void main() { ...@@ -258,7 +262,8 @@ void main() {
[ [
'four: install', 'four: install',
'four: didPush', 'four: didPush',
'three: didPushNext four', 'four: didChangeNext null',
'three: didChangeNext four',
] ]
); );
runNavigatorTest( runNavigatorTest(
...@@ -268,6 +273,7 @@ void main() { ...@@ -268,6 +273,7 @@ void main() {
transaction.removeRouteBefore(four); transaction.removeRouteBefore(four);
}, },
[ [
'second: didChangeNext four',
'three: dispose', 'three: dispose',
] ]
); );
...@@ -306,6 +312,7 @@ void main() { ...@@ -306,6 +312,7 @@ void main() {
[ [
'A: install', 'A: install',
'A: didPush', 'A: didPush',
'A: didChangeNext null',
] ]
); );
runNavigatorTest( runNavigatorTest(
...@@ -317,7 +324,8 @@ void main() { ...@@ -317,7 +324,8 @@ void main() {
[ [
'B: install', 'B: install',
'B: didPush', 'B: didPush',
'A: didPushNext B', 'B: didChangeNext null',
'A: didChangeNext B',
] ]
); );
TestRoute routeC; TestRoute routeC;
...@@ -330,7 +338,8 @@ void main() { ...@@ -330,7 +338,8 @@ void main() {
[ [
'C: install', 'C: install',
'C: didPush', 'C: didPush',
'B: didPushNext C', 'C: didChangeNext null',
'B: didChangeNext C',
] ]
); );
TestRoute routeB; TestRoute routeB;
...@@ -343,7 +352,8 @@ void main() { ...@@ -343,7 +352,8 @@ void main() {
[ [
'b: install', 'b: install',
'b: didReplace B', 'b: didReplace B',
'A: didReplaceNext B b', 'b: didChangeNext C',
'A: didChangeNext b',
'B: dispose', 'B: 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