Milad-Akarie / auto_route_library

Flutter route generator
MIT License
1.5k stars 375 forks source link

removeWhere removes the wrong route #1943

Open hassan-saleh-ml opened 1 month ago

hassan-saleh-ml commented 1 month ago

We investigated an issue in our app after upgrading to the latest version of auto_route where if we have 2 routes of the same type in the stack, try to remove the second one using context.router.removeWhere, the topmost route is being removed.

Here's an example:

              context.replaceRoute(
                InfoRoute(
                  key: loaderKey,
                  canPop: false,
                  content: [
                    InfoScreenTitleSubtitle(
                      title: l10n.processing,
                      subtitle: l10n.loading,
                      addLoader: true,
                    ),
                  ],
                ),
              );

Then after loading is completed:

        context.pushRoute(
          InfoRoute(
            canPop: false,
            content: [
              successScreen(),
            ],
          ),
        );

        /// To keep the fade-in-out animation of the loader,
        /// we must just push the success screen instead of replacing the loader route.
        /// When closing the success screen the loader is visible for a little while,
        /// so the solution is to remove it like this.
        await Future.delayed(RouteConstants.routeClosureDelayDuration.ms);
        if (context.mounted) {
          context.router.removeWhere(
            (route) => route.isInfoRoute(withKey: loaderKey),
          );
        }
extension RouteDataExtensions on RouteData {
  /// Can be used to conveniently check if the Route is [InfoRoute].
  bool isInfoRoute({ValueKey? withKey}) {
    final args = this.args;
    if (args is! InfoRouteArgs) {
      return false;
    }

    if (withKey != null) {
      return args.key == withKey;
    }

    return true;
  }
}

This used to work just fine before the only difference was how we identify the route using the key, the key used to be in RouteData, now it lives in the argument class (InfoRouteArgs)

After investigating this we found the root cause which is in routing_controller.dart:

  void _removeRoute(RouteMatch route, {bool notify = true}) {
    var pageIndex = _pages.lastIndexWhere((p) => p.routeKey == route.key);
    if (pageIndex != -1) {
      _pages.removeAt(pageIndex);
    }

    _updateSharedPathData(includeAncestors: true);
    _removeTopRouterOf(route.key);
    if (notify) {
      notifyAll(forceUrlRebuild: true);
    }
  }

It used the route key to identify the route, however this key is the same for both screens, the key is set to the route's name which is InfoRoute.

nivisi commented 1 month ago

@Milad-Akarie hi sir! Any chance you could guide us on how to resolve this issue? Is there any way to help AutoRoute to distinguish two different routes of the same type based on custom conditions?