milestone/stable-1-reconcile-auth-3 #176
@ -20,4 +20,6 @@ abstract class AuthFormField {
 | 
			
		||||
  static const email = 'wyattEmailField';
 | 
			
		||||
  /// Password field: `wyattPasswordField`
 | 
			
		||||
  static const password = 'wyattPasswordField';
 | 
			
		||||
  /// Confirm Password field: `wyattConfirmPasswordField`
 | 
			
		||||
  static const confirmPassword = 'wyattConfirmPasswordField';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -22,4 +22,6 @@ abstract class AuthFormName {
 | 
			
		||||
  static const String signInForm = 'wyattSignInForm';
 | 
			
		||||
  /// Password reset form: `wyattPasswordResetForm`
 | 
			
		||||
  static const String passwordResetForm = 'wyattPasswordResetForm';
 | 
			
		||||
  /// Edit account form: `wyattEditAccountForm`
 | 
			
		||||
  static const String editAccountForm = 'wyattEditAccountForm';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,96 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart';
 | 
			
		||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
 | 
			
		||||
 | 
			
		||||
abstract class Forms {
 | 
			
		||||
  static WyattForm buildSignInForm(
 | 
			
		||||
    FormInputValidator<String?, ValidationError>? customEmailValidator,
 | 
			
		||||
    FormInputValidator<String?, ValidationError>? customPasswordValidator,
 | 
			
		||||
  ) =>
 | 
			
		||||
      WyattFormImpl(
 | 
			
		||||
        [
 | 
			
		||||
          FormInput(
 | 
			
		||||
            AuthFormField.email,
 | 
			
		||||
            customEmailValidator ?? const Email.pure(),
 | 
			
		||||
          ),
 | 
			
		||||
          FormInput(
 | 
			
		||||
            AuthFormField.password,
 | 
			
		||||
            customPasswordValidator ?? const Password.pure(),
 | 
			
		||||
          )
 | 
			
		||||
        ],
 | 
			
		||||
        name: AuthFormName.signInForm,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
  static WyattForm buildSignUpForm(
 | 
			
		||||
    FormInputValidator<String?, ValidationError>? customEmailValidator,
 | 
			
		||||
    FormInputValidator<String?, ValidationError>? customPasswordValidator,
 | 
			
		||||
    // ignore: strict_raw_type
 | 
			
		||||
    List<FormInput>? extraSignUpInputs,
 | 
			
		||||
  ) =>
 | 
			
		||||
      WyattFormImpl(
 | 
			
		||||
        [
 | 
			
		||||
          FormInput(
 | 
			
		||||
            AuthFormField.email,
 | 
			
		||||
            customEmailValidator ?? const Email.pure(),
 | 
			
		||||
          ),
 | 
			
		||||
          FormInput(
 | 
			
		||||
            AuthFormField.password,
 | 
			
		||||
            customPasswordValidator ?? const Password.pure(),
 | 
			
		||||
          ),
 | 
			
		||||
          ...extraSignUpInputs ?? []
 | 
			
		||||
        ],
 | 
			
		||||
        name: AuthFormName.signUpForm,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
  static WyattForm buildPasswordResetForm(
 | 
			
		||||
    FormInputValidator<String?, ValidationError>? customEmailValidator,
 | 
			
		||||
  ) =>
 | 
			
		||||
      WyattFormImpl(
 | 
			
		||||
        [
 | 
			
		||||
          FormInput(
 | 
			
		||||
            AuthFormField.email,
 | 
			
		||||
            customEmailValidator ?? const Email.pure(),
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
        name: AuthFormName.passwordResetForm,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
  static WyattForm buildEditAccountForm(
 | 
			
		||||
    FormInputValidator<String?, ValidationError>? customEmailValidator,
 | 
			
		||||
    FormInputValidator<String?, ValidationError>? customPasswordValidator,
 | 
			
		||||
    // ignore: strict_raw_type
 | 
			
		||||
    List<FormInput>? extraEditAccountInputs,
 | 
			
		||||
  ) =>
 | 
			
		||||
      WyattFormImpl(
 | 
			
		||||
        [
 | 
			
		||||
          FormInput(
 | 
			
		||||
            AuthFormField.email,
 | 
			
		||||
            customEmailValidator ?? const Email.pure(),
 | 
			
		||||
            metadata: const FormInputMetadata(isRequired: false),
 | 
			
		||||
          ),
 | 
			
		||||
          FormInput(
 | 
			
		||||
            AuthFormField.password,
 | 
			
		||||
            customPasswordValidator ?? const Password.pure(),
 | 
			
		||||
            metadata: const FormInputMetadata(isRequired: false),
 | 
			
		||||
          ),
 | 
			
		||||
          ...extraEditAccountInputs ?? []
 | 
			
		||||
        ],
 | 
			
		||||
        validationStrategy: const OnlyRequiredInputValidator(),
 | 
			
		||||
        name: AuthFormName.editAccountForm,
 | 
			
		||||
      );
 | 
			
		||||
}
 | 
			
		||||
@ -254,7 +254,11 @@ class AuthenticationFirebaseDataSourceImpl<Data>
 | 
			
		||||
  Future<Account> updateEmail({required String email}) async {
 | 
			
		||||
    try {
 | 
			
		||||
      await _firebaseAuth.currentUser!.updateEmail(email);
 | 
			
		||||
      final account = AccountModel.fromFirebaseUser(_firebaseAuth.currentUser);
 | 
			
		||||
      final jwt = await _firebaseAuth.currentUser!.getIdToken(true);
 | 
			
		||||
      final account = AccountModel.fromFirebaseUser(
 | 
			
		||||
        _firebaseAuth.currentUser,
 | 
			
		||||
        accessToken: jwt,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      return account;
 | 
			
		||||
    } on FirebaseAuthException catch (e) {
 | 
			
		||||
@ -269,7 +273,11 @@ class AuthenticationFirebaseDataSourceImpl<Data>
 | 
			
		||||
  Future<Account> updatePassword({required String password}) async {
 | 
			
		||||
    try {
 | 
			
		||||
      await _firebaseAuth.currentUser!.updatePassword(password);
 | 
			
		||||
      final account = AccountModel.fromFirebaseUser(_firebaseAuth.currentUser);
 | 
			
		||||
      final jwt = await _firebaseAuth.currentUser!.getIdToken(true);
 | 
			
		||||
      final account = AccountModel.fromFirebaseUser(
 | 
			
		||||
        _firebaseAuth.currentUser,
 | 
			
		||||
        accessToken: jwt,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      return account;
 | 
			
		||||
    } on FirebaseAuthException catch (e) {
 | 
			
		||||
 | 
			
		||||
@ -15,8 +15,7 @@
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
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_name.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/core/utils/forms.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/domain/data_sources/remote/authentication_remote_data_source.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/domain/entities/session_wrapper.dart';
 | 
			
		||||
@ -31,6 +30,8 @@ class AuthenticationRepositoryImpl<Data extends Object>
 | 
			
		||||
    FormRepository? formRepository,
 | 
			
		||||
    // ignore: strict_raw_type
 | 
			
		||||
    List<FormInput>? extraSignUpInputs,
 | 
			
		||||
    // ignore: strict_raw_type
 | 
			
		||||
    List<FormInput>? extraEditAccountInputs,
 | 
			
		||||
    FormInputValidator<String?, ValidationError>? customEmailValidator,
 | 
			
		||||
    FormInputValidator<String?, ValidationError>? customPasswordValidator,
 | 
			
		||||
  }) {
 | 
			
		||||
@ -41,45 +42,26 @@ class AuthenticationRepositoryImpl<Data extends Object>
 | 
			
		||||
    }
 | 
			
		||||
    _formRepository
 | 
			
		||||
      ..registerForm(
 | 
			
		||||
        WyattFormImpl(
 | 
			
		||||
          [
 | 
			
		||||
            FormInput(
 | 
			
		||||
              AuthFormField.email,
 | 
			
		||||
              customEmailValidator ?? const Email.pure(),
 | 
			
		||||
            ),
 | 
			
		||||
            FormInput(
 | 
			
		||||
              AuthFormField.password,
 | 
			
		||||
              customPasswordValidator ?? const Password.pure(),
 | 
			
		||||
            )
 | 
			
		||||
          ],
 | 
			
		||||
          name: AuthFormName.signInForm,
 | 
			
		||||
        Forms.buildSignUpForm(
 | 
			
		||||
          customEmailValidator,
 | 
			
		||||
          customPasswordValidator,
 | 
			
		||||
          extraSignUpInputs,
 | 
			
		||||
        ),
 | 
			
		||||
      )
 | 
			
		||||
      ..registerForm(
 | 
			
		||||
        WyattFormImpl(
 | 
			
		||||
          [
 | 
			
		||||
            FormInput(
 | 
			
		||||
              AuthFormField.email,
 | 
			
		||||
              customEmailValidator ?? const Email.pure(),
 | 
			
		||||
            ),
 | 
			
		||||
            FormInput(
 | 
			
		||||
              AuthFormField.password,
 | 
			
		||||
              customPasswordValidator ?? const Password.pure(),
 | 
			
		||||
            ),
 | 
			
		||||
            ...extraSignUpInputs ?? []
 | 
			
		||||
          ],
 | 
			
		||||
          name: AuthFormName.signUpForm,
 | 
			
		||||
        Forms.buildSignInForm(
 | 
			
		||||
          customEmailValidator,
 | 
			
		||||
          customPasswordValidator,
 | 
			
		||||
        ),
 | 
			
		||||
      )
 | 
			
		||||
      ..registerForm(
 | 
			
		||||
        WyattFormImpl(
 | 
			
		||||
          [
 | 
			
		||||
            FormInput(
 | 
			
		||||
              AuthFormField.email,
 | 
			
		||||
              customEmailValidator ?? const Email.pure(),
 | 
			
		||||
            ),
 | 
			
		||||
          ],
 | 
			
		||||
          name: AuthFormName.passwordResetForm,
 | 
			
		||||
        Forms.buildPasswordResetForm(customEmailValidator),
 | 
			
		||||
      )
 | 
			
		||||
      ..registerForm(
 | 
			
		||||
        Forms.buildEditAccountForm(
 | 
			
		||||
          customEmailValidator,
 | 
			
		||||
          customPasswordValidator,
 | 
			
		||||
          extraEditAccountInputs,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,100 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
part of 'edit_account_cubit.dart';
 | 
			
		||||
 | 
			
		||||
/// Abstract edit account cubit useful for implementing a cubit with fine
 | 
			
		||||
/// granularity by adding only the required mixins.
 | 
			
		||||
abstract class BaseEditAccountCubit<Data>
 | 
			
		||||
    extends FormDataCubit<EditAccountState> {
 | 
			
		||||
  BaseEditAccountCubit({
 | 
			
		||||
    required this.authenticationRepository,
 | 
			
		||||
  }) : super(
 | 
			
		||||
          EditAccountState(
 | 
			
		||||
            form: authenticationRepository.formRepository
 | 
			
		||||
                .accessForm(AuthFormName.signInForm),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
  final AuthenticationRepository<Data> authenticationRepository;
 | 
			
		||||
  FormRepository get formRepository => authenticationRepository.formRepository;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String get formName => AuthFormName.signInForm;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOr<void> dataChanged<Value>(
 | 
			
		||||
    String key,
 | 
			
		||||
    FormInputValidator<Value, ValidationError> dirtyValue,
 | 
			
		||||
  ) {
 | 
			
		||||
    final form = formRepository.accessForm(formName).clone();
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      form.updateValidator(key, dirtyValue);
 | 
			
		||||
      formRepository.updateForm(form);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      rethrow;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    emit(
 | 
			
		||||
      EditAccountState(form: form, status: form.validate()),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOr<void> reset() {
 | 
			
		||||
    final form = state.form.reset();
 | 
			
		||||
    formRepository.updateForm(form);
 | 
			
		||||
    emit(
 | 
			
		||||
      EditAccountState(form: form, status: form.validate()),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @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(
 | 
			
		||||
      EditAccountState(form: newForm, status: newForm.validate()),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOr<void> validate() {
 | 
			
		||||
    final WyattForm form = formRepository.accessForm(formName);
 | 
			
		||||
    emit(
 | 
			
		||||
      EditAccountState(form: form, status: form.validate()),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOr<void> submit() async {
 | 
			
		||||
    final WyattForm form = formRepository.accessForm(formName);
 | 
			
		||||
    const error = '`submit()` is not implemented for BaseEditAccountCubit, '
 | 
			
		||||
        'please use `updateEmail()` or `updatePassword()`.';
 | 
			
		||||
    emit(
 | 
			
		||||
      EditAccountState(
 | 
			
		||||
        form: form,
 | 
			
		||||
        errorMessage: error,
 | 
			
		||||
        status: FormStatus.submissionFailure,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,51 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
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/constants/form_name.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/domain/entities/account.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/domain/repositories/authentication_repository.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/features/edit_account/edit_account.dart';
 | 
			
		||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
 | 
			
		||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
			
		||||
 | 
			
		||||
part 'base_edit_account_cubit.dart';
 | 
			
		||||
part 'edit_account_state.dart';
 | 
			
		||||
 | 
			
		||||
/// Fully featured edit account cubit.
 | 
			
		||||
///
 | 
			
		||||
/// Sufficient in most cases. (Where fine granularity is not required.)
 | 
			
		||||
class EditAccountCubit<Data> extends BaseEditAccountCubit<Data>
 | 
			
		||||
    with UpdateEmail<Data>, UpdatePassword<Data> {
 | 
			
		||||
  EditAccountCubit({required super.authenticationRepository});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOrResult<Data?> onEmailUpdated(
 | 
			
		||||
    Result<Account, AppException> result,
 | 
			
		||||
    WyattForm form,
 | 
			
		||||
  ) =>
 | 
			
		||||
      const Ok(null);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOrResult<Data?> onPasswordUpdated(
 | 
			
		||||
    Result<Account, AppException> result,
 | 
			
		||||
    WyattForm form,
 | 
			
		||||
  ) =>
 | 
			
		||||
      const Ok(null);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,48 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
part of 'edit_account_cubit.dart';
 | 
			
		||||
 | 
			
		||||
/// Edit account cubit state to manage the form.
 | 
			
		||||
class EditAccountState extends FormDataState {
 | 
			
		||||
  const EditAccountState({
 | 
			
		||||
    required super.form,
 | 
			
		||||
    super.status = FormStatus.pure,
 | 
			
		||||
    super.errorMessage,
 | 
			
		||||
  });
 | 
			
		||||
  FormInputValidator<String?, ValidationError> get email =>
 | 
			
		||||
      form.validatorOf(AuthFormField.email);
 | 
			
		||||
  FormInputValidator<String?, ValidationError> get password =>
 | 
			
		||||
      form.validatorOf(AuthFormField.password);
 | 
			
		||||
 | 
			
		||||
  EditAccountState copyWith({
 | 
			
		||||
    WyattForm? form,
 | 
			
		||||
    FormStatus? status,
 | 
			
		||||
    String? errorMessage,
 | 
			
		||||
  }) =>
 | 
			
		||||
      EditAccountState(
 | 
			
		||||
        form: form ?? this.form,
 | 
			
		||||
        status: status ?? this.status,
 | 
			
		||||
        errorMessage: errorMessage ?? this.errorMessage,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  List<Object> get props => [email, password, status];
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => 'EditAccountState(status: ${status.name} '
 | 
			
		||||
      '${(errorMessage != null) ? " [$errorMessage]" : ""}, $form)';
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,131 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
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/edit_account/cubit/edit_account_cubit.dart';
 | 
			
		||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
 | 
			
		||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
			
		||||
 | 
			
		||||
/// Edit account mixin.
 | 
			
		||||
///
 | 
			
		||||
/// Allows the user to edit his email
 | 
			
		||||
///
 | 
			
		||||
/// Gives access to the `updateEmail` method and
 | 
			
		||||
/// `onEmailUpdated` callback.
 | 
			
		||||
mixin UpdateEmail<Data> on BaseEditAccountCubit<Data> {
 | 
			
		||||
  /// This callback is triggered when user updates his email
 | 
			
		||||
  FutureOrResult<Data?> onEmailUpdated(
 | 
			
		||||
    Result<Account, AppException> result,
 | 
			
		||||
    WyattForm form,
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// 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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// {@macro update_email}
 | 
			
		||||
  FutureOr<void> updateEmail() async {
 | 
			
		||||
    if (state.status.isSubmissionInProgress) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!state.status.isValidated) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final form = formRepository.accessForm(formName);
 | 
			
		||||
    emit(
 | 
			
		||||
      EditAccountState(
 | 
			
		||||
        form: form,
 | 
			
		||||
        status: FormStatus.submissionInProgress,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    final email = form.valueOf<String?>(AuthFormField.email);
 | 
			
		||||
 | 
			
		||||
    if (email.isNullOrEmpty) {
 | 
			
		||||
      emit(
 | 
			
		||||
        EditAccountState(
 | 
			
		||||
          form: form,
 | 
			
		||||
          errorMessage: 'An error occured while retrieving data from the form.',
 | 
			
		||||
          status: FormStatus.submissionFailure,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CustomRoutine<Account, Data?>(
 | 
			
		||||
      routine: () => authenticationRepository.updateEmail(
 | 
			
		||||
        email: email!,
 | 
			
		||||
      ),
 | 
			
		||||
      attachedLogic: (routineResult) => onEmailUpdated(
 | 
			
		||||
        routineResult,
 | 
			
		||||
        form,
 | 
			
		||||
      ),
 | 
			
		||||
      onError: (error) {
 | 
			
		||||
        emit(
 | 
			
		||||
          EditAccountState(
 | 
			
		||||
            form: form,
 | 
			
		||||
            errorMessage: error.message,
 | 
			
		||||
            status: FormStatus.submissionFailure,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        addError(error);
 | 
			
		||||
      },
 | 
			
		||||
      onSuccess: (account, data) {
 | 
			
		||||
        authenticationRepository.addSession(
 | 
			
		||||
          SessionWrapper(
 | 
			
		||||
            event: UpdatedEvent(account: account),
 | 
			
		||||
            session: Session<Data>(
 | 
			
		||||
              account: account,
 | 
			
		||||
              data: data,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        emit(
 | 
			
		||||
          EditAccountState(
 | 
			
		||||
            form: form,
 | 
			
		||||
            status: FormStatus.submissionSuccess,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    ).call();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,130 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
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/edit_account/cubit/edit_account_cubit.dart';
 | 
			
		||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
 | 
			
		||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
			
		||||
 | 
			
		||||
/// Edit account mixin.
 | 
			
		||||
///
 | 
			
		||||
/// Allows the user to edit his password
 | 
			
		||||
///
 | 
			
		||||
/// Gives access to the `updatePassword` method and
 | 
			
		||||
/// `onPasswordUpdated` callback.
 | 
			
		||||
mixin UpdatePassword<Data> on BaseEditAccountCubit<Data> {
 | 
			
		||||
  /// This callback is triggered when a user edits his password.
 | 
			
		||||
  FutureOrResult<Data?> onPasswordUpdated(
 | 
			
		||||
    Result<Account, AppException> result,
 | 
			
		||||
    WyattForm form,
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  void passwordChanged(String value) {
 | 
			
		||||
    final passwordValidatorType = formRepository
 | 
			
		||||
        .accessForm(formName)
 | 
			
		||||
        .validatorOf(AuthFormField.password)
 | 
			
		||||
        .runtimeType;
 | 
			
		||||
    assert(
 | 
			
		||||
      passwordValidatorType == Password,
 | 
			
		||||
      'Use passwordCustomChanged(...) with validator $passwordValidatorType',
 | 
			
		||||
    );
 | 
			
		||||
    final Password password = Password.dirty(value);
 | 
			
		||||
    dataChanged(AuthFormField.password, password);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Same as [passwordChanged] but with a custom [Validator].
 | 
			
		||||
  ///
 | 
			
		||||
  /// Sort of short hand for [dataChanged].
 | 
			
		||||
  void passwordCustomChanged<
 | 
			
		||||
      Validator extends FormInputValidator<String?, ValidationError>>(
 | 
			
		||||
    Validator validator,
 | 
			
		||||
  ) {
 | 
			
		||||
    dataChanged(AuthFormField.password, validator);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// {@macro update_password}
 | 
			
		||||
  FutureOr<void> updatePassword() async {
 | 
			
		||||
    if (state.status.isSubmissionInProgress) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!state.status.isValidated) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final form = formRepository.accessForm(formName);
 | 
			
		||||
    emit(
 | 
			
		||||
      EditAccountState(
 | 
			
		||||
        form: form,
 | 
			
		||||
        status: FormStatus.submissionInProgress,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    final password = form.valueOf<String?>(AuthFormField.password);
 | 
			
		||||
 | 
			
		||||
    if (password.isNullOrEmpty) {
 | 
			
		||||
      emit(
 | 
			
		||||
        EditAccountState(
 | 
			
		||||
          form: form,
 | 
			
		||||
          errorMessage: 'An error occured while retrieving data from the form.',
 | 
			
		||||
          status: FormStatus.submissionFailure,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CustomRoutine<Account, Data?>(
 | 
			
		||||
      routine: () => authenticationRepository.updatePassword(
 | 
			
		||||
        password: password!,
 | 
			
		||||
      ),
 | 
			
		||||
      attachedLogic: (routineResult) => onPasswordUpdated(
 | 
			
		||||
        routineResult,
 | 
			
		||||
        form,
 | 
			
		||||
      ),
 | 
			
		||||
      onError: (error) {
 | 
			
		||||
        emit(
 | 
			
		||||
          EditAccountState(
 | 
			
		||||
            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(
 | 
			
		||||
          EditAccountState(
 | 
			
		||||
            form: form,
 | 
			
		||||
            status: FormStatus.submissionSuccess,
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    ).call();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
export 'cubit/edit_account_cubit.dart';
 | 
			
		||||
export 'cubit/mixin/edit_email.dart';
 | 
			
		||||
export 'cubit/mixin/edit_password.dart';
 | 
			
		||||
export 'listener/edit_account_listener.dart';
 | 
			
		||||
@ -0,0 +1,69 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_bloc/flutter_bloc.dart';
 | 
			
		||||
import 'package:wyatt_authentication_bloc/src/features/edit_account/cubit/edit_account_cubit.dart';
 | 
			
		||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
 | 
			
		||||
 | 
			
		||||
/// Widget that listens and builds a child based on the state of
 | 
			
		||||
/// the edit account cubit
 | 
			
		||||
class EditAccountListener<Data> extends StatelessWidget {
 | 
			
		||||
  const EditAccountListener({
 | 
			
		||||
    required this.child,
 | 
			
		||||
    this.onProgress,
 | 
			
		||||
    this.onSuccess,
 | 
			
		||||
    this.onError,
 | 
			
		||||
    this.customBuilder,
 | 
			
		||||
    super.key,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  final void Function(BuildContext context)? onProgress;
 | 
			
		||||
  final void Function(BuildContext context)? onSuccess;
 | 
			
		||||
  final void Function(
 | 
			
		||||
    BuildContext context,
 | 
			
		||||
    FormStatus status,
 | 
			
		||||
    String? errorMessage,
 | 
			
		||||
  )? onError;
 | 
			
		||||
  final void Function(BuildContext context, EditAccountState state)?
 | 
			
		||||
      customBuilder;
 | 
			
		||||
  final Widget child;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) =>
 | 
			
		||||
      BlocListener<EditAccountCubit<Data>, EditAccountState>(
 | 
			
		||||
        listener: (context, state) {
 | 
			
		||||
          if (customBuilder != null) {
 | 
			
		||||
            return customBuilder!(context, state);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if (onSuccess != null &&
 | 
			
		||||
              state.status == FormStatus.submissionSuccess) {
 | 
			
		||||
            return onSuccess!(context);
 | 
			
		||||
          }
 | 
			
		||||
          if (onProgress != null &&
 | 
			
		||||
              state.status == FormStatus.submissionInProgress) {
 | 
			
		||||
            return onProgress!(context);
 | 
			
		||||
          }
 | 
			
		||||
          if (onError != null &&
 | 
			
		||||
              (state.status == FormStatus.submissionCanceled ||
 | 
			
		||||
                  state.status == FormStatus.submissionFailure)) {
 | 
			
		||||
            return onError!(context, state.status, state.errorMessage);
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        child: child,
 | 
			
		||||
      );
 | 
			
		||||
}
 | 
			
		||||
@ -15,6 +15,7 @@
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
export 'authentication/authentication.dart';
 | 
			
		||||
export 'edit_account/edit_account.dart';
 | 
			
		||||
export 'email_verification/email_verification.dart';
 | 
			
		||||
export 'password_reset/password_reset.dart';
 | 
			
		||||
export 'sign_in/sign_in.dart';
 | 
			
		||||
 | 
			
		||||
@ -86,7 +86,7 @@ abstract class BaseSignInCubit<Data> extends FormDataCubit<SignInState> {
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOr<void> submit() async {
 | 
			
		||||
    final WyattForm form = formRepository.accessForm(formName);
 | 
			
		||||
    const error = '`submit()` is not implemented for BaseSignUpCubit, '
 | 
			
		||||
    const error = '`submit()` is not implemented for BaseSignInCubit, '
 | 
			
		||||
        'please use `signUpWithEmailAndPassword()`.';
 | 
			
		||||
    emit(
 | 
			
		||||
      SignInState(
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user