From 0e97637299d7ef55be8c12f508ec9aece483b97d Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Thu, 1 Jun 2017 11:26:54 -0700 Subject: [PATCH] Implement a pushRoute service to satisfy the FlutterView.pushRoute API (#10415) Fixes https://github.com/flutter/flutter/issues/10399 --- packages/flutter/lib/src/widgets/app.dart | 9 ++++++ packages/flutter/lib/src/widgets/binding.dart | 29 ++++++++++++++++--- .../flutter/test/widgets/binding_test.dart | 23 +++++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index ecdeed592d..669716d9c1 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -166,6 +166,15 @@ class _WidgetsAppState extends State implements WidgetsBindingObserv return await navigator.maybePop(); } + @override + Future didPushRoute(String route) async { + assert(mounted); + final NavigatorState navigator = _navigator.currentState; + assert(navigator != null); + navigator.pushNamed(route); + return true; + } + @override void didChangeMetrics() { setState(() { diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index db80dcc676..6af1ed7175 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -37,6 +37,14 @@ abstract class WidgetsBindingObserver { /// its current route if possible. Future didPopRoute() => new Future.value(false); + /// Called when the host tells the app to push a new route onto the + /// navigator. + /// + /// Observers are expected to return true if they were able to + /// handle the notification. Observers are notified in registration + /// order until one returns true. + Future didPushRoute(String route) => new Future.value(false); + /// Called when the application's dimensions change. For example, /// when a phone is rotated. void didChangeMetrics() { } @@ -198,10 +206,23 @@ abstract class WidgetsBinding extends BindingBase implements GestureBinding, Ren SystemNavigator.pop(); } - Future _handleNavigationInvocation(MethodCall methodCall) async { - if (methodCall.method == 'popRoute') - handlePopRoute(); - // TODO(abarth): Handle 'pushRoute'. + /// Called when the host tells the app to push a new route onto the + /// navigator. + Future handlePushRoute(String route) async { + for (WidgetsBindingObserver observer in new List.from(_observers)) { + if (await observer.didPushRoute(route)) + return; + } + } + + Future _handleNavigationInvocation(MethodCall methodCall) { + switch (methodCall.method) { + case 'popRoute': + return handlePopRoute(); + case 'pushRoute': + return handlePushRoute(methodCall.arguments); + } + return new Future.value(); } /// Called when the application lifecycle state changes. diff --git a/packages/flutter/test/widgets/binding_test.dart b/packages/flutter/test/widgets/binding_test.dart index 610733afb1..8839333224 100644 --- a/packages/flutter/test/widgets/binding_test.dart +++ b/packages/flutter/test/widgets/binding_test.dart @@ -26,6 +26,16 @@ class AppLifecycleStateObserver extends WidgetsBindingObserver { } } +class PushRouteObserver extends WidgetsBindingObserver { + String pushedRoute; + + @override + Future didPushRoute(String route) async { + pushedRoute = route; + return true; + } +} + void main() { setUp(() { WidgetsFlutterBinding.ensureInitialized(); @@ -61,4 +71,17 @@ void main() { await BinaryMessages.handlePlatformMessage('flutter/lifecycle', message, (_) {}); expect(observer.lifecycleState, AppLifecycleState.suspending); }); + + testWidgets('didPushRoute callback', (WidgetTester tester) async { + final PushRouteObserver observer = new PushRouteObserver(); + WidgetsBinding.instance.addObserver(observer); + + final String testRouteName = 'testRouteName'; + final ByteData message = const JSONMethodCodec().encodeMethodCall( + new MethodCall('pushRoute', testRouteName)); + await BinaryMessages.handlePlatformMessage('flutter/navigation', message, (_) {}); + expect(observer.pushedRoute, testRouteName); + + WidgetsBinding.instance.removeObserver(observer); + }); }