Skip to content

Instantly share code, notes, and snippets.

@roboncode
Last active April 14, 2020 11:44
Show Gist options
  • Save roboncode/cd82ee61304fff3e0e110daade4b796a to your computer and use it in GitHub Desktop.
Save roboncode/cd82ee61304fff3e0e110daade4b796a to your computer and use it in GitHub Desktop.
Dart - Bloc Auth Example
import 'dart:async';
class ServiceRespository {
Future<String> authenticate(String username, String password) {
if(username == "admin" && password == "admin") {
return Future<String>.delayed(Duration(milliseconds: 2000))
.then((_) => "abc");
}
return Future<String>.delayed(Duration(milliseconds: 1000))
.then((_) => throw "invalid credentials");
}
Future clearSession() {
return Future<String>.delayed(Duration(milliseconds: 100));
}
}
class AuthEvent {}
class UnauthorizedEvent extends AuthEvent {
final String message;
UnauthorizedEvent(this.message);
}
class AuthorizedEvent extends AuthEvent {
final String token;
AuthorizedEvent(this.token);
}
class AuthorizingEvent extends AuthEvent {}
class LogoutEvent extends AuthEvent {}
class ErrorEvent extends AuthEvent{
final String message;
ErrorEvent({this.message = "unknown error"});
}
class AuthState {}
class GuestState extends AuthState {}
class UnauthorizedState extends AuthState {
final String message;
UnauthorizedState({this.message});
}
class AuthorizedState extends AuthState {
final String token;
AuthorizedState(this.token);
}
class AuthorizingState extends AuthState {}
class ErrorState extends AuthState{
final String message;
ErrorState(this.message);
}
class AuthTransition {
final AuthState currentState;
final AuthEvent event;
final AuthState nextState;
AuthTransition(this.currentState, this.event, this.nextState);
toString() {
return 'Transition { currentState: ${currentState.runtimeType}, event: ${event.runtimeType}, nextState: ${nextState.runtimeType} }';
}
}
class AuthBloc {
ServiceRespository _repository;
AuthState _state = GuestState();
get state => _state;
final _stateController = StreamController<AuthState>();
Stream<AuthState> get auth => _stateController.stream;
final _eventController = StreamController<AuthEvent>();
get add => _eventController.sink.add;
AuthBloc(ServiceRespository repository) {
this._repository = repository;
_eventController.stream.listen(_mapEventToState);
}
Future login(String username, String password) async {
add(AuthorizingEvent());
try {
String token = await _repository.authenticate(username, password);
add(AuthorizedEvent(token));
} catch(e) {
add(UnauthorizedEvent(e));
}
}
Future logout() async {
await _repository.clearSession();
add(LogoutEvent());
}
_mapEventToState(AuthEvent event) {
AuthState currentState = _state;
if(event is UnauthorizedEvent) {
_state = UnauthorizedState(message: event.message);
onTransition(AuthTransition(currentState, event, _state));
_stateController.sink.add(_state);
_state = GuestState();
} else if (event is AuthorizedEvent) {
_state = AuthorizedState(event.token);
} else if (event is AuthorizingEvent) {
_state = AuthorizingState();
} else if (event is LogoutEvent) {
_state = GuestState();
} else {
_state = ErrorState("invalid event");
}
if(currentState.toString() != state.toString()) {
onTransition(AuthTransition(currentState, event, _state));
}
_stateController.sink.add(_state);
}
void onTransition(AuthTransition transition) {
print(transition);
// print('you are here ${transition.currentState}');
}
void close() {
_stateController.close();
_eventController.close();
}
}
AuthBloc startListen() {
final AuthBloc authBloc = AuthBloc(ServiceRespository());
authBloc.auth.listen((AuthState state) {
print(state);
if (state is AuthorizedState) {
print("Auth token is " + state.token);
} else if (state is UnauthorizedState) {
print("Unauthorized: " + state.message);
}
}).onError((err) => print(err));
return authBloc;
}
void stopListten(AuthBloc authBloc) {
authBloc.close();
}
void main() async {
AuthBloc authBloc = startListen();
print(authBloc.state);
// print("login with valid credentials");
await authBloc.login("admin", "admin");
// print("logout");
await authBloc.logout();
// print("login with invalid credentials");
await authBloc.login("demo", "demo");
}
@roboncode
Copy link
Author

Not really intending to use this, just wanted to understand Bloc better by creating a Bloc from scratch. I will be using ...
https://bloclibrary.dev/

YouTube video from author: https://www.youtube.com/watch?v=knMvKPKBzGE

@roboncode
Copy link
Author

HydratedBloc will store / restore the state - https://pub.dev/packages/hydrated_bloc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment