feat!(form): migrate to wyatt architecture

This commit is contained in:
2022-11-09 22:35:41 -05:00
parent 79fdd3c837
commit b89ef3de8a
62 changed files with 1387 additions and 818 deletions
@@ -14,17 +14,4 @@
// 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 'form/every_input_validator.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';
export 'enums/enums.dart';
@@ -0,0 +1,39 @@
// 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/data/form_operations/form_difference.dart';
import 'package:wyatt_form_bloc/src/data/form_operations/form_intersection.dart';
import 'package:wyatt_form_bloc/src/data/form_operations/form_replace.dart';
import 'package:wyatt_form_bloc/src/data/form_operations/form_union.dart';
import 'package:wyatt_form_bloc/src/domain/form_operations/form_operation.dart';
enum SetOperation {
/// Replace entire set with new set.
replace(FormReplace()),
/// Keep common elements between sets.
intersection(FormIntersection()),
/// Remove common elements between sets.
difference(FormDifference()),
/// Add new elements to set.
union(FormUnion());
final FormOperation operation;
const SetOperation(this.operation);
}
@@ -23,5 +23,6 @@ abstract class ValidationError {}
enum ValidationStandardError implements ValidationError {
invalid,
empty
empty,
notEqual,
}
@@ -1,110 +0,0 @@
// 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 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.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> {
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<V>(
String field,
FormInputValidator<V, ValidationError> dirtyValue,
) {
final form = state.data.clone();
if (form.contains(field)) {
form.updateValidator(field, dirtyValue);
} else {
throw Exception('Form field $field not found');
}
emit(
state.copyWith(
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:
/// - `data`: The new entries list.
/// - `operation`: The operation to perform on the entries set.
void updateFormData(
FormData data, {
SetOperation operation = SetOperation.replace,
}) {
FormData form = data;
switch (operation) {
case SetOperation.replace:
form = data;
break;
case SetOperation.difference:
form = state.data.difference(data);
break;
case SetOperation.intersection:
form = state.data.intersection(data);
break;
case SetOperation.union:
form = state.data.union(data);
break;
}
emit(
state.copyWith(
data: form,
status: validationStrategy.validate(form),
),
);
}
/// Reset all form inputs
void resetForm() {
emit(FormDataState(data: formCopy));
}
/// Submit the form.
Future<void> submitForm();
}
@@ -0,0 +1,34 @@
// 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/>.
export 'form/wyatt_form_impl.dart';
export 'form_encoders/form_json_encoder.dart';
export 'form_encoders/form_map_encoder.dart';
export 'form_operations/form_difference.dart';
export 'form_operations/form_intersection.dart';
export 'form_operations/form_replace.dart';
export 'form_operations/form_union.dart';
export 'form_validators/every_input_validator.dart';
export 'form_validators/only_required_input_validator.dart';
export 'input_validators/boolean.dart';
export 'input_validators/confirmed_password.dart';
export 'input_validators/email.dart';
export 'input_validators/enum_option.dart';
export 'input_validators/list_option.dart';
export 'input_validators/name.dart';
export 'input_validators/password.dart';
export 'input_validators/phone.dart';
export 'input_validators/text_string.dart';
@@ -0,0 +1,136 @@
// 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/core/enums/form_status.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/data/form_validators/every_input_validator.dart';
import 'package:wyatt_form_bloc/src/domain/entities/form_input.dart';
import 'package:wyatt_form_bloc/src/domain/entities/form_input_metadata.dart';
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
import 'package:wyatt_form_bloc/src/domain/form_operations/form_operation.dart';
import 'package:wyatt_form_bloc/src/domain/form_validators/form_validator.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
// ignore: must_be_immutable
class WyattFormImpl extends WyattForm {
final List<
FormInput<dynamic, FormInputValidator<dynamic, ValidationError>,
dynamic>> _inputs;
final FormValidator _validator;
late List<
FormInput<dynamic, FormInputValidator<dynamic, ValidationError>,
dynamic>> _inputsInitial;
WyattFormImpl(
this._inputs, {
FormValidator validationStrategy = const EveryInputValidator(),
}) : _validator = validationStrategy {
_inputsInitial = _inputs.map((input) => input.clone()).toList();
}
@override
List<
FormInput<dynamic, FormInputValidator<dynamic, ValidationError>,
dynamic>> get inputs => _inputs;
@override
FormValidator get formValidationStrategy => _validator;
@override
bool containsKey(String key) => inputs.any((input) => input.key == key);
@override
List<FormInputValidator<Value, Error>>
asValidatorList<Value, Error extends ValidationError>() => inputs
.map<FormInputValidator<Value, Error>>(
(input) => input.validator as FormInputValidator<Value, Error>,
)
.toList();
@override
FormInput<dynamic, FormInputValidator<dynamic, ValidationError>, dynamic>
inputOf(String key) {
if (containsKey(key)) {
return inputs.firstWhere((input) => input.key == key);
} else {
throw Exception('FormInput with key `$key` does not exist in form');
}
}
@override
Error? errorOf<Error extends ValidationError>(String key) =>
(inputOf(key).validator as FormInputValidator<dynamic, Error>).error;
@override
FormInputMetadata<Extra> metadataOf<Extra>(String key) =>
inputOf(key).metadata as FormInputMetadata<Extra>;
@override
Validator validatorOf<
Validator extends FormInputValidator<dynamic, ValidationError>>(
String key,
) =>
inputOf(key).validator as Validator;
@override
Value? valueOf<Value>(String key) =>
(inputOf(key).validator as FormInputValidator<Value, dynamic>).value;
@override
FormStatus validate() => formValidationStrategy.validate(this);
@override
WyattForm clone() => WyattFormImpl(
_inputs.map((input) => input.clone()).toList(),
validationStrategy: formValidationStrategy,
);
@override
WyattForm reset() => WyattFormImpl(
_inputsInitial,
validationStrategy: formValidationStrategy,
);
@override
bool? get stringify => true;
@override
List<Object?> get props => _inputs;
@override
void updateMetadata<Extra>(String key, FormInputMetadata<Extra> metadata) {
final index = _inputs.indexOf(
inputOf(key),
);
_inputs[index] = _inputs[index].copyWith(metadata: metadata);
}
@override
void updateValidator<Value>(
String key,
FormInputValidator<Value?, ValidationError> dirtyValue,
) {
final index = _inputs.indexOf(
inputOf(key),
);
_inputs[index] = _inputs[index].copyWith(validator: dirtyValue);
}
@override
WyattForm operationWith(FormOperation operation, WyattForm other) =>
operation.call(this, other);
}
@@ -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 'dart:convert';
import 'package:wyatt_form_bloc/src/data/form_encoders/form_map_encoder.dart';
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
import 'package:wyatt_form_bloc/src/domain/form_encoders/form_encoder.dart';
class FormJsonEncoder extends FormEncoder<String> {
@override
String encode(WyattForm form) {
final mapEncoder = FormMapEncoder();
final map = mapEncoder.encode(form);
return jsonEncode(map);
}
}
@@ -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/domain/form/wyatt_form.dart';
import 'package:wyatt_form_bloc/src/domain/form_encoders/form_encoder.dart';
class FormMapEncoder extends FormEncoder<Map<String, dynamic>> {
@override
Map<String, dynamic> encode(WyattForm form) {
final inputs = form.inputs;
final map = <String, dynamic>{};
for (final input in inputs) {
if (input.metadata.export) {
map[input.name] = input.validator.value;
}
}
return map;
}
}
@@ -0,0 +1,50 @@
// 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/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/data/form/wyatt_form_impl.dart';
import 'package:wyatt_form_bloc/src/domain/entities/form_input.dart';
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
import 'package:wyatt_form_bloc/src/domain/form_operations/form_operation.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
class FormDifference extends FormOperation {
const FormDifference();
@override
WyattForm call(WyattForm a, WyattForm b) {
final inputs = <
FormInput<dynamic, FormInputValidator<dynamic, ValidationError>,
dynamic>>[];
for (final i in b.inputs) {
if (!a.containsKey(i.key)) {
inputs.add(i);
}
}
for (final i in a.inputs) {
if (!b.containsKey(i.key)) {
inputs.add(i);
}
}
return WyattFormImpl(
inputs,
validationStrategy: a.formValidationStrategy,
);
}
}
@@ -0,0 +1,44 @@
// 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/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/data/form/wyatt_form_impl.dart';
import 'package:wyatt_form_bloc/src/domain/entities/form_input.dart';
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
import 'package:wyatt_form_bloc/src/domain/form_operations/form_operation.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
class FormIntersection extends FormOperation {
const FormIntersection();
@override
WyattForm call(WyattForm a, WyattForm b) {
final inputs = <
FormInput<dynamic, FormInputValidator<dynamic, ValidationError>,
dynamic>>[];
for (final i in a.inputs) {
if (b.containsKey(i.key)) {
inputs.add(i);
}
}
return WyattFormImpl(
inputs,
validationStrategy: a.formValidationStrategy,
);
}
}
@@ -14,15 +14,12 @@
// 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:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
import 'package:wyatt_form_bloc/src/domain/form_operations/form_operation.dart';
import 'package:equatable/equatable.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';
class FormReplace extends FormOperation {
const FormReplace();
part 'form_data.dart';
part 'form_input.dart';
part 'form_input_metadata.dart';
part 'form_input_validator.dart';
part 'form_validator.dart';
@override
WyattForm call(WyattForm a, WyattForm b) => b;
}
@@ -0,0 +1,48 @@
// 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/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/data/form/wyatt_form_impl.dart';
import 'package:wyatt_form_bloc/src/domain/entities/form_input.dart';
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
import 'package:wyatt_form_bloc/src/domain/form_operations/form_operation.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
class FormUnion extends FormOperation {
const FormUnion();
@override
WyattForm call(WyattForm a, WyattForm b) {
final inputs = <
FormInput<dynamic, FormInputValidator<dynamic, ValidationError>,
dynamic>>[];
for (final i in a.inputs) {
inputs.add(i);
}
for (final i in b.inputs) {
if (!a.containsKey(i.key)) {
inputs.add(i);
}
}
return WyattFormImpl(
inputs,
validationStrategy: a.formValidationStrategy,
);
}
}
@@ -14,7 +14,10 @@
// 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';
import 'package:wyatt_form_bloc/src/core/enums/form_status.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
import 'package:wyatt_form_bloc/src/domain/form_validators/form_validator.dart';
/// {@template every}
/// Check and validate every input of a form
@@ -24,18 +27,13 @@ class EveryInputValidator extends FormValidator {
const EveryInputValidator() : super();
@override
FormStatus validate(FormData form) {
FormStatus validate(WyattForm form) {
if (isPure(form)) {
return FormStatus.pure;
}
return rawValidate(form.validators<dynamic, ValidationError>());
}
final validators = form.asValidatorList<dynamic, ValidationError>();
@override
FormStatus rawValidate(
List<FormInputValidator<dynamic, ValidationError>> validators,
) {
if (validators.any((validator) => validator.valid == false)) {
return FormStatus.invalid;
}
@@ -0,0 +1,29 @@
// 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/core/enums/form_status.dart';
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
import 'package:wyatt_form_bloc/src/domain/form_validators/form_validator.dart';
class OnlyRequiredInputValidator extends FormValidator {
const OnlyRequiredInputValidator() : super();
@override
FormStatus validate(WyattForm form) {
// TODO(hpcl): use metadata to check if input is required or not.
return FormStatus.valid;
}
}
@@ -14,21 +14,25 @@
// 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/enums.dart';
import 'package:wyatt_form_bloc/src/form/form.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
/// {@template boolean}
/// Form input for a bool input
/// {@endtemplate}
class Boolean extends FormInputValidator<bool, ValidationStandardError> {
class Boolean extends NullableValidator<bool, ValidationStandardError> {
/// {@macro boolean}
const Boolean.pure({bool? defaultValue = false})
: super.pure(defaultValue ?? false);
/// {@macro boolean}
const Boolean.dirty({bool value = false}) : super.dirty(value);
@override
ValidationStandardError get onNull => ValidationStandardError.invalid;
@override
ValidationStandardError? validator(bool? value) =>
value != null ? null : ValidationStandardError.invalid;
value != null ? null : onNull;
}
@@ -14,25 +14,31 @@
// 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/enums.dart';
import 'package:wyatt_form_bloc/src/form/form.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
/// {@template confirmed_password}
/// Form input for a confirmed password input.
/// {@endtemplate}
class ConfirmedPassword
extends FormInputValidator<String, ValidationStandardError> {
extends EqualityValidator<String, ValidationStandardError> {
/// {@macro confirmed_password}
const ConfirmedPassword.pure({this.password = ''}) : super.pure('');
const ConfirmedPassword.pure({this.password = '', String? defaultValue})
: super.pure(defaultValue);
/// {@macro confirmed_password}
const ConfirmedPassword.dirty({required this.password, String value = ''})
const ConfirmedPassword.dirty({required this.password, String? value})
: super.dirty(value);
/// The original password.
final String password;
@override
ValidationStandardError? validator(String? value) =>
password == value ? null : ValidationStandardError.invalid;
String get another => password;
@override
ValidationStandardError get onNotEqual => ValidationStandardError.notEqual;
@override
ValidationStandardError get onNull => ValidationStandardError.invalid;
}
@@ -14,15 +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 'package:wyatt_form_bloc/src/enums/enums.dart';
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
/// {@template email}
/// Form input for an email input.
/// {@endtemplate}
class Email extends RegexValidator<ValidationStandardError> {
/// {@macro email}
const Email.pure() : super.pure();
const Email.pure([super.value]) : super.pure();
/// {@macro email}
const Email.dirty([super.value = '']) : super.dirty();
@@ -14,24 +14,27 @@
// 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/enums.dart';
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
/// {@template siren}
/// Form input for a SIREN input.
/// {@endtemplate}
class Siren extends RegexValidator<ValidationStandardError> {
/// {@macro siren}
const Siren.pure() : super.pure();
class EnumOption<T> extends AnyValidator<T, List<T>, ValidationError> {
const EnumOption.pure({this.enums = const [], T? defaultValue})
: super.pure(defaultValue);
/// {@macro siren}
const Siren.dirty([super.value = '']) : super.dirty();
const EnumOption.dirty({required this.enums, T? value})
: super.dirty(value);
final List<T> enums;
@override
ValidationStandardError get onEmpty => ValidationStandardError.empty;
@override
ValidationStandardError get onError => ValidationStandardError.invalid;
List<T> get allChoices => enums;
@override
RegExp get regex => RegExp(r'(\d{9}|\d{3}[ ]\d{3}[ ]\d{3})$');
ValidationError get onError => ValidationStandardError.invalid;
@override
ValidationError get onNull => ValidationStandardError.invalid;
@override
bool test(T? element, T value) => element == value;
}
@@ -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/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
class ListOption<T> extends AnyValidator<T, Iterable<T>, ValidationError> {
const ListOption.pure({this.choices = const [], T? defaultValue})
: super.pure(defaultValue);
const ListOption.dirty({required this.choices, T? value})
: super.dirty(value);
final Iterable<T> choices;
@override
Iterable<T> get allChoices => choices;
@override
ValidationError get onError => ValidationStandardError.invalid;
@override
ValidationError get onNull => ValidationStandardError.invalid;
@override
bool test(T? element, T value) => element == value;
}
@@ -14,15 +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 'package:wyatt_form_bloc/src/enums/enums.dart';
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
/// {@template name}
/// Form input for a name input.
/// {@endtemplate}
class Name extends RegexValidator<ValidationStandardError> {
/// {@macro name}
const Name.pure() : super.pure();
const Name.pure([super.value]) : super.pure();
/// {@macro name}
const Name.dirty([super.value = '']) : super.dirty();
@@ -14,18 +14,18 @@
// 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/enums.dart';
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
/// {@template password}
/// Form input for a password input.
/// {@endtemplate}
class Password extends RegexValidator<ValidationStandardError> {
/// {@macro password}
const Password.pure() : super.pure();
const Password.pure([super.value]) : super.pure();
/// {@macro password}
const Password.dirty([super.value = '']) : super.dirty();
const Password.dirty([super.value]) : super.dirty();
@override
ValidationStandardError get onEmpty => ValidationStandardError.empty;
@@ -14,15 +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 'package:wyatt_form_bloc/src/enums/enums.dart';
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
/// {@template phone}
/// Form input for a phone input.
/// {@endtemplate}
class Phone extends RegexValidator<ValidationStandardError> {
/// {@macro phone}
const Phone.pure() : super.pure();
const Phone.pure([super.value]) : super.pure();
/// {@macro phone}
const Phone.dirty([super.value = '']) : super.dirty();
@@ -14,15 +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 'package:wyatt_form_bloc/src/enums/enums.dart';
import 'package:wyatt_form_bloc/src/validators/inputs/base/text_validator.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
/// {@template text_string}
/// Form input for a text input
/// {@endtemplate}
class TextString extends TextValidator<ValidationStandardError> {
/// {@macro text_string}
const TextString.pure() : super.pure();
const TextString.pure([super.value]) : super.pure();
/// {@macro text_string}
const TextString.dirty([super.value = '']) : super.dirty();
@@ -0,0 +1,23 @@
// 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/>.
export 'entities/form_input.dart';
export 'entities/form_input_metadata.dart';
export 'form/wyatt_form.dart';
export 'form_encoders/form_encoder.dart';
export 'form_operations/form_operation.dart';
export 'form_validators/form_validator.dart';
export 'input_validators/form_input_validator.dart';
@@ -15,27 +15,36 @@
// 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';
import 'package:equatable/equatable.dart';
import 'package:wyatt_architecture/wyatt_architecture.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/entities/form_input_metadata.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
class FormInput<Validator extends FormInputValidator<dynamic, ValidationError>>
extends Equatable {
// ignore: must_be_immutable
class FormInput<
Value,
Validator extends FormInputValidator<Value, ValidationError>,
Extra> extends Equatable implements Entity {
final String key;
final Validator validator;
final FormInputMetadata<dynamic> metadata;
late FormInputMetadata<Extra> metadata;
String get name => metadata._name ?? key;
String get name => metadata.name ?? key;
const FormInput(
FormInput(
this.key,
this.validator, {
// ignore: avoid_redundant_argument_values
this.metadata = const FormInputMetadata<void>(export: true),
});
FormInputMetadata<Extra>? metadata,
}) {
this.metadata = metadata ?? FormInputMetadata<Extra>();
}
FormInput copyWith({
FormInput<Value, Validator, Extra> copyWith({
String? key,
Validator? validator,
FormInputMetadata? metadata,
FormInputMetadata<Extra>? metadata,
}) =>
FormInput(
key ?? this.key,
@@ -43,11 +52,12 @@ class FormInput<Validator extends FormInputValidator<dynamic, ValidationError>>
metadata: metadata ?? this.metadata,
);
FormInput clone() => copyWith(
FormInput<Value, Validator, Extra> clone() => copyWith(
key: key,
validator: validator,
metadata: metadata,
);
@override
bool? get stringify => true;
@@ -15,33 +15,35 @@
// 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';
import 'package:equatable/equatable.dart';
import 'package:wyatt_architecture/wyatt_architecture.dart';
class FormInputMetadata<T extends Object?> extends Equatable {
class FormInputMetadata<Extra> extends Equatable
implements Entity {
final bool export;
final String? _name;
final T? extra;
final String? name;
final Extra? extra;
const FormInputMetadata({
this.export = true,
this.name,
this.extra,
String? name,
}) : _name = name;
});
FormInputMetadata<T> copyWith({
FormInputMetadata<Extra> copyWith({
bool? export,
String? name,
T? extra,
Extra? extra,
}) =>
FormInputMetadata<T>(
FormInputMetadata<Extra>(
export: export ?? this.export,
name: name ?? _name,
name: name ?? this.name,
extra: extra ?? this.extra,
);
FormInputMetadata<T> clone() => copyWith(
FormInputMetadata<Extra> clone() => copyWith(
export: export,
name: _name,
name: name,
extra: extra,
);
@@ -49,5 +51,5 @@ class FormInputMetadata<T extends Object?> extends Equatable {
bool? get stringify => true;
@override
List<Object?> get props => [export, _name, extra];
List<Object?> get props => [export, name, extra];
}
@@ -0,0 +1,60 @@
// 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/>.
// ignore_for_file: strict_raw_type
import 'package:equatable/equatable.dart';
import 'package:wyatt_form_bloc/src/core/enums/form_status.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/entities/form_input.dart';
import 'package:wyatt_form_bloc/src/domain/entities/form_input_metadata.dart';
import 'package:wyatt_form_bloc/src/domain/form_operations/form_operation.dart';
import 'package:wyatt_form_bloc/src/domain/form_validators/form_validator.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
abstract class WyattForm extends Equatable {
List<FormInput> get inputs;
FormValidator get formValidationStrategy;
bool containsKey(String key);
FormInput inputOf(String key);
Validator validatorOf<
Validator extends FormInputValidator<dynamic, ValidationError>>(
String key,
);
Error? errorOf<Error extends ValidationError>(String key);
Value? valueOf<Value>(String key);
FormInputMetadata<Extra> metadataOf<Extra>(String key);
List<FormInputValidator<Value, Error>>
asValidatorList<Value, Error extends ValidationError>();
void updateValidator<Value>(
String key,
FormInputValidator<Value?, ValidationError> dirtyValue,
);
void updateMetadata<Extra>(
String key,
FormInputMetadata<Extra> metadata,
);
FormStatus validate();
WyattForm clone();
WyattForm operationWith(FormOperation operation, WyattForm other);
WyattForm reset();
}
@@ -14,16 +14,9 @@
// 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 SetOperation {
/// Replace entire set with new set.
replace,
/// Keep common elements between sets.
intersection,
/// Remove common elements between sets.
difference,
/// Add new elements to set.
union
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
// ignore: one_member_abstracts
abstract class FormEncoder<Output> {
Output encode(WyattForm form);
}
@@ -0,0 +1,23 @@
// 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/domain/form/wyatt_form.dart';
// ignore: one_member_abstracts
abstract class FormOperation {
const FormOperation();
WyattForm call(WyattForm a, WyattForm b);
}
@@ -14,7 +14,9 @@
// 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';
import 'package:wyatt_form_bloc/src/core/enums/form_status.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
/// {@template form_validator}
/// A [FormValidator] represents the global validaton state of a Form.
@@ -23,13 +25,9 @@ abstract class FormValidator {
/// {@macro form_validator}
const FormValidator();
bool isPure(FormData form) => form
.validators<dynamic, ValidationError>()
bool isPure(WyattForm form) => form
.asValidatorList<dynamic, ValidationError>()
.every((validator) => validator.pure);
FormStatus validate(FormData form);
FormStatus rawValidate(
List<FormInputValidator<dynamic, ValidationError>> validators,
);
FormStatus validate(WyattForm form);
}
@@ -0,0 +1,45 @@
// 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_input_validator.dart';
abstract class AnyValidator<O, I extends Iterable<O?>,
E extends ValidationError> extends FormInputValidator<O?, E> {
const AnyValidator.pure(super.value) : super.pure();
const AnyValidator.dirty(super.value) : super.dirty();
I get allChoices;
bool test(O? element, O value);
E get onError;
/// If value is null.
E get onNull;
@override
E? validator(O? value) {
if (value == null) {
return onNull;
}
if (allChoices.any(
(element) => test(element, value),
)) {
return null;
}
return onError;
}
}
@@ -0,0 +1,45 @@
// 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_input_validator.dart';
/// {@template equality_validator}
/// Abstract equality validator validating a value when equals to another.
/// {@endtemplate}
abstract class EqualityValidator<O extends Object, E extends ValidationError>
extends FormInputValidator<O?, E> {
const EqualityValidator.pure(super.value) : super.pure();
const EqualityValidator.dirty(super.value) : super.dirty();
O get another;
/// If values are different.
E get onNotEqual;
/// If value is null.
E get onNull;
@override
E? validator(O? value) {
if (value == null) {
return onNull;
}
if (value != another) {
return onNotEqual;
}
return null;
}
}
@@ -14,7 +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/>.
part of 'form.dart';
import 'package:equatable/equatable.dart';
import 'package:wyatt_form_bloc/src/core/enums/form_input_status.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
part 'regex_validator.dart';
part 'text_validator.dart';
part 'nullable_validator.dart';
part 'equality_validator.dart';
part 'any_validator.dart';
/// {@template form_input_validator}
/// A [FormInputValidator] represents the value of a single form input field.
@@ -39,21 +47,21 @@ part of 'form.dart';
/// }
/// ```
/// {@endtemplate}
abstract class FormInputValidator<V, E extends ValidationError>
abstract class FormInputValidator<Value, Error extends ValidationError>
extends Equatable {
const FormInputValidator._(this.value, [this.pure = true]);
/// Constructor which create a `pure` [FormInputValidator] with a given value.
const FormInputValidator.pure(V value) : this._(value);
const FormInputValidator.pure(Value value) : this._(value);
/// Constructor which create a `dirty` [FormInputValidator] with a
/// given value.
const FormInputValidator.dirty(V value) : this._(value, false);
const FormInputValidator.dirty(Value value) : this._(value, false);
/// The value of the given [FormInputValidator].
/// For example, if you have a `FormInputValidator` for `FirstName`,
/// the value could be 'Joe'.
final V value;
final Value? value;
/// If the [FormInputValidator] is pure (has been touched/modified).
/// Typically when the `FormInputValidator` is initially created,
@@ -80,7 +88,7 @@ abstract class FormInputValidator<V, E extends ValidationError>
/// Returns a validation error if the [FormInputValidator] is invalid.
/// Returns `null` if the [FormInputValidator] is valid.
E? get error => validator(value);
Error? get error => validator(value);
/// Whether the [FormInputValidator] value is valid according to the
/// overridden `validator`.
@@ -96,7 +104,7 @@ abstract class FormInputValidator<V, E extends ValidationError>
/// A function that must return a validation error if the provided
/// [value] is invalid and `null` otherwise.
E? validator(V value);
Error? validator(Value? value);
@override
bool? get stringify => true;
@@ -14,19 +14,24 @@
// 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';
part of 'form_input_validator.dart';
class EnumValidator<E> extends TextValidator<ValidationStandardError> {
/// {@macro text_string}
const EnumValidator.pure() : super.pure();
/// {@template nullable_validator}
/// Abstract nullable validator not validating null values.
/// {@endtemplate}
abstract class NullableValidator<O extends Object, E extends ValidationError>
extends FormInputValidator<O?, E> {
const NullableValidator.pure(super.value) : super.pure();
const NullableValidator.dirty(super.value) : super.dirty();
/// {@macro text_string}
EnumValidator.dirty(E value) : super.dirty(value.toString());
/// If value is null.
E get onNull;
@override
ValidationStandardError get onEmpty => ValidationStandardError.empty;
@override
ValidationStandardError get onNull => ValidationStandardError.invalid;
E? validator(O? value) {
if (value == null) {
return onNull;
}
return null;
}
}
@@ -14,20 +14,21 @@
// 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';
part of 'form_input_validator.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();
extends FormInputValidator<String?, E> {
const RegexValidator.pure(super.value) : 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;
@@ -14,13 +14,12 @@
// 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';
part of 'form_input_validator.dart';
abstract class TextValidator<E extends ValidationError>
extends FormInputValidator<String, E> {
const TextValidator.pure() : super.pure('');
const TextValidator.dirty([super.value = '']) : super.dirty();
extends FormInputValidator<String?, E> {
const TextValidator.pure(super.value) : super.pure();
const TextValidator.dirty(super.value) : super.dirty();
/// If the value is **not** null, but empty.
E get onEmpty;
@@ -1,184 +0,0 @@
// 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';
class FormData extends Equatable {
final List<FormInput> _inputs;
const FormData(this._inputs);
const FormData.empty() : this(const <FormInput>[]);
/// Returns all inputs as a list
List<FormInput> inputs() => _inputs;
/// Returns the input for the associated key
FormInput inputOf(String key) {
if (contains(key)) {
return _inputs.firstWhere((input) => input.key == key);
} else {
throw Exception('FormInput with key `$key` does not exist in form');
}
}
/// Updates a input (perform a replace at index).
void updateInput(String key, FormInput input) {
if (contains(key)) {
final index = _inputs.indexOf(
inputOf(key),
);
_inputs[index] = input;
}
}
/// Returns all associated validators as a list
List<FormInputValidator<V, E>> validators<V, E extends ValidationError>() =>
_inputs
.map<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) => inputOf(key).validator as T;
/// Updates validator of a given input. (perform copyWith)
void updateValidator<V>(
String key,
FormInputValidator<V, ValidationError> dirtyValue,
) {
if (contains(key)) {
final index = _inputs.indexOf(
inputOf(key),
);
_inputs[index] = _inputs[index].copyWith(validator: dirtyValue);
}
}
/// Returns a validation error if the [FormInputValidator] is invalid.
/// Returns null if the [FormInputValidator] is valid.
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>(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) => !inputOf(key).validator.valid;
/// Returns all associated metadata as a list
List<FormInputMetadata<M>> metadata<M>() => _inputs
.map<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) =>
inputOf(key).metadata as FormInputMetadata<M>;
/// Updates metadata of a given input. (perform copyWith)
void updateMetadata<M>(String key, FormInputMetadata<M> meta) {
if (contains(key)) {
final index = _inputs.indexOf(
inputOf(key),
);
_inputs[index] = _inputs[index].copyWith(metadata: meta);
}
}
/// Check if this contains an input with the given 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) {
final List<FormInput> inputs = <FormInput>[];
for (final FormInput i in _inputs) {
if (other.contains(i.key)) {
inputs.add(i);
}
}
return FormData(inputs);
}
/// Makes a difference set operation and returns newly created [FormData]
FormData difference(FormData other) {
final List<FormInput> inputs = <FormInput>[];
for (final FormInput i in other._inputs) {
if (!contains(i.key)) {
inputs.add(i);
}
}
for (final FormInput i in _inputs) {
if (!other.contains(i.key)) {
inputs.add(i);
}
}
return FormData(inputs);
}
/// Makes an union set operation and returns newly created [FormData]
FormData union(FormData other) {
final List<FormInput> inputs = <FormInput>[];
for (final FormInput i in _inputs) {
inputs.add(i);
}
for (final FormInput i in other._inputs) {
if (!contains(i.key)) {
inputs.add(i);
}
}
return FormData(inputs);
}
/// Deeply copy this.
FormData clone() => FormData(
_inputs.map((input) => input.clone()).toList(),
);
/// Export this to [Map] format.
Map<String, dynamic> toMap() {
final map = <String, dynamic>{};
for (final input in _inputs) {
if (input.metadata.export) {
map[input.name] = input.validator.value;
}
}
return map;
}
/// Export this to [String] format.
String toJson() => jsonEncode(toMap());
@override
bool? get stringify => true;
@override
List<Object?> get props => _inputs;
}
@@ -0,0 +1,47 @@
// 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 'dart:async';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:wyatt_form_bloc/src/core/enums/form_status.dart';
import 'package:wyatt_form_bloc/src/core/enums/set_operations.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
part 'form_data_state.dart';
abstract class FormDataCubit<State extends FormDataState> extends Cubit<State> {
FormDataCubit(super.initialState) : super();
FutureOr<void> dataChanged<Value>(
String key,
FormInputValidator<Value, ValidationError> dirtyValue,
);
FutureOr<void> update(
WyattForm form, {
SetOperation operation = SetOperation.replace,
});
FutureOr<void> validate();
FutureOr<void> reset();
FutureOr<void> submit();
}
@@ -16,35 +16,19 @@
part of 'form_data_cubit.dart';
class FormDataState extends Equatable {
abstract class FormDataState extends Equatable {
/// Global status of a form.
final FormStatus status;
/// FormData with all inputs, and associated metadata.
final FormData data;
final WyattForm form;
/// Optional error message.
final String? errorMessage;
const FormDataState({
required this.data,
required this.form,
this.status = FormStatus.pure,
this.errorMessage,
});
FormDataState copyWith({
FormStatus? status,
FormData? data,
String? errorMessage,
}) => FormDataState(
status: status ?? this.status,
data: data ?? this.data,
errorMessage: errorMessage ?? this.errorMessage,
);
@override
bool? get stringify => true;
@override
List<Object?> get props => [status, data, errorMessage];
}
@@ -0,0 +1,86 @@
// 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 'dart:async';
import 'package:wyatt_form_bloc/src/core/enums/form_status.dart';
import 'package:wyatt_form_bloc/src/core/enums/set_operations.dart';
import 'package:wyatt_form_bloc/src/core/enums/validation_error.dart';
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
import 'package:wyatt_form_bloc/src/presentation/features/form_data/form_data_cubit.dart';
part 'form_data_state_impl.dart';
abstract class FormDataCubitImpl extends FormDataCubit<FormDataStateImpl> {
FormDataCubitImpl(WyattForm form) : super(FormDataStateImpl(form: form));
@override
FutureOr<void> dataChanged<Value>(
String key,
FormInputValidator<Value, ValidationError> dirtyValue,
) {
final form = state.form.clone();
try {
form.updateValidator(key, dirtyValue);
} catch (e) {
rethrow;
}
emit(
state.copyWith(
form: form,
status: form.validate(),
),
);
}
@override
FutureOr<void> update(
WyattForm form, {
SetOperation operation = SetOperation.replace,
}) {
final WyattForm newForm = operation.operation.call(state.form, form);
emit(
state.copyWith(
form: newForm,
status: newForm.validate(),
),
);
}
@override
FutureOr<void> reset() {
final form = state.form.reset();
emit(
state.copyWith(
form: form,
status: form.validate(),
),
);
}
@override
FutureOr<void> validate() {
emit(
state.copyWith(
status: state.form.validate(),
),
);
}
}
@@ -0,0 +1,42 @@
// 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_data_cubit_impl.dart';
class FormDataStateImpl extends FormDataState {
const FormDataStateImpl({
required super.form,
super.status = FormStatus.pure,
super.errorMessage,
});
FormDataStateImpl copyWith({
FormStatus? status,
WyattForm? form,
String? errorMessage,
}) =>
FormDataStateImpl(
status: status ?? this.status,
form: form ?? this.form,
errorMessage: errorMessage ?? this.errorMessage,
);
@override
bool? get stringify => true;
@override
List<Object?> get props => [status, form, errorMessage];
}
@@ -0,0 +1,43 @@
// 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:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
class InputBuilder<Cubit extends FormDataCubit> extends StatelessWidget {
const InputBuilder({required this.field, required this.builder, super.key});
final String field;
final Widget Function(
BuildContext context,
Cubit cubit,
FormDataState state,
String field,
bool inputValid,
) builder;
@override
Widget build(BuildContext context) =>
BlocBuilder<Cubit, FormDataState>(
builder: (context, state) {
final cubit = context.read<Cubit>();
final inputValid = state.form.validatorOf(field).valid;
return builder.call(context, cubit, state, field, inputValid);
},
);
}
@@ -0,0 +1,57 @@
// 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:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:wyatt_form_bloc/src/domain/entities/form_input_metadata.dart';
import 'package:wyatt_form_bloc/src/presentation/presentation.dart';
class InputBuilderMetadata<Cubit extends FormDataCubit, Extra>
extends StatelessWidget {
const InputBuilderMetadata({
required this.field,
required this.builder,
super.key,
});
final String field;
final Widget Function(
BuildContext context,
Cubit cubit,
FormDataState state,
String field,
bool inputValid,
FormInputMetadata<Extra>? metadata,
) builder;
@override
Widget build(BuildContext context) => BlocBuilder<Cubit, FormDataState>(
builder: (context, state) {
final cubit = context.read<Cubit>();
final inputValid = state.form.validatorOf(field).valid;
final metadata = state.form.metadataOf<Extra>(field);
return builder.call(
context,
cubit,
state,
field,
inputValid,
metadata,
);
},
);
}
@@ -0,0 +1,37 @@
// 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:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:wyatt_form_bloc/src/core/enums/form_status.dart';
import 'package:wyatt_form_bloc/src/presentation/features/form_data/form_data_cubit.dart';
class SubmitBuilder<Cubit extends FormDataCubit> extends StatelessWidget {
const SubmitBuilder({required this.builder, super.key});
final Widget Function(BuildContext context, Cubit cubit, FormStatus status)
builder;
@override
Widget build(BuildContext context) => BlocBuilder<Cubit, FormDataState>(
buildWhen: (previous, current) => previous.status != current.status,
builder: (context, state) => builder.call(
context,
context.read<Cubit>(),
state.status,
),
);
}
@@ -0,0 +1,21 @@
// 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/>.
export 'features/form_data/form_data_cubit.dart';
export 'features/form_data_impl/form_data_cubit_impl.dart';
export 'features/widgets/input_builder.dart';
export 'features/widgets/input_builder_metadata.dart';
export 'features/widgets/submit_builder.dart';
+4 -4
View File
@@ -14,7 +14,7 @@
// 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/form_data_cubit.dart';
export 'enums/enums.dart';
export 'form/form.dart';
export 'validators/validators.dart';
export 'core/core.dart';
export 'data/data.dart';
export 'domain/domain.dart';
export 'presentation/presentation.dart';
@@ -1,39 +0,0 @@
// 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/enums.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 RegexValidator<ValidationStandardError> {
/// {@macro iban}
const Iban.pure() : super.pure();
/// {@macro iban}
const Iban.dirty([super.value = '']) : super.dirty();
@override
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}))$',
);
}
@@ -1,50 +0,0 @@
// 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/enums.dart';
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>, ValidationStandardError> {
/// {@macro list_option}
const ListOption.pure({List<T>? defaultValue})
: super.pure(defaultValue ?? const []);
/// {@macro list_option}
const ListOption.dirty({List<T>? value}) : super.dirty(value ?? const []);
ListOption<T> select(T? v) {
if (v == null) {
return this;
}
if (value.contains(v)) {
final List<T> newValue = List.from(value)..remove(v);
return ListOption<T>.dirty(value: newValue);
} else {
final List<T> newValue = List.from(value)..add(v);
return ListOption<T>.dirty(value: newValue);
}
}
@override
ValidationStandardError? validator(List<T>? value) =>
value?.isNotEmpty ?? false == true
? null
: ValidationStandardError.invalid;
}