[go_router] Nested stateful navigation with ShellRoute (#2650)
Added functionality for building route configuration with support for preserving state in nested navigators. This change introduces a new shell route class called StatefulShellRoute, that uses separate navigators for its child routes as well as preserving state in each navigation branch. This is convenient when for instance implementing a UI with a BottomNavigationBar, with a persistent navigation state for each tab (i.e. building a Navigator for each tab).
An example showcasing a UI with BottomNavigationBar and StatefulShellRoute has also been added ([stateful_shell_route.dart](https://github.com/tolo/flutter_packages/blob/nested-persistent-navigation/packages/go_router/example/lib/stateful_shell_route.dart)).
Other examples of using StatefulShellRoute are also available in these repositories:
* [stateful_books](https://github.com/tolo/stateful_books) - A fork of the Books example of go_router.
* [stateful_navbar](https://github.com/tolo/stateful_navbar) - A clone of the Flutter Material 3 Navigation Bar example.
<br/>
Below is a short example of how a StatefulShellRoute can be setup:
```dart
StatefulShellRoute(
/// Each separate stateful navigation tree (i.e. Navigator) is represented by
/// a StatefulShellBranch, which defines the routes that will be placed on that
/// Navigator. StatefulShellBranch also makes it possible to configure
/// things like an (optional) Navigator key, the default location (i.e. the
/// location the branch will be navigated to when loading it for the first time) etc.
branches: <StatefulShellBranch>[
StatefulShellBranch(navigatorKey: optionalNavigatorKey, routes: <RouteBase>[
GoRoute(
path: '/a',
builder: (BuildContext context, GoRouterState state) =>
const RootScreen(label: 'A'),
routes: <RouteBase>[
GoRoute(
path: 'details',
builder: (BuildContext context, GoRouterState state) =>
const DetailsScreen(label: 'A'),
),
],
),
]),
/// The default location of a branch will by default be the first of the
/// configured routes. To configure a different route, provide the
/// defaultLocation parameter.
StatefulShellBranch(defaultLocation: '/b/detail', routes: <RouteBase>[
GoRoute(
path: '/b',
builder: (BuildContext context, GoRouterState state) =>
const RootScreen(label: 'B'),
routes: <RouteBase>[
GoRoute(
path: 'details',
builder: (BuildContext context, GoRouterState state) =>
const DetailsScreen(label: 'B'),
),
],
),
]),
],
/// Like ShellRoute, the builder builds the navigation shell around the
/// sub-routes, but with StatefulShellRoute, this navigation shell is able to
/// maintain the state of the Navigators for each branch. The navigation shell
/// could for instance use a BottomNavigationBar or similar.
builder: (BuildContext context, StatefulShellRouteState state, Widget child) =>
ScaffoldWithNavBar(shellState: state, body: child),
)
```
This fixes issue flutter/flutter#99124.
It also (at least partially) addresses flutter/flutter#112267.
[various] Migrate example apps' AppDelegate.swift (#8155)
Migrated by running:
```
dart run script/tool/bin/flutter_plugin_tools.dart build-examples --ios --swift-package-manager
dart run script/tool/bin/flutter_plugin_tools.dart build-examples --macos --swift-package-manager
```
Tests aren't updated as this change should not affect semantics. I will get a test exemption.
Part of https://github.com/flutter/flutter/issues/159173