diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md index 2eb1a7707c9..4e1c23474d8 100644 --- a/packages/go_router/CHANGELOG.md +++ b/packages/go_router/CHANGELOG.md @@ -1,3 +1,9 @@ +## 11.0.0 + +- Fixes the GoRouter.goBranch so that it doesn't reset extra to null if extra is not serializable. +- **BREAKING CHANGE**: + - Updates the function signature of `GoRouteInformationProvider.restore`. + ## 10.1.0 - Supports setting `requestFocus`. diff --git a/packages/go_router/README.md b/packages/go_router/README.md index 0a72dd18d20..f2cd542f95b 100644 --- a/packages/go_router/README.md +++ b/packages/go_router/README.md @@ -37,6 +37,7 @@ See the API documentation for details on the following topics: - [Error handling](https://pub.dev/documentation/go_router/latest/topics/Error%20handling-topic.html) ## Migration Guides +- [Migrating to 11.0.0](https://flutter.dev/go/go-router-v11-breaking-changes). - [Migrating to 10.0.0](https://flutter.dev/go/go-router-v10-breaking-changes). - [Migrating to 9.0.0](https://flutter.dev/go/go-router-v9-breaking-changes). - [Migrating to 8.0.0](https://flutter.dev/go/go-router-v8-breaking-changes). diff --git a/packages/go_router/lib/src/information_provider.dart b/packages/go_router/lib/src/information_provider.dart index 31a9e694279..31b100a8b74 100644 --- a/packages/go_router/lib/src/information_provider.dart +++ b/packages/go_router/lib/src/information_provider.dart @@ -33,6 +33,10 @@ enum NavigatingType { /// Replace the entire [RouteMatchList] with the new location. go, + + /// Restore the current match list with + /// [RouteInformationState.baseRouteMatchList]. + restore, } /// The data class to be stored in [RouteInformation.state] to be used by @@ -48,8 +52,9 @@ class RouteInformationState { this.completer, this.baseRouteMatchList, required this.type, - }) : assert((type != NavigatingType.go) == - (completer != null && baseRouteMatchList != null)); + }) : assert((type == NavigatingType.go || type == NavigatingType.restore) == + (completer == null)), + assert((type != NavigatingType.go) == (baseRouteMatchList != null)); /// The extra object used when navigating with [GoRouter]. final Object? extra; @@ -57,7 +62,8 @@ class RouteInformationState { /// The completer that needs to be completed when the newly added route is /// popped off the screen. /// - /// This is only null if [type] is [NavigatingType.go]. + /// This is only null if [type] is [NavigatingType.go] or + /// [NavigatingType.restore]. final Completer? completer; /// The base route match list to push on top to. @@ -178,10 +184,14 @@ class GoRouteInformationProvider extends RouteInformationProvider } /// Restores the current route matches with the `encodedMatchList`. - void restore(String location, {required Object encodedMatchList}) { + void restore(String location, {required RouteMatchList matchList}) { _setValue( - location, - encodedMatchList, + matchList.uri.toString(), + RouteInformationState( + extra: matchList.extra, + baseRouteMatchList: matchList, + type: NavigatingType.restore, + ), ); } diff --git a/packages/go_router/lib/src/parser.dart b/packages/go_router/lib/src/parser.dart index df4d551a8bf..cd7f7529e13 100644 --- a/packages/go_router/lib/src/parser.dart +++ b/packages/go_router/lib/src/parser.dart @@ -188,6 +188,11 @@ class GoRouteInformationParser extends RouteInformationParser { ); case NavigatingType.go: return newMatchList; + case NavigatingType.restore: + // Still need to consider redirection. + return baseRouteMatchList!.uri.toString() == newMatchList.uri.toString() + ? baseRouteMatchList + : newMatchList; } } diff --git a/packages/go_router/lib/src/router.dart b/packages/go_router/lib/src/router.dart index a5671e2fc9d..e37151d4ffe 100644 --- a/packages/go_router/lib/src/router.dart +++ b/packages/go_router/lib/src/router.dart @@ -327,7 +327,7 @@ class GoRouter implements RouterConfig { log.info('restoring ${matchList.uri}'); routeInformationProvider.restore( matchList.uri.toString(), - encodedMatchList: RouteMatchListCodec(configuration).encode(matchList), + matchList: matchList, ); } diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml index 3ad93e7ee93..f776480793a 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: 10.1.0 +version: 11.0.0 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/go_router_test.dart b/packages/go_router/test/go_router_test.dart index e840b00cbd7..13a28bcc396 100644 --- a/packages/go_router/test/go_router_test.dart +++ b/packages/go_router/test/go_router_test.dart @@ -2797,6 +2797,52 @@ void main() { expect(matches.pathParameters['pid'], pid); }); + testWidgets('StatefulShellRoute preserve extra when switching branch', + (WidgetTester tester) async { + StatefulNavigationShell? routeState; + Object? latestExtra; + final List routes = [ + StatefulShellRoute.indexedStack( + builder: (BuildContext context, GoRouterState state, + StatefulNavigationShell navigationShell) { + routeState = navigationShell; + return navigationShell; + }, + branches: [ + StatefulShellBranch( + routes: [ + GoRoute( + path: '/a', + builder: (BuildContext context, GoRouterState state) => + const Text('Screen A'), + ), + ], + ), + StatefulShellBranch( + routes: [ + GoRoute( + path: '/b', + builder: (BuildContext context, GoRouterState state) { + latestExtra = state.extra; + return const DummyScreen(); + }), + ], + ), + ], + ), + ]; + final Object expectedExtra = Object(); + + await createRouter(routes, tester, + initialLocation: '/b', initialExtra: expectedExtra); + expect(latestExtra, expectedExtra); + routeState!.goBranch(0); + await tester.pumpAndSettle(); + routeState!.goBranch(1); + await tester.pumpAndSettle(); + expect(latestExtra, expectedExtra); + }); + testWidgets('goNames should allow dynamics values for queryParams', (WidgetTester tester) async { const Map queryParametersAll = >{