Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
6be9a5d
[go_router] Added top level onEnter callback.
omar-hanafy Dec 22, 2024
171b639
added version 14.7.0
omar-hanafy Dec 22, 2024
f52a269
Merge branch 'main' into main
omar-hanafy Dec 25, 2024
3bbd241
Merge branch 'main' into main
omar-hanafy Dec 27, 2024
6a60006
Merge branch 'main' into main
omar-hanafy Jan 3, 2025
d1e1fc2
[go_router] added nextState, and currentState to OnEnter signature, a…
omar-hanafy Jan 24, 2025
516db13
Merge branch 'main' into main
omar-hanafy Jan 24, 2025
e1f10b1
Merge branch 'main' into main
omar-hanafy Jan 26, 2025
7a847b8
Merge branch 'main' into main
omar-hanafy Jan 28, 2025
b08d804
Merge branch 'main' into main
omar-hanafy Feb 2, 2025
1e25466
Merge branch 'main' into main
omar-hanafy Feb 4, 2025
aec8e47
Add router instance to OnEnter callback
omar-hanafy Feb 4, 2025
2bdc147
Merge branch 'main' into main
omar-hanafy Feb 8, 2025
1bd3c18
[go_router] Async onEnter, improved redirection, and loop prevention.
omar-hanafy Feb 15, 2025
61729b2
Merge branch 'main' into main
omar-hanafy Feb 15, 2025
8334a64
Merge branch 'main' into main
omar-hanafy Feb 17, 2025
f28337e
improved redirection and async handling.
omar-hanafy Feb 18, 2025
4092405
extracting the onEnter logic into its own helper class.
omar-hanafy Feb 18, 2025
c1c09d0
added named params to handleTopOnEnter.
omar-hanafy Feb 18, 2025
d9e6ea6
move tests
cedvdb Feb 20, 2025
07c15f0
Merge pull request #3 from cedvdb/move_tests
omar-hanafy Feb 22, 2025
3fbe011
Merge branch 'main' into main
omar-hanafy Mar 28, 2025
67df52a
added tests
cedvdb Apr 6, 2025
eef39b1
Merge pull request #4 from cedvdb/omar-add-on-enter-tests
omar-hanafy Apr 7, 2025
359eb0e
Merge branch 'flutter:main' into main
omar-hanafy Apr 7, 2025
cc57519
[go_router] Fix onEnter callback exception handling and enhance tests
omar-hanafy Apr 8, 2025
d4f2416
[go_router] updated Should allow redirection with query parameters te…
omar-hanafy Apr 9, 2025
56f2dbe
Merge branch 'main' into main
omar-hanafy Apr 16, 2025
c458982
Merge branch 'main' into main
omar-hanafy Apr 28, 2025
921dcb3
Merge branch 'main' into main
omar-hanafy May 30, 2025
757f5a1
[go_router] Use specific imports in on_enter.dart
omar-hanafy May 30, 2025
b5e1e9e
Merge branch 'main' of https://github.com/omar-hanafy/packages
omar-hanafy May 30, 2025
86c506b
Merge branch 'main' into main
omar-hanafy Jun 10, 2025
3c4a85f
Merge branch 'main' into main
omar-hanafy Jun 11, 2025
9d52c0d
Merge branch 'main' into main
omar-hanafy Jun 18, 2025
97c5ed8
Merge branch 'main' into main
omar-hanafy Jun 24, 2025
0323a45
Merge branch 'main' into main
omar-hanafy Jul 9, 2025
4a9e6ff
[go_router] Replace boolean return with sealed class API for onEnter
omar-hanafy Jul 9, 2025
3b2df49
[go_router] Make OnEnterHandler private and ensure onEnter priority o…
omar-hanafy Aug 2, 2025
1dd95d8
Merge branch 'main' into main
omar-hanafy Aug 2, 2025
ade3f54
Merge branch 'main' into main
omar-hanafy Aug 19, 2025
ed43b0b
Merge branch 'main' into main
omar-hanafy Aug 19, 2025
d0d5e6d
[go_router] added allow/block factories for the OnEnterResult
omar-hanafy Aug 19, 2025
a484965
[go_router] ran dart format
omar-hanafy Aug 19, 2025
10404f8
[go_router] returned back missing docs in GoRouterRedirect
omar-hanafy Aug 19, 2025
2b3d0be
[go_router] Fix license headers to match repository standards
omar-hanafy Aug 19, 2025
b554e6c
[go_router] sealed `onEnter` (Allow/Block.then) + compose legacy redi…
omar-hanafy Aug 20, 2025
99ab3c3
[go_router] Fix license headers to match repository standards
omar-hanafy Aug 20, 2025
265f26f
[go_router] Refactor parser and on_enter for clarity and type safety
omar-hanafy Aug 22, 2025
01f7ea6
[go_router] Remove unused initialLocation parameter from parser.
omar-hanafy Aug 22, 2025
22a29bd
[go_router] Ensure onEnter runs during state restoration, and unified…
omar-hanafy Aug 27, 2025
887c528
Merge branch 'main' into main
omar-hanafy Aug 28, 2025
37712e5
Merge branch 'main' into main
omar-hanafy Aug 30, 2025
ee55004
Merge branch 'main' into main
omar-hanafy Sep 21, 2025
9e37af9
[go_router] polish onEnter handling and docs
omar-hanafy Sep 22, 2025
faa9d81
Merge branch 'main' into main
omar-hanafy Sep 25, 2025
20c4148
[go_router] Refine onEnter documentation and API adjustments
omar-hanafy Sep 25, 2025
2b4c348
[go_router] Improve context safety and docs in navigation logic
omar-hanafy Sep 27, 2025
d1bc684
[go_router] Improve documentation for legacy redirect method
omar-hanafy Oct 13, 2025
54afc72
Merge branch 'main' into main
omar-hanafy Oct 15, 2025
33996c6
Merge remote-tracking branch 'upstream/main'
omar-hanafy Oct 16, 2025
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
Prev Previous commit
Next Next commit
extracting the onEnter logic into its own helper class.
  • Loading branch information
omar-hanafy committed Feb 18, 2025
commit 4092405d39c023dfd378d7b4fd1798238b5dba7a
183 changes: 183 additions & 0 deletions packages/go_router/lib/src/on_enter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// on_enter.dart
// ignore_for_file: use_build_context_synchronously
// Copyright 2013 The Flutter Authors.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

import '../go_router.dart';

/// Handles the `onEnter` callback logic and redirection history for GoRouter.
///
/// This class encapsulates the logic to execute the top-level `onEnter`
/// callback, track redirection history, enforce the redirection limit,
/// and generate an error match list when the limit is exceeded.
class OnEnterHandler {
/// Creates an [OnEnterHandler] instance.
///
/// [configuration] is the route configuration.
/// [router] is used to access GoRouter methods.
/// [onParserException] is the exception handler for the parser.
OnEnterHandler({
required RouteConfiguration configuration,
required GoRouter router,
required ParserExceptionHandler? onParserException,
}) : _onParserException = onParserException,
_configuration = configuration,
_router = router;

/// The route configuration for the current router.
///
/// This object contains all the route definitions, redirection logic, and other
/// navigation settings. It is used to determine which routes match the incoming
/// URI and to build the corresponding navigation state.
final RouteConfiguration _configuration;

/// Optional exception handler for route parsing errors.
///
/// When an error occurs during route parsing (e.g., when the onEnter redirection
/// limit is exceeded), this handler is invoked with the current [BuildContext]
/// and a [RouteMatchList] that contains the error details. It must conform to the
/// [ParserExceptionHandler] typedef and is responsible for returning a fallback
/// [RouteMatchList].
final ParserExceptionHandler? _onParserException;

/// The [GoRouter] instance used to perform navigation actions.
///
/// This instance provides access to various navigation methods and serves as a
/// fallback when the [BuildContext] does not have an inherited GoRouter. It is
/// essential for executing onEnter callbacks and handling redirections.
final GoRouter _router;

/// A history of URIs encountered during onEnter redirections.
///
/// This list tracks each URI that triggers an onEnter redirection and is used to
/// enforce the redirection limit defined in [RouteConfiguration.redirectLimit]. It
/// helps prevent infinite redirection loops by generating an error if the limit is exceeded.
final List<Uri> _redirectionHistory = <Uri>[];

/// Executes the top-level `onEnter` callback and decides whether navigation
/// should proceed.
///
/// This method first checks for redirection errors via
/// [_redirectionErrorMatchList]. If no error is found, it builds the current
/// and next navigation states, executes the onEnter callback, and based on its
/// result returns either [onCanEnter] or [onCanNotEnter].
///
/// [context] is the BuildContext.
/// [routeInformation] is the current RouteInformation.
/// [infoState] is the state embedded in the RouteInformation.
/// [lastMatchList] is the last successful match list (if any).
/// [onCanEnter] is called when navigation is allowed.
/// [onCanNotEnter] is called when navigation is blocked.
///
/// Returns a Future that resolves to a [RouteMatchList].
Future<RouteMatchList> handleTopOnEnter(
BuildContext context,
RouteInformation routeInformation,
RouteInformationState<dynamic> infoState,
RouteMatchList? lastMatchList,
Future<RouteMatchList> Function() onCanEnter,
Future<RouteMatchList> Function() onCanNotEnter,
) {
final OnEnter? topOnEnter = _configuration.topOnEnter;
// If no onEnter is configured, simply allow navigation.
if (topOnEnter == null) {
return onCanEnter();
}

// Check if the redirection history already exceeds the configured limit.
final RouteMatchList? redirectionErrorMatchList =
_redirectionErrorMatchList(context, routeInformation.uri, infoState);

if (redirectionErrorMatchList != null) {
// Return immediately if the redirection limit is exceeded.
return SynchronousFuture<RouteMatchList>(redirectionErrorMatchList);
}

// Build route matches for the incoming URI.
final RouteMatchList incomingMatches = _configuration.findMatch(
routeInformation.uri,
extra: infoState.extra,
);

// Build the next navigation state.
final GoRouterState nextState =
_configuration.buildTopLevelGoRouterState(incomingMatches);
// Use the last successful state if available.
final GoRouterState currentState = lastMatchList != null
? _configuration.buildTopLevelGoRouterState(lastMatchList)
: nextState;

// Execute the onEnter callback and get a Future<bool> result.
final Future<bool> canEnterFuture = topOnEnter(
context,
currentState,
nextState,
_router,
);
// Reset history after attempting the callback.
_resetRedirectionHistory();
// Return the appropriate match list based on whether navigation is allowed.
return canEnterFuture.then(
(bool canEnter) => canEnter ? onCanEnter() : onCanNotEnter(),
);
}

/// Processes the redirection history and checks for redirection limits.
///
/// Adds [redirectedUri] to the redirection history. If the number of redirections
/// exceeds [_configuration.redirectLimit], returns an error match list.
/// Otherwise, returns null.
RouteMatchList? _redirectionErrorMatchList(
BuildContext context,
Uri redirectedUri,
RouteInformationState<dynamic> infoState,
) {
_redirectionHistory.add(redirectedUri);
if (_redirectionHistory.length > _configuration.redirectLimit) {
final String formattedHistory =
_formatOnEnterRedirectionHistory(_redirectionHistory);
final RouteMatchList errorMatchList = _errorRouteMatchList(
redirectedUri,
GoException('Too many onEnter calls detected: $formattedHistory'),
extra: infoState.extra,
);
_resetRedirectionHistory();
// Use onParserException if available to process the error match list.
return _onParserException != null
? _onParserException(context, errorMatchList)
: errorMatchList;
}
return null;
}

/// Resets the onEnter redirection history.
void _resetRedirectionHistory() {
_redirectionHistory.clear();
}

/// Formats the redirection history as a string for error messages.
String _formatOnEnterRedirectionHistory(List<Uri> history) {
return history.map((Uri uri) => uri.toString()).join(' => ');
}

/// Creates an error match list for a given [uri] and [exception].
static RouteMatchList _errorRouteMatchList(
Uri uri,
GoException exception, {
Object? extra,
}) {
return RouteMatchList(
matches: const <RouteMatch>[],
extra: extra,
error: exception,
uri: uri,
pathParameters: const <String, String>{},
);
}
}
Loading