Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/go_router/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 13.3.0

- Feat add route redirect to ShellRoutes

## 13.2.3

- Fixes an issue where deep links without path caused an exception
Expand Down
22 changes: 9 additions & 13 deletions packages/go_router/lib/src/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -394,14 +394,13 @@ class RouteConfiguration {
return prevMatchList;
}

final List<RouteMatch> routeMatches = <RouteMatch>[];
final List<RouteMatchBase> routeMatches = <RouteMatchBase>[];
prevMatchList.visitRouteMatches((RouteMatchBase match) {
if (match is RouteMatch) {
if (match.route.redirect != null) {
routeMatches.add(match);
}
return true;
});

final FutureOr<String?> routeLevelRedirectResult =
_getRouteLevelRedirect(context, prevMatchList, routeMatches, 0);

Expand Down Expand Up @@ -434,25 +433,22 @@ class RouteConfiguration {
FutureOr<String?> _getRouteLevelRedirect(
BuildContext context,
RouteMatchList matchList,
List<RouteMatch> routeMatches,
List<RouteMatchBase> routeMatches,
int currentCheckIndex,
) {
if (currentCheckIndex >= routeMatches.length) {
return null;
}
final RouteMatch match = routeMatches[currentCheckIndex];
final RouteMatchBase match = routeMatches[currentCheckIndex];
FutureOr<String?> processRouteRedirect(String? newLocation) =>
newLocation ??
_getRouteLevelRedirect(
context, matchList, routeMatches, currentCheckIndex + 1);
final GoRoute route = match.route;
FutureOr<String?> routeRedirectResult;
if (route.redirect != null) {
routeRedirectResult = route.redirect!(
context,
match.buildState(this, matchList),
);
}
final RouteBase route = match.route;
FutureOr<String?> routeRedirectResult = route.redirect?.call(
context,
match.buildState(this, matchList),
);
if (routeRedirectResult is String?) {
return processRouteRedirect(routeRedirectResult);
}
Expand Down
127 changes: 67 additions & 60 deletions packages/go_router/lib/src/route.dart
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,67 @@ typedef ExitCallback = FutureOr<bool> Function(BuildContext context);
@immutable
abstract class RouteBase with Diagnosticable {
const RouteBase._({
this.redirect,
required this.routes,
required this.parentNavigatorKey,
});

/// An optional redirect function for this route.
///
/// In the case that you like to make a redirection decision for a specific
/// route (or sub-route), consider doing so by passing a redirect function to
/// the GoRoute constructor.
///
/// For example:
/// ```
/// final GoRouter _router = GoRouter(
/// routes: <GoRoute>[
/// GoRoute(
/// path: '/',
/// redirect: (_) => '/family/${Families.data[0].id}',
/// ),
/// GoRoute(
/// path: '/family/:fid',
/// pageBuilder: (BuildContext context, GoRouterState state) => ...,
/// ),
/// ],
/// );
/// ```
///
/// If there are multiple redirects in the matched routes, the parent route's
/// redirect takes priority over sub-route's.
///
/// For example:
/// ```
/// final GoRouter _router = GoRouter(
/// routes: <GoRoute>[
/// GoRoute(
/// path: '/',
/// redirect: (_) => '/page1', // this takes priority over the sub-route.
/// routes: <GoRoute>[
/// GoRoute(
/// path: 'child',
/// redirect: (_) => '/page2',
/// ),
/// ],
/// ),
/// ],
/// );
/// ```
///
/// The `context.go('/child')` will be redirected to `/page1` instead of
/// `/page2`.
///
/// Redirect can also be used for conditionally preventing users from visiting
/// routes, also known as route guards. One canonical example is user
/// authentication. See [Redirection](https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/redirection.dart)
/// for a complete runnable example.
///
/// If [BuildContext.dependOnInheritedWidgetOfExactType] is used during the
/// redirection (which is how `of` method is usually implemented), a
/// re-evaluation will be triggered if the [InheritedWidget] changes.
final GoRouterRedirect? redirect;

/// The list of child routes associated with this route.
final List<RouteBase> routes;

Expand Down Expand Up @@ -208,7 +265,7 @@ class GoRoute extends RouteBase {
this.builder,
this.pageBuilder,
super.parentNavigatorKey,
this.redirect,
super.redirect,
this.onExit,
super.routes = const <RouteBase>[],
}) : assert(path.isNotEmpty, 'GoRoute path cannot be empty'),
Expand Down Expand Up @@ -324,62 +381,6 @@ class GoRoute extends RouteBase {
///
final GoRouterWidgetBuilder? builder;

/// An optional redirect function for this route.
///
/// In the case that you like to make a redirection decision for a specific
/// route (or sub-route), consider doing so by passing a redirect function to
/// the GoRoute constructor.
///
/// For example:
/// ```
/// final GoRouter _router = GoRouter(
/// routes: <GoRoute>[
/// GoRoute(
/// path: '/',
/// redirect: (_) => '/family/${Families.data[0].id}',
/// ),
/// GoRoute(
/// path: '/family/:fid',
/// pageBuilder: (BuildContext context, GoRouterState state) => ...,
/// ),
/// ],
/// );
/// ```
///
/// If there are multiple redirects in the matched routes, the parent route's
/// redirect takes priority over sub-route's.
///
/// For example:
/// ```
/// final GoRouter _router = GoRouter(
/// routes: <GoRoute>[
/// GoRoute(
/// path: '/',
/// redirect: (_) => '/page1', // this takes priority over the sub-route.
/// routes: <GoRoute>[
/// GoRoute(
/// path: 'child',
/// redirect: (_) => '/page2',
/// ),
/// ],
/// ),
/// ],
/// );
/// ```
///
/// The `context.go('/child')` will be redirected to `/page1` instead of
/// `/page2`.
///
/// Redirect can also be used for conditionally preventing users from visiting
/// routes, also known as route guards. One canonical example is user
/// authentication. See [Redirection](https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/redirection.dart)
/// for a complete runnable example.
///
/// If [BuildContext.dependOnInheritedWidgetOfExactType] is used during the
/// redirection (which is how `of` method is usually implemented), a
/// re-evaluation will be triggered if the [InheritedWidget] changes.
final GoRouterRedirect? redirect;

/// Called when this route is removed from GoRouter's route history.
///
/// Some example this callback may be called:
Expand Down Expand Up @@ -457,9 +458,11 @@ class GoRoute extends RouteBase {
/// as [ShellRoute] and [StatefulShellRoute].
abstract class ShellRouteBase extends RouteBase {
/// Constructs a [ShellRouteBase].
const ShellRouteBase._(
{required super.routes, required super.parentNavigatorKey})
: super._();
const ShellRouteBase._({
super.redirect,
required super.routes,
required super.parentNavigatorKey,
}) : super._();

static void _debugCheckSubRouteParentNavigatorKeys(
List<RouteBase> subRoutes, GlobalKey<NavigatorState> navigatorKey) {
Expand Down Expand Up @@ -622,6 +625,7 @@ class ShellRouteContext {
class ShellRoute extends ShellRouteBase {
/// Constructs a [ShellRoute].
ShellRoute({
super.redirect,
this.builder,
this.pageBuilder,
this.observers,
Expand Down Expand Up @@ -782,6 +786,7 @@ class StatefulShellRoute extends ShellRouteBase {
/// [navigatorContainerBuilder].
StatefulShellRoute({
required this.branches,
super.redirect,
this.builder,
this.pageBuilder,
required this.navigatorContainerBuilder,
Expand All @@ -808,12 +813,14 @@ class StatefulShellRoute extends ShellRouteBase {
/// for a complete runnable example using StatefulShellRoute.indexedStack.
StatefulShellRoute.indexedStack({
required List<StatefulShellBranch> branches,
GoRouterRedirect? redirect,
StatefulShellRouteBuilder? builder,
GlobalKey<NavigatorState>? parentNavigatorKey,
StatefulShellRoutePageBuilder? pageBuilder,
String? restorationScopeId,
}) : this(
branches: branches,
redirect: redirect,
builder: builder,
pageBuilder: pageBuilder,
parentNavigatorKey: parentNavigatorKey,
Expand Down
2 changes: 1 addition & 1 deletion packages/go_router/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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: 13.2.3
version: 13.3.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

Expand Down