diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md index a52afff1b9cf..abb5d9198a7c 100644 --- a/packages/go_router/CHANGELOG.md +++ b/packages/go_router/CHANGELOG.md @@ -1,3 +1,7 @@ +## 11.0.1 + +- Fixes the Android back button ignores top level route's onExit. + ## 11.0.0 - Fixes the GoRouter.goBranch so that it doesn't reset extra to null if extra is not serializable. diff --git a/packages/go_router/lib/src/delegate.dart b/packages/go_router/lib/src/delegate.dart index 8e9befe3555b..bcd737a65367 100644 --- a/packages/go_router/lib/src/delegate.dart +++ b/packages/go_router/lib/src/delegate.dart @@ -62,6 +62,12 @@ class GoRouterDelegate extends RouterDelegate return true; } } + // This should be the only place where the last GoRoute exit the screen. + final GoRoute lastRoute = + currentConfiguration.matches.last.route as GoRoute; + if (lastRoute.onExit != null && navigatorKey.currentContext != null) { + return !(await lastRoute.onExit!(navigatorKey.currentContext!)); + } return false; } diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml index 4e3ba3dcbadd..14a0cdcad5e0 100644 --- a/packages/go_router/pubspec.yaml +++ b/packages/go_router/pubspec.yaml @@ -1,7 +1,7 @@ name: go_router description: A declarative router for Flutter based on Navigation 2 supporting deep linking, data-driven routes and more -version: 11.0.0 +version: 11.0.1 repository: https://github.com/flutter/packages/tree/main/packages/go_router issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22 diff --git a/packages/go_router/test/on_exit_test.dart b/packages/go_router/test/on_exit_test.dart index cd8789a64af6..044a6ff399bc 100644 --- a/packages/go_router/test/on_exit_test.dart +++ b/packages/go_router/test/on_exit_test.dart @@ -166,4 +166,81 @@ void main() { await tester.pumpAndSettle(); expect(find.byKey(home), findsOneWidget); }); + + testWidgets('android back button respects the last route.', + (WidgetTester tester) async { + bool allow = false; + final UniqueKey home = UniqueKey(); + final List routes = [ + GoRoute( + path: '/', + builder: (BuildContext context, GoRouterState state) => + DummyScreen(key: home), + onExit: (BuildContext context) { + return allow; + }, + ), + ]; + + final GoRouter router = await createRouter(routes, tester); + expect(find.byKey(home), findsOneWidget); + + // Not allow system pop. + expect(await router.routerDelegate.popRoute(), true); + + allow = true; + expect(await router.routerDelegate.popRoute(), false); + }); + + testWidgets('android back button respects the last route. async', + (WidgetTester tester) async { + bool allow = false; + final UniqueKey home = UniqueKey(); + final List routes = [ + GoRoute( + path: '/', + builder: (BuildContext context, GoRouterState state) => + DummyScreen(key: home), + onExit: (BuildContext context) async { + return allow; + }, + ), + ]; + + final GoRouter router = await createRouter(routes, tester); + expect(find.byKey(home), findsOneWidget); + + // Not allow system pop. + expect(await router.routerDelegate.popRoute(), true); + + allow = true; + expect(await router.routerDelegate.popRoute(), false); + }); + + testWidgets('android back button respects the last route with shell route.', + (WidgetTester tester) async { + bool allow = false; + final UniqueKey home = UniqueKey(); + final List routes = [ + ShellRoute(builder: (_, __, Widget child) => child, routes: [ + GoRoute( + path: '/', + builder: (BuildContext context, GoRouterState state) => + DummyScreen(key: home), + onExit: (BuildContext context) { + return allow; + }, + ), + ]) + ]; + + final GoRouter router = await createRouter(routes, tester); + expect(find.byKey(home), findsOneWidget); + + // Not allow system pop. + expect(await router.routerDelegate.popRoute(), true); + + allow = true; + expect(await router.routerDelegate.popRoute(), false); + }); }