hesham shawky
hesham shawky

Reputation: 1151

How to pass bloc instance with auto_route guard latest version

I am migrating my project from 4.XX into the latest version now of auto_route package ^7.7.1 and what I got broke are the guards, before we passed it in the AppRouter( ...guards ) as prams and now that is not possible

So from the documentation, I found that I have to do it on the AppRouter class but how to pass the context or a Stream instance like bloc to that class, the documentation is not clear for that at all, and no real-world sample

So before it was like that

 _router = AppRouter(
       fingerPrintGuard: FingerPrintGuard(
         BlocProvider.of<SettingsCubit>(context),
       ),
    );

Now I did the following, but it throws an error for missing argument ( the settings bloc )

@AutoRouterConfig(replaceInRouteName: 'Page,Route')
class AppRouter extends $AppRouter {
  @override
  List<AutoRoute> get routes => [
        AutoRoute(
          initial: true,
          page: TabsRoute.page,
          guards: [
            FingerPrintGuard( ) // 
          ],
          children: [
            // children
          ],
        ),
      ];
}

From the doc, I found that I have to pass the stream like this in the router.config(), so I did but I don't know what next and how to retrieve it from the guard

MaterialApp.router(             
              routerConfig: _router.config(
                  reevaluateListenable: ReevaluateListenable.stream(
                      context.watch<SettingsCubit>().stream)),
            ),

Also here's my guard

class FingerPrintGuard extends AutoRouteGuard {
  final SettingsCubit _settingsCubit;

  FingerPrintGuard(this._settingsCubit);

  @override
  void onNavigation(NavigationResolver resolver, StackRouter router) async {
    // _authCubit.state.authenticated
    //     ? resolver.next()
    //     : router.replace(const FingerPrintRoute());
    resolver.next();

    if (!_settingsCubit.state.authenticated) {
      router.push(const FingerPrintRoute());
    }
  }
}

Upvotes: 0

Views: 1447

Answers (1)

Claudio Grasso
Claudio Grasso

Reputation: 101

1.- You need to pass an instance of your AuthService (check at the end of the post for a possible implementation) to your AppRouter:

  final authProvider = AuthService();

 _router = AppRouter(authProvider);

2.- Then set reevaluateListenable parameter to authProvider

  MaterialApp.router(             
          routerConfig: _router.config(
              reevaluateListenable: authProvider,
        ),

3.- Add a parameter to your AppRouter class:

@AutoRouterConfig()
class AppRouter extends _$AppRouter {
  AuthService authService;
  AppRouter(this.authService);

4.- And in your guarded pages routes you should supply said parameter to AuthGuard:

  List<AutoRoute> get routes => [
        AutoRoute(
          initial: true,
          page: TabsRoute.page,
          guards: [
            AuthGuard(authService) // 
          ],
          children: [
            // children
          ],
        ),
      ];
}

5.- Add the same parameter to your AuthGuard:

class AuthGuard extends AutoRouteGuard {
  final AuthService authService;
  AuthGuard(this.authService);

6.- Now you can check if the user is authenticated by means of:

   if(authService.authenticated){
      // if user is authenticated we continue
      resolver.next(true);
    } else {...}

7.- Just for the sake of completeness please find below a possible AuthSevice implementation:

class AuthService extends ChangeNotifier {
  bool _authenticated = false; 
  bool get authenticated => _authenticated;
  set authenticated(bool value) {
    _authenticated = value;
    notifyListeners();
  }
}

Hope this helps, it took me several hours of research and trial and error.

Best regards,

           Claudio

Upvotes: 2

Related Questions