wyatt_authentication_bloc (0.5.1)
Installation
dart pub add wyatt_authentication_bloc:0.5.1 --hosted-url=
About this package
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
Getting started
Simply add wyatt_authentication_bloc
in pubspec.yaml
, then
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
Data source
The first step is to provide a data source.
getIt.registerLazySingleton<AuthenticationRemoteDataSource<int>>(
() => AuthenticationFirebaseDataSourceImpl<int>(
firebaseAuth: FirebaseAuth.instance,
googleSignIn:
GoogleSignIn(clientId: DefaultFirebaseOptions.ios.iosClientId)),
);
Here we use GetIt (see example project)
Repository
Then you can configure your repository.
final AuthenticationRepository<int> authenticationRepository = AuthenticationRepositoryImpl(
authenticationRemoteDataSource:
getIt<AuthenticationRemoteDataSource<int>>(),
customPasswordValidator: const CustomPassword.pure(),
extraSignUpInputs: [
FormInput(
AuthFormField.confirmPassword,
const ConfirmedPassword.pure(),
metadata: const FormInputMetadata<void>(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 aint
Authentication
In the authentication are managed, the refresh, the deletion of account or the disconnection.
class ExampleAuthenticationCubit extends AuthenticationCubit<int> {
ExampleAuthenticationCubit({required super.authenticationRepository});
@override
FutureOrResult<int?> onReauthenticate(Result<Account, AppException> result) async {
// TODO
}
@override
FutureOrResult<int?> onRefresh(Result<Account, AppException> result) {
// TODO
}
@override
FutureOrResult<int?> onSignInFromCache(SessionWrapper<int> wrapper) {
// TODO
}
@override
FutureOrResult<void> onSignOut() {
// TODO
}
@override
FutureOrResult<void> onDelete() {
// TODO
}
}
Sign Up
class ExampleSignUpCubit extends SignUpCubit<int> {
ExampleSignUpCubit({
required super.authenticationRepository,
});
@override
FutureOrResult<int?> onSignUpWithEmailAndPassword(Result<Account, AppException> result, WyattForm form) async {
// TODO
}
}
Sign In
class ExampleSignInCubit extends SignInCubit<int> {
ExampleSignInCubit({
required super.authenticationRepository,
});
@override
FutureOrResult<int?> onSignInWithEmailAndPassword(Result<Account, AppException> result, WyattForm form) {
// TODO
}
@override
FutureOrResult<int?> onSignInAnonymously(Result<Account, AppException> result, WyattForm form) {
// TODO
}
@override
FutureOrResult<int?> onSignInWithGoogle(Result<Account, AppException> result, WyattForm form) {
// TODO
}
}
After setting up all these cubits you can provide them in the application. And that's it!
BlocProvider<SignUpCubit<int>>(
create: (_) => ExampleSignUpCubit(
authenticationRepository: authenticationRepository,
),
),
BlocProvider<SignInCubit<int>>(
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.
AuthenticationBuilder<int>(
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.
Text('Home | ${context.account<AuthenticationCubit<int>, int>()?.email}'),
Listeners are used to listen to the status of the sign in and sign up forms.
return SignInListener<int>(
onError: (context, status, errorMessage) => ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(
SnackBar(content: Text(errorMessage ?? 'Sign In Failure')),
),
child: ...
);