Verilyzed
Verilyzed

Reputation: 91

Flutter GoRouter: ShellRoute with Subroutes

I am currently developing a flutter application using the go_router package.

At the base there is one Shellroute with 4 routes in total. So this is the main screen containing a "Home", "Search", "Events" and an "Account" page.

Then I have multiple "secondary" screens that I want as sub routes of all of the above mentioned. So the shell route (one of those routes) needs to be the first in the hierarchy.

Currently I have a setup like this:

created an entity class

abstract class ScreenEntity {
  ScreenEntity(this.name, this.path);

  final String name;
  final String path;
}

All my Screens inherit this.

I then have a whole list of those screens so I don't need to write the whole go router stack myself.

const mainScreens = <ScreenEntity>[
  ScreenHome(),
  ScreenSearchActivity(),
  ScreenParty(),
  ScreenAccount(),
];

final secondaryScreens = <ScreenEntity>[
  const ScreenLoggingErrors(),
  ScreenUserSettings(),
  const ScreenFriendList(),
  const ScreenNotification(),
  const ScreenSearchUser(),
  const ScreenCreateLocation(),
  const ScreenSettings(),
  const ScreenPartySettings(),
  const ScreenSettingsPayments(),
  const ScreenCamera(),
  const ScreenPartyArchive(),
  const ScreenPartyCreateFlow(),
  const ScreenIntroduction(),
  ScreenPolicyAgreement(),
  const ScreenLocations(),
];

And some other smaller lists. Then I've just iterated through them as sub routes in the first of the 4 main screens.

GoRouter createGoRouter(Ref ref) => GoRouter(
      initialLocation: mainScreens.first.path,
      refreshListenable: ref.read(deeplinkStateProvider),
      navigatorKey: _rootNavigatorKey,
      routes: [
        ShellRoute(
          navigatorKey: _shellNavigatorKey,
          pageBuilder: (context, state, child) => MaterialPage(
            child: MainScreenWrapper(child: child),
          ),
          routes: [
            GoRoute(
              parentNavigatorKey: _shellNavigatorKey,
              path: mainScreens[0].path,
              name: mainScreens[0].name,
              pageBuilder: (context, state) {
                return NoTransitionPage(child: mainScreens[0] as Widget);
              },
              routes: [
                ...secondaryScreens.map(
                  (screen) => GoRoute(
                    parentNavigatorKey: _rootNavigatorKey,
                    path: screen.path,
                    name: screen.name,
                    pageBuilder: (context, state) => MaterialPage(
                      child: screen as Widget,
                    ),
                  ),
                ),
                ...screensWithPathParams.map(
                  (screenEntity) => GoRoute(
                    parentNavigatorKey: _rootNavigatorKey,
                    path: screenEntity.path,
                    name: screenEntity.name,
                    pageBuilder: (context, state) {
                      final param =
                          state.pathParameters[screenEntity.paramName];
                      return MaterialPage(
                        child: screenEntity.build(context, param!),
                      );
                    },
                  ),
                ),
                ...screensWithParams.map(
                  (screenEntity) => GoRoute(
                    parentNavigatorKey: _rootNavigatorKey,
                    path: screenEntity.path,
                    name: screenEntity.name,
                    pageBuilder: (context, state) {
                      final extra = state.extra as ScreenProps;
                      return MaterialPage(
                        child: screenEntity.build(context, extra),
                      );
                    },
                  ),
                ),
                ...modalEntities.map(
                  (modalEntity) => GoRoute(
                    parentNavigatorKey: _rootNavigatorKey,
                    path: modalEntity.path,
                    name: modalEntity.name,
                    pageBuilder: (context, state) => ModalPage(
                      isDismissible: modalEntity.isDismissible,
                      isScrollControlled: modalEntity.isScrollControlled,
                      enableDrag: modalEntity.enableDrag,
                      builder: (context) => modalEntity.build(
                        context,
                        state.extra as ModalProps,
                        ref: ref,
                      ),
                    ),
                  ),
                ),
                ...modalEntitiesWithPath.map(
                  (modalEntity) => GoRoute(
                    parentNavigatorKey: _rootNavigatorKey,
                    path: modalEntity.path,
                    name: modalEntity.name,
                    pageBuilder: (context, state) {
                      final param = state.pathParameters[modalEntity.pathParam];

                      return ModalPage(
                        isDismissible: modalEntity.isDismissible,
                        isScrollControlled: modalEntity.isScrollControlled,
                        enableDrag: modalEntity.enableDrag,
                        builder: (context) => modalEntity.build(
                          context,
                          state.extra as ModalProps?,
                          param ?? '',
                          ref: ref,
                        ),
                      );
                    },
                  ),
                ),
                ...dialogEntities.map(
                  (dialogEntity) => GoRoute(
                    parentNavigatorKey: _rootNavigatorKey,
                    path: dialogEntity.path,
                    name: dialogEntity.name,
                    pageBuilder: (context, state) => DialogPage(
                      barrierDismissible: dialogEntity.barrierDismissible,
                      builder: (context) => dialogEntity.build(
                        context,
                        state.extra as DialogProps,
                        ref: ref,
                      ),
                    ),
                  ),
                ),
              ],
            ),
            GoRoute(
              parentNavigatorKey: _shellNavigatorKey,
              path: mainScreens[1].path,
              name: mainScreens[1].name,
              pageBuilder: (context, state) {
                return NoTransitionPage(child: mainScreens[1] as Widget);
              },
            ),
            GoRoute(
              parentNavigatorKey: _shellNavigatorKey,
              path: mainScreens[2].path,
              name: mainScreens[2].name,
              pageBuilder: (context, state) {
                return NoTransitionPage(child: mainScreens[2] as Widget);
              },
            ),
            GoRoute(
              parentNavigatorKey: _shellNavigatorKey,
              path: mainScreens[3].path,
              name: mainScreens[3].name,
              pageBuilder: (context, state) {
                return NoTransitionPage(child: mainScreens[3] as Widget);
              },
            ),
          ],
        ),
        ...primaryScreens.map(
          (screen) => GoRoute(
            path: screen.path,
            name: screen.name,
            pageBuilder: (context, state) => MaterialPage(
              child: screen as Widget,
            ),
          ),
        ),
      ],
      redirect: (context, state) async {
        ...
      },
    );

What I wanted: I want that all these "secondary" screens need one of these four screens under them. That when I use context.go() it automatically uses one of the main screens that I am currently on and puts the routed screen on top.

But the way I implemented it right now it routes to the first page of the shell route every time.

Upvotes: 0

Views: 73

Answers (0)

Related Questions