How can I read the user auth states from my bloc? I am trying to use BlocBuilder, but not sure how do I get the data from AuthenticationState. I am trying to access the state and user. So the state should check for all the constructors, if authenticated then I want to display user data. Also in my app, I would like to automatically redirect an user to login page if he is not authorized - where this should be set up?
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
BlocBuilder<AuthenticationBloc, AuthenticationState>(builder: (context, state) {
if(state is ...) {
return Text("Unknown");
}
})
],
),
class AuthenticationState extends Equatable {
final AuthStatus status;
final User? user;
const AuthenticationState._({this.user, this.status = AuthStatus.unknown});
const AuthenticationState.unknown() : this._(status: AuthStatus.unknown);
const AuthenticationState.authenticated({required User user})
: this._(user: user, status: AuthStatus.authenticated);
const AuthenticationState.unauthorized()
: this._(status: AuthStatus.unauthenticated);
@override
List<Object?> get props => [user, status];
}
class AuthenticationBloc
extends Bloc<AuthenticationEvent, AuthenticationState> {
final AuthenticationRepository _authRepository;
late StreamSubscription<AuthStatus> _authSubscription;
AuthenticationBloc(
{required AuthenticationRepository authenticationRepository})
: _authRepository = authenticationRepository,
super(const AuthenticationState.unknown()) {
on<AuthStateChanged>(_onAuthStatusChanged);
on<AuthenticationLogoutRequested>(_onLogoutRequested);
_authSubscription = _authRepository.status
.listen((status) => add(AuthStateChanged(authStatus: status)));
}
void _onAuthStatusChanged(
AuthStateChanged event, Emitter<AuthenticationState> emit) {
switch (event.authStatus) {
case AuthStatus.unauthenticated:
return emit(const AuthenticationState.unauthorized());
case AuthStatus.authenticated:
final User _user = User();
return emit(AuthenticationState.authenticated(user: _user));
default:
return emit(AuthenticationState.unknown());
}
}
void _onLogoutRequested(
AuthenticationLogoutRequested event, Emitter<AuthenticationState> emit) {
_authRepository.logOut();
}
}
CodePudding user response:
If you are trying to check the state of user (authenticated or not) and show proper page according to its status i suggest to use get package. Get page middle ware is powerful and useful feature and you can call it in different situation.
Another solution for you is checking the user status in AuthenticationBloc.First save your user status in share it preference or hive or etc ... and everywhere you need to check user status, check it and by using bloc listener redirect your user to login page
CodePudding user response:
You access state variables simply with state.status
inside the BlocBuilder
. Here's an example of a BlocConsumer
which is basically a BlocBuilder
and BlocListener
in the same widget.
BlocConsumer<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
if (state.status == AuthStatus.unauthenticated) {
// navigate back to login screen for example
}
},
builder: (context, state) {
switch (state.status) {
case AuthStatus.unknown:
// do what ya gotta do here
break;
case AuthStatus.unauthenticated:
// do what ya gotta do here
break;
case AuthStatus.authenticated:
return Text(state.user!.name); // example of showing user data
}
},
),
Your state class can also be simplified a bit. You don't need all those constructors. When you emit an updated AuthStatus
that is a state
update and will trigger the BlocConsumer
. When the status
is AuthStatus.authenticated
you're also emitting the user
with that state update.
class AuthenticationState extends Equatable {
final AuthStatus status;
final User? user;
AuthenticationState(this.status)
: user =
null; // null on first app launch, updates when you emit a User on successful login
@override
List<Object?> get props => [status, user];
}
If you want the app to load in a logged in state you can check your _authRepository
for a non null currentUser
(assuming you're using FirebaseAuth
it has a getter called currentUser
and returns null if user isn't signed in) and if its not null you emit an AuthStatus.authenticated
state with the user
in the constructor of your bloc it it'll fire on app start.
AuthenticationBloc(
{required AuthenticationRepository authenticationRepository})
: _authRepository = authenticationRepository,
super(const AuthenticationState.unknown()) {
on<AuthStateChanged>(_onAuthStatusChanged);
on<AuthenticationLogoutRequested>(_onLogoutRequested);
_authSubscription = _authRepository.status
.listen((status) => add(AuthStateChanged(authStatus: status)));
// This is assuming your can access the user directly via _userRepository
if(_userRepistory.user != null) {
emit(AuthenticationState.authenticated(user: _userRepistory.user))
}