stacked icon indicating copy to clipboard operation
stacked copied to clipboard

[bug]: router generator create multiples screen arguments with same name

Open scognito opened this issue 2 years ago • 3 comments

Describe the bug

I'm trying to create 2 nested routes:

  • /shop/giftguide
  • /explore/giftguide

Both points to the same giftguide screen. Running dart run build_runner build --delete-conflicting-outputs it generates NestedGiftGuideScreenArguments 2 times in my .router.dart class causing me some headache. Is there something wrong I'm doing?

To reproduce

router.dart

@StackedApp(
  routes: [
    MaterialRoute(
      //path: '/home',
      page: HomeScreen,
      // initial: true,
    ),
    MaterialRoute(
      path: '/shop',
      page: ShopNavigationStackScreen,
      children: [
        MaterialRoute(path: 'shophome', page: ShopScreen),
        MaterialRoute(path: 'giftguide', page: GiftGuideScreen),
      ],
    ),
    MaterialRoute(
      path: '/explore',
      page: ExploreNavigationStackScreen,
      children: [
        MaterialRoute(path: 'giftguide', page: GiftGuideScreen),
      ],
    )
  ],
)
class App {
  // This class has no purpose besides housing the annotation that generates the required functionality
}

shopNavigationStackScreen.dart

class ShopNavigationStackScreen extends StatelessWidget {
  const ShopNavigationStackScreen({Key? key}) : super(key: key);

  static var router = ExtendedNavigator(
    router: ShopNavigationStackScreenRouter(),
    navigatorKey: StackedService.nestedNavigationKey(
      ScalaRouteConfig.shopNavigationId,
    ),
    initialRoute: ShopNavigationStackScreenRoutes.shopScreen,
  );

  @override
  Widget build(BuildContext context) {
    return router;
  }
}

exploreNavigationStackScreen.dart

class  ExploreNavigationStackScreen extends StatelessWidget {
  const ExploreNavigationStackScreen ({Key? key}) : super(key: key);

  static var router = ExtendedNavigator(
    router: ExploreNavigationStackScreenRouter(),
    navigatorKey: StackedService.nestedNavigationKey(
      ScalaRouteConfig.shopNavigationId,
    ),
    initialRoute: ExploreNavigationStackScreenRoutes.shopScreen,
  );

  @override
  Widget build(BuildContext context) {
    return router;
  }
}

generated router.router.dart

// GENERATED CODE - DO NOT MODIFY BY HAND

// **************************************************************************
// StackedNavigatorGenerator
// **************************************************************************

// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:flutter/material.dart' as _i5;
import 'package:flutter/material.dart';
import 'package:routing_test/screen/explore_navigation_stack_screen.dart'
    as _i4;
import 'package:routing_test/screen/gift_guide_screen.dart' as _i7;
import 'package:routing_test/screen/home_screen.dart' as _i2;
import 'package:routing_test/screen/shop_navigation_stack_screen.dart' as _i3;
import 'package:routing_test/screen/shop_screen.dart' as _i6;
import 'package:stacked/stacked.dart' as _i1;
import 'package:stacked_services/stacked_services.dart' as _i8;

class Routes {
  static const homeScreen = '/home-screen';

  static const shopNavigationStackScreen = '/shop-navigation-stack-screen';

  static const exploreNavigationStackScreen =
      '/explore-navigation-stack-screen';

  static const all = <String>{
    homeScreen,
    shopNavigationStackScreen,
    exploreNavigationStackScreen,
  };
}

class StackedRouter extends _i1.RouterBase {
  final _routes = <_i1.RouteDef>[
    _i1.RouteDef(
      Routes.homeScreen,
      page: _i2.HomeScreen,
    ),
    _i1.RouteDef(
      Routes.shopNavigationStackScreen,
      page: _i3.ShopNavigationStackScreen,
    ),
    _i1.RouteDef(
      Routes.exploreNavigationStackScreen,
      page: _i4.ExploreNavigationStackScreen,
    ),
  ];

  final _pagesMap = <Type, _i1.StackedRouteFactory>{
    _i2.HomeScreen: (data) {
      return _i5.MaterialPageRoute<dynamic>(
        builder: (context) => const _i2.HomeScreen(),
        settings: data,
      );
    },
    _i3.ShopNavigationStackScreen: (data) {
      return _i5.MaterialPageRoute<dynamic>(
        builder: (context) => const _i3.ShopNavigationStackScreen(),
        settings: data,
      );
    },
    _i4.ExploreNavigationStackScreen: (data) {
      return _i5.MaterialPageRoute<dynamic>(
        builder: (context) => const _i4.ExploreNavigationStackScreen(),
        settings: data,
      );
    },
  };

  @override
  List<_i1.RouteDef> get routes => _routes;

  @override
  Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
}

class ShopNavigationStackScreenRoutes {
  static const shopScreen = 'shophome';

  static const giftGuideScreen = 'gift-guide-screen';

  static const all = <String>{
    shopScreen,
    giftGuideScreen,
  };
}

class ShopNavigationStackScreenRouter extends _i1.RouterBase {
  final _routes = <_i1.RouteDef>[
    _i1.RouteDef(
      ShopNavigationStackScreenRoutes.shopScreen,
      page: _i6.ShopScreen,
    ),
    _i1.RouteDef(
      ShopNavigationStackScreenRoutes.giftGuideScreen,
      page: _i7.GiftGuideScreen,
    ),
  ];

  final _pagesMap = <Type, _i1.StackedRouteFactory>{
    _i6.ShopScreen: (data) {
      return _i5.MaterialPageRoute<dynamic>(
        builder: (context) => const _i6.ShopScreen(),
        settings: data,
      );
    },
    _i7.GiftGuideScreen: (data) {
      final args = data.getArgs<NestedGiftGuideScreenArguments>(nullOk: false);
      return _i5.MaterialPageRoute<dynamic>(
        builder: (context) =>
            _i7.GiftGuideScreen(groupId: args.groupId, key: args.key),
        settings: data,
      );
    },
  };

  @override
  List<_i1.RouteDef> get routes => _routes;

  @override
  Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
}

class NestedGiftGuideScreenArguments {
  const NestedGiftGuideScreenArguments({
    required this.groupId,
    this.key,
  });

  final String groupId;

  final _i5.Key? key;

  @override
  String toString() {
    return '{"groupId": "$groupId", "key": "$key"}';
  }

  @override
  bool operator ==(covariant NestedGiftGuideScreenArguments other) {
    if (identical(this, other)) return true;
    return other.groupId == groupId && other.key == key;
  }

  @override
  int get hashCode {
    return groupId.hashCode ^ key.hashCode;
  }
}

class ExploreNavigationStackScreenRoutes {
  static const giftGuideScreen = 'gift-guide-screen';

  static const all = <String>{giftGuideScreen};
}

class ExploreNavigationStackScreenRouter extends _i1.RouterBase {
  final _routes = <_i1.RouteDef>[
    _i1.RouteDef(
      ExploreNavigationStackScreenRoutes.giftGuideScreen,
      page: _i7.GiftGuideScreen,
    )
  ];

  final _pagesMap = <Type, _i1.StackedRouteFactory>{
    _i7.GiftGuideScreen: (data) {
      final args = data.getArgs<NestedGiftGuideScreenArguments>(nullOk: false);
      return _i5.MaterialPageRoute<dynamic>(
        builder: (context) =>
            _i7.GiftGuideScreen(groupId: args.groupId, key: args.key),
        settings: data,
      );
    }
  };

  @override
  List<_i1.RouteDef> get routes => _routes;

  @override
  Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
}

class NestedGiftGuideScreenArguments {
  const NestedGiftGuideScreenArguments({
    required this.groupId,
    this.key,
  });

  final String groupId;

  final _i5.Key? key;

  @override
  String toString() {
    return '{"groupId": "$groupId", "key": "$key"}';
  }

  @override
  bool operator ==(covariant NestedGiftGuideScreenArguments other) {
    if (identical(this, other)) return true;
    return other.groupId == groupId && other.key == key;
  }

  @override
  int get hashCode {
    return groupId.hashCode ^ key.hashCode;
  }
}

extension NavigatorStateExtension on _i8.NavigationService {
  Future<dynamic> navigateToHomeScreen([
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  ]) async {
    return navigateTo<dynamic>(Routes.homeScreen,
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }

  Future<dynamic> navigateToShopNavigationStackScreen([
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  ]) async {
    return navigateTo<dynamic>(Routes.shopNavigationStackScreen,
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }

  Future<dynamic> navigateToExploreNavigationStackScreen([
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  ]) async {
    return navigateTo<dynamic>(Routes.exploreNavigationStackScreen,
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }

  Future<dynamic> navigateToNestedShopScreenInShopNavigationStackScreenRouter([
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  ]) async {
    return navigateTo<dynamic>(ShopNavigationStackScreenRoutes.shopScreen,
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }

  Future<dynamic>
      navigateToNestedGiftGuideScreenInShopNavigationStackScreenRouter({
    required String groupId,
    _i5.Key? key,
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  }) async {
    return navigateTo<dynamic>(ShopNavigationStackScreenRoutes.giftGuideScreen,
        arguments: NestedGiftGuideScreenArguments(groupId: groupId, key: key),
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }

  Future<dynamic>
      navigateToNestedGiftGuideScreenInExploreNavigationStackScreenRouter({
    required String groupId,
    _i5.Key? key,
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  }) async {
    return navigateTo<dynamic>(
        ExploreNavigationStackScreenRoutes.giftGuideScreen,
        arguments: NestedGiftGuideScreenArguments(groupId: groupId, key: key),
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }

  Future<dynamic> replaceWithHomeScreen([
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  ]) async {
    return replaceWith<dynamic>(Routes.homeScreen,
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }

  Future<dynamic> replaceWithShopNavigationStackScreen([
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  ]) async {
    return replaceWith<dynamic>(Routes.shopNavigationStackScreen,
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }

  Future<dynamic> replaceWithExploreNavigationStackScreen([
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  ]) async {
    return replaceWith<dynamic>(Routes.exploreNavigationStackScreen,
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }

  Future<dynamic> replaceWithNestedShopScreenInShopNavigationStackScreenRouter([
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  ]) async {
    return replaceWith<dynamic>(ShopNavigationStackScreenRoutes.shopScreen,
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }

  Future<dynamic>
      replaceWithNestedGiftGuideScreenInShopNavigationStackScreenRouter({
    required String groupId,
    _i5.Key? key,
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  }) async {
    return replaceWith<dynamic>(ShopNavigationStackScreenRoutes.giftGuideScreen,
        arguments: NestedGiftGuideScreenArguments(groupId: groupId, key: key),
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }

  Future<dynamic>
      replaceWithNestedGiftGuideScreenInExploreNavigationStackScreenRouter({
    required String groupId,
    _i5.Key? key,
    int? routerId,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
    Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
        transition,
  }) async {
    return replaceWith<dynamic>(
        ExploreNavigationStackScreenRoutes.giftGuideScreen,
        arguments: NestedGiftGuideScreenArguments(groupId: groupId, key: key),
        id: routerId,
        preventDuplicates: preventDuplicates,
        parameters: parameters,
        transition: transition);
  }
}

Expected behavior

No response

Screenshots

No response

Additional Context

No response

scognito avatar Oct 16 '23 14:10 scognito

You need a unique name if you're using the same types.

I would suggest adding the parent path in front of the name.

FilledStacks avatar Oct 19 '23 08:10 FilledStacks

Hi Dane, thanks for answering. What you mean for unique name? Can you make an example related to this case? Also what you mean adding parent path in front of the name? Should this fix the issue? Anyway I don't understand why with old version of stacked the generator worked. I mean, I think it is normal to have the same view (gift guide in my case) that exists in different path, in the real world. Unfortunately my company didn't upgrade stacked for more than a year and this is the result...Thanks

scognito avatar Oct 19 '23 13:10 scognito

@scognito Were you able to solve your issue?

coruscant187 avatar May 04 '24 15:05 coruscant187

@scognito I agree that it should work.

Me and @ferrarafer will discuss a solution and implement it.

I've just come back from leave so catching up on everything now.

FilledStacks avatar May 20 '24 13:05 FilledStacks

Hi @scognito @coruscant187

The issue was fixed, please let us know if something doesn't work as expected. Sorry for the delay.

ferrarafer avatar Jul 09 '24 13:07 ferrarafer

@ferrarafer I have a similar issue where the same navigateTo name is created each time the route is added as a nested route of a different section. Using the latest stacked version

rlee1990 avatar Aug 24 '24 04:08 rlee1990