Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: DestinationPersistence #16

Merged
merged 1 commit into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
35 changes: 19 additions & 16 deletions lib/src/guarded_go_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,17 @@ class GuardedGoRouter {
return null;
}

final resolvedContinuePath = state.maybeResolveContinuePath();
if (resolvedContinuePath != null) {
if (goRouter.namedLocation(firstFollowUpRouteName) == resolvedContinuePath) {
return goRouter.namedLocation(
firstFollowUpRouteName,
queryParameters: {...state.uri.queryParametersAll}..remove("continue"),
pathParameters: state.pathParameters,
);
}
}

return goRouter.namedLocationFrom(state, firstFollowUpRouteName);
}

Expand All @@ -184,28 +195,23 @@ class GuardedGoRouter {
if (firstBlockingGuard != null) {
final blockingShieldName = _getShieldRouteName(firstBlockingGuard.guard);

final isThisAShieldRoute = guardsShieldingOnThisRoute.isNotEmpty;
final guardSavesLocation = firstBlockingGuard.savesLocation;
final destinationPersistence = firstBlockingGuard.destinationPersistence;
final routeIgnoreAsContinue = thisRoute.ignoreAsContinueLocation;

if (isThisAShieldRoute || _isNeglectingContinue || routeIgnoreAsContinue || !guardSavesLocation) {
final destination = goRouter.namedLocation(blockingShieldName, queryParameters: state.uri.queryParameters);
if (firstBlockingGuard.clearsContinue) {
return destination.removeContinuePath();
}
return destination;
if (_isNeglectingContinue || routeIgnoreAsContinue || destinationPersistence == DestinationPersistence.ignore) {
return goRouter.namedLocation(blockingShieldName, queryParameters: state.uri.queryParameters);
}

final resolvedContinuePath = state.maybeResolveContinuePath();
if (resolvedContinuePath != null) {
final Map<String, String> queryParameters = {...state.uri.queryParameters};
if (firstBlockingGuard.clearsContinue) {
if (destinationPersistence == DestinationPersistence.clear) {
queryParameters.remove('continue');
}
return goRouter.namedLocation(blockingShieldName, queryParameters: queryParameters);
}

if (firstBlockingGuard.clearsContinue) {
if (destinationPersistence == DestinationPersistence.clear) {
return goRouter.namedLocation(blockingShieldName);
}

Expand Down Expand Up @@ -268,8 +274,7 @@ class GuardedGoRouter {
final shell = guardShellRoutes.firstWhere((element) => element.guardType == guard.runtimeType);
return _GuardShellContext(
guard: guard,
savesLocation: shell.savesLocation,
clearsContinue: shell.clearsContinue,
destinationPersistence: shell.destinationPersistence,
);
},
).toList();
Expand Down Expand Up @@ -422,11 +427,9 @@ extension GoGuardX on GoGuard {
class _GuardShellContext<T extends GoGuard> {
_GuardShellContext({
required this.guard,
required this.savesLocation,
required this.clearsContinue,
required this.destinationPersistence,
});

final T guard;
final bool savesLocation;
final bool clearsContinue;
final DestinationPersistence destinationPersistence;
}
35 changes: 26 additions & 9 deletions lib/src/routes/guard_shell.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,32 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:guarded_go_router/src/go_guard.dart';

/// Defines how the destination should be persisted when a guard is activated.
enum DestinationPersistence {
/// Stores the path as the 'continue' query parameter.
store,

/// Ignores the path, meaning it doesn not store it as 'continue' query parameter.
ignore,

/// Clears any existing 'continue' query parameter. This is useful when the guard is a "hard" block,
/// meaning that users are not able to resolve the guard's requirements. So it is not needed to store
/// where should the user be continued, as they won't be continued to that path.
/// Eg: A user wanting to access a page to which they are not authorized.
///
/// This option (more strict than the `ignore` option) is needed when the app is deep linked with a continue query param.
/// Or maybe a previous guard already stored a continue path, although that should resolve itself.
clear,
}

/// A shell route that applies a guard to its child routes.
class GuardShell<GuardType extends GoGuard> extends ShellRoute {
/// By default when a destination is protected by a guard, then the router will redirect to
/// the associated shield route of that guard and also append the original destination as `continue` query param.
/// When `savesLocation` is set to false, then the original destination is ignored and the app simply redirects to the shield route
final bool savesLocation;
final bool clearsContinue;
/// Determines how the destination should be handled when this guard blocks and it is the first one doing so.
final DestinationPersistence destinationPersistence;

GuardShell(
List<RouteBase> routes, {
this.savesLocation = true,
this.clearsContinue = false,
this.destinationPersistence = DestinationPersistence.store,
super.navigatorKey,
}) : super(routes: routes);

Expand All @@ -23,16 +38,18 @@ class GuardShell<GuardType extends GoGuard> extends ShellRoute {
Widget child,
)? get builder => (context, state, child) => child;

/// The type of guard associated with this shell.
Type get guardType => GuardType;

/// Creates a copy of this [GuardShell] with the given fields replaced with new values.
GuardShell<GuardType> copyWith({
List<RouteBase>? routes,
GlobalKey<NavigatorState>? navigatorKey,
DestinationPersistence? destinationPersistence,
}) =>
GuardShell<GuardType>(
routes ?? this.routes,
savesLocation: savesLocation,
clearsContinue: clearsContinue,
destinationPersistence: destinationPersistence ?? this.destinationPersistence,
navigatorKey: navigatorKey ?? this.navigatorKey,
);
}
Loading