Commit 467daba4 authored by Volodymyr Lykhonis's avatar Volodymyr Lykhonis Committed by Ian Hickson

RouteObserver supports multiple RouteAware per Route. (#13757)

Unsubscribe should remove RouteAware for all routes.
parent 107c812f
...@@ -1116,7 +1116,7 @@ abstract class PopupRoute<T> extends ModalRoute<T> { ...@@ -1116,7 +1116,7 @@ abstract class PopupRoute<T> extends ModalRoute<T> {
/// } /// }
/// ``` /// ```
class RouteObserver<T extends Route<dynamic>> extends NavigatorObserver { class RouteObserver<T extends Route<dynamic>> extends NavigatorObserver {
final Map<T, RouteAware> _listeners = <T, RouteAware>{}; final Map<T, Set<RouteAware>> _listeners = <T, Set<RouteAware>>{};
/// Subscribe [routeAware] to be informed about changes to [route]. /// Subscribe [routeAware] to be informed about changes to [route].
/// ///
...@@ -1126,32 +1126,55 @@ class RouteObserver<T extends Route<dynamic>> extends NavigatorObserver { ...@@ -1126,32 +1126,55 @@ class RouteObserver<T extends Route<dynamic>> extends NavigatorObserver {
void subscribe(RouteAware routeAware, T route) { void subscribe(RouteAware routeAware, T route) {
assert(routeAware != null); assert(routeAware != null);
assert(route != null); assert(route != null);
if (!_listeners.containsKey(route)) { final Set<RouteAware> subscribers = _listeners.putIfAbsent(route, () => new Set<RouteAware>());
if (subscribers.add(routeAware)) {
routeAware.didPush(); routeAware.didPush();
_listeners[route] = routeAware;
} }
} }
/// Unsubscribe [routeAware]. /// Unsubscribe [routeAware].
/// ///
/// [routeAware] is no longer informed about changes to its route. /// [routeAware] is no longer informed about changes to its route. If the given argument was
/// subscribed to multiple types, this will unregister it (once) from each type.
void unsubscribe(RouteAware routeAware) { void unsubscribe(RouteAware routeAware) {
assert(routeAware != null); assert(routeAware != null);
_listeners.remove(routeAware); for (T route in _listeners.keys) {
final Set<RouteAware> subscribers = _listeners[route];
subscribers?.remove(routeAware);
}
} }
@override @override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
if (route is T && previousRoute is T) { if (route is T && previousRoute is T) {
_listeners[previousRoute]?.didPopNext(); final List<RouteAware> previousSubscribers = _listeners[previousRoute]?.toList();
_listeners[route]?.didPop();
if (previousSubscribers != null) {
for (RouteAware routeAware in previousSubscribers) {
routeAware.didPopNext();
}
}
final List<RouteAware> subscribers = _listeners[route]?.toList();
if (subscribers != null) {
for (RouteAware routeAware in subscribers) {
routeAware.didPop();
}
}
} }
} }
@override @override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) { void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
if (route is T && previousRoute is T) { if (route is T && previousRoute is T) {
_listeners[previousRoute]?.didPushNext(); final Set<RouteAware> previousSubscribers = _listeners[previousRoute];
if (previousSubscribers != null) {
for (RouteAware routeAware in previousSubscribers) {
routeAware.didPushNext();
}
}
} }
} }
} }
......
...@@ -453,6 +453,31 @@ void main() { ...@@ -453,6 +453,31 @@ void main() {
observer.didPop(route, pageRoute); observer.didPop(route, pageRoute);
verifyNoMoreInteractions(pageRouteAware); verifyNoMoreInteractions(pageRouteAware);
}); });
test('does not call listeners when already subscribed', () {
final RouteObserver<PageRoute<dynamic>> observer = new RouteObserver<PageRoute<dynamic>>();
final RouteAware pageRouteAware = new MockRouteAware();
final MockPageRoute pageRoute = new MockPageRoute();
observer.subscribe(pageRouteAware, pageRoute);
observer.subscribe(pageRouteAware, pageRoute);
verify(pageRouteAware.didPush()).called(1);
});
test('does not call listeners when unsubscribed', () {
final RouteObserver<PageRoute<dynamic>> observer = new RouteObserver<PageRoute<dynamic>>();
final RouteAware pageRouteAware = new MockRouteAware();
final MockPageRoute pageRoute = new MockPageRoute();
final MockPageRoute nextPageRoute = new MockPageRoute();
observer.subscribe(pageRouteAware, pageRoute);
observer.subscribe(pageRouteAware, nextPageRoute);
verify(pageRouteAware.didPush()).called(2);
observer.unsubscribe(pageRouteAware);
observer.didPush(nextPageRoute, pageRoute);
observer.didPop(nextPageRoute, pageRoute);
verifyNoMoreInteractions(pageRouteAware);
});
}); });
} }
......
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