2

Implementing navigation based on auth changes using flutter_bloc and go_router.

What i need to do is at start if User is authenticated it should be redirected to HomeScreen with the ability to navigate through the auth flow...(HomeScreen,TestScreen1,TestScreen2)

If User is unAunthenticated at any point it should be redirected to LoginScreen and if Unknown then to Splash Screen.

I have gone through many stackoverflow questions and github issues but none of them provides a best pratice of how could we acheive this.

Problems:

  • Cannot navigate it in the auth flow, HomeScreen -> Test1 || HomeScreen -> Test2

Gives the following assetion:

Tried to listen to a value exposed with provider, from outside of the widget tree.

This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.

To fix, write:
Provider.of<$T>(context, listen: false);

It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.

The context used was: $context
  • When working with flutter_web, if I'm on Home Screen (/auth/home_screen) and change the URL manually to /login_screen it throws an exception:
======== Exception caught by foundation library ====================================================
The following assertion was thrown while dispatching notifications for GoRouteInformationProvider:
Tried to listen to a value exposed with provider, from outside of the widget tree.

This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.

Changing to context.read instead of watch is not what i'm really into, because then i cannot listen to changes from the bloc.

What i have tried soo far is:

My AppRouter:

class AppRouter {
  GoRouter get router => _goRouter;

  late final GoRouter _goRouter = GoRouter(
    routes: <GoRoute>[
      GoRoute(
        path: '/',
        name: 'SPLASH',
        builder: (context, state) => const SplashScreen(),
      ),
      GoRoute(
        path: '/auth',
        name: 'AUTH',
        builder: (context, state) => HomeScreen(),
        routes: <GoRoute>[
          GoRoute(
            path: 'home_screen',
            name: 'HOME',
            builder: (context, state) => HomeScreen(),
          ),
          GoRoute(
            path: 'test_screen_1',
            name: 'TEST_SCREEN_1',
            builder: (context, state) => TESTSCREEN1(),
          ),
          GoRoute(
            path: 'test_screen_2',
            name: 'TEST_SCREEN_2',
            builder: (context, state) => TESTSCREEN2(),
          ),
        ],
      ),
      GoRoute(
        path: '/login_screen',
        name: 'LOGIN',
        builder: (context, state) => LoginScreen(),
      ),
    ],
    redirect: (context, state) {
      final authState = context.watch<AuthBloc>().state;
      final loginLocation = state.namedLocation('LOGIN');
      final authFlow = state.namedLocation('AUTH');
      final splashLocation = state.namedLocation('SPLASH');

      if (authState is AuthStateAuthenticated) {
        return authFlow;
      } else if (authState is AuthStateUnAuthenticated) {
        return loginLocation;
      } else {
        return splashLocation;
      }
    },
  );
}

App:

class App extends StatelessWidget {

  AppRouter appRouter = AppRouter();
  @override
  Widget build(BuildContext context) {
    return RepositoryProvider<AuthService>(
      create: (context) => AuthService(),
      child: MultiBlocProvider(
        providers: [
          BlocProvider<AuthBloc>(create: (context) => AuthBloc(authService:    RepositoryProvider.of<AuthService>(context))),
                  ],
        child: MaterialApp.router(
          routerDelegate: appRouter.router.routerDelegate,
          routeInformationParser: appRouter.router.routeInformationParser,
          routeInformationProvider: appRouter.router.routeInformationProvider,
        ),
      ),
    );
  }
}

Taha Aslam
  • 21
  • 3
  • any luck fixing this? – raquelhortab May 22 '23 at 10:26
  • No, because of the lack of docs I switched to auto_route temporarily – Taha Aslam May 23 '23 at 12:55
  • I was actually able to fix it in my cas and it was due to calling provider without `listen:false`when getting the auth state. So, instead of `Provider.of(context)` I needed to call `Provider.of(context, listen: false)`. In your case, it seems due to this: `context.watch().state` – raquelhortab May 23 '23 at 13:26
  • How are able to listen to the auth changes, what if the user gets unauthenticated while using the application at any point? I know redirect is called on every navigation try. But navigating inside the Auth flow i.e /auth/home , /auth/home/test1 , /auth/home/test2, still remains a valid problem in my case. – Taha Aslam May 25 '23 at 05:08
  • since this (the redirect method) is called before accessing any route, if the user gets unauthenticated, this will be checked and the user will be redirected – raquelhortab May 25 '23 at 09:40

0 Answers0