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