feat(from): add form validator class with strategy design pattern #12
| @ -1 +1,4 @@ | ||||
| include: package:wyatt_analysis/analysis_options.yaml | ||||
| 
 | ||||
| analyzer: | ||||
|   exclude: "!example/**" | ||||
| @ -61,10 +61,10 @@ class App extends StatelessWidget { | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     FormDataCubit _formCubit = CustomFormCubit(inputs: getNormalFormData()); | ||||
|     FormDataCubit formCubit = CustomFormCubit(inputs: getNormalFormData()); | ||||
| 
 | ||||
|     return BlocProvider( | ||||
|       create: (context) => _formCubit, | ||||
|       create: (context) => formCubit, | ||||
|       child: const WidgetTree(), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| @ -187,9 +187,9 @@ class _CheckListInput extends StatelessWidget { | ||||
|   Widget build(BuildContext context) { | ||||
|     return BlocBuilder<FormDataCubit, FormDataState>( | ||||
|       builder: (context, state) { | ||||
|         final _input = | ||||
|         final input = | ||||
|             state.data.validatorOf<ListOption<String>>(formFieldList); | ||||
|         final _options = _input.value; | ||||
|         final options = input.value; | ||||
| 
 | ||||
|         return Column( | ||||
|           mainAxisSize: MainAxisSize.min, | ||||
| @ -197,33 +197,33 @@ class _CheckListInput extends StatelessWidget { | ||||
|             ListTile( | ||||
|               title: const Text('Checkbox1'), | ||||
|               trailing: Checkbox( | ||||
|                   value: _options.contains('checkbox1'), | ||||
|                   value: options.contains('checkbox1'), | ||||
|                   onChanged: (_) { | ||||
|                     context.read<FormDataCubit>().dataChanged( | ||||
|                           formFieldList, | ||||
|                           _input.select('checkbox1'), | ||||
|                           input.select('checkbox1'), | ||||
|                         ); | ||||
|                   }), | ||||
|             ), | ||||
|             ListTile( | ||||
|               title: const Text('Checkbox2'), | ||||
|               trailing: Checkbox( | ||||
|                   value: _options.contains('checkbox2'), | ||||
|                   value: options.contains('checkbox2'), | ||||
|                   onChanged: (_) { | ||||
|                     context.read<FormDataCubit>().dataChanged( | ||||
|                           formFieldList, | ||||
|                           _input.select('checkbox2'), | ||||
|                           input.select('checkbox2'), | ||||
|                         ); | ||||
|                   }), | ||||
|             ), | ||||
|             ListTile( | ||||
|               title: const Text('Checkbox3 (default)'), | ||||
|               trailing: Checkbox( | ||||
|                   value: _options.contains('checkbox3'), | ||||
|                   value: options.contains('checkbox3'), | ||||
|                   onChanged: (_) { | ||||
|                     context.read<FormDataCubit>().dataChanged( | ||||
|                           formFieldList, | ||||
|                           _input.select('checkbox3'), | ||||
|                           input.select('checkbox3'), | ||||
|                         ); | ||||
|                   }), | ||||
|             ), | ||||
| @ -239,7 +239,7 @@ class _RadioListInput extends StatelessWidget { | ||||
|   Widget build(BuildContext context) { | ||||
|     return BlocBuilder<FormDataCubit, FormDataState>( | ||||
|       builder: (context, state) { | ||||
|         final _input = state.data.validatorOf<TextString>(formFieldRadio); | ||||
|         final input = state.data.validatorOf<TextString>(formFieldRadio); | ||||
| 
 | ||||
|         return Column( | ||||
|           mainAxisSize: MainAxisSize.min, | ||||
| @ -248,7 +248,7 @@ class _RadioListInput extends StatelessWidget { | ||||
|               title: const Text('Radio1'), | ||||
|               trailing: Radio<bool>( | ||||
|                   groupValue: true, | ||||
|                   value: _input.value == 'radio1', | ||||
|                   value: input.value == 'radio1', | ||||
|                   onChanged: (_) { | ||||
|                     context.read<FormDataCubit>().dataChanged( | ||||
|                           formFieldRadio, | ||||
| @ -260,7 +260,7 @@ class _RadioListInput extends StatelessWidget { | ||||
|               title: const Text('Radio2'), | ||||
|               trailing: Radio<bool>( | ||||
|                   groupValue: true, | ||||
|                   value: _input.value == 'radio2', | ||||
|                   value: input.value == 'radio2', | ||||
|                   onChanged: (_) { | ||||
|                     context.read<FormDataCubit>().dataChanged( | ||||
|                           formFieldRadio, | ||||
| @ -272,7 +272,7 @@ class _RadioListInput extends StatelessWidget { | ||||
|               title: const Text('Radio3'), | ||||
|               trailing: Radio<bool>( | ||||
|                   groupValue: true, | ||||
|                   value: _input.value == 'radio3', | ||||
|                   value: input.value == 'radio3', | ||||
|                   onChanged: (_) { | ||||
|                     context.read<FormDataCubit>().dataChanged( | ||||
|                           formFieldRadio, | ||||
| @ -378,6 +378,20 @@ class _DebugButton extends StatelessWidget { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class _ResetButton extends StatelessWidget { | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return BlocBuilder<FormDataCubit, FormDataState>( | ||||
|       builder: (context, state) { | ||||
|         return ElevatedButton( | ||||
|           onPressed: () => context.read<FormDataCubit>().resetForm(), | ||||
|           child: const Text('RESET'), | ||||
|         ); | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class SignUpForm extends StatelessWidget { | ||||
|   const SignUpForm({Key? key}) : super(key: key); | ||||
| 
 | ||||
| @ -431,6 +445,8 @@ class SignUpForm extends StatelessWidget { | ||||
|             _SignUpButton(), | ||||
|             const SizedBox(height: 8), | ||||
|             _DebugButton(), | ||||
|             const SizedBox(height: 8), | ||||
|             _ResetButton(), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|  | ||||
| @ -18,38 +18,54 @@ import 'dart:async'; | ||||
| 
 | ||||
| import 'package:bloc/bloc.dart'; | ||||
| import 'package:equatable/equatable.dart'; | ||||
| import 'package:meta/meta.dart'; | ||||
| import 'package:wyatt_form_bloc/src/enums/enums.dart'; | ||||
| import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| import 'package:wyatt_form_bloc/src/validators/form/every_input_validator.dart'; | ||||
| 
 | ||||
| part 'form_data_state.dart'; | ||||
| 
 | ||||
| abstract class FormDataCubit extends Cubit<FormDataState> { | ||||
|   FormDataCubit({required FormData inputs}) | ||||
|       : super(FormDataState(data: inputs)); | ||||
|   FormValidator validationStrategy; | ||||
|   FormData formCopy; | ||||
| 
 | ||||
|   FormDataCubit({ | ||||
|     required FormData inputs, | ||||
|     FormValidator validator = const EveryInputValidator(), | ||||
|   })  : formCopy = inputs.clone(), | ||||
|         validationStrategy = validator, | ||||
|         super(FormDataState(data: inputs)); | ||||
| 
 | ||||
|   /// Change value of a field. | ||||
|   /// | ||||
|   /// Inputs: | ||||
|   /// - `field`: The key of the field to change. | ||||
|   /// - `dirtyValue`: The new value of the field. (Wrapped in a dirty validator) | ||||
|   void dataChanged(String field, FormInputValidator dirtyValue) { | ||||
|     final _form = state.data.clone(); | ||||
|   void dataChanged<V>( | ||||
|     String field, | ||||
|     FormInputValidator<V, ValidationError> dirtyValue, | ||||
|   ) { | ||||
|     final form = state.data.clone(); | ||||
| 
 | ||||
|     if (_form.contains(field)) { | ||||
|       _form.updateValidator(field, dirtyValue); | ||||
|     if (form.contains(field)) { | ||||
|       form.updateValidator(field, dirtyValue); | ||||
|     } else { | ||||
|       throw Exception('Form field $field not found'); | ||||
|     } | ||||
| 
 | ||||
|     emit( | ||||
|       state.copyWith( | ||||
|         data: _form, | ||||
|         status: _form.validate(), | ||||
|         data: form, | ||||
|         status: validationStrategy.validate(form), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   /// Just validate the form manually. (Useful if you just update the strategy) | ||||
|   void validate() { | ||||
|     final form = state.data; | ||||
|     emit(state.copyWith(status: validationStrategy.validate(form))); | ||||
|   } | ||||
| 
 | ||||
|   /// Update entries list. | ||||
|   /// | ||||
|   /// Inputs: | ||||
| @ -59,31 +75,36 @@ abstract class FormDataCubit extends Cubit<FormDataState> { | ||||
|     FormData data, { | ||||
|     SetOperation operation = SetOperation.replace, | ||||
|   }) { | ||||
|     FormData _form = data; | ||||
|     FormData form = data; | ||||
| 
 | ||||
|     switch (operation) { | ||||
|       case SetOperation.replace: | ||||
|         _form = data; | ||||
|         form = data; | ||||
|         break; | ||||
|       case SetOperation.difference: | ||||
|         _form = state.data.difference(data); | ||||
|         form = state.data.difference(data); | ||||
|         break; | ||||
|       case SetOperation.intersection: | ||||
|         _form = state.data.intersection(data); | ||||
|         form = state.data.intersection(data); | ||||
|         break; | ||||
|       case SetOperation.union: | ||||
|         _form = state.data.union(data); | ||||
|         form = state.data.union(data); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     emit( | ||||
|       state.copyWith( | ||||
|         data: _form, | ||||
|         status: _form.validate(), | ||||
|         data: form, | ||||
|         status: validationStrategy.validate(form), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   /// Reset all form inputs | ||||
|   void resetForm() { | ||||
|     emit(FormDataState(data: formCopy)); | ||||
|   } | ||||
| 
 | ||||
|   /// Submit the form. | ||||
|   Future<void> submitForm(); | ||||
| } | ||||
|  | ||||
| @ -16,7 +16,6 @@ | ||||
| 
 | ||||
| part of 'form_data_cubit.dart'; | ||||
| 
 | ||||
| @immutable | ||||
| class FormDataState extends Equatable { | ||||
|   /// Global status of a form. | ||||
|   final FormStatus status; | ||||
| @ -37,13 +36,11 @@ class FormDataState extends Equatable { | ||||
|     FormStatus? status, | ||||
|     FormData? data, | ||||
|     String? errorMessage, | ||||
|   }) { | ||||
|     return FormDataState( | ||||
|   }) => FormDataState( | ||||
|       status: status ?? this.status, | ||||
|       data: data ?? this.data, | ||||
|       errorMessage: errorMessage ?? this.errorMessage, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   bool? get stringify => true; | ||||
|  | ||||
| @ -14,8 +14,6 @@ | ||||
| // 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/src/form/form.dart'; | ||||
| 
 | ||||
| const Set<FormStatus> _validatedFormStatuses = <FormStatus>{ | ||||
|   FormStatus.valid, | ||||
|   FormStatus.submissionInProgress, | ||||
| @ -51,6 +49,8 @@ enum FormStatus { | ||||
|   bool get isPure => this == FormStatus.pure; | ||||
| 
 | ||||
|   /// Indicates whether the form is completely validated. | ||||
|   /// This means the [FormStatus] is strictly: | ||||
|   /// * `FormStatus.valid` | ||||
|   bool get isValid => this == FormStatus.valid; | ||||
| 
 | ||||
|   /// Indicates whether the form has been validated successfully. | ||||
| @ -75,23 +75,4 @@ enum FormStatus { | ||||
| 
 | ||||
|   /// Indicates whether the form submission has been canceled. | ||||
|   bool get isSubmissionCanceled => this == FormStatus.submissionCanceled; | ||||
| 
 | ||||
|   /// Validate a list of inputs by processing them in `validate` as validators. | ||||
|   static FormStatus validateInputs(List<FormInput> inputs) { | ||||
|     return validate( | ||||
|       inputs | ||||
|           .map<FormInputValidator>((FormInput input) => input.validator) | ||||
|           .toList(), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   /// Validate a list of validators. | ||||
|   static FormStatus validate(List<FormInputValidator> validators) { | ||||
|     return validators.every((FormInputValidator validator) => validator.pure) | ||||
|         ? FormStatus.pure | ||||
|         : validators | ||||
|                 .any((FormInputValidator validator) => validator.valid == false) | ||||
|             ? FormStatus.invalid | ||||
|             : FormStatus.valid; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -14,7 +14,14 @@ | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| enum ValidationError { | ||||
|   /// Generic invalid error. | ||||
|   invalid | ||||
| // enum ValidationError { | ||||
| //   /// Generic invalid error. | ||||
| //   invalid | ||||
| // } | ||||
| 
 | ||||
| abstract class ValidationError {} | ||||
| 
 | ||||
| enum ValidationStandardError implements ValidationError { | ||||
|   invalid, | ||||
|   empty | ||||
| } | ||||
|  | ||||
| @ -14,12 +14,15 @@ | ||||
| // 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:convert'; | ||||
| 
 | ||||
| import 'package:equatable/equatable.dart'; | ||||
| import 'package:meta/meta.dart'; | ||||
| import 'package:wyatt_form_bloc/src/enums/form_input_status.dart'; | ||||
| import 'package:wyatt_form_bloc/src/enums/form_status.dart'; | ||||
| import 'package:wyatt_form_bloc/src/enums/validation_error.dart'; | ||||
| 
 | ||||
| part 'form_data.dart'; | ||||
| part 'form_input.dart'; | ||||
| part 'form_input_metadata.dart'; | ||||
| part 'form_input_validator.dart'; | ||||
| part 'form_data.dart'; | ||||
| part 'form_validator.dart'; | ||||
|  | ||||
| @ -16,7 +16,6 @@ | ||||
| 
 | ||||
| part of 'form.dart'; | ||||
| 
 | ||||
| @immutable | ||||
| class FormData extends Equatable { | ||||
|   final List<FormInput> _inputs; | ||||
| 
 | ||||
| @ -29,7 +28,7 @@ class FormData extends Equatable { | ||||
|   /// Returns the input for the associated key | ||||
|   FormInput inputOf(String key) { | ||||
|     if (contains(key)) { | ||||
|       return _inputs.firstWhere((FormInput input) => input.key == key); | ||||
|       return _inputs.firstWhere((input) => input.key == key); | ||||
|     } else { | ||||
|       throw Exception('FormInput with key `$key` does not exist in form'); | ||||
|     } | ||||
| @ -46,23 +45,23 @@ class FormData extends Equatable { | ||||
|   } | ||||
| 
 | ||||
|   /// Returns all associated validators as a list | ||||
|   List<FormInputValidator<V, E>> validators<V, E>() { | ||||
|     return _inputs | ||||
|   List<FormInputValidator<V, E>> validators<V, E extends ValidationError>() => | ||||
|       _inputs | ||||
|           .map<FormInputValidator<V, E>>( | ||||
|           (FormInput input) => input.validator as FormInputValidator<V, E>, | ||||
|             (input) => input.validator as FormInputValidator<V, E>, | ||||
|           ) | ||||
|           .toList(); | ||||
|   } | ||||
| 
 | ||||
|   /// A [FormInputValidator] represents the value of a single form input field. | ||||
|   /// It contains information about the [FormInputStatus], value, as well | ||||
|   /// as validation status. | ||||
|   T validatorOf<T>(String key) { | ||||
|     return inputOf(key).validator as T; | ||||
|   } | ||||
|   T validatorOf<T>(String key) => inputOf(key).validator as T; | ||||
| 
 | ||||
|   /// Updates validator of a given input. (perform copyWith) | ||||
|   void updateValidator(String key, FormInputValidator dirtyValue) { | ||||
|   void updateValidator<V>( | ||||
|     String key, | ||||
|     FormInputValidator<V, ValidationError> dirtyValue, | ||||
|   ) { | ||||
|     if (contains(key)) { | ||||
|       final index = _inputs.indexOf( | ||||
|         inputOf(key), | ||||
| @ -73,38 +72,31 @@ class FormData extends Equatable { | ||||
| 
 | ||||
|   /// Returns a validation error if the [FormInputValidator] is invalid. | ||||
|   /// Returns null if the [FormInputValidator] is valid. | ||||
|   E? errorOf<V, E>(String key) { | ||||
|     return (inputOf(key).validator as FormInputValidator<V, E>).error; | ||||
|   } | ||||
|   E? errorOf<E extends ValidationError>(String key) => | ||||
|       (inputOf(key).validator as FormInputValidator<dynamic, E>).error; | ||||
| 
 | ||||
|   /// The value of the associated [FormInputValidator]. For example, | ||||
|   /// if you have a FormInputValidator for FirstName, the value could be 'Joe'. | ||||
|   V valueOf<V, E>(String key) { | ||||
|     return (inputOf(key).validator as FormInputValidator<V, E>).value; | ||||
|   } | ||||
|   V valueOf<V>(String key) => | ||||
|       (inputOf(key).validator as FormInputValidator<V, dynamic>).value; | ||||
| 
 | ||||
|   /// Returns `true` if the [FormInputValidator] is not valid. | ||||
|   /// Same as `E? errorOf<V, E>(String key) != null` | ||||
|   bool isNotValid(String key) { | ||||
|     return !inputOf(key).validator.valid; | ||||
|   } | ||||
|   bool isNotValid(String key) => !inputOf(key).validator.valid; | ||||
| 
 | ||||
|   /// Returns all associated metadata as a list | ||||
|   List<FormInputMetadata<M>> metadata<M>() { | ||||
|     return _inputs | ||||
|   List<FormInputMetadata<M>> metadata<M>() => _inputs | ||||
|       .map<FormInputMetadata<M>>( | ||||
|           (FormInput input) => input.metadata as FormInputMetadata<M>, | ||||
|         (input) => input.metadata as FormInputMetadata<M>, | ||||
|       ) | ||||
|       .toList(); | ||||
|   } | ||||
| 
 | ||||
|   /// Returns the metadata associated. With `M` the type of extra data. | ||||
|   FormInputMetadata<M> metadataOf<M>(String key) { | ||||
|     return inputOf(key).metadata as FormInputMetadata<M>; | ||||
|   } | ||||
|   FormInputMetadata<M> metadataOf<M>(String key) => | ||||
|       inputOf(key).metadata as FormInputMetadata<M>; | ||||
| 
 | ||||
|   /// Updates metadata of a given input. (perform copyWith) | ||||
|   void updateMetadata(String key, FormInputMetadata meta) { | ||||
|   void updateMetadata<M>(String key, FormInputMetadata<M> meta) { | ||||
|     if (contains(key)) { | ||||
|       final index = _inputs.indexOf( | ||||
|         inputOf(key), | ||||
| @ -113,15 +105,8 @@ class FormData extends Equatable { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /// Validate self inputs. | ||||
|   FormStatus validate() { | ||||
|     return FormStatus.validateInputs(_inputs); | ||||
|   } | ||||
| 
 | ||||
|   /// Check if this contains an input with the given key. | ||||
|   bool contains(String key) { | ||||
|     return _inputs.any((FormInput input) => input.key == key); | ||||
|   } | ||||
|   bool contains(String key) => _inputs.any((input) => input.key == key); | ||||
| 
 | ||||
|   /// Makes an intersection set operation and returns newly created [FormData] | ||||
|   FormData intersection(FormData other) { | ||||
| @ -173,11 +158,9 @@ class FormData extends Equatable { | ||||
|   } | ||||
| 
 | ||||
|   /// Deeply copy this. | ||||
|   FormData clone() { | ||||
|     return FormData( | ||||
|       _inputs.map((FormInput input) => input.clone()).toList(), | ||||
|   FormData clone() => FormData( | ||||
|         _inputs.map((input) => input.clone()).toList(), | ||||
|       ); | ||||
|   } | ||||
| 
 | ||||
|   /// Export this to [Map] format. | ||||
|   Map<String, dynamic> toMap() { | ||||
| @ -190,6 +173,9 @@ class FormData extends Equatable { | ||||
|     return map; | ||||
|   } | ||||
| 
 | ||||
|   /// Export this to [String] format. | ||||
|   String toJson() => jsonEncode(toMap()); | ||||
| 
 | ||||
|   @override | ||||
|   bool? get stringify => true; | ||||
| 
 | ||||
|  | ||||
| @ -17,10 +17,11 @@ | ||||
| 
 | ||||
| part of 'form.dart'; | ||||
| 
 | ||||
| class FormInput extends Equatable { | ||||
| class FormInput<Validator extends FormInputValidator<dynamic, ValidationError>> | ||||
|     extends Equatable { | ||||
|   final String key; | ||||
|   final FormInputValidator validator; | ||||
|   final FormInputMetadata metadata; | ||||
|   final Validator validator; | ||||
|   final FormInputMetadata<dynamic> metadata; | ||||
| 
 | ||||
|   String get name => metadata._name ?? key; | ||||
| 
 | ||||
| @ -31,29 +32,25 @@ class FormInput extends Equatable { | ||||
|     this.metadata = const FormInputMetadata<void>(export: true), | ||||
|   }); | ||||
| 
 | ||||
|   FormInput copyWith({ | ||||
|     String? key, | ||||
|     Validator? validator, | ||||
|     FormInputMetadata? metadata, | ||||
|   }) => | ||||
|       FormInput( | ||||
|         key ?? this.key, | ||||
|         validator ?? this.validator, | ||||
|         metadata: metadata ?? this.metadata, | ||||
|       ); | ||||
| 
 | ||||
|   FormInput clone() => copyWith( | ||||
|         key: key, | ||||
|         validator: validator, | ||||
|         metadata: metadata, | ||||
|       ); | ||||
|   @override | ||||
|   bool? get stringify => true; | ||||
| 
 | ||||
|   @override | ||||
|   List<Object?> get props => [key, validator, metadata]; | ||||
| 
 | ||||
|   FormInput copyWith({ | ||||
|     String? key, | ||||
|     FormInputValidator? validator, | ||||
|     FormInputMetadata? metadata, | ||||
|   }) { | ||||
|     return FormInput( | ||||
|       key ?? this.key, | ||||
|       validator ?? this.validator, | ||||
|       metadata: metadata ?? this.metadata, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   FormInput clone() { | ||||
|     return copyWith( | ||||
|       key: key, | ||||
|       validator: validator, | ||||
|       metadata: metadata, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
| 
 | ||||
| part of 'form.dart'; | ||||
| 
 | ||||
| class FormInputMetadata<T> extends Equatable { | ||||
| class FormInputMetadata<T extends Object?> extends Equatable { | ||||
|   final bool export; | ||||
|   final String? _name; | ||||
|   final T? extra; | ||||
| @ -28,29 +28,26 @@ class FormInputMetadata<T> extends Equatable { | ||||
|     String? name, | ||||
|   }) : _name = name; | ||||
| 
 | ||||
|   FormInputMetadata<T> copyWith({ | ||||
|     bool? export, | ||||
|     String? name, | ||||
|     T? extra, | ||||
|   }) => | ||||
|       FormInputMetadata<T>( | ||||
|         export: export ?? this.export, | ||||
|         name: name ?? _name, | ||||
|         extra: extra ?? this.extra, | ||||
|       ); | ||||
| 
 | ||||
|   FormInputMetadata<T> clone() => copyWith( | ||||
|         export: export, | ||||
|         name: _name, | ||||
|         extra: extra, | ||||
|       ); | ||||
| 
 | ||||
|   @override | ||||
|   bool? get stringify => true; | ||||
| 
 | ||||
|   @override | ||||
|   List<Object?> get props => [export, _name, extra]; | ||||
| 
 | ||||
|   FormInputMetadata<T> copyWith({ | ||||
|     bool? export, | ||||
|     String? name, | ||||
|     T? extra, | ||||
|   }) { | ||||
|     return FormInputMetadata<T>( | ||||
|       export: export ?? this.export, | ||||
|       name: name ?? _name, | ||||
|       extra: extra ?? this.extra, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   FormInputMetadata<T> clone() { | ||||
|     return copyWith( | ||||
|       export: export, | ||||
|       name: _name, | ||||
|       extra: extra, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -16,7 +16,7 @@ | ||||
| 
 | ||||
| part of 'form.dart'; | ||||
| 
 | ||||
| /// {@template form_input} | ||||
| /// {@template form_input_validator} | ||||
| /// A [FormInputValidator] represents the value of a single form input field. | ||||
| /// It contains information about the [FormInputStatus], [value], as well | ||||
| /// as validation status. | ||||
| @ -25,20 +25,22 @@ part of 'form.dart'; | ||||
| /// [FormInputValidator] instances. | ||||
| /// | ||||
| /// ```dart | ||||
| /// enum FirstNameError { empty } | ||||
| /// class FirstName extends FormInputValidator<String, FirstNameError> { | ||||
| ///   const FirstName.pure({String value = ''}) : super.pure(value); | ||||
| ///   const FirstName.dirty({String value = ''}) : super.dirty(value); | ||||
| /// class Name extends FormInputValidator<String, ValidationStandardError> { | ||||
| ///   const Name.pure({String value = ''}) : super.pure(value); | ||||
| ///   const Name.dirty({String value = ''}) : super.dirty(value); | ||||
| /// | ||||
| ///   @override | ||||
| ///   FirstNameError? validator(String value) { | ||||
| ///     return value.isEmpty ? FirstNameError.empty : null; | ||||
| ///   ValidationStandardError? validator(String? value) { | ||||
| ///     if (value?.isEmpty ?? false) { | ||||
| ///       return ValidationStandardError.empty | ||||
| ///     } | ||||
| ///     return value == null ? ValidationStandardError.invalid : null; | ||||
| ///   } | ||||
| /// } | ||||
| /// ``` | ||||
| /// {@endtemplate} | ||||
| @immutable | ||||
| abstract class FormInputValidator<V, E> extends Equatable { | ||||
| abstract class FormInputValidator<V, E extends ValidationError> | ||||
|     extends Equatable { | ||||
|   const FormInputValidator._(this.value, [this.pure = true]); | ||||
| 
 | ||||
|   /// Constructor which create a `pure` [FormInputValidator] with a given value. | ||||
|  | ||||
							
								
								
									
										31
									
								
								packages/wyatt_form_bloc/lib/src/form/form_validator.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								packages/wyatt_form_bloc/lib/src/form/form_validator.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| // 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/>. | ||||
| 
 | ||||
| part of 'form.dart'; | ||||
| 
 | ||||
| /// {@template form_validator} | ||||
| /// A [FormValidator] represents the global validaton state of a Form. | ||||
| /// {@endtemplate} | ||||
| abstract class FormValidator { | ||||
|   /// {@macro form_validator} | ||||
|   const FormValidator(); | ||||
| 
 | ||||
|   bool isPure(FormData form) => form | ||||
|       .validators<dynamic, ValidationError>() | ||||
|       .every((validator) => validator.pure); | ||||
| 
 | ||||
|   FormStatus validate(FormData form); | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| // 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'; | ||||
| 
 | ||||
| /// {@template every} | ||||
| /// Check and validate every input of a form | ||||
| /// {@endtemplate} | ||||
| class EveryInputValidator extends FormValidator { | ||||
|   /// {@macro every} | ||||
|   const EveryInputValidator() : super(); | ||||
| 
 | ||||
|   @override | ||||
|   FormStatus validate(FormData form) { | ||||
|     if (isPure(form)) { | ||||
|       return FormStatus.pure; | ||||
|     } | ||||
| 
 | ||||
|     if (form | ||||
|         .validators<dynamic, ValidationError>() | ||||
|         .any((validator) => validator.valid == false)) { | ||||
|       return FormStatus.invalid; | ||||
|     } | ||||
| 
 | ||||
|     return FormStatus.valid; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,41 @@ | ||||
| // 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/src/enums/validation_error.dart'; | ||||
| import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| 
 | ||||
| /// {@template regex_validator} | ||||
| /// Abstract regex validator for form input. | ||||
| /// {@endtemplate} | ||||
| abstract class RegexValidator<E extends ValidationError> | ||||
|     extends FormInputValidator<String, E> { | ||||
|   const RegexValidator.pure() : super.pure(''); | ||||
|   const RegexValidator.dirty([super.value = '']) : super.dirty(); | ||||
| 
 | ||||
|   RegExp get regex; | ||||
|   /// If the value is **not** null, but empty. | ||||
|   E get onEmpty; | ||||
|   /// If value does not conform to regex. | ||||
|   E get onError; | ||||
| 
 | ||||
|   @override | ||||
|   E? validator(String? value) { | ||||
|     if (value?.isEmpty ?? false) { | ||||
|       return onEmpty; | ||||
|     } | ||||
|     return regex.hasMatch(value ?? '') ? null : onError; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,38 @@ | ||||
| // 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/src/enums/validation_error.dart'; | ||||
| import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| 
 | ||||
| abstract class TextValidator<E extends ValidationError> | ||||
|     extends FormInputValidator<String, E> { | ||||
|   const TextValidator.pure() : super.pure(''); | ||||
|   const TextValidator.dirty([super.value = '']) : super.dirty(); | ||||
| 
 | ||||
|   /// If the value is **not** null, but empty. | ||||
|   E get onEmpty; | ||||
| 
 | ||||
|   /// If value is null. | ||||
|   E get onNull; | ||||
| 
 | ||||
|   @override | ||||
|   E? validator(String? value) { | ||||
|     if (value?.isEmpty ?? false) { | ||||
|       return onEmpty; | ||||
|     } | ||||
|     return value != null ? null : onNull; | ||||
|   } | ||||
| } | ||||
| @ -20,7 +20,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| /// {@template boolean} | ||||
| /// Form input for a bool input | ||||
| /// {@endtemplate} | ||||
| class Boolean extends FormInputValidator<bool, ValidationError> { | ||||
| class Boolean extends FormInputValidator<bool, ValidationStandardError> { | ||||
|   /// {@macro boolean} | ||||
|   const Boolean.pure({bool? defaultValue = false}) | ||||
|       : super.pure(defaultValue ?? false); | ||||
| @ -29,7 +29,6 @@ class Boolean extends FormInputValidator<bool, ValidationError> { | ||||
|   const Boolean.dirty({bool value = false}) : super.dirty(value); | ||||
| 
 | ||||
|   @override | ||||
|   ValidationError? validator(bool? value) { | ||||
|     return value != null ? null : ValidationError.invalid; | ||||
|   } | ||||
|   ValidationStandardError? validator(bool? value) => | ||||
|       value != null ? null : ValidationStandardError.invalid; | ||||
| } | ||||
| @ -21,7 +21,7 @@ import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| /// Form input for a confirmed password input. | ||||
| /// {@endtemplate} | ||||
| class ConfirmedPassword | ||||
|     extends FormInputValidator<String, ValidationError> { | ||||
|     extends FormInputValidator<String, ValidationStandardError> { | ||||
|   /// {@macro confirmed_password} | ||||
|   const ConfirmedPassword.pure({this.password = ''}) : super.pure(''); | ||||
| 
 | ||||
| @ -33,7 +33,6 @@ class ConfirmedPassword | ||||
|   final String password; | ||||
| 
 | ||||
|   @override | ||||
|   ValidationError? validator(String? value) { | ||||
|     return password == value ? null : ValidationError.invalid; | ||||
|   } | ||||
|   ValidationStandardError? validator(String? value) => | ||||
|       password == value ? null : ValidationStandardError.invalid; | ||||
| } | ||||
| @ -15,24 +15,25 @@ | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| import 'package:wyatt_form_bloc/src/enums/enums.dart'; | ||||
| import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart'; | ||||
| 
 | ||||
| /// {@template email} | ||||
| /// Form input for an email input. | ||||
| /// {@endtemplate} | ||||
| class Email extends FormInputValidator<String, ValidationError> { | ||||
| class Email extends RegexValidator<ValidationStandardError> { | ||||
|   /// {@macro email} | ||||
|   const Email.pure() : super.pure(''); | ||||
|   const Email.pure() : super.pure(); | ||||
| 
 | ||||
|   /// {@macro email} | ||||
|   const Email.dirty([String value = '']) : super.dirty(value); | ||||
| 
 | ||||
|   static final RegExp _emailRegExp = RegExp( | ||||
|     r'[^@ \t\r\n]+@[^@ \t\r\n]+\.[^@ \t\r\n]+', | ||||
|   ); | ||||
|   const Email.dirty([super.value = '']) : super.dirty(); | ||||
| 
 | ||||
|   @override | ||||
|   ValidationError? validator(String? value) { | ||||
|     return _emailRegExp.hasMatch(value ?? '') ? null : ValidationError.invalid; | ||||
|   } | ||||
|   ValidationStandardError get onEmpty => ValidationStandardError.empty; | ||||
|   @override | ||||
|   ValidationStandardError get onError => ValidationStandardError.invalid; | ||||
| 
 | ||||
|   @override | ||||
|   RegExp get regex => RegExp( | ||||
|         r'[^@ \t\r\n]+@[^@ \t\r\n]+\.[^@ \t\r\n]+', | ||||
|       ); | ||||
| } | ||||
| @ -0,0 +1,32 @@ | ||||
| // 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/src/enums/validation_error.dart'; | ||||
| import 'package:wyatt_form_bloc/src/validators/inputs/base/text_validator.dart'; | ||||
| 
 | ||||
| class EnumValidator<E> extends TextValidator<ValidationStandardError> { | ||||
|   /// {@macro text_string} | ||||
|   const EnumValidator.pure() : super.pure(); | ||||
| 
 | ||||
|   /// {@macro text_string} | ||||
|   EnumValidator.dirty(E value) : super.dirty(value.toString()); | ||||
| 
 | ||||
|   @override | ||||
|   ValidationStandardError get onEmpty => ValidationStandardError.empty; | ||||
| 
 | ||||
|   @override | ||||
|   ValidationStandardError get onNull => ValidationStandardError.invalid; | ||||
| } | ||||
| @ -15,24 +15,25 @@ | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| import 'package:wyatt_form_bloc/src/enums/enums.dart'; | ||||
| import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart'; | ||||
| 
 | ||||
| /// {@template iban} | ||||
| /// Form input for an IBAN input. | ||||
| /// {@endtemplate} | ||||
| class Iban extends FormInputValidator<String, ValidationError> { | ||||
| class Iban extends RegexValidator<ValidationStandardError> { | ||||
|   /// {@macro iban} | ||||
|   const Iban.pure() : super.pure(''); | ||||
|   const Iban.pure() : super.pure(); | ||||
| 
 | ||||
|   /// {@macro iban} | ||||
|   const Iban.dirty([String value = '']) : super.dirty(value); | ||||
| 
 | ||||
|   static final RegExp _regExp = RegExp( | ||||
|     r'^(?:((?:IT|SM)\d{2}[A-Z]{1}\d{22})|(NL\d{2}[A-Z]{4}\d{10})|(LV\d{2}[A-Z]{4}\d{13})|((?:BG|GB|IE)\d{2}[A-Z]{4}\d{14})|(GI\d{2}[A-Z]{4}\d{15})|(RO\d{2}[A-Z]{4}\d{16})|(MT\d{2}[A-Z]{4}\d{23})|(NO\d{13})|((?:DK|FI)\d{16})|((?:SI)\d{17})|((?:AT|EE|LU|LT)\d{18})|((?:HR|LI|CH)\d{19})|((?:DE|VA)\d{20})|((?:AD|CZ|ES|MD|SK|SE)\d{22})|(PT\d{23})|((?:IS)\d{24})|((?:BE)\d{14})|((?:FR|MC|GR)\d{25})|((?:PL|HU|CY)\d{26}))$', | ||||
|   ); | ||||
|   const Iban.dirty([super.value = '']) : super.dirty(); | ||||
| 
 | ||||
|   @override | ||||
|   ValidationError? validator(String? value) { | ||||
|     return _regExp.hasMatch(value ?? '') ? null : ValidationError.invalid; | ||||
|   } | ||||
|   ValidationStandardError get onEmpty => ValidationStandardError.empty; | ||||
|   @override | ||||
|   ValidationStandardError get onError => ValidationStandardError.invalid; | ||||
| 
 | ||||
|   @override | ||||
|   RegExp get regex => RegExp( | ||||
|         r'^(?:((?:IT|SM)\d{2}[A-Z]{1}\d{22})|(NL\d{2}[A-Z]{4}\d{10})|(LV\d{2}[A-Z]{4}\d{13})|((?:BG|GB|IE)\d{2}[A-Z]{4}\d{14})|(GI\d{2}[A-Z]{4}\d{15})|(RO\d{2}[A-Z]{4}\d{16})|(MT\d{2}[A-Z]{4}\d{23})|(NO\d{13})|((?:DK|FI)\d{16})|((?:SI)\d{17})|((?:AT|EE|LU|LT)\d{18})|((?:HR|LI|CH)\d{19})|((?:DE|VA)\d{20})|((?:AD|CZ|ES|MD|SK|SE)\d{22})|(PT\d{23})|((?:IS)\d{24})|((?:BE)\d{14})|((?:FR|MC|GR)\d{25})|((?:PL|HU|CY)\d{26}))$', | ||||
|       ); | ||||
| } | ||||
| @ -20,7 +20,8 @@ import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| /// {@template list_option} | ||||
| /// Form input for a list input | ||||
| /// {@endtemplate} | ||||
| class ListOption<T> extends FormInputValidator<List<T>, ValidationError> { | ||||
| class ListOption<T> | ||||
|     extends FormInputValidator<List<T>, ValidationStandardError> { | ||||
|   /// {@macro list_option} | ||||
|   const ListOption.pure({List<T>? defaultValue}) | ||||
|       : super.pure(defaultValue ?? const []); | ||||
| @ -28,7 +29,7 @@ class ListOption<T> extends FormInputValidator<List<T>, ValidationError> { | ||||
|   /// {@macro list_option} | ||||
|   const ListOption.dirty({List<T>? value}) : super.dirty(value ?? const []); | ||||
| 
 | ||||
|   ListOption select(T? v) { | ||||
|   ListOption<T> select(T? v) { | ||||
|     if (v == null) { | ||||
|       return this; | ||||
|     } | ||||
| @ -42,7 +43,8 @@ class ListOption<T> extends FormInputValidator<List<T>, ValidationError> { | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   ValidationError? validator(List<T>? value) { | ||||
|     return value?.isNotEmpty == true ? null : ValidationError.invalid; | ||||
|   } | ||||
|   ValidationStandardError? validator(List<T>? value) => | ||||
|       value?.isNotEmpty ?? false == true | ||||
|           ? null | ||||
|           : ValidationStandardError.invalid; | ||||
| } | ||||
| @ -15,22 +15,23 @@ | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| import 'package:wyatt_form_bloc/src/enums/enums.dart'; | ||||
| import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart'; | ||||
| 
 | ||||
| /// {@template name} | ||||
| /// Form input for a name input. | ||||
| /// {@endtemplate} | ||||
| class Name extends FormInputValidator<String, ValidationError> { | ||||
| class Name extends RegexValidator<ValidationStandardError> { | ||||
|   /// {@macro name} | ||||
|   const Name.pure() : super.pure(''); | ||||
|   const Name.pure() : super.pure(); | ||||
| 
 | ||||
|   /// {@macro name} | ||||
|   const Name.dirty([String value = '']) : super.dirty(value); | ||||
| 
 | ||||
|   static final RegExp _nameRegExp = RegExp(r"^([ \u00c0-\u01ffa-zA-Z'\-])+$"); | ||||
|   const Name.dirty([super.value = '']) : super.dirty(); | ||||
| 
 | ||||
|   @override | ||||
|   ValidationError? validator(String? value) { | ||||
|     return _nameRegExp.hasMatch(value ?? '') ? null : ValidationError.invalid; | ||||
|   } | ||||
|   ValidationStandardError get onEmpty => ValidationStandardError.empty; | ||||
|   @override | ||||
|   ValidationStandardError get onError => ValidationStandardError.invalid; | ||||
| 
 | ||||
|   @override | ||||
|   RegExp get regex => RegExp(r"^([ \u00c0-\u01ffa-zA-Z'\-])+$"); | ||||
| } | ||||
| @ -15,25 +15,23 @@ | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| import 'package:wyatt_form_bloc/src/enums/enums.dart'; | ||||
| import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart'; | ||||
| 
 | ||||
| /// {@template password} | ||||
| /// Form input for a password input. | ||||
| /// {@endtemplate} | ||||
| class Password extends FormInputValidator<String, ValidationError> { | ||||
| class Password extends RegexValidator<ValidationStandardError> { | ||||
|   /// {@macro password} | ||||
|   const Password.pure() : super.pure(''); | ||||
|   const Password.pure() : super.pure(); | ||||
| 
 | ||||
|   /// {@macro password} | ||||
|   const Password.dirty([String value = '']) : super.dirty(value); | ||||
| 
 | ||||
|   static final RegExp _passwordRegExp = | ||||
|       RegExp(r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$'); | ||||
|   const Password.dirty([super.value = '']) : super.dirty(); | ||||
| 
 | ||||
|   @override | ||||
|   ValidationError? validator(String? value) { | ||||
|     return _passwordRegExp.hasMatch(value ?? '') | ||||
|         ? null | ||||
|         : ValidationError.invalid; | ||||
|   } | ||||
|   ValidationStandardError get onEmpty => ValidationStandardError.empty; | ||||
|   @override | ||||
|   ValidationStandardError get onError => ValidationStandardError.invalid; | ||||
| 
 | ||||
|   @override | ||||
|   RegExp get regex => RegExp(r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$'); | ||||
| } | ||||
| @ -15,23 +15,24 @@ | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| import 'package:wyatt_form_bloc/src/enums/enums.dart'; | ||||
| import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart'; | ||||
| 
 | ||||
| /// {@template phone} | ||||
| /// Form input for a phone input. | ||||
| /// {@endtemplate} | ||||
| class Phone extends FormInputValidator<String, ValidationError> { | ||||
| class Phone extends RegexValidator<ValidationStandardError> { | ||||
|   /// {@macro phone} | ||||
|   const Phone.pure() : super.pure(''); | ||||
|   const Phone.pure() : super.pure(); | ||||
| 
 | ||||
|   /// {@macro phone} | ||||
|   const Phone.dirty([String value = '']) : super.dirty(value); | ||||
| 
 | ||||
|   static final RegExp _phoneRegExp = | ||||
|       RegExp(r'^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$'); | ||||
|   const Phone.dirty([super.value = '']) : super.dirty(); | ||||
| 
 | ||||
|   @override | ||||
|   ValidationError? validator(String? value) { | ||||
|     return _phoneRegExp.hasMatch(value ?? '') ? null : ValidationError.invalid; | ||||
|   } | ||||
|   ValidationStandardError get onEmpty => ValidationStandardError.empty; | ||||
|   @override | ||||
|   ValidationStandardError get onError => ValidationStandardError.invalid; | ||||
| 
 | ||||
|   @override | ||||
|   RegExp get regex => | ||||
|       RegExp(r'^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$'); | ||||
| } | ||||
| @ -15,22 +15,23 @@ | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| import 'package:wyatt_form_bloc/src/enums/enums.dart'; | ||||
| import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart'; | ||||
| 
 | ||||
| /// {@template siren} | ||||
| /// Form input for a SIREN input. | ||||
| /// {@endtemplate} | ||||
| class Siren extends FormInputValidator<String, ValidationError> { | ||||
| class Siren extends RegexValidator<ValidationStandardError> { | ||||
|   /// {@macro siren} | ||||
|   const Siren.pure() : super.pure(''); | ||||
|   const Siren.pure() : super.pure(); | ||||
| 
 | ||||
|   /// {@macro siren} | ||||
|   const Siren.dirty([String value = '']) : super.dirty(value); | ||||
| 
 | ||||
|   static final RegExp _regExp = RegExp(r'(\d{9}|\d{3}[ ]\d{3}[ ]\d{3})$'); | ||||
|   const Siren.dirty([super.value = '']) : super.dirty(); | ||||
| 
 | ||||
|   @override | ||||
|   ValidationError? validator(String? value) { | ||||
|     return _regExp.hasMatch(value ?? '') ? null : ValidationError.invalid; | ||||
|   } | ||||
|   ValidationStandardError get onEmpty => ValidationStandardError.empty; | ||||
|   @override | ||||
|   ValidationStandardError get onError => ValidationStandardError.invalid; | ||||
| 
 | ||||
|   @override | ||||
|   RegExp get regex => RegExp(r'(\d{9}|\d{3}[ ]\d{3}[ ]\d{3})$'); | ||||
| } | ||||
| @ -15,20 +15,21 @@ | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| import 'package:wyatt_form_bloc/src/enums/enums.dart'; | ||||
| import 'package:wyatt_form_bloc/src/form/form.dart'; | ||||
| import 'package:wyatt_form_bloc/src/validators/inputs/base/text_validator.dart'; | ||||
| 
 | ||||
| /// {@template text_string} | ||||
| /// Form input for a text input | ||||
| /// {@endtemplate} | ||||
| class TextString extends FormInputValidator<String, ValidationError> { | ||||
| class TextString extends TextValidator<ValidationStandardError> { | ||||
|   /// {@macro text_string} | ||||
|   const TextString.pure() : super.pure(''); | ||||
|   const TextString.pure() : super.pure(); | ||||
| 
 | ||||
|   /// {@macro text_string} | ||||
|   const TextString.dirty([String value = '']) : super.dirty(value); | ||||
|   const TextString.dirty([super.value = '']) : super.dirty(); | ||||
| 
 | ||||
|   @override | ||||
|   ValidationError? validator(String? value) { | ||||
|     return (value?.isNotEmpty ?? false) ? null : ValidationError.invalid; | ||||
|   } | ||||
|   ValidationStandardError get onEmpty => ValidationStandardError.empty; | ||||
| 
 | ||||
|   @override | ||||
|   ValidationStandardError get onNull => ValidationStandardError.invalid; | ||||
| } | ||||
| @ -14,13 +14,16 @@ | ||||
| // 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 'boolean.dart'; | ||||
| export 'confirmed_password.dart'; | ||||
| export 'email.dart'; | ||||
| export 'iban.dart'; | ||||
| export 'list_option.dart'; | ||||
| export 'name.dart'; | ||||
| export 'password.dart'; | ||||
| export 'phone.dart'; | ||||
| export 'siren.dart'; | ||||
| export 'text_string.dart'; | ||||
| export 'inputs/base/regex_validator.dart'; | ||||
| export 'inputs/base/text_validator.dart'; | ||||
| export 'inputs/boolean.dart'; | ||||
| export 'inputs/confirmed_password.dart'; | ||||
| export 'inputs/email.dart'; | ||||
| export 'inputs/enum_validator.dart'; | ||||
| export 'inputs/iban.dart'; | ||||
| export 'inputs/list_option.dart'; | ||||
| export 'inputs/name.dart'; | ||||
| export 'inputs/password.dart'; | ||||
| export 'inputs/phone.dart'; | ||||
| export 'inputs/siren.dart'; | ||||
| export 'inputs/text_string.dart'; | ||||
|  | ||||
| @ -9,7 +9,6 @@ environment: | ||||
| dependencies: | ||||
|   bloc: ^8.0.3 | ||||
|   equatable: ^2.0.3 | ||||
|   meta: ^1.7.0 | ||||
| 
 | ||||
| dev_dependencies: | ||||
|   test: ^1.21.4 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user