Commit b6197591 authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Adds a RouteObserver (#11236)

* Adds a PageRouteObserver

Required for https://github.com/flutter/plugins/pull/174.
See also https://github.com/flutter/flutter/issues/11216.

* formatting fixes

* Make RouteObserver generic
parent e967b4b3
...@@ -967,3 +967,85 @@ abstract class PopupRoute<T> extends ModalRoute<T> { ...@@ -967,3 +967,85 @@ abstract class PopupRoute<T> extends ModalRoute<T> {
super.didChangeNext(nextRoute); super.didChangeNext(nextRoute);
} }
} }
/// A [Navigator] observer that notifies [RouteAware]s of changes to the
/// state of their [Route].
///
/// To make a [StatefulWidget] aware of its current [Route] state, implement
/// [RouteAware] in its [State] and subscribe it to the [RouteObserver]:
///
/// ```dart
/// class RouteAwareWidgetState extends State<RouteAwareWidget> with RouteAware {
/// @override
/// void didChangeDependencies() {
/// super.didChangeDependencies();
/// routeObserver.subscribe(this, ModalRoute.of(context));
/// }
///
/// @override
/// void dispose() {
/// routeObserver.unsubscribe(this);
/// super.dispose();
/// }
///
/// @override
/// void didPush() {
/// // Do something
/// }
///
/// @override
/// void didPopNext() {
/// // Do something
/// }
///
/// }
/// ```
class RouteObserver<T extends Route<dynamic>> extends NavigatorObserver {
final Map<T, RouteAware> _listeners = <T, RouteAware>{};
void subscribe(RouteAware routeAware, T route) {
assert(routeAware != null);
assert(route != null);
if (!_listeners.containsKey(route)) {
routeAware.didPush();
_listeners[route] = routeAware;
}
}
void unsubscribe(RouteAware routeAware) {
assert(routeAware != null);
_listeners.remove(routeAware);
}
@override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
if (route is T && previousRoute is T) {
_listeners[previousRoute]?.didPopNext();
_listeners[route]?.didPop();
}
}
@override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
if (route is T && previousRoute is T) {
_listeners[previousRoute]?.didPushNext();
}
}
}
/// A interface that is aware of its current Route.
abstract class RouteAware {
/// Called when the top route has been popped off, and the current route
/// shows up.
void didPopNext() { }
/// Called when the current route has been pushed.
void didPush() { }
/// Called when the current route has been popped off.
void didPop() { }
/// Called when a new route has been pushed, and the current route is no
/// longer visible.
void didPushNext() { }
}
\ No newline at end of file
...@@ -18,6 +18,7 @@ dependencies: ...@@ -18,6 +18,7 @@ dependencies:
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
mockito: "^2.0.2"
environment: environment:
sdk: '>=1.19.0 <2.0.0' sdk: '>=1.19.0 <2.0.0'
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:collection'; import 'dart:collection';
import 'package:mockito/mockito.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
...@@ -397,4 +398,45 @@ void main() { ...@@ -397,4 +398,45 @@ void main() {
] ]
); );
}); });
group('PageRouteObserver', () {
test('calls correct listeners', () {
final RouteObserver<PageRoute<dynamic>> observer = new RouteObserver<PageRoute<dynamic>>();
final RouteAware pageRouteAware1 = new MockRouteAware();
final MockPageRoute route1 = new MockPageRoute();
observer.subscribe(pageRouteAware1, route1);
verify(pageRouteAware1.didPush()).called(1);
final RouteAware pageRouteAware2 = new MockRouteAware();
final MockPageRoute route2 = new MockPageRoute();
observer.didPush(route2, route1);
verify(pageRouteAware1.didPushNext()).called(1);
observer.subscribe(pageRouteAware2, route2);
verify(pageRouteAware2.didPush()).called(1);
observer.didPop(route2, route1);
verify(pageRouteAware2.didPop()).called(1);
verify(pageRouteAware1.didPopNext()).called(1);
});
test('does not call listeners for non-PageRoute', () {
final RouteObserver<PageRoute<dynamic>> observer = new RouteObserver<PageRoute<dynamic>>();
final RouteAware pageRouteAware = new MockRouteAware();
final MockPageRoute pageRoute = new MockPageRoute();
final MockRoute route = new MockRoute();
observer.subscribe(pageRouteAware, pageRoute);
verify(pageRouteAware.didPush());
observer.didPush(route, pageRoute);
observer.didPop(route, pageRoute);
verifyNoMoreInteractions(pageRouteAware);
});
});
} }
class MockPageRoute extends Mock implements PageRoute<dynamic> { }
class MockRoute extends Mock implements Route<dynamic> { }
class MockRouteAware extends Mock implements RouteAware { }
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