setNewRoutePath method

  1. @override
SynchronousFuture<void> setNewRoutePath(
  1. covariant AdvancedRouteInformation configuration
)
override

Called by the Router when the Router.routeInformationProvider reports that a new route has been pushed to the application by the operating system.

Consider using a SynchronousFuture if the result can be computed synchronously, so that the Router does not need to wait for the next microtask to schedule a build.

Implementation

@override
SynchronousFuture<void> setNewRoutePath(
    covariant AdvancedRouteInformation configuration) {
  if (configuration == _currentInternalPath) {
    return SynchronousFuture(null);
  }
  List<Page>? changedPages;
  AdvancedRouteInformation? currentInternalPath;
  AdvancedRouteInformation? currentNestedPath;
  // check for match in paths map
  if (paths.isNotEmpty) {
    // find matching reference
    var uri = Uri.parse(configuration.location ?? '');
    var query = uri.query;
    var path = uri.path;
    if (path.isEmpty) {
      path = initialLocation;
    }
    PathGroup? pathGroup;
    String? internalPath;
    String? nestedPath;
    paths.keys.forEach((iterationPathGroup) {
      var match = iterationPathGroup.pattern.firstMatch(path);
      if (match != null) {
        // longest matched path takes precidence
        if (iterationPathGroup.length > (pathGroup?.length ?? -1)) {
          var iterationRemainingPath = match.input.substring(match.end);
          pathGroup = iterationPathGroup;
          internalPath = match.group(0);
          // nestedPath location must start with '/'
          if (iterationRemainingPath.isNotEmpty &&
              iterationRemainingPath[0] != '/') {
            iterationRemainingPath = '/' + iterationRemainingPath;
          }
          // when no remaining path, nested navigator sets neseted path during build
          nestedPath = iterationRemainingPath.isEmpty && query.isEmpty
              ? null
              : iterationRemainingPath + '?' + query;
        }
      }
    });
    // update router config if match found
    if (pathGroup != null) {
      // parse args
      var pathArgs = <String, String>{};
      pathArgs.addAll(uri.queryParameters);
      pathArgs.addAll(pathGroup!.args
          .map((pos, argName) => MapEntry(argName, uri.pathSegments[pos])));
      var args =
          PathArguments(path: pathArgs, arguments: configuration.arguments);
      changedPages = paths[pathGroup]?.call(args);
      currentInternalPath = AdvancedRouteInformation(
        location: internalPath,
        state: configuration.state,
        arguments: configuration.arguments,
      );
      currentNestedPath = nestedPath == null
          ? null
          : AdvancedRouteInformation(
              location: nestedPath, arguments: configuration.arguments);
    }
  }
  // generate path with callback
  if (changedPages == null) {
    assert(() {
      if (onGeneratePath == null) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary(
              'AdvancedNavigator.onGeneratePath was null but the referenced path had no corresponding path in the app.'),
          ErrorDescription(
              'The referenced path was: "${configuration.location}" '
              'To use the AdvancedNavigator API with named paths (openNamed), '
              'the AdvancedNavigator must be provided with either a matching reference '
              'in the paths map or an onGeneratePath handler.\n'),
          DiagnosticsProperty<String>('The AdvancedNavigator tag was', tag,
              style: DiagnosticsTreeStyle.errorProperty),
          DiagnosticsProperty<RouterDelegate>('The RouterDelegate was', this,
              style: DiagnosticsTreeStyle.errorProperty),
        ]);
      }
      return true;
    }());
    var routerConfiguration = onGeneratePath!.call(configuration);
    changedPages = routerConfiguration?.pages;
    currentInternalPath = routerConfiguration?.internalPath;
    currentNestedPath = routerConfiguration?.nestedPath;
    if (changedPages == null) {
      assert(() {
        if (onUnknownPath == null) {
          throw FlutterError.fromParts(<DiagnosticsNode>[
            ErrorSummary(
                'AdvancedNavigator.onGeneratePath returned null when requested to build path "${configuration.location}".'),
            ErrorDescription(
                'The onGeneratePath callback must never return null, unless an onUnknownPath '
                'callback is provided as well.'),
            DiagnosticsProperty<String>('The AdvancedNavigator tag was', tag,
                style: DiagnosticsTreeStyle.errorProperty),
            DiagnosticsProperty<RouterDelegate>(
                'The RouterDelegate was', this,
                style: DiagnosticsTreeStyle.errorProperty),
          ]);
        }
        return true;
      }());
      routerConfiguration = onUnknownPath!.call(configuration);
      changedPages = routerConfiguration?.pages;
      currentInternalPath = routerConfiguration?.internalPath;
      currentNestedPath = routerConfiguration?.nestedPath;
      assert(() {
        if (changedPages == null) {
          throw FlutterError.fromParts(<DiagnosticsNode>[
            ErrorSummary(
                'Navigator.onUnknownPath returned null when requested to build path "${configuration.location}".'),
            ErrorDescription(
                'The onUnknownPath callback must never return null.'),
            DiagnosticsProperty<String>('The AdvancedNavigator tag was', tag,
                style: DiagnosticsTreeStyle.errorProperty),
            DiagnosticsProperty<RouterDelegate>(
                'The RouterDelegate was', this,
                style: DiagnosticsTreeStyle.errorProperty),
          ]);
        }
        return true;
      }());
    }
  }
  assert(changedPages != null);
  _currentNestedPath = currentNestedPath;
  _currentInternalPath = currentInternalPath ?? configuration;
  _pages = List.unmodifiable(changedPages!);
  onNestedPathUpdate(_currentNestedPath);
  notifyListeners();
  return SynchronousFuture(null);
}