# Authentication BLoC
Authentication Bloc for Flutter.
## Features
* ๐ง Wyatt Architecture
* ๐งฑ Entities
- Account -> Contains account information from provider.
- Session -> Contains account and associated data retrieved from an external source.
- AuthenticationChangeEvent -> Describes an event in authentication change (sign in, sign up, sign out, etc...)
- SessionWrapper -> Contains latest authentication change event and session.
* ๐ Powerful and secured authentication repository
* ๐ฅ Multiple data sources
- Mock
- Firebase
* ๐ง Cubits, why make it complicated when you can make it simple?
- Goes to the essential.
* ๐ Consistent
- Every class have same naming convention
* ๐งช Tested
* ๐ Documented: [available here](./doc/api/index.md)
## Getting started
Simply add `wyatt_authentication_bloc` in `pubspec.yaml` , then
```dart
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
```
### Data source
The first step is to provide a data source.
```dart
getIt.registerLazySingleton>(
() => AuthenticationFirebaseDataSourceImpl(
firebaseAuth: FirebaseAuth.instance,
googleSignIn:
GoogleSignIn(clientId: DefaultFirebaseOptions.ios.iosClientId)),
);
```
> Here we use GetIt (see example project)
### Repository
Then you can configure your repository.
```dart
final AuthenticationRepository authenticationRepository = AuthenticationRepositoryImpl(
authenticationRemoteDataSource:
getIt>(),
customPasswordValidator: const CustomPassword.pure(),
extraSignUpInputs: [
FormInput(
AuthFormField.confirmPassword,
const ConfirmedPassword.pure(),
metadata: const FormInputMetadata(export: false),
),
],
);
```
> Here we pass some extra inputs for the sign up, and a custom password validator.
### Cubits
It is necessary to implement each cubit. Don't panic, most of the work is already done ๐ you just have to customize the logic of these.
In each of these cubits it is necessary to overload the various callbacks.
> Here the associated data `Data` is a `int`
#### Authentication
In the authentication are managed, the refresh, the deletion of account or the disconnection.
```dart
class ExampleAuthenticationCubit extends AuthenticationCubit {
ExampleAuthenticationCubit({required super.authenticationRepository});
@override
FutureOrResult onReauthenticate(Result result) async {
// TODO
}
@override
FutureOrResult onRefresh(Result result) {
// TODO
}
@override
FutureOrResult onSignInFromCache(SessionWrapper wrapper) {
// TODO
}
@override
FutureOrResult onSignOut() {
// TODO
}
@override
FutureOrResult onDelete() {
// TODO
}
}
```
#### Sign Up
```dart
class ExampleSignUpCubit extends SignUpCubit {
ExampleSignUpCubit({
required super.authenticationRepository,
});
@override
FutureOrResult onSignUpWithEmailAndPassword(Result result, WyattForm form) async {
// TODO
}
}
```
#### Sign In
```dart
class ExampleSignInCubit extends SignInCubit {
ExampleSignInCubit({
required super.authenticationRepository,
});
@override
FutureOrResult onSignInWithEmailAndPassword(Result result, WyattForm form) {
// TODO
}
@override
FutureOrResult onSignInAnonymously(Result result, WyattForm form) {
// TODO
}
@override
FutureOrResult onSignInWithGoogle(Result result, WyattForm form) {
// TODO
}
}
```
After setting up all these cubits you can provide them in the application. And that's it!
```dart
BlocProvider>(
create: (_) => ExampleSignUpCubit(
authenticationRepository: authenticationRepository,
),
),
BlocProvider>(
create: (_) => ExampleSignInCubit(
authenticationRepository: authenticationRepository,
),
),
```
### Widgets
Widgets are provided to make your life easier. Starting with the `AuthenticationBuilder` which allows you to build according to the authentication state.
```dart
AuthenticationBuilder(
authenticated: (context, sessionWrapper) => Text(
'Logged as ${sessionWrapper.session?.account.email} | GeneratedId is ${sessionWrapper.session?.data}'),
unauthenticated: (context) =>
const Text('Not logged (unauthenticated)'),
unknown: (context) => const Text('Not logged (unknown)'),
),
```
A `BuildContext` extension is also available to access certain attributes more quickly.
```dart
Text('Home | ${context.account, int>()?.email}'),
```
Listeners are used to listen to the status of the sign in and sign up forms.
```dart
return SignInListener(
onError: (context, status, errorMessage) => ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(
SnackBar(content: Text(errorMessage ?? 'Sign In Failure')),
),
child: ...
);
```