master #81
@ -72,9 +72,9 @@ class AppRouter {
|
|||||||
state,
|
state,
|
||||||
const HomePage(),
|
const HomePage(),
|
||||||
),
|
),
|
||||||
),
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/home/sub',
|
path: 'sub',
|
||||||
name: SubPage.pageName,
|
name: SubPage.pageName,
|
||||||
pageBuilder: (context, state) => defaultTransition(
|
pageBuilder: (context, state) => defaultTransition(
|
||||||
context,
|
context,
|
||||||
@ -82,5 +82,6 @@ class AppRouter {
|
|||||||
const SubPage(),
|
const SubPage(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
]),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -30,19 +30,6 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
|
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
|
|
||||||
// FutureOrResult<int?> onAccountChanges(
|
|
||||||
// AuthenticationRepository<int> repo,
|
|
||||||
// AuthChangeEvent? authEvent,
|
|
||||||
// ) async {
|
|
||||||
// final id = Random().nextInt(1000);
|
|
||||||
// final token =
|
|
||||||
// await repo.getIdentityToken().fold((value) => value, (error) => 'null');
|
|
||||||
|
|
||||||
// debugPrint(
|
|
||||||
// 'onAccountChanges: ${authEvent?.account}, type: ${authEvent.runtimeType}, token: $token, generatedId: $id');
|
|
||||||
// return Ok<int, AppException>(id);
|
|
||||||
// }
|
|
||||||
|
|
||||||
class App extends StatelessWidget {
|
class App extends StatelessWidget {
|
||||||
final AuthenticationRepository<int> authenticationRepository =
|
final AuthenticationRepository<int> authenticationRepository =
|
||||||
AuthenticationRepositoryImpl(
|
AuthenticationRepositoryImpl(
|
||||||
@ -64,7 +51,9 @@ class App extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
AuthenticationState<int>? previous;
|
AuthenticationState<int>? previous;
|
||||||
|
|
||||||
final AuthenticationCubit<int> authenticationCubit = ExampleAuthenticationCubit(authenticationRepository: authenticationRepository);
|
final AuthenticationCubit<int> authenticationCubit =
|
||||||
|
ExampleAuthenticationCubit(
|
||||||
|
authenticationRepository: authenticationRepository);
|
||||||
|
|
||||||
final GoRouter router = GoRouter(
|
final GoRouter router = GoRouter(
|
||||||
initialLocation: '/',
|
initialLocation: '/',
|
||||||
@ -91,7 +80,7 @@ class App extends StatelessWidget {
|
|||||||
return '/home';
|
return '/home';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return state.name;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -49,4 +49,11 @@ class ExampleAuthenticationCubit extends AuthenticationCubit<int> {
|
|||||||
|
|
||||||
return const Ok(null);
|
return const Ok(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOrResult<void> onDelete() {
|
||||||
|
print('onDelete');
|
||||||
|
|
||||||
|
return const Ok(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,14 +35,20 @@ class SubPage extends StatelessWidget {
|
|||||||
icon: const Icon(Icons.logout_rounded)),
|
icon: const Icon(Icons.logout_rounded)),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
context.read<AuthenticationRepository<int>>().refresh(),
|
context.read<AuthenticationCubit<int>>().refresh(),
|
||||||
icon: const Icon(Icons.refresh))
|
icon: const Icon(Icons.refresh))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: const Padding(
|
body: Padding(
|
||||||
padding: EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: SingleChildScrollView(
|
child: ListView(
|
||||||
child: Text('Another page'),
|
children: [
|
||||||
|
const Text('Another page'),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => context.read<AuthenticationCubit<int>>().delete(),
|
||||||
|
child: const Text('Delete account'),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -35,7 +35,7 @@ class CustomRoutine<R, Data> {
|
|||||||
final FutureOr<Result<Data?, AppException>> Function(
|
final FutureOr<Result<Data?, AppException>> Function(
|
||||||
Result<R, AppException> routineResult,
|
Result<R, AppException> routineResult,
|
||||||
) attachedLogic;
|
) attachedLogic;
|
||||||
final void Function(AppException? exception) onError;
|
final void Function(AppException exception) onError;
|
||||||
final void Function(R result, Data? data) onSuccess;
|
final void Function(R result, Data? data) onSuccess;
|
||||||
|
|
||||||
FutureOr<void> call() async {
|
FutureOr<void> call() async {
|
||||||
@ -46,17 +46,17 @@ class CustomRoutine<R, Data> {
|
|||||||
|
|
||||||
// Check for errors
|
// Check for errors
|
||||||
if (result.isErr) {
|
if (result.isErr) {
|
||||||
onError.call(result.err);
|
onError.call(result.err!);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (customRoutineResult.isErr) {
|
if (customRoutineResult.isErr) {
|
||||||
onError.call(customRoutineResult.err);
|
onError.call(customRoutineResult.err!);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no error
|
// If no error
|
||||||
return onSuccess.call(result.ok as Input, customRoutineResult.ok);
|
return onSuccess.call(result.ok as R, customRoutineResult.ok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ abstract class AuthenticationCubit<Data>
|
|||||||
}
|
}
|
||||||
final AuthenticationRepository<Data> authenticationRepository;
|
final AuthenticationRepository<Data> authenticationRepository;
|
||||||
|
|
||||||
SessionWrapper<Data>? latestSession;
|
SessionWrapper<Data>? _latestSession;
|
||||||
|
|
||||||
void _listenForAuthenticationChanges() {
|
void _listenForAuthenticationChanges() {
|
||||||
authenticationRepository.sessionStream().asyncMap((wrapper) async {
|
authenticationRepository.sessionStream().asyncMap((wrapper) async {
|
||||||
@ -67,7 +67,7 @@ abstract class AuthenticationCubit<Data>
|
|||||||
}
|
}
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}).listen((wrapper) async {
|
}).listen((wrapper) async {
|
||||||
latestSession = wrapper;
|
_latestSession = wrapper;
|
||||||
final session = wrapper.session;
|
final session = wrapper.session;
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
emit(AuthenticationState<Data>.authenticated(wrapper));
|
emit(AuthenticationState<Data>.authenticated(wrapper));
|
||||||
@ -79,143 +79,59 @@ abstract class AuthenticationCubit<Data>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// {@macro refresh}
|
/// {@macro refresh}
|
||||||
FutureOr<void> refresh() async {
|
FutureOr<void> refresh() async => CustomRoutine<Account, Data?>(
|
||||||
final refreshedAccount = await authenticationRepository.refresh();
|
routine: authenticationRepository.refresh,
|
||||||
final customRoutineResult = await onRefresh(refreshedAccount);
|
attachedLogic: onRefresh,
|
||||||
|
onError: addError,
|
||||||
if (refreshedAccount.isOk && customRoutineResult.isOk) {
|
onSuccess: (result, data) => authenticationRepository.addSession(
|
||||||
final account = refreshedAccount.ok!;
|
SessionWrapper(
|
||||||
final sessionData = customRoutineResult.ok;
|
event: RefreshedEvent(account: result),
|
||||||
|
|
||||||
final refreshedSession = SessionWrapper(
|
|
||||||
event: RefreshedEvent(account: account),
|
|
||||||
session: Session<Data>(
|
session: Session<Data>(
|
||||||
account: account,
|
account: result,
|
||||||
data: sessionData,
|
data: data,
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
|
),
|
||||||
authenticationRepository.addSession(refreshedSession);
|
).call();
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (refreshedAccount.isErr) {
|
|
||||||
addError(refreshedAccount.err!);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customRoutineResult.isErr) {
|
|
||||||
addError(customRoutineResult.err!);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// {@macro reauthenticate}
|
/// {@macro reauthenticate}
|
||||||
FutureOr<void> reauthenticate() async {
|
FutureOr<void> reauthenticate() async => CustomRoutine<Account, Data?>(
|
||||||
final reauthenticatedAccount =
|
routine: authenticationRepository.reauthenticate,
|
||||||
await authenticationRepository.reauthenticate();
|
attachedLogic: onReauthenticate,
|
||||||
final customRoutineResult = await onReauthenticate(reauthenticatedAccount);
|
onError: addError,
|
||||||
|
onSuccess: (result, data) => authenticationRepository.addSession(
|
||||||
if (reauthenticatedAccount.isOk && customRoutineResult.isOk) {
|
SessionWrapper(
|
||||||
final account = reauthenticatedAccount.ok!;
|
event: ReauthenticatedEvent(account: result),
|
||||||
final sessionData = customRoutineResult.ok;
|
|
||||||
|
|
||||||
final reauthenticatedSession = SessionWrapper(
|
|
||||||
event: ReauthenticatedEvent(account: account),
|
|
||||||
session: Session<Data>(
|
session: Session<Data>(
|
||||||
account: account,
|
account: result,
|
||||||
data: sessionData,
|
data: data,
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
|
),
|
||||||
authenticationRepository.addSession(reauthenticatedSession);
|
).call();
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reauthenticatedAccount.isErr) {
|
|
||||||
addError(reauthenticatedAccount.err!);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customRoutineResult.isErr) {
|
|
||||||
addError(customRoutineResult.err!);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// {@macro signout}
|
/// {@macro signout}
|
||||||
FutureOr<void> signOut() async {
|
FutureOr<void> signOut() async => CustomRoutine<void, void>(
|
||||||
final customRoutine = CustomRoutine<void, void>(
|
routine: authenticationRepository.signOut,
|
||||||
// ignore: unnecessary_lambdas
|
|
||||||
routine: () => authenticationRepository.signOut(),
|
|
||||||
attachedLogic: (routineResult) => onSignOut(),
|
attachedLogic: (routineResult) => onSignOut(),
|
||||||
onError: (error) => addError(error!),
|
onError: addError,
|
||||||
onSuccess: (result, data) => authenticationRepository
|
onSuccess: (result, data) => authenticationRepository
|
||||||
.addSession(const SessionWrapper(event: SignedOutEvent())),
|
.addSession(SessionWrapper<Data>(event: const SignedOutEvent())),
|
||||||
);
|
).call();
|
||||||
|
|
||||||
customRoutine.call();
|
|
||||||
|
|
||||||
final signOut = await authenticationRepository.signOut();
|
|
||||||
|
|
||||||
final customRoutineResult = await onSignOut();
|
|
||||||
|
|
||||||
if (signOut.isOk && customRoutineResult.isOk) {
|
|
||||||
authenticationRepository
|
|
||||||
.addSession(const SessionWrapper(event: SignedOutEvent()));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signOut.isErr) {
|
|
||||||
addError(signOut.err!);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customRoutineResult.isErr) {
|
|
||||||
addError(customRoutineResult.err!);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// {@macro delete}
|
/// {@macro delete}
|
||||||
FutureOr<void> delete() async {
|
FutureOr<void> delete() async => CustomRoutine<void, void>(
|
||||||
final signOut = await authenticationRepository.delete();
|
routine: authenticationRepository.delete,
|
||||||
|
attachedLogic: (routineResult) => onDelete(),
|
||||||
final customRoutineResult = await onDelete();
|
onError: addError,
|
||||||
|
onSuccess: (result, data) => authenticationRepository
|
||||||
if (signOut.isOk && customRoutineResult.isOk) {
|
.addSession(SessionWrapper<Data>(event: const DeletedEvent())),
|
||||||
authenticationRepository
|
).call();
|
||||||
.addSession(const SessionWrapper(event: DeletedEvent()));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signOut.isErr) {
|
|
||||||
addError(signOut.err!);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customRoutineResult.isErr) {
|
|
||||||
addError(customRoutineResult.err!);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns latest session wrapper.
|
/// Returns latest session wrapper.
|
||||||
///
|
///
|
||||||
/// Contains latest event and latest session data (account + extra data)
|
/// Contains latest event and latest session data (account + extra data)
|
||||||
SessionWrapper<Data>? currentSession() => latestSession;
|
SessionWrapper<Data>? currentSession() => _latestSession;
|
||||||
|
|
||||||
/// This callback is triggered when the user is automaticcaly logged in from
|
/// This callback is triggered when the user is automaticcaly logged in from
|
||||||
/// the cache.
|
/// the cache.
|
||||||
|
@ -24,28 +24,22 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
|||||||
|
|
||||||
part 'password_reset_state.dart';
|
part 'password_reset_state.dart';
|
||||||
|
|
||||||
|
/// Cubit that allows user to reset his password
|
||||||
class PasswordResetCubit<Extra> extends FormDataCubit<PasswordResetState> {
|
class PasswordResetCubit<Extra> extends FormDataCubit<PasswordResetState> {
|
||||||
PasswordResetCubit({
|
PasswordResetCubit({
|
||||||
required this.authenticationRepository,
|
required this.authenticationRepository,
|
||||||
}) :
|
}) : super(
|
||||||
super(
|
|
||||||
PasswordResetState(
|
PasswordResetState(
|
||||||
form: authenticationRepository.formRepository
|
form: authenticationRepository.formRepository
|
||||||
.accessForm(AuthFormName.passwordResetForm),
|
.accessForm(AuthFormName.passwordResetForm),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final AuthenticationRepository<Extra> authenticationRepository;
|
final AuthenticationRepository<Extra> authenticationRepository;
|
||||||
FormRepository get formRepository =>
|
FormRepository get formRepository => authenticationRepository.formRepository;
|
||||||
authenticationRepository.formRepository;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formName => AuthFormName.passwordResetForm;
|
String get formName => AuthFormName.passwordResetForm;
|
||||||
|
|
||||||
void emailChanged(String value) {
|
|
||||||
final Email email = Email.dirty(value);
|
|
||||||
dataChanged(AuthFormField.email, email);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<void> dataChanged<Value>(
|
FutureOr<void> dataChanged<Value>(
|
||||||
String key,
|
String key,
|
||||||
@ -74,6 +68,33 @@ class PasswordResetCubit<Extra> extends FormDataCubit<PasswordResetState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> update(
|
||||||
|
WyattForm form, {
|
||||||
|
SetOperation operation = SetOperation.replace,
|
||||||
|
}) {
|
||||||
|
final WyattForm current = formRepository.accessForm(formName).clone();
|
||||||
|
final WyattForm newForm = operation.operation.call(current, form);
|
||||||
|
formRepository.updateForm(newForm);
|
||||||
|
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
form: newForm,
|
||||||
|
status: newForm.validate(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> validate() {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
status: formRepository.accessForm(formName).validate(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sends a password reset email to the user
|
||||||
@override
|
@override
|
||||||
FutureOr<void> submit() async {
|
FutureOr<void> submit() async {
|
||||||
if (!state.status.isValidated) {
|
if (!state.status.isValidated) {
|
||||||
@ -109,29 +130,29 @@ class PasswordResetCubit<Extra> extends FormDataCubit<PasswordResetState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
void emailChanged(String value) {
|
||||||
FutureOr<void> update(
|
final emailValidatorType = formRepository
|
||||||
WyattForm form, {
|
.accessForm(formName)
|
||||||
SetOperation operation = SetOperation.replace,
|
.validatorOf(AuthFormField.email)
|
||||||
}) {
|
.runtimeType;
|
||||||
final WyattForm current = formRepository.accessForm(formName).clone();
|
assert(
|
||||||
final WyattForm newForm = operation.operation.call(current, form);
|
emailValidatorType == Email,
|
||||||
formRepository.updateForm(newForm);
|
'Use emailCustomChanged(...) with validator $emailValidatorType',
|
||||||
|
|
||||||
emit(
|
|
||||||
state.copyWith(
|
|
||||||
form: newForm,
|
|
||||||
status: newForm.validate(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final Email email = Email.dirty(value);
|
||||||
|
dataChanged(AuthFormField.email, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
/// Same as [emailChanged] but with a custom [Validator].
|
||||||
FutureOr<void> validate() {
|
///
|
||||||
emit(
|
/// Sort of short hand for [dataChanged].
|
||||||
state.copyWith(
|
void emailCustomChanged<
|
||||||
status: formRepository.accessForm(formName).validate(),
|
Validator extends FormInputValidator<String?, ValidationError>>(
|
||||||
),
|
Validator validator,
|
||||||
);
|
) {
|
||||||
|
dataChanged(AuthFormField.email, validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(wyatt): create base_password_reset_cubit and create mixins
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
part of 'sign_in_cubit.dart';
|
part of 'sign_in_cubit.dart';
|
||||||
|
|
||||||
|
/// Abstract sign in cubit useful for implementing a cubit with fine
|
||||||
|
/// granularity by adding only the required mixins.
|
||||||
abstract class BaseSignInCubit<Data> extends FormDataCubit<SignInState> {
|
abstract class BaseSignInCubit<Data> extends FormDataCubit<SignInState> {
|
||||||
BaseSignInCubit({
|
BaseSignInCubit({
|
||||||
required this.authenticationRepository,
|
required this.authenticationRepository,
|
||||||
|
@ -17,17 +17,26 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||||
|
import 'package:wyatt_authentication_bloc/src/core/utils/custom_routine.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/entities.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/entities.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart';
|
import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart';
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
||||||
|
|
||||||
|
/// Sign in mixin.
|
||||||
|
///
|
||||||
|
/// Allows the user to sign in anonymously
|
||||||
|
///
|
||||||
|
/// Gives access to the `signInAnonymously` method and
|
||||||
|
/// `onSignInAnonymously` callback.
|
||||||
mixin SignInAnonymously<Data> on BaseSignInCubit<Data> {
|
mixin SignInAnonymously<Data> on BaseSignInCubit<Data> {
|
||||||
|
/// This callback is triggered when a user signs in anonymously.
|
||||||
FutureOrResult<Data?> onSignInAnonymously(
|
FutureOrResult<Data?> onSignInAnonymously(
|
||||||
Result<Account, AppException> result,
|
Result<Account, AppException> result,
|
||||||
WyattForm form,
|
WyattForm form,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// {@macro signin_anom}
|
||||||
FutureOr<void> signInAnonymously() async {
|
FutureOr<void> signInAnonymously() async {
|
||||||
if (state.status.isSubmissionInProgress) {
|
if (state.status.isSubmissionInProgress) {
|
||||||
return;
|
return;
|
||||||
@ -36,12 +45,13 @@ mixin SignInAnonymously<Data> on BaseSignInCubit<Data> {
|
|||||||
final form = formRepository.accessForm(formName);
|
final form = formRepository.accessForm(formName);
|
||||||
emit(SignInState(form: form, status: FormStatus.submissionInProgress));
|
emit(SignInState(form: form, status: FormStatus.submissionInProgress));
|
||||||
|
|
||||||
final result = await authenticationRepository.signInAnonymously();
|
return CustomRoutine<Account, Data?>(
|
||||||
|
routine: authenticationRepository.signInAnonymously,
|
||||||
// Custom routine
|
attachedLogic: (routineResult) => onSignInAnonymously(
|
||||||
final customRoutineResult = await onSignInAnonymously(result, form);
|
routineResult,
|
||||||
if (customRoutineResult.isErr) {
|
form,
|
||||||
final error = customRoutineResult.err!;
|
),
|
||||||
|
onError: (error) {
|
||||||
emit(
|
emit(
|
||||||
SignInState(
|
SignInState(
|
||||||
form: form,
|
form: form,
|
||||||
@ -50,43 +60,24 @@ mixin SignInAnonymously<Data> on BaseSignInCubit<Data> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
addError(error);
|
addError(error);
|
||||||
}
|
},
|
||||||
|
onSuccess: (account, data) {
|
||||||
// Check result
|
authenticationRepository.addSession(
|
||||||
if (result.isErr) {
|
SessionWrapper(
|
||||||
final error = result.err!;
|
|
||||||
emit(
|
|
||||||
SignInState(
|
|
||||||
form: form,
|
|
||||||
errorMessage: error.message,
|
|
||||||
status: FormStatus.submissionFailure,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
addError(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
final account = result.ok!;
|
|
||||||
|
|
||||||
final signedInSession = SessionWrapper(
|
|
||||||
event: SignedInEvent(account: account),
|
event: SignedInEvent(account: account),
|
||||||
session: Session<Data>(
|
session: Session<Data>(
|
||||||
account: account,
|
account: account,
|
||||||
data: customRoutineResult.ok,
|
data: data,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
authenticationRepository.addSession(signedInSession);
|
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
result.fold(
|
SignInState(
|
||||||
(value) =>
|
|
||||||
SignInState(form: form, status: FormStatus.submissionSuccess),
|
|
||||||
(error) => SignInState(
|
|
||||||
form: form,
|
form: form,
|
||||||
errorMessage: error.message,
|
status: FormStatus.submissionSuccess,
|
||||||
status: FormStatus.submissionFailure,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
).call();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,20 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart';
|
import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart';
|
||||||
|
import 'package:wyatt_authentication_bloc/src/core/utils/custom_routine.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/domain.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/domain.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart';
|
import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart';
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
||||||
|
|
||||||
|
/// Sign in mixin.
|
||||||
|
///
|
||||||
|
/// Allows the user to sign in with email and password
|
||||||
|
///
|
||||||
|
/// Gives access to the `signInWithEmailAndPassword` method and
|
||||||
|
/// `onSignInWithEmailAndPassword` callback.
|
||||||
mixin SignInWithEmailPassword<Data> on BaseSignInCubit<Data> {
|
mixin SignInWithEmailPassword<Data> on BaseSignInCubit<Data> {
|
||||||
|
/// This callback is triggered when a user signs in with email and password.
|
||||||
FutureOrResult<Data?> onSignInWithEmailAndPassword(
|
FutureOrResult<Data?> onSignInWithEmailAndPassword(
|
||||||
Result<Account, AppException> result,
|
Result<Account, AppException> result,
|
||||||
WyattForm form,
|
WyattForm form,
|
||||||
@ -76,6 +84,7 @@ mixin SignInWithEmailPassword<Data> on BaseSignInCubit<Data> {
|
|||||||
dataChanged(AuthFormField.password, validator);
|
dataChanged(AuthFormField.password, validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro signin_pwd}
|
||||||
FutureOr<void> signInWithEmailAndPassword() async {
|
FutureOr<void> signInWithEmailAndPassword() async {
|
||||||
if (state.status.isSubmissionInProgress) {
|
if (state.status.isSubmissionInProgress) {
|
||||||
return;
|
return;
|
||||||
@ -106,18 +115,16 @@ mixin SignInWithEmailPassword<Data> on BaseSignInCubit<Data> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final result = await authenticationRepository.signInWithEmailAndPassword(
|
return CustomRoutine<Account, Data?>(
|
||||||
|
routine: () => authenticationRepository.signInWithEmailAndPassword(
|
||||||
email: email!,
|
email: email!,
|
||||||
password: password!,
|
password: password!,
|
||||||
);
|
),
|
||||||
|
attachedLogic: (routineResult) => onSignInWithEmailAndPassword(
|
||||||
// Custom routine
|
routineResult,
|
||||||
final customRoutineResult = await onSignInWithEmailAndPassword(
|
|
||||||
result,
|
|
||||||
form,
|
form,
|
||||||
);
|
),
|
||||||
if (customRoutineResult.isErr) {
|
onError: (error) {
|
||||||
final error = customRoutineResult.err!;
|
|
||||||
emit(
|
emit(
|
||||||
SignInState(
|
SignInState(
|
||||||
form: form,
|
form: form,
|
||||||
@ -126,43 +133,24 @@ mixin SignInWithEmailPassword<Data> on BaseSignInCubit<Data> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
addError(error);
|
addError(error);
|
||||||
}
|
},
|
||||||
|
onSuccess: (account, data) {
|
||||||
// Check result
|
authenticationRepository.addSession(
|
||||||
if (result.isErr) {
|
SessionWrapper(
|
||||||
final error = result.err!;
|
|
||||||
emit(
|
|
||||||
SignInState(
|
|
||||||
form: form,
|
|
||||||
errorMessage: error.message,
|
|
||||||
status: FormStatus.submissionFailure,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
addError(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
final account = result.ok!;
|
|
||||||
|
|
||||||
final signedInSession = SessionWrapper(
|
|
||||||
event: SignedInEvent(account: account),
|
event: SignedInEvent(account: account),
|
||||||
session: Session<Data>(
|
session: Session<Data>(
|
||||||
account: account,
|
account: account,
|
||||||
data: customRoutineResult.ok,
|
data: data,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
authenticationRepository.addSession(signedInSession);
|
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
result.fold(
|
SignInState(
|
||||||
(value) =>
|
|
||||||
SignInState(form: form, status: FormStatus.submissionSuccess),
|
|
||||||
(error) => SignInState(
|
|
||||||
form: form,
|
form: form,
|
||||||
errorMessage: error.message,
|
status: FormStatus.submissionSuccess,
|
||||||
status: FormStatus.submissionFailure,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
).call();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,26 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||||
|
import 'package:wyatt_authentication_bloc/src/core/utils/custom_routine.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/entities.dart';
|
import 'package:wyatt_authentication_bloc/src/domain/entities/entities.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart';
|
import 'package:wyatt_authentication_bloc/src/features/sign_in/cubit/sign_in_cubit.dart';
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
||||||
|
|
||||||
|
/// Sign in mixin.
|
||||||
|
///
|
||||||
|
/// Allows the user to sign in with google
|
||||||
|
///
|
||||||
|
/// Gives access to the `signInWithGoogle` method and
|
||||||
|
/// `onSignInWithGoogle` callback.
|
||||||
mixin SignInWithGoogle<Data> on BaseSignInCubit<Data> {
|
mixin SignInWithGoogle<Data> on BaseSignInCubit<Data> {
|
||||||
|
/// This callback is triggered when a user signs in with google.
|
||||||
FutureOrResult<Data?> onSignInWithGoogle(
|
FutureOrResult<Data?> onSignInWithGoogle(
|
||||||
Result<Account, AppException> result,
|
Result<Account, AppException> result,
|
||||||
WyattForm form,
|
WyattForm form,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// {@macro signin_google}
|
||||||
FutureOr<void> signInWithGoogle() async {
|
FutureOr<void> signInWithGoogle() async {
|
||||||
if (state.status.isSubmissionInProgress) {
|
if (state.status.isSubmissionInProgress) {
|
||||||
return;
|
return;
|
||||||
@ -35,15 +44,13 @@ mixin SignInWithGoogle<Data> on BaseSignInCubit<Data> {
|
|||||||
final form = formRepository.accessForm(formName);
|
final form = formRepository.accessForm(formName);
|
||||||
emit(SignInState(form: form, status: FormStatus.submissionInProgress));
|
emit(SignInState(form: form, status: FormStatus.submissionInProgress));
|
||||||
|
|
||||||
final result = await authenticationRepository.signInWithGoogle();
|
return CustomRoutine<Account, Data?>(
|
||||||
|
routine: authenticationRepository.signInWithGoogle,
|
||||||
// Custom routine
|
attachedLogic: (routineResult) => onSignInWithGoogle(
|
||||||
final customRoutineResult = await onSignInWithGoogle(
|
routineResult,
|
||||||
result,
|
|
||||||
form,
|
form,
|
||||||
);
|
),
|
||||||
if (customRoutineResult.isErr) {
|
onError: (error) {
|
||||||
final error = customRoutineResult.err!;
|
|
||||||
emit(
|
emit(
|
||||||
SignInState(
|
SignInState(
|
||||||
form: form,
|
form: form,
|
||||||
@ -52,43 +59,24 @@ mixin SignInWithGoogle<Data> on BaseSignInCubit<Data> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
addError(error);
|
addError(error);
|
||||||
}
|
},
|
||||||
|
onSuccess: (account, data) {
|
||||||
// Check result
|
authenticationRepository.addSession(
|
||||||
if (result.isErr) {
|
SessionWrapper(
|
||||||
final error = result.err!;
|
|
||||||
emit(
|
|
||||||
SignInState(
|
|
||||||
form: form,
|
|
||||||
errorMessage: error.message,
|
|
||||||
status: FormStatus.submissionFailure,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
addError(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
final account = result.ok!;
|
|
||||||
|
|
||||||
final signedInSession = SessionWrapper(
|
|
||||||
event: SignedInEvent(account: account),
|
event: SignedInEvent(account: account),
|
||||||
session: Session<Data>(
|
session: Session<Data>(
|
||||||
account: account,
|
account: account,
|
||||||
data: customRoutineResult.ok,
|
data: data,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
authenticationRepository.addSession(signedInSession);
|
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
result.fold(
|
SignInState(
|
||||||
(value) =>
|
|
||||||
SignInState(form: form, status: FormStatus.submissionSuccess),
|
|
||||||
(error) => SignInState(
|
|
||||||
form: form,
|
form: form,
|
||||||
errorMessage: error.message,
|
status: FormStatus.submissionSuccess,
|
||||||
status: FormStatus.submissionFailure,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
).call();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,8 @@ part 'base_sign_in_cubit.dart';
|
|||||||
part 'sign_in_state.dart';
|
part 'sign_in_state.dart';
|
||||||
|
|
||||||
/// Fully featured sign in cubit.
|
/// Fully featured sign in cubit.
|
||||||
|
///
|
||||||
|
/// Sufficient in most cases. (Where fine granularity is not required.)
|
||||||
class SignInCubit<Data> extends BaseSignInCubit<Data>
|
class SignInCubit<Data> extends BaseSignInCubit<Data>
|
||||||
with
|
with
|
||||||
SignInAnonymously<Data>,
|
SignInAnonymously<Data>,
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
part of 'sign_in_cubit.dart';
|
part of 'sign_in_cubit.dart';
|
||||||
|
|
||||||
|
/// Sign in cubit state to manage the form.
|
||||||
class SignInState extends FormDataState {
|
class SignInState extends FormDataState {
|
||||||
const SignInState({
|
const SignInState({
|
||||||
required super.form,
|
required super.form,
|
||||||
|
@ -19,7 +19,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:wyatt_authentication_bloc/src/features/sign_in/sign_in.dart';
|
import 'package:wyatt_authentication_bloc/src/features/sign_in/sign_in.dart';
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
|
|
||||||
class SignInListener<Extra> extends StatelessWidget {
|
/// Widget that listens and builds a child based on the state of
|
||||||
|
/// the sign in cubit
|
||||||
|
class SignInListener<Data> extends StatelessWidget {
|
||||||
const SignInListener({
|
const SignInListener({
|
||||||
required this.child,
|
required this.child,
|
||||||
this.onProgress,
|
this.onProgress,
|
||||||
@ -41,7 +43,7 @@ class SignInListener<Extra> extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) =>
|
Widget build(BuildContext context) =>
|
||||||
BlocListener<SignInCubit<Extra>, SignInState>(
|
BlocListener<SignInCubit<Data>, SignInState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
if (customBuilder != null) {
|
if (customBuilder != null) {
|
||||||
return customBuilder!(context, state);
|
return customBuilder!(context, state);
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
part of 'sign_up_cubit.dart';
|
part of 'sign_up_cubit.dart';
|
||||||
|
|
||||||
|
/// Abstract sign up cubit useful for implementing a cubit with fine
|
||||||
|
/// granularity by adding only the required mixins.
|
||||||
abstract class BaseSignUpCubit<Data> extends FormDataCubit<SignUpState> {
|
abstract class BaseSignUpCubit<Data> extends FormDataCubit<SignUpState> {
|
||||||
BaseSignUpCubit({
|
BaseSignUpCubit({
|
||||||
required this.authenticationRepository,
|
required this.authenticationRepository,
|
||||||
|
@ -17,13 +17,20 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/core/constants/form_field.dart';
|
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
|
||||||
import 'package:wyatt_authentication_bloc/src/domain/entities/entities.dart';
|
|
||||||
import 'package:wyatt_authentication_bloc/src/features/sign_up/cubit/sign_up_cubit.dart';
|
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
||||||
|
|
||||||
|
/// Sign up mixin.
|
||||||
|
///
|
||||||
|
/// Allows the user to register with an email and a password.
|
||||||
|
///
|
||||||
|
/// Gives access to the `signUpWithEmailPassword` method and
|
||||||
|
/// `onSignUpWithEmailAndPassword` callback.
|
||||||
mixin SignUpWithEmailPassword<Data> on BaseSignUpCubit<Data> {
|
mixin SignUpWithEmailPassword<Data> on BaseSignUpCubit<Data> {
|
||||||
|
/// This callback is triggered when a user creates an account.
|
||||||
|
///
|
||||||
|
/// For example: when a user sign up in firebase.
|
||||||
FutureOrResult<Data?> onSignUpWithEmailAndPassword(
|
FutureOrResult<Data?> onSignUpWithEmailAndPassword(
|
||||||
Result<Account, AppException> result,
|
Result<Account, AppException> result,
|
||||||
WyattForm form,
|
WyattForm form,
|
||||||
@ -76,6 +83,7 @@ mixin SignUpWithEmailPassword<Data> on BaseSignUpCubit<Data> {
|
|||||||
dataChanged(AuthFormField.password, validator);
|
dataChanged(AuthFormField.password, validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro signup_pwd}
|
||||||
FutureOr<void> signUpWithEmailPassword() async {
|
FutureOr<void> signUpWithEmailPassword() async {
|
||||||
if (!state.status.isValidated) {
|
if (!state.status.isValidated) {
|
||||||
return;
|
return;
|
||||||
@ -97,18 +105,16 @@ mixin SignUpWithEmailPassword<Data> on BaseSignUpCubit<Data> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final result = await authenticationRepository.signUpWithEmailAndPassword(
|
return CustomRoutine<Account, Data?>(
|
||||||
|
routine: () => authenticationRepository.signUpWithEmailAndPassword(
|
||||||
email: email!,
|
email: email!,
|
||||||
password: password!,
|
password: password!,
|
||||||
);
|
),
|
||||||
|
attachedLogic: (routineResult) => onSignUpWithEmailAndPassword(
|
||||||
// Custom routine
|
routineResult,
|
||||||
final customRoutineResult = await onSignUpWithEmailAndPassword(
|
|
||||||
result,
|
|
||||||
form,
|
form,
|
||||||
);
|
),
|
||||||
if (customRoutineResult.isErr) {
|
onError: (error) {
|
||||||
final error = customRoutineResult.err!;
|
|
||||||
emit(
|
emit(
|
||||||
SignUpState(
|
SignUpState(
|
||||||
form: form,
|
form: form,
|
||||||
@ -117,45 +123,24 @@ mixin SignUpWithEmailPassword<Data> on BaseSignUpCubit<Data> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
addError(error);
|
addError(error);
|
||||||
}
|
},
|
||||||
|
onSuccess: (account, data) {
|
||||||
// Check result
|
authenticationRepository.addSession(
|
||||||
if (result.isErr) {
|
SessionWrapper(
|
||||||
final error = result.err!;
|
|
||||||
emit(
|
|
||||||
SignUpState(
|
|
||||||
form: form,
|
|
||||||
errorMessage: error.message,
|
|
||||||
status: FormStatus.submissionFailure,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
addError(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
final account = result.ok!;
|
|
||||||
|
|
||||||
final signedUpSession = SessionWrapper(
|
|
||||||
event: SignedUpEvent(account: account),
|
event: SignedUpEvent(account: account),
|
||||||
session: Session<Data>(
|
session: Session<Data>(
|
||||||
account: account,
|
account: account,
|
||||||
data: customRoutineResult.ok,
|
data: data,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
authenticationRepository.addSession(signedUpSession);
|
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
result.fold(
|
SignUpState(
|
||||||
(value) => SignUpState(
|
|
||||||
form: form,
|
form: form,
|
||||||
status: FormStatus.submissionSuccess,
|
status: FormStatus.submissionSuccess,
|
||||||
),
|
),
|
||||||
(error) => SignUpState(
|
|
||||||
form: form,
|
|
||||||
errorMessage: error.message,
|
|
||||||
status: FormStatus.submissionFailure,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
).call();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,9 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
|||||||
part 'base_sign_up_cubit.dart';
|
part 'base_sign_up_cubit.dart';
|
||||||
part 'sign_up_state.dart';
|
part 'sign_up_state.dart';
|
||||||
|
|
||||||
|
/// Fully featured sign up cubit.
|
||||||
|
///
|
||||||
|
/// Sufficient in most cases. (Where fine granularity is not required.)
|
||||||
class SignUpCubit<Data> extends BaseSignUpCubit<Data>
|
class SignUpCubit<Data> extends BaseSignUpCubit<Data>
|
||||||
with SignUpWithEmailPassword<Data> {
|
with SignUpWithEmailPassword<Data> {
|
||||||
SignUpCubit({required super.authenticationRepository});
|
SignUpCubit({required super.authenticationRepository});
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
part of 'sign_up_cubit.dart';
|
part of 'sign_up_cubit.dart';
|
||||||
|
|
||||||
|
/// Sign up cubit state to manage the form.
|
||||||
class SignUpState extends FormDataState {
|
class SignUpState extends FormDataState {
|
||||||
const SignUpState({
|
const SignUpState({
|
||||||
required super.form,
|
required super.form,
|
||||||
|
@ -19,7 +19,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:wyatt_authentication_bloc/src/features/sign_up/cubit/sign_up_cubit.dart';
|
import 'package:wyatt_authentication_bloc/src/features/sign_up/cubit/sign_up_cubit.dart';
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
|
|
||||||
class SignUpListener<Extra> extends StatelessWidget {
|
/// Widget that listens and builds a child based on the state of
|
||||||
|
/// the sign up cubit
|
||||||
|
class SignUpListener<Data> extends StatelessWidget {
|
||||||
const SignUpListener({
|
const SignUpListener({
|
||||||
required this.child,
|
required this.child,
|
||||||
this.onProgress,
|
this.onProgress,
|
||||||
@ -41,7 +43,7 @@ class SignUpListener<Extra> extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) =>
|
Widget build(BuildContext context) =>
|
||||||
BlocListener<SignUpCubit<Extra>, SignUpState>(
|
BlocListener<SignUpCubit<Data>, SignUpState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
if (customBuilder != null) {
|
if (customBuilder != null) {
|
||||||
return customBuilder!(context, state);
|
return customBuilder!(context, state);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user