milestone/stable-1-reconcile-auth-3 #176
@ -65,22 +65,23 @@ class AppRouter {
 | 
			
		||||
      ),
 | 
			
		||||
    ),
 | 
			
		||||
    GoRoute(
 | 
			
		||||
      path: '/home',
 | 
			
		||||
      name: HomePage.pageName,
 | 
			
		||||
      pageBuilder: (context, state) => defaultTransition(
 | 
			
		||||
        context,
 | 
			
		||||
        state,
 | 
			
		||||
        const HomePage(),
 | 
			
		||||
      ),
 | 
			
		||||
    ),
 | 
			
		||||
    GoRoute(
 | 
			
		||||
      path: '/home/sub',
 | 
			
		||||
      name: SubPage.pageName,
 | 
			
		||||
      pageBuilder: (context, state) => defaultTransition(
 | 
			
		||||
        context,
 | 
			
		||||
        state,
 | 
			
		||||
        const SubPage(),
 | 
			
		||||
      ),
 | 
			
		||||
    ),
 | 
			
		||||
        path: '/home',
 | 
			
		||||
        name: HomePage.pageName,
 | 
			
		||||
        pageBuilder: (context, state) => defaultTransition(
 | 
			
		||||
              context,
 | 
			
		||||
              state,
 | 
			
		||||
              const HomePage(),
 | 
			
		||||
            ),
 | 
			
		||||
        routes: [
 | 
			
		||||
          GoRoute(
 | 
			
		||||
            path: 'sub',
 | 
			
		||||
            name: SubPage.pageName,
 | 
			
		||||
            pageBuilder: (context, state) => defaultTransition(
 | 
			
		||||
              context,
 | 
			
		||||
              state,
 | 
			
		||||
              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_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 {
 | 
			
		||||
  final AuthenticationRepository<int> authenticationRepository =
 | 
			
		||||
      AuthenticationRepositoryImpl(
 | 
			
		||||
@ -64,7 +51,9 @@ class App extends StatelessWidget {
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    AuthenticationState<int>? previous;
 | 
			
		||||
 | 
			
		||||
    final AuthenticationCubit<int> authenticationCubit = ExampleAuthenticationCubit(authenticationRepository: authenticationRepository);
 | 
			
		||||
    final AuthenticationCubit<int> authenticationCubit =
 | 
			
		||||
        ExampleAuthenticationCubit(
 | 
			
		||||
            authenticationRepository: authenticationRepository);
 | 
			
		||||
 | 
			
		||||
    final GoRouter router = GoRouter(
 | 
			
		||||
      initialLocation: '/',
 | 
			
		||||
@ -91,7 +80,7 @@ class App extends StatelessWidget {
 | 
			
		||||
            return '/home';
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
        return state.name;
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -49,4 +49,11 @@ class ExampleAuthenticationCubit extends AuthenticationCubit<int> {
 | 
			
		||||
 | 
			
		||||
    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)),
 | 
			
		||||
          IconButton(
 | 
			
		||||
              onPressed: () =>
 | 
			
		||||
                  context.read<AuthenticationRepository<int>>().refresh(),
 | 
			
		||||
                  context.read<AuthenticationCubit<int>>().refresh(),
 | 
			
		||||
              icon: const Icon(Icons.refresh))
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
      body: const Padding(
 | 
			
		||||
        padding: EdgeInsets.all(8),
 | 
			
		||||
        child: SingleChildScrollView(
 | 
			
		||||
          child: Text('Another page'),
 | 
			
		||||
      body: Padding(
 | 
			
		||||
        padding: const EdgeInsets.all(8),
 | 
			
		||||
        child: ListView(
 | 
			
		||||
          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(
 | 
			
		||||
    Result<R, AppException> routineResult,
 | 
			
		||||
  ) attachedLogic;
 | 
			
		||||
  final void Function(AppException? exception) onError;
 | 
			
		||||
  final void Function(AppException exception) onError;
 | 
			
		||||
  final void Function(R result, Data? data) onSuccess;
 | 
			
		||||
 | 
			
		||||
  FutureOr<void> call() async {
 | 
			
		||||
@ -46,17 +46,17 @@ class CustomRoutine<R, Data> {
 | 
			
		||||
 | 
			
		||||
    // Check for errors
 | 
			
		||||
    if (result.isErr) {
 | 
			
		||||
      onError.call(result.err);
 | 
			
		||||
      onError.call(result.err!);
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (customRoutineResult.isErr) {
 | 
			
		||||
      onError.call(customRoutineResult.err);
 | 
			
		||||
      onError.call(customRoutineResult.err!);
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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;
 | 
			
		||||
 | 
			
		||||
  SessionWrapper<Data>? latestSession;
 | 
			
		||||
  SessionWrapper<Data>? _latestSession;
 | 
			
		||||
 | 
			
		||||
  void _listenForAuthenticationChanges() {
 | 
			
		||||
    authenticationRepository.sessionStream().asyncMap((wrapper) async {
 | 
			
		||||
@ -67,7 +67,7 @@ abstract class AuthenticationCubit<Data>
 | 
			
		||||
      }
 | 
			
		||||
      return wrapper;
 | 
			
		||||
    }).listen((wrapper) async {
 | 
			
		||||
      latestSession = wrapper;
 | 
			
		||||
      _latestSession = wrapper;
 | 
			
		||||
      final session = wrapper.session;
 | 
			
		||||
      if (session != null) {
 | 
			
		||||
        emit(AuthenticationState<Data>.authenticated(wrapper));
 | 
			
		||||
@ -79,143 +79,59 @@ abstract class AuthenticationCubit<Data>
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// {@macro refresh}
 | 
			
		||||
  FutureOr<void> refresh() async {
 | 
			
		||||
    final refreshedAccount = await authenticationRepository.refresh();
 | 
			
		||||
    final customRoutineResult = await onRefresh(refreshedAccount);
 | 
			
		||||
 | 
			
		||||
    if (refreshedAccount.isOk && customRoutineResult.isOk) {
 | 
			
		||||
      final account = refreshedAccount.ok!;
 | 
			
		||||
      final sessionData = customRoutineResult.ok;
 | 
			
		||||
 | 
			
		||||
      final refreshedSession = SessionWrapper(
 | 
			
		||||
        event: RefreshedEvent(account: account),
 | 
			
		||||
        session: Session<Data>(
 | 
			
		||||
          account: account,
 | 
			
		||||
          data: sessionData,
 | 
			
		||||
  FutureOr<void> refresh() async => CustomRoutine<Account, Data?>(
 | 
			
		||||
      routine: authenticationRepository.refresh,
 | 
			
		||||
      attachedLogic: onRefresh,
 | 
			
		||||
      onError: addError,
 | 
			
		||||
      onSuccess: (result, data) => authenticationRepository.addSession(
 | 
			
		||||
        SessionWrapper(
 | 
			
		||||
          event: RefreshedEvent(account: result),
 | 
			
		||||
          session: Session<Data>(
 | 
			
		||||
            account: result,
 | 
			
		||||
            data: data,
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      authenticationRepository.addSession(refreshedSession);
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (refreshedAccount.isErr) {
 | 
			
		||||
      addError(refreshedAccount.err!);
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (customRoutineResult.isErr) {
 | 
			
		||||
      addError(customRoutineResult.err!);
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
      ),
 | 
			
		||||
    ).call();
 | 
			
		||||
 | 
			
		||||
  /// {@macro reauthenticate}
 | 
			
		||||
  FutureOr<void> reauthenticate() async {
 | 
			
		||||
    final reauthenticatedAccount =
 | 
			
		||||
        await authenticationRepository.reauthenticate();
 | 
			
		||||
    final customRoutineResult = await onReauthenticate(reauthenticatedAccount);
 | 
			
		||||
 | 
			
		||||
    if (reauthenticatedAccount.isOk && customRoutineResult.isOk) {
 | 
			
		||||
      final account = reauthenticatedAccount.ok!;
 | 
			
		||||
      final sessionData = customRoutineResult.ok;
 | 
			
		||||
 | 
			
		||||
      final reauthenticatedSession = SessionWrapper(
 | 
			
		||||
        event: ReauthenticatedEvent(account: account),
 | 
			
		||||
        session: Session<Data>(
 | 
			
		||||
          account: account,
 | 
			
		||||
          data: sessionData,
 | 
			
		||||
  FutureOr<void> reauthenticate() async => CustomRoutine<Account, Data?>(
 | 
			
		||||
        routine: authenticationRepository.reauthenticate,
 | 
			
		||||
        attachedLogic: onReauthenticate,
 | 
			
		||||
        onError: addError,
 | 
			
		||||
        onSuccess: (result, data) => authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: ReauthenticatedEvent(account: result),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: result,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      authenticationRepository.addSession(reauthenticatedSession);
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (reauthenticatedAccount.isErr) {
 | 
			
		||||
      addError(reauthenticatedAccount.err!);
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (customRoutineResult.isErr) {
 | 
			
		||||
      addError(customRoutineResult.err!);
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
      ).call();
 | 
			
		||||
 | 
			
		||||
  /// {@macro signout}
 | 
			
		||||
  FutureOr<void> signOut() async {
 | 
			
		||||
    final customRoutine = CustomRoutine<void, void>(
 | 
			
		||||
      // ignore: unnecessary_lambdas
 | 
			
		||||
      routine: () => authenticationRepository.signOut(),
 | 
			
		||||
      attachedLogic: (routineResult) => onSignOut(),
 | 
			
		||||
      onError: (error) => addError(error!),
 | 
			
		||||
      onSuccess: (result, data) => authenticationRepository
 | 
			
		||||
          .addSession(const SessionWrapper(event: SignedOutEvent())),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  FutureOr<void> signOut() async => CustomRoutine<void, void>(
 | 
			
		||||
        routine: authenticationRepository.signOut,
 | 
			
		||||
        attachedLogic: (routineResult) => onSignOut(),
 | 
			
		||||
        onError: addError,
 | 
			
		||||
        onSuccess: (result, data) => authenticationRepository
 | 
			
		||||
            .addSession(SessionWrapper<Data>(event: const SignedOutEvent())),
 | 
			
		||||
      ).call();
 | 
			
		||||
 | 
			
		||||
  /// {@macro delete}
 | 
			
		||||
  FutureOr<void> delete() async {
 | 
			
		||||
    final signOut = await authenticationRepository.delete();
 | 
			
		||||
 | 
			
		||||
    final customRoutineResult = await onDelete();
 | 
			
		||||
 | 
			
		||||
    if (signOut.isOk && customRoutineResult.isOk) {
 | 
			
		||||
      authenticationRepository
 | 
			
		||||
          .addSession(const SessionWrapper(event: DeletedEvent()));
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (signOut.isErr) {
 | 
			
		||||
      addError(signOut.err!);
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (customRoutineResult.isErr) {
 | 
			
		||||
      addError(customRoutineResult.err!);
 | 
			
		||||
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  FutureOr<void> delete() async => CustomRoutine<void, void>(
 | 
			
		||||
        routine: authenticationRepository.delete,
 | 
			
		||||
        attachedLogic: (routineResult) => onDelete(),
 | 
			
		||||
        onError: addError,
 | 
			
		||||
        onSuccess: (result, data) => authenticationRepository
 | 
			
		||||
            .addSession(SessionWrapper<Data>(event: const DeletedEvent())),
 | 
			
		||||
      ).call();
 | 
			
		||||
 | 
			
		||||
  /// Returns latest session wrapper.
 | 
			
		||||
  ///
 | 
			
		||||
  /// 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
 | 
			
		||||
  /// the cache.
 | 
			
		||||
 | 
			
		||||
@ -24,28 +24,22 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
			
		||||
 | 
			
		||||
part 'password_reset_state.dart';
 | 
			
		||||
 | 
			
		||||
/// Cubit that allows user to reset his password
 | 
			
		||||
class PasswordResetCubit<Extra> extends FormDataCubit<PasswordResetState> {
 | 
			
		||||
  PasswordResetCubit({
 | 
			
		||||
    required this.authenticationRepository,
 | 
			
		||||
  })  : 
 | 
			
		||||
        super(
 | 
			
		||||
  }) : super(
 | 
			
		||||
          PasswordResetState(
 | 
			
		||||
            form: authenticationRepository.formRepository
 | 
			
		||||
                .accessForm(AuthFormName.passwordResetForm),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
  final AuthenticationRepository<Extra> authenticationRepository;
 | 
			
		||||
  FormRepository get formRepository =>
 | 
			
		||||
      authenticationRepository.formRepository;
 | 
			
		||||
  FormRepository get formRepository => authenticationRepository.formRepository;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String get formName => AuthFormName.passwordResetForm;
 | 
			
		||||
 | 
			
		||||
  void emailChanged(String value) {
 | 
			
		||||
    final Email email = Email.dirty(value);
 | 
			
		||||
    dataChanged(AuthFormField.email, email);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOr<void> dataChanged<Value>(
 | 
			
		||||
    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
 | 
			
		||||
  FutureOr<void> submit() async {
 | 
			
		||||
    if (!state.status.isValidated) {
 | 
			
		||||
@ -109,29 +130,29 @@ 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(),
 | 
			
		||||
      ),
 | 
			
		||||
  void emailChanged(String value) {
 | 
			
		||||
    final emailValidatorType = formRepository
 | 
			
		||||
        .accessForm(formName)
 | 
			
		||||
        .validatorOf(AuthFormField.email)
 | 
			
		||||
        .runtimeType;
 | 
			
		||||
    assert(
 | 
			
		||||
      emailValidatorType == Email,
 | 
			
		||||
      'Use emailCustomChanged(...) with validator $emailValidatorType',
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    final Email email = Email.dirty(value);
 | 
			
		||||
    dataChanged(AuthFormField.email, email);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOr<void> validate() {
 | 
			
		||||
    emit(
 | 
			
		||||
      state.copyWith(
 | 
			
		||||
        status: formRepository.accessForm(formName).validate(),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  /// Same as [emailChanged] but with a custom [Validator].
 | 
			
		||||
  ///
 | 
			
		||||
  /// Sort of short hand for [dataChanged].
 | 
			
		||||
  void emailCustomChanged<
 | 
			
		||||
      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';
 | 
			
		||||
 | 
			
		||||
/// 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> {
 | 
			
		||||
  BaseSignInCubit({
 | 
			
		||||
    required this.authenticationRepository,
 | 
			
		||||
 | 
			
		||||
@ -17,17 +17,26 @@
 | 
			
		||||
import 'dart:async';
 | 
			
		||||
 | 
			
		||||
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/features/sign_in/cubit/sign_in_cubit.dart';
 | 
			
		||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.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> {
 | 
			
		||||
  /// This callback is triggered when a user signs in anonymously.
 | 
			
		||||
  FutureOrResult<Data?> onSignInAnonymously(
 | 
			
		||||
    Result<Account, AppException> result,
 | 
			
		||||
    WyattForm form,
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  /// {@macro signin_anom}
 | 
			
		||||
  FutureOr<void> signInAnonymously() async {
 | 
			
		||||
    if (state.status.isSubmissionInProgress) {
 | 
			
		||||
      return;
 | 
			
		||||
@ -36,57 +45,39 @@ mixin SignInAnonymously<Data> on BaseSignInCubit<Data> {
 | 
			
		||||
    final form = formRepository.accessForm(formName);
 | 
			
		||||
    emit(SignInState(form: form, status: FormStatus.submissionInProgress));
 | 
			
		||||
 | 
			
		||||
    final result = await authenticationRepository.signInAnonymously();
 | 
			
		||||
 | 
			
		||||
    // Custom routine
 | 
			
		||||
    final customRoutineResult = await onSignInAnonymously(result, form);
 | 
			
		||||
    if (customRoutineResult.isErr) {
 | 
			
		||||
      final error = customRoutineResult.err!;
 | 
			
		||||
      emit(
 | 
			
		||||
        SignInState(
 | 
			
		||||
          form: form,
 | 
			
		||||
          errorMessage: error.message,
 | 
			
		||||
          status: FormStatus.submissionFailure,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
      addError(error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check result
 | 
			
		||||
    if (result.isErr) {
 | 
			
		||||
      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),
 | 
			
		||||
      session: Session<Data>(
 | 
			
		||||
        account: account,
 | 
			
		||||
        data: customRoutineResult.ok,
 | 
			
		||||
    return CustomRoutine<Account, Data?>(
 | 
			
		||||
      routine: authenticationRepository.signInAnonymously,
 | 
			
		||||
      attachedLogic: (routineResult) => onSignInAnonymously(
 | 
			
		||||
        routineResult,
 | 
			
		||||
        form,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    authenticationRepository.addSession(signedInSession);
 | 
			
		||||
 | 
			
		||||
    emit(
 | 
			
		||||
      result.fold(
 | 
			
		||||
        (value) =>
 | 
			
		||||
            SignInState(form: form, status: FormStatus.submissionSuccess),
 | 
			
		||||
        (error) => SignInState(
 | 
			
		||||
          form: form,
 | 
			
		||||
          errorMessage: error.message,
 | 
			
		||||
          status: FormStatus.submissionFailure,
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
      onError: (error) {
 | 
			
		||||
        emit(
 | 
			
		||||
          SignInState(
 | 
			
		||||
            form: form,
 | 
			
		||||
            errorMessage: error.message,
 | 
			
		||||
            status: FormStatus.submissionFailure,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        addError(error);
 | 
			
		||||
      },
 | 
			
		||||
      onSuccess: (account, data) {
 | 
			
		||||
        authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: SignedInEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        emit(
 | 
			
		||||
          SignInState(
 | 
			
		||||
            form: form,
 | 
			
		||||
            status: FormStatus.submissionSuccess,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    ).call();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -18,12 +18,20 @@ import 'dart:async';
 | 
			
		||||
 | 
			
		||||
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/utils/custom_routine.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_form_bloc/wyatt_form_bloc.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> {
 | 
			
		||||
  /// This callback is triggered when a user signs in with email and password.
 | 
			
		||||
  FutureOrResult<Data?> onSignInWithEmailAndPassword(
 | 
			
		||||
    Result<Account, AppException> result,
 | 
			
		||||
    WyattForm form,
 | 
			
		||||
@ -76,6 +84,7 @@ mixin SignInWithEmailPassword<Data> on BaseSignInCubit<Data> {
 | 
			
		||||
    dataChanged(AuthFormField.password, validator);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// {@macro signin_pwd}
 | 
			
		||||
  FutureOr<void> signInWithEmailAndPassword() async {
 | 
			
		||||
    if (state.status.isSubmissionInProgress) {
 | 
			
		||||
      return;
 | 
			
		||||
@ -106,63 +115,42 @@ mixin SignInWithEmailPassword<Data> on BaseSignInCubit<Data> {
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final result = await authenticationRepository.signInWithEmailAndPassword(
 | 
			
		||||
      email: email!,
 | 
			
		||||
      password: password!,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Custom routine
 | 
			
		||||
    final customRoutineResult = await onSignInWithEmailAndPassword(
 | 
			
		||||
      result,
 | 
			
		||||
      form,
 | 
			
		||||
    );
 | 
			
		||||
    if (customRoutineResult.isErr) {
 | 
			
		||||
      final error = customRoutineResult.err!;
 | 
			
		||||
      emit(
 | 
			
		||||
        SignInState(
 | 
			
		||||
          form: form,
 | 
			
		||||
          errorMessage: error.message,
 | 
			
		||||
          status: FormStatus.submissionFailure,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
      addError(error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check result
 | 
			
		||||
    if (result.isErr) {
 | 
			
		||||
      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),
 | 
			
		||||
      session: Session<Data>(
 | 
			
		||||
        account: account,
 | 
			
		||||
        data: customRoutineResult.ok,
 | 
			
		||||
    return CustomRoutine<Account, Data?>(
 | 
			
		||||
      routine: () => authenticationRepository.signInWithEmailAndPassword(
 | 
			
		||||
        email: email!,
 | 
			
		||||
        password: password!,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    authenticationRepository.addSession(signedInSession);
 | 
			
		||||
 | 
			
		||||
    emit(
 | 
			
		||||
      result.fold(
 | 
			
		||||
        (value) =>
 | 
			
		||||
            SignInState(form: form, status: FormStatus.submissionSuccess),
 | 
			
		||||
        (error) => SignInState(
 | 
			
		||||
          form: form,
 | 
			
		||||
          errorMessage: error.message,
 | 
			
		||||
          status: FormStatus.submissionFailure,
 | 
			
		||||
        ),
 | 
			
		||||
      attachedLogic: (routineResult) => onSignInWithEmailAndPassword(
 | 
			
		||||
        routineResult,
 | 
			
		||||
        form,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
      onError: (error) {
 | 
			
		||||
        emit(
 | 
			
		||||
          SignInState(
 | 
			
		||||
            form: form,
 | 
			
		||||
            errorMessage: error.message,
 | 
			
		||||
            status: FormStatus.submissionFailure,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        addError(error);
 | 
			
		||||
      },
 | 
			
		||||
      onSuccess: (account, data) {
 | 
			
		||||
        authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: SignedInEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        emit(
 | 
			
		||||
          SignInState(
 | 
			
		||||
            form: form,
 | 
			
		||||
            status: FormStatus.submissionSuccess,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    ).call();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,17 +17,26 @@
 | 
			
		||||
import 'dart:async';
 | 
			
		||||
 | 
			
		||||
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/features/sign_in/cubit/sign_in_cubit.dart';
 | 
			
		||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.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> {
 | 
			
		||||
  /// This callback is triggered when a user signs in with google.
 | 
			
		||||
  FutureOrResult<Data?> onSignInWithGoogle(
 | 
			
		||||
    Result<Account, AppException> result,
 | 
			
		||||
    WyattForm form,
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  /// {@macro signin_google}
 | 
			
		||||
  FutureOr<void> signInWithGoogle() async {
 | 
			
		||||
    if (state.status.isSubmissionInProgress) {
 | 
			
		||||
      return;
 | 
			
		||||
@ -35,60 +44,39 @@ mixin SignInWithGoogle<Data> on BaseSignInCubit<Data> {
 | 
			
		||||
    final form = formRepository.accessForm(formName);
 | 
			
		||||
    emit(SignInState(form: form, status: FormStatus.submissionInProgress));
 | 
			
		||||
 | 
			
		||||
    final result = await authenticationRepository.signInWithGoogle();
 | 
			
		||||
 | 
			
		||||
    // Custom routine
 | 
			
		||||
    final customRoutineResult = await onSignInWithGoogle(
 | 
			
		||||
      result,
 | 
			
		||||
      form,
 | 
			
		||||
    );
 | 
			
		||||
    if (customRoutineResult.isErr) {
 | 
			
		||||
      final error = customRoutineResult.err!;
 | 
			
		||||
      emit(
 | 
			
		||||
        SignInState(
 | 
			
		||||
          form: form,
 | 
			
		||||
          errorMessage: error.message,
 | 
			
		||||
          status: FormStatus.submissionFailure,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
      addError(error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check result
 | 
			
		||||
    if (result.isErr) {
 | 
			
		||||
      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),
 | 
			
		||||
      session: Session<Data>(
 | 
			
		||||
        account: account,
 | 
			
		||||
        data: customRoutineResult.ok,
 | 
			
		||||
    return CustomRoutine<Account, Data?>(
 | 
			
		||||
      routine: authenticationRepository.signInWithGoogle,
 | 
			
		||||
      attachedLogic: (routineResult) => onSignInWithGoogle(
 | 
			
		||||
        routineResult,
 | 
			
		||||
        form,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    authenticationRepository.addSession(signedInSession);
 | 
			
		||||
 | 
			
		||||
    emit(
 | 
			
		||||
      result.fold(
 | 
			
		||||
        (value) =>
 | 
			
		||||
            SignInState(form: form, status: FormStatus.submissionSuccess),
 | 
			
		||||
        (error) => SignInState(
 | 
			
		||||
          form: form,
 | 
			
		||||
          errorMessage: error.message,
 | 
			
		||||
          status: FormStatus.submissionFailure,
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
      onError: (error) {
 | 
			
		||||
        emit(
 | 
			
		||||
          SignInState(
 | 
			
		||||
            form: form,
 | 
			
		||||
            errorMessage: error.message,
 | 
			
		||||
            status: FormStatus.submissionFailure,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        addError(error);
 | 
			
		||||
      },
 | 
			
		||||
      onSuccess: (account, data) {
 | 
			
		||||
        authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: SignedInEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        emit(
 | 
			
		||||
          SignInState(
 | 
			
		||||
            form: form,
 | 
			
		||||
            status: FormStatus.submissionSuccess,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    ).call();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,8 @@ part 'base_sign_in_cubit.dart';
 | 
			
		||||
part 'sign_in_state.dart';
 | 
			
		||||
 | 
			
		||||
/// Fully featured sign in cubit.
 | 
			
		||||
/// 
 | 
			
		||||
/// Sufficient in most cases. (Where fine granularity is not required.)
 | 
			
		||||
class SignInCubit<Data> extends BaseSignInCubit<Data>
 | 
			
		||||
    with
 | 
			
		||||
        SignInAnonymously<Data>,
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@
 | 
			
		||||
 | 
			
		||||
part of 'sign_in_cubit.dart';
 | 
			
		||||
 | 
			
		||||
/// Sign in cubit state to manage the form.
 | 
			
		||||
class SignInState extends FormDataState {
 | 
			
		||||
  const SignInState({
 | 
			
		||||
    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_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({
 | 
			
		||||
    required this.child,
 | 
			
		||||
    this.onProgress,
 | 
			
		||||
@ -41,7 +43,7 @@ class SignInListener<Extra> extends StatelessWidget {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) =>
 | 
			
		||||
      BlocListener<SignInCubit<Extra>, SignInState>(
 | 
			
		||||
      BlocListener<SignInCubit<Data>, SignInState>(
 | 
			
		||||
        listener: (context, state) {
 | 
			
		||||
          if (customBuilder != null) {
 | 
			
		||||
            return customBuilder!(context, state);
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,8 @@
 | 
			
		||||
 | 
			
		||||
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> {
 | 
			
		||||
  BaseSignUpCubit({
 | 
			
		||||
    required this.authenticationRepository,
 | 
			
		||||
 | 
			
		||||
@ -17,13 +17,20 @@
 | 
			
		||||
import 'dart:async';
 | 
			
		||||
 | 
			
		||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/core/constants/form_field.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_authentication_bloc/wyatt_authentication_bloc.dart';
 | 
			
		||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.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> {
 | 
			
		||||
  /// This callback is triggered when a user creates an account.
 | 
			
		||||
  ///
 | 
			
		||||
  /// For example: when a user sign up in firebase.
 | 
			
		||||
  FutureOrResult<Data?> onSignUpWithEmailAndPassword(
 | 
			
		||||
    Result<Account, AppException> result,
 | 
			
		||||
    WyattForm form,
 | 
			
		||||
@ -76,6 +83,7 @@ mixin SignUpWithEmailPassword<Data> on BaseSignUpCubit<Data> {
 | 
			
		||||
    dataChanged(AuthFormField.password, validator);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// {@macro signup_pwd}
 | 
			
		||||
  FutureOr<void> signUpWithEmailPassword() async {
 | 
			
		||||
    if (!state.status.isValidated) {
 | 
			
		||||
      return;
 | 
			
		||||
@ -97,65 +105,42 @@ mixin SignUpWithEmailPassword<Data> on BaseSignUpCubit<Data> {
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final result = await authenticationRepository.signUpWithEmailAndPassword(
 | 
			
		||||
      email: email!,
 | 
			
		||||
      password: password!,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Custom routine
 | 
			
		||||
    final customRoutineResult = await onSignUpWithEmailAndPassword(
 | 
			
		||||
      result,
 | 
			
		||||
      form,
 | 
			
		||||
    );
 | 
			
		||||
    if (customRoutineResult.isErr) {
 | 
			
		||||
      final error = customRoutineResult.err!;
 | 
			
		||||
      emit(
 | 
			
		||||
        SignUpState(
 | 
			
		||||
          form: form,
 | 
			
		||||
          errorMessage: error.message,
 | 
			
		||||
          status: FormStatus.submissionFailure,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
      addError(error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check result
 | 
			
		||||
    if (result.isErr) {
 | 
			
		||||
      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),
 | 
			
		||||
      session: Session<Data>(
 | 
			
		||||
        account: account,
 | 
			
		||||
        data: customRoutineResult.ok,
 | 
			
		||||
    return CustomRoutine<Account, Data?>(
 | 
			
		||||
      routine: () => authenticationRepository.signUpWithEmailAndPassword(
 | 
			
		||||
        email: email!,
 | 
			
		||||
        password: password!,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    authenticationRepository.addSession(signedUpSession);
 | 
			
		||||
 | 
			
		||||
    emit(
 | 
			
		||||
      result.fold(
 | 
			
		||||
        (value) => SignUpState(
 | 
			
		||||
          form: form,
 | 
			
		||||
          status: FormStatus.submissionSuccess,
 | 
			
		||||
        ),
 | 
			
		||||
        (error) => SignUpState(
 | 
			
		||||
          form: form,
 | 
			
		||||
          errorMessage: error.message,
 | 
			
		||||
          status: FormStatus.submissionFailure,
 | 
			
		||||
        ),
 | 
			
		||||
      attachedLogic: (routineResult) => onSignUpWithEmailAndPassword(
 | 
			
		||||
        routineResult,
 | 
			
		||||
        form,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
      onError: (error) {
 | 
			
		||||
        emit(
 | 
			
		||||
          SignUpState(
 | 
			
		||||
            form: form,
 | 
			
		||||
            errorMessage: error.message,
 | 
			
		||||
            status: FormStatus.submissionFailure,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        addError(error);
 | 
			
		||||
      },
 | 
			
		||||
      onSuccess: (account, data) {
 | 
			
		||||
        authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: SignedUpEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        emit(
 | 
			
		||||
          SignUpState(
 | 
			
		||||
            form: form,
 | 
			
		||||
            status: FormStatus.submissionSuccess,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    ).call();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,9 @@ import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
			
		||||
part 'base_sign_up_cubit.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>
 | 
			
		||||
    with SignUpWithEmailPassword<Data> {
 | 
			
		||||
  SignUpCubit({required super.authenticationRepository});
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@
 | 
			
		||||
 | 
			
		||||
part of 'sign_up_cubit.dart';
 | 
			
		||||
 | 
			
		||||
/// Sign up cubit state to manage the form.
 | 
			
		||||
class SignUpState extends FormDataState {
 | 
			
		||||
  const SignUpState({
 | 
			
		||||
    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_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({
 | 
			
		||||
    required this.child,
 | 
			
		||||
    this.onProgress,
 | 
			
		||||
@ -41,7 +43,7 @@ class SignUpListener<Extra> extends StatelessWidget {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) =>
 | 
			
		||||
      BlocListener<SignUpCubit<Extra>, SignUpState>(
 | 
			
		||||
      BlocListener<SignUpCubit<Data>, SignUpState>(
 | 
			
		||||
        listener: (context, state) {
 | 
			
		||||
          if (customBuilder != null) {
 | 
			
		||||
            return customBuilder!(context, state);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user