Bloc state not updating with GoRouter and flutter_native_splash

25 views Asked by At

I've just started learning flutter weeks back. I'm building a project with Go router and Bloc & get_it for dependency injection & also making use of flutter_native_splash for my splash screen , I'm trying to solve my authentication navigation

I have 3 states - Authenticated, Unauthenticated, FirstTime (Will see onboarding screens)

This is my current implementation, the state released is always Unauthenticated, whenever I open the app. Ideally the first time it should be FirstTime

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => serviceLocator<AuthBloc>()..add(AppStarted()),
      child: MaterialApp.router(
        title: "Fittro",
        debugShowCheckedModeBanner: false,
        theme: ThemeData(primarySwatch: Colors.blue),
        routerDelegate: _router.routerDelegate,
        routeInformationParser: _router.routeInformationParser,
        routeInformationProvider: _router.routeInformationProvider,
      ),
    );
  }
}

final GoRouter _router = GoRouter(
  redirect: (context, state) {
    // Assuming your AuthBloc is accessible here and provides the current state
    final authState = serviceLocator<AuthBloc>().state;
    debugPrint(authState.toString());
    // Determine if the current state is FirstTime, Unauthenticated, or Authenticated
    if (authState is FirstTime) {
      // Redirect to onboarding for FirstTime state
      return '/onboarding';
    } else if (authState is Unauthenticated) {
      // Redirect to login if unauthenticated and not on login or onboarding page
      return '/login';
    } else if (authState is Authenticated) {
      return '/home';
    }
    // No redirection needed
    return null;
  },
  routes: <RouteBase>[
    GoRoute(
      name: "home",
      path: "/home",
      builder: (context, state) => const HomePage(),
    ),
    GoRoute(
      name: "onboarding",
      path: "/onboarding",
      builder: (context, state) => const OnboardingView(),
    ),
    GoRoute(
      name: "login",
      path: "/login",
      builder: (context, state) => const LoginScreen(),
    ),
  ],
);

If I don't use the GoRouter then things work fine i.e my main widget looks like this

@override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => serviceLocator<AuthBloc>()..add(AppStarted()),
      child: MaterialApp(
          title: "Fittro",
          debugShowCheckedModeBanner: false,
          theme: ThemeData(primarySwatch: Colors.blue),
          home: BlocConsumer<AuthBloc, AuthState>(
            listener: (context, state) {},
            builder: (context, state) {
              if (state is Authenticated) {
                return const HomePage();
              } else if (state is Unauthenticated) {
                return const LoginScreen();
              } else {
                return const OnboardingView();
              }
            },
          )),
    );
  }

My auth_bloc.dart

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  final LoginUser _loginUserUseCase;

  AuthBloc({required LoginUser loginUserUseCase})
      : _loginUserUseCase = loginUserUseCase,
        super(Unauthenticated()) {
    on<AppStarted>(_onAppStarted);
    on<LoggedIn>(_onLoggedIn);
    on<LoggedOut>(_onLoggedOut);
  }

  void _onAppStarted(AppStarted event, Emitter<AuthState> emit) async {
    final prefs = await SharedPreferences.getInstance();
    final isFirstTime = prefs.getBool('onboarding') ?? true;
    final token = prefs.getString("access_token") ?? "";

    if (isFirstTime) {
      emit(FirstTime());
    } else {
      // Check login status and emit either Authenticated or Unauthenticated
      if (token != "") {
        emit(Authenticated());
      } else {
        emit(Unauthenticated());
      }
    }
  }

  void _onLoggedIn(LoggedIn event, Emitter<AuthState> emit) async {
    final prefs = await SharedPreferences.getInstance();
    final email = event.email;
    final password = event.password;

    final token = await _loginUserUseCase.call(
      LoginParams(
        email: email,
        password: password,
      ),
    );
    token.fold((l) => debugPrint('error'), (tk) {
      prefs.setString("token", tk);
      emit(Authenticated());
    });
  }

  void _onLoggedOut(LoggedOut event, Emitter<AuthState> emit) async {
    final prefs = await SharedPreferences.getInstance();
    prefs.clear();
    emit(Unauthenticated());
  }
}
0

There are 0 answers