Search code examples
flutterdartflutter-go-router

Navigate to a root StatefulShellRoute route


I'm trying to navigate to a route with StatefulShellRoute.indexedStack() implemented, and the problem in first instance is that I can't navigate to that view because StatefulShellRoute doens't let me use the path or name parameter, so i navigate to an internal view of main one.

It works ONLY in that view, if I try to switch to one of the branches that accompanies the branch i navigated, the application crashes because none of the other branches have the object i need to pass for the application to work.

The code of the routes implemented with the package go_router:

StatefulShellRoute.indexedStack(
          builder: (context, state, navigationShell) {
            Empresa empresa = state.extra as Empresa;
            return VistaGeneralEmpresa(
              empresa: empresa,
              navigationShell: navigationShell,
            );
          },
          branches: <StatefulShellBranch>[
            StatefulShellBranch(
              navigatorKey: _rootNavigatorInicio,
              routes: <RouteBase>[
                GoRoute(
                    name: 'inicioEmpresa',
                    path: '/inicioEmpresa',
                    builder: (context, state) {
                      final Empresa empresa = state.extra as Empresa;
                      return VistaInicioEmpresa(empresa: empresa);
                    },
                    routes: [
                      GoRoute(
                          name: 'gestionInventario',
                          path: 'gestionInventario',
                          builder: (context, state) {
                            final Empresa empresa = state.extra as Empresa;
                            return VistaGeneralInventario(empresa);
                          }),
                      GoRoute(
                          name: 'historial',
                          path: 'historial',
                          builder: (context, state) {
                            final Empresa empresa = state.extra as Empresa;
                            return VistaHistorial(empresa: empresa);
                          }),
                      GoRoute(
                          name: 'estadisticas',
                          path: 'estadisticas',
                          builder: (context, state) {
                            final Empresa empresa = state.extra as Empresa;
                            return VistaEstadisticas(empresa: empresa);
                          }),
                    ]),
              ],
            ),
            StatefulShellBranch(
              navigatorKey: _rootNavigatorCaja,
              routes: <RouteBase>[
                GoRoute(
                    path: '/caja',
                    builder: (context, state) {
                      final Empresa empresa = state.extra as Empresa;
                      return VistaCaja(empresa: empresa);
                    },
                    routes: []),
              ],
            ),
            StatefulShellBranch(
              navigatorKey: _rootNavigatorAjustes,
              routes: <RouteBase>[
                GoRoute(
                  path: '/ajustes',
                  builder: (context, state) {
                    final Empresa empresa = state.extra as Empresa;
                    return VistaAjustesEmpresa(empresa: empresa);
                  },
                  routes: [],
                ),
              ],
            ),
          ],
        ),

So with the code in hand, I try to navigate to VistaGeneralEmpresa, but since it's impossible, i just navigate to VistaInicioEmpresa. That works only for the nested views inside VistaInicioEmpresa, but if i try to go to VistaCaja or VistaAjustes, the app crashes with the mentioned error (empresa is null in VistaGeneralEmpresa).

I will show the implementation of the call to VistaInicioEmpresa() and the code of VistaGeneralEmpresa():

class VistaGeneralEmpresa extends StatefulWidget {
  final Empresa empresa;

  const VistaGeneralEmpresa({
    super.key,
    required this.empresa,
    required this.navigationShell,
  });

  final StatefulNavigationShell navigationShell;

  @override
  State<VistaGeneralEmpresa> createState() => _VistaGeneralEmpresaState();
}

class _VistaGeneralEmpresaState extends State<VistaGeneralEmpresa> {
  int selectedIndex = 0;

  void _goBranch(int index) {
    widget.navigationShell.goBranch(
      index,
      initialLocation: index == widget.navigationShell.currentIndex,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SizedBox(
        width: double.infinity,
        height: double.infinity,
        child: widget.navigationShell,
      ),
      bottomNavigationBar: GNav(
        onTabChange: (value) {
          setState(() {
            selectedIndex = value;
            _goBranch(selectedIndex);
          });
        },
        selectedIndex: selectedIndex,
        gap: 8,
        backgroundColor: Colors.amberAccent,
        color: const Color.fromARGB(255, 70, 70, 70),
        activeColor: Colors.black,
        padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 20),
        tabs: const [
          GButton(
            icon: Icons.home,
            text: 'Inicio',
          ),
          GButton(
            icon: Icons.inventory,
            text: 'Caja',
          ),
          GButton(
            icon: Icons.settings,
            text: 'Ajustes',
          )
        ],
      ),
    );
  }
}

Call to VistaInicioEmpresa:

void _navigateToVistaEmpresa(BuildContext context) {
    context.goNamed("inicioEmpresa", extra: empresa);
  }

Solution

  • Ok, so what i did to accomplish this situation is to make a method to call it where i want to make the navigation.

    The method just updates the dummy object i created in the router class to use it in all the structure, and now, i can access every view without a problem.

      static void actualizarEmpresa(Empresa em) {
        empresaX = em;
      }
    

    I still call the inner view because the wrapper causes some problems, but with this solution, I mitigate the problem:

      void _navigateToVistaEmpresa(BuildContext context) {
        ControladorNavegacion.actualizarEmpresa(empresa);
        context.push('/inicioEmpresa', extra: empresa);
      }
    

    And the routes looks almost the same:

            StatefulShellRoute.indexedStack(
              builder: (context, state, navigationShell) {
                return VistaGeneralEmpresa(
                  navigationShell: navigationShell,
                );
              },
              branches: <StatefulShellBranch>[
                StatefulShellBranch(
                  navigatorKey: _rootNavigatorInicio,
                  routes: <RouteBase>[
                    GoRoute(
                        name: 'inicioEmpresa',
                        path: '/inicioEmpresa',
                        builder: (context, state) {
                          //final Empresa empresa = empresaX;
                          return VistaInicioEmpresa(empresa: empresaX);
                        },
                        routes: [
                          GoRoute(
                              name: 'gestionInventario',
                              path: 'gestionInventario',
                              builder: (context, state) {
                                final Empresa empresa = state.extra as Empresa;
                                return VistaGeneralInventario(empresa);
                              }),
                          GoRoute(
                              name: 'historial',
                              path: 'historial',
                              builder: (context, state) {
                                final Empresa empresa = state.extra as Empresa;
                                return VistaHistorial(empresa: empresa);
                              }),
                          GoRoute(
                              name: 'estadisticas',
                              path: 'estadisticas',
                              builder: (context, state) {
                                final Empresa empresa = state.extra as Empresa;
                                return VistaEstadisticas(empresa: empresa);
                              }),
                        ]),
                  ],
                ),
                StatefulShellBranch(
                  navigatorKey: _rootNavigatorCaja,
                  routes: <RouteBase>[
                    GoRoute(
                        path: '/caja',
                        builder: (context, state) {
                          //final Empresa empresa = state.extra as Empresa;
                          return VistaCaja(empresa: empresaX);
                        },
                        routes: []),
                  ],
                ),
                StatefulShellBranch(
                  navigatorKey: _rootNavigatorAjustes,
                  routes: <RouteBase>[
                    GoRoute(
                      path: '/ajustes',
                      builder: (context, state) {
                        //final Empresa empresa = state.extra as Empresa;
                        return VistaAjustesEmpresa(empresa: empresaX);
                      },
                      routes: [],
                    ),
                  ],
                ),
              ],
            ),