navigate<T> method

Future<T?> navigate<T>(
  1. String name, {
  2. NyArgument? args,
  3. NavigationType navigationType = NavigationType.push,
  4. dynamic result,
  5. bool removeUntilPredicate(
    1. Route route
    )?,
  6. TransitionType? transitionType,
  7. PageTransitionType? pageTransitionType,
  8. PageTransitionSettings? pageTransitionSettings,
})

Function used to navigate pages.

name is the route name that was registered using addRoute.

args are optional arguments that can be passed to the next page. To retrieve these arguments use args method on NyRouterRoute.

navigationType can be specified to choose from various navigation strategies such as NavigationType.push, NavigationType.pushReplace, NavigationType.pushAndRemoveUntil.

removeUntilPredicate should be provided if using NavigationType.pushAndRemoveUntil strategy.

Returns the result from the navigated page, or null if navigation was cancelled by a route guard redirect.

Implementation

Future<T?> navigate<T>(
  String name, {
  NyArgument? args,
  NavigationType navigationType = NavigationType.push,
  dynamic result,
  bool Function(Route<dynamic> route)? removeUntilPredicate,
  TransitionType? transitionType,
  PageTransitionType? pageTransitionType,
  PageTransitionSettings? pageTransitionSettings,
}) async {
  assert(
    navigationType != NavigationType.pushAndRemoveUntil ||
        removeUntilPredicate != null,
  );

  if (transitionType != null) {
    pageTransitionType = transitionType.pageTransitionType;
    pageTransitionSettings = transitionType.pageTransitionSettings;
  }

  Uri? uriSettingName;
  try {
    uriSettingName = Uri.parse(name);
  } on FormatException catch (e) {
    NyLogger.error(e.toString());
  }

  String routeName = name;
  if (uriSettingName != null) {
    routeName = uriSettingName.path;
  }

  NyQueryParameters? nyQueryParameters;
  if (uriSettingName != null && uriSettingName.queryParameters.isNotEmpty) {
    nyQueryParameters = NyQueryParameters(uriSettingName.queryParameters);
  }

  bool checkRouteNamedArg = isRouteNamedArg(routeName);
  if (!checkRouteNamedArg) {
    _checkAndThrowRouteNotFound(routeName, args, navigationType);
  }

  final NyRouterRoute? targetRoute = _findRouteForName(routeName);

  _log('Navigating to: $routeName (type: ${navigationType.name})');

  // Execute route guards before navigation
  if (targetRoute != null) {
    final guards = targetRoute.getRouteGuards();
    if (guards.isNotEmpty) {
      // Create the initial route context
      RouteContext currentContext = RouteContext(
        context: navigatorKey?.currentContext,
        data: args?.data,
        queryParameters: nyQueryParameters?.data ?? {},
        routeName: routeName,
        originalRouteName: name,
      );

      for (final guard in guards) {
        _log('Running route guard: ${guard.runtimeType}');

        // Check if this is a new-style NyRouteGuard
        if (guard is NyRouteGuard) {
          guard.setRouteContext(currentContext);
          final result = await guard.onBefore(currentContext);

          if (result == GuardResult.handled) {
            // Check if guard requested a redirect
            if (guard.redirectConfig != null) {
              final config = guard.redirectConfig!;
              _log('Route guard redirected to: ${config.path}');
              final routeData = RouteData.fromRedirectConfig(config);
              await routeData.routeToPage();
            }
            return null;
          }

          // Pass modified data to next guard
          if (guard.hasModifiedData) {
            currentContext = currentContext.withData(guard.modifiedData);
            // Update args with modified data for the route
            args = NyArgument(guard.modifiedData);
          }
        } else {
          // Legacy RouteGuard support
          final pageRequest = PageRequest(
            context: navigatorKey?.currentContext,
            nyArgument: args,
            queryParameters: nyQueryParameters?.data,
          );
          final guardResult = await guard.onRequest(pageRequest);
          if (guardResult != null &&
              guardResult.isRedirect &&
              guardResult.routeData != null) {
            _log('Route guard redirected to: ${guardResult.routeData!.path}');
            await guardResult.routeData!.routeToPage();
            return null;
          }
        }
      }
    }
  }

  final navigationResult = await _navigate(
    routeName,
    args,
    navigationType,
    result,
    removeUntilPredicate,
    pageTransitionType,
    pageTransitionSettings,
    queryParameters: nyQueryParameters,
    originalRouteName: name,
  );

  // Execute onAfter lifecycle for guards
  if (targetRoute != null) {
    final afterContext = RouteContext(
      context: navigatorKey?.currentContext,
      data: args?.data,
      queryParameters: nyQueryParameters?.data ?? {},
      routeName: routeName,
      originalRouteName: name,
    );

    for (final guard in targetRoute.getRouteGuards()) {
      if (guard is NyRouteGuard) {
        await guard.onAfter(afterContext);
      }
    }
  }

  return navigationResult as T?;
}