Reputation: 11
Trying to implement guest access to my app,
The app flow goes as this: Walkthrough screen (/onboarding) => user can either login/signup/continueAsguest after the first installation as the user return always can access the /home route and some other protected routes need the user to login I want to reuse the same routes after he login he will return the actual protected route
class AppRouter {
late GoRouter _router;
late GlobalKey<NavigatorState> _rootNavigatorKey;
late GlobalKey<NavigatorState> _homeNavigatorKey;
late GlobalKey<NavigatorState> _exploreNavigatorKey;
late GlobalKey<NavigatorState> _realEstateNavigatorKey;
late GlobalKey<NavigatorState> _profileNavigatorKey;
AppRouter() {
_rootNavigatorKey = GlobalKey<NavigatorState>();
_homeNavigatorKey = GlobalKey<NavigatorState>();
_exploreNavigatorKey = GlobalKey<NavigatorState>();
_realEstateNavigatorKey = GlobalKey<NavigatorState>();
_profileNavigatorKey = GlobalKey<NavigatorState>();
_router = GoRouter(
debugLogDiagnostics: true,
initialLocation: '/home',
navigatorKey: _rootNavigatorKey,
routes: [
GoRoute(
name: 'Onboarding',
path: '/onboarding',
pageBuilder: (context, state) => const MaterialPage(
child: OnboardingScreen(),
),
),
GoRoute(
parentNavigatorKey: _rootNavigatorKey,
name: 'Login',
path: '/login',
redirect: (context, state) async {
final onBoarding = context.read<OnboardingCubit>().state;
final authState = context.read<AuthBloc>().state;
if (onBoarding is OnboardingInitial) {
return '/onboarding';
} else if (authState is Unauthenticated) {
return null;
} else if (authState is Guest || authState is Authenticated) {
return '/home';
} else {
return null;
}
},
pageBuilder: (context, state) => MaterialPage(
child: LoginScreen(
showGuestButton: state.extra as bool? ?? true,
),
),
routes: [
GoRoute(
name: 'ResetPassword',
path: 'reset-password',
pageBuilder: (context, state) => const MaterialPage(
child: ResetPasswordScreen(),
),
routes: [
GoRoute(
name: 'ResetPasswordOtp',
path: 'reset-password-otp/:email',
pageBuilder: (context, state) {
print('state.extra: ${state.extra}');
return MaterialPage(
child: ResetPasswordOtpScreen(
email: state.pathParameters['email'] as String,
),
);
},
),
.....
// main screen
StatefulShellRoute.indexedStack(
parentNavigatorKey: _rootNavigatorKey,
builder: (context, state, navigationShell) {
return MainScreen(
navigationShell: navigationShell,
);
},
pageBuilder: (context, state, navigationShell) => MaterialPage(
child: MainScreen(
navigationShell: navigationShell,
),
),
redirect: (context, state) {
final authState = context.read<AuthBloc>().state;
if (authState is Unauthenticated) {
return '/login';
} else {
return null;
}
},
branches: [
// home
StatefulShellBranch(
navigatorKey: _homeNavigatorKey,
initialLocation: '/home',
routes: [
GoRoute(
name: 'Home',
path: '/home',
pageBuilder: (context, state) => const NoTransitionPage(
child: HomeScreen(),
),
redirect: (context, state) {
final authState = context.read<AuthBloc>().state;
final user = context.read<AuthBloc>().user;
if (authState is Authenticated && !user!.isValid()) {
Logger().i('states is Authenticated');
return '/signup/user-infos';
} else {
return null;
}
},
),
],
),
// explore
StatefulShellBranch(
navigatorKey: _exploreNavigatorKey,
initialLocation: '/explore',
......
GoRoute(
name: 'StaysPayment',
path: '/stays-payment',
pageBuilder: (context, state) => MaterialPage(
child: RealestatePaymentScreen(
property: state.extra as Property,
),
),
the route I'm checking the auth state is /stays-payment and in MyApp widget
BlocBuilder<LanguageCubit, LanguageState>(
builder: (context, state) {
return BlocListener<AuthBloc, AuthState>(
listener: (context, state) {
debugPrint(state.toString());
sl<AppRouter>().router.refresh();
},
child: MaterialApp.router(
UserModel? _user;
final _userController = StreamController<UserModel?>.broadcast();
AuthBloc({
required ConfirmInfos confirmInfos,
required GetUser getUser,
}) : _confirmInfos = confirmInfos,
_getUser = getUser,
super(AuthInitial()) {
on<OnLoggedIn>((event, emit) {
_user = event.user as UserModel;
emit(Authenticated(
user: event.user,
credentials: event.credentials,
currentPath: event.currentPath));
});
on<OnLoggedOut>((event, emit) {
print("OnLoggedOut");
final sharedPrefs = sl<SharedPreferences>();
sharedPrefs.remove('accessToken');
sharedPrefs.remove('refreshToken');
sharedPrefs.remove('user');
emit(Guest());
});
on<OnAppStarted>((event, emit) async {
print("OnAppStarted getting user");
final sharedPrefs = sl<SharedPreferences>();
final UserModel? user = sharedPrefs.containsKey('user')
? UserModel.fromJson(sharedPrefs.getString('user')!)
: null;
final AuthCredentials? credentials =
sharedPrefs.containsKey('accessToken') &&
sharedPrefs.containsKey('refreshToken')
? AuthCredentials(
accessToken: sharedPrefs.getString('accessToken')!,
refreshToken: sharedPrefs.getString('refreshToken')!,
)
: null;
if (user != null && credentials != null) {
_user = user;
emit(Authenticated(
user: user, credentials: credentials, currentPath: '/home'));
} else if (sharedPrefs.containsKey('isGuest') &&
sharedPrefs.getBool('isGuest')!) {
emit(Guest());
} else {
emit(Unauthenticated());
}
});
on<OnUserUpdated>(_updateUser);
on<ContinueAsGuest>((event, emit) {
final sharedPrefs = sl<SharedPreferences>();
sharedPrefs.setBool('isGuest', true);
emit(Guest());
});
on<LoginAsGuest>((event, emit) {
emit(AuthInitial());
});
on<GetUserEvent>(_fetchUser);
}
I tried to pass the redirect path as a params as login/?redirect.. didn't work due to "Multiple widgets used the same GlobalKey." error
Upvotes: 1
Views: 18