fix(authentication): allow email/password validators customization (closes #57) #60
| @ -0,0 +1,30 @@ | ||||
| // Copyright (C) 2022 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_form_bloc/wyatt_form_bloc.dart'; | ||||
| 
 | ||||
| class CustomPassword extends RegexValidator<ValidationStandardError> { | ||||
|   const CustomPassword.pure([super.value]) : super.pure(); | ||||
|   const CustomPassword.dirty([super.value]) : super.dirty(); | ||||
| 
 | ||||
|   @override | ||||
|   ValidationStandardError get onEmpty => ValidationStandardError.empty; | ||||
|   @override | ||||
|   ValidationStandardError get onError => ValidationStandardError.invalid; | ||||
| 
 | ||||
|   @override | ||||
|   RegExp get regex => RegExp(r'^(?=.*[A-Za-z\w\s])(?=.*\d).{6,}$'); | ||||
| } | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: app.dart | ||||
| // Created Date: 19/08/2022 12:05:38 | ||||
| // Last Modified: Wed Nov 23 2022 | ||||
| // Last Modified: Sat Dec 03 2022 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| @ -13,6 +13,7 @@ import 'dart:math'; | ||||
| import 'package:example_router/core/constants/form_field.dart'; | ||||
| import 'package:example_router/core/dependency_injection/get_it.dart'; | ||||
| import 'package:example_router/core/routes/router.dart'; | ||||
| import 'package:example_router/core/utils/custom_password.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
| @ -47,6 +48,7 @@ class App extends StatelessWidget { | ||||
|     authenticationRemoteDataSource: getIt<AuthenticationRemoteDataSource>(), | ||||
|     onSignUpSuccess: onSignUpSuccess, | ||||
|     onAuthChange: onAccountChanges, | ||||
|     customPasswordValidator: const CustomPassword.pure(), | ||||
|     extraSignUpInputs: [ | ||||
|       FormInput( | ||||
|         AppFormField.confirmedPassword, | ||||
|  | ||||
| @ -3,10 +3,11 @@ | ||||
| // ----- | ||||
| // File: sign_in_form.dart | ||||
| // Created Date: 19/08/2022 15:24:37 | ||||
| // Last Modified: Wed Nov 16 2022 | ||||
| // Last Modified: Sat Dec 03 2022 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| import 'package:example_router/core/utils/custom_password.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; | ||||
| import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; | ||||
| @ -38,7 +39,8 @@ class _PasswordInput extends StatelessWidget { | ||||
|       field: AuthFormField.password, | ||||
|       builder: ((context, cubit, state, field, input) { | ||||
|         return TextField( | ||||
|           onChanged: (pwd) => cubit.passwordChanged(pwd), | ||||
|           onChanged: (pwd) => cubit | ||||
|               .passwordCustomChanged<CustomPassword>(CustomPassword.dirty(pwd)), | ||||
|           obscureText: true, | ||||
|           decoration: InputDecoration( | ||||
|             labelText: 'Password', | ||||
| @ -59,7 +61,9 @@ class _SignInButton extends StatelessWidget { | ||||
|         return status.isSubmissionInProgress | ||||
|             ? const CircularProgressIndicator() | ||||
|             : ElevatedButton( | ||||
|                 onPressed: status.isValidated ? () => cubit.signInWithEmailAndPassword() : null, | ||||
|                 onPressed: status.isValidated | ||||
|                     ? () => cubit.signInWithEmailAndPassword() | ||||
|                     : null, | ||||
|                 child: const Text('Sign in with credentials'), | ||||
|               ); | ||||
|       }), | ||||
|  | ||||
| @ -3,11 +3,12 @@ | ||||
| // ----- | ||||
| // File: sign_up_form.dart | ||||
| // Created Date: 19/08/2022 14:41:08 | ||||
| // Last Modified: Wed Nov 16 2022 | ||||
| // Last Modified: Sat Dec 03 2022 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| import 'package:example_router/core/constants/form_field.dart'; | ||||
| import 'package:example_router/core/utils/custom_password.dart'; | ||||
| import 'package:flutter/material.dart' hide FormField; | ||||
| import 'package:wyatt_authentication_bloc/wyatt_authentication_bloc.dart'; | ||||
| import 'package:wyatt_form_bloc/wyatt_form_bloc.dart'; | ||||
| @ -40,7 +41,8 @@ class _PasswordInput extends StatelessWidget { | ||||
|       builder: ((context, cubit, state, field, input) { | ||||
|         return TextField( | ||||
|           onChanged: (pwd) { | ||||
|             cubit.passwordChanged(pwd); | ||||
|             cubit.passwordCustomChanged<CustomPassword>( | ||||
|                 CustomPassword.dirty(pwd)); | ||||
|             cubit.dataChanged( | ||||
|                 AppFormField.confirmedPassword, | ||||
|                 ConfirmedPassword.dirty( | ||||
|  | ||||
| @ -57,6 +57,8 @@ class AuthenticationRepositoryImpl<T extends Object> | ||||
|     FormRepository? formRepository, | ||||
|     // ignore: strict_raw_type | ||||
|     List<FormInput>? extraSignUpInputs, | ||||
|     FormInputValidator<String?, ValidationError>? customEmailValidator, | ||||
|     FormInputValidator<String?, ValidationError>? customPasswordValidator, | ||||
|     OnSignUpSuccess<T>? onSignUpSuccess, | ||||
|     OnAuthChange<T>? onAuthChange, | ||||
|   })  : _authenticationLocalDataSource = authenticationCacheDataSource, | ||||
| @ -71,8 +73,14 @@ class AuthenticationRepositoryImpl<T extends Object> | ||||
|       ..registerForm( | ||||
|         WyattFormImpl( | ||||
|           [ | ||||
|             FormInput(AuthFormField.email, const Email.pure()), | ||||
|             FormInput(AuthFormField.password, const Password.pure()) | ||||
|             FormInput( | ||||
|               AuthFormField.email, | ||||
|               customEmailValidator ?? const Email.pure(), | ||||
|             ), | ||||
|             FormInput( | ||||
|               AuthFormField.password, | ||||
|               customPasswordValidator ?? const Password.pure(), | ||||
|             ) | ||||
|           ], | ||||
|           name: AuthFormName.signInForm, | ||||
|         ), | ||||
| @ -80,8 +88,14 @@ class AuthenticationRepositoryImpl<T extends Object> | ||||
|       ..registerForm( | ||||
|         WyattFormImpl( | ||||
|           [ | ||||
|             FormInput(AuthFormField.email, const Email.pure()), | ||||
|             FormInput(AuthFormField.password, const Password.pure()), | ||||
|             FormInput( | ||||
|               AuthFormField.email, | ||||
|               customEmailValidator ?? const Email.pure(), | ||||
|             ), | ||||
|             FormInput( | ||||
|               AuthFormField.password, | ||||
|               customPasswordValidator ?? const Password.pure(), | ||||
|             ), | ||||
|             ...extraSignUpInputs ?? [] | ||||
|           ], | ||||
|           name: AuthFormName.signUpForm, | ||||
|  | ||||
| @ -41,15 +41,52 @@ class SignInCubit<Extra> extends FormDataCubit<SignInState> { | ||||
|   String get formName => AuthFormName.signInForm; | ||||
| 
 | ||||
|   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); | ||||
|   } | ||||
| 
 | ||||
|   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 [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); | ||||
|   } | ||||
| 
 | ||||
|   /// 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); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   FutureOr<void> dataChanged<Value>( | ||||
|     String key, | ||||
|  | ||||
| @ -17,8 +17,10 @@ | ||||
| part of 'sign_in_cubit.dart'; | ||||
| 
 | ||||
| class SignInState extends FormDataState { | ||||
|   Email get email => form.validatorOf(AuthFormField.email); | ||||
|   Password get password => form.validatorOf(AuthFormField.password); | ||||
|   FormInputValidator<String?, ValidationError> get email => | ||||
|       form.validatorOf(AuthFormField.email); | ||||
|   FormInputValidator<String?, ValidationError> get password => | ||||
|       form.validatorOf(AuthFormField.password); | ||||
| 
 | ||||
|   const SignInState({ | ||||
|     required super.form, | ||||
|  | ||||
| @ -43,15 +43,52 @@ class SignUpCubit<Extra> extends FormDataCubit<SignUpState> { | ||||
|   String get formName => AuthFormName.signUpForm; | ||||
| 
 | ||||
|   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); | ||||
|   } | ||||
| 
 | ||||
|   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 [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); | ||||
|   } | ||||
| 
 | ||||
|   /// 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); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   FutureOr<void> dataChanged<Value>( | ||||
|     String key, | ||||
|  | ||||
| @ -17,8 +17,10 @@ | ||||
| part of 'sign_up_cubit.dart'; | ||||
| 
 | ||||
| class SignUpState extends FormDataState { | ||||
|   Email get email => form.validatorOf(AuthFormField.email); | ||||
|   Password get password => form.validatorOf(AuthFormField.password); | ||||
|   FormInputValidator<String?, ValidationError> get email => | ||||
|       form.validatorOf(AuthFormField.email); | ||||
|   FormInputValidator<String?, ValidationError> get password => | ||||
|       form.validatorOf(AuthFormField.password); | ||||
| 
 | ||||
|   const SignUpState({ | ||||
|     required super.form, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user