feat!(form): migrate to wyatt architecture
This commit is contained in:
parent
79fdd3c837
commit
b89ef3de8a
@ -16,16 +16,16 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
# Dart - Form BLoC
|
# Flutter - Form BLoC
|
||||||
|
|
||||||
<p align="left">
|
<p align="left">
|
||||||
<a href="https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_analysis">
|
<a href="https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_analysis">
|
||||||
<img src="https://img.shields.io/badge/Style-Wyatt%20Analysis-blue.svg?style=flat-square" alt="Style: Wyatt Analysis" />
|
<img src="https://img.shields.io/badge/Style-Wyatt%20Analysis-blue.svg?style=flat-square" alt="Style: Wyatt Analysis" />
|
||||||
</a>
|
</a>
|
||||||
<img src="https://img.shields.io/badge/SDK-Dart%20%7C%20Flutter-blue?style=flat-square" alt="SDK: Dart & Flutter" />
|
<img src="https://img.shields.io/badge/SDK-Flutter-blue?style=flat-square" alt="SDK: Flutter" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Form Bloc for Dart & Flutter.
|
Form Bloc for Flutter.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
include: package:wyatt_analysis/analysis_options.yaml
|
include: package:wyatt_analysis/analysis_options.flutter.yaml
|
||||||
|
|
||||||
analyzer:
|
analyzer:
|
||||||
exclude: "!example/**"
|
exclude: "!example/**"
|
@ -21,6 +21,6 @@
|
|||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
<string>9.0</string>
|
<string>11.0</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -272,7 +272,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
@ -349,7 +349,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@ -398,7 +398,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
@ -43,5 +43,7 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -18,7 +18,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:form_bloc_example/app/metadata.dart';
|
import 'package:form_bloc_example/app/metadata.dart';
|
||||||
import 'package:form_bloc_example/constants.dart';
|
import 'package:form_bloc_example/constants.dart';
|
||||||
import 'package:form_bloc_example/cubit/custom_form_cubit.dart';
|
import 'package:form_bloc_example/simple_custom_form_cubit/simple_custom_form_cubit.dart';
|
||||||
import 'package:form_bloc_example/sign_up/sign_up_page.dart';
|
import 'package:form_bloc_example/sign_up/sign_up_page.dart';
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
|
|
||||||
@ -29,41 +29,43 @@ class App extends StatelessWidget {
|
|||||||
const App({Key? key}) : super(key: key);
|
const App({Key? key}) : super(key: key);
|
||||||
|
|
||||||
static List<FormInput> getNormalEntries() {
|
static List<FormInput> getNormalEntries() {
|
||||||
return const [
|
return [
|
||||||
FormInput(formFieldName, Name.pure(), metadata: FormInputMetadata<Metadata>(extra: blue)),
|
FormInput(formFieldName, const Name.pure(),
|
||||||
FormInput(formFieldEmail, Email.pure(), metadata: FormInputMetadata<Metadata>(extra: blue)),
|
metadata: const FormInputMetadata<Metadata>(extra: blue)),
|
||||||
FormInput(formFieldPhone, Phone.pure(), metadata: FormInputMetadata<Metadata>(extra: red)),
|
FormInput(formFieldEmail, const Email.pure(),
|
||||||
FormInput(
|
metadata: const FormInputMetadata<Metadata>(extra: blue)),
|
||||||
formFieldList, ListOption<String>.pure(defaultValue: ['checkbox3'])),
|
FormInput(formFieldList,
|
||||||
FormInput(formFieldRadio, TextString.pure()),
|
const ListOption<String>.pure(defaultValue: 'c3')),
|
||||||
FormInput(formFieldPro, Boolean.pure(),
|
FormInput(formFieldRadio, const TextString.pure()),
|
||||||
metadata: FormInputMetadata<Metadata>(name: 'business')),
|
FormInput(formFieldPro, const Boolean.pure(),
|
||||||
FormInput(formFieldHidden, Boolean.pure(),
|
metadata: const FormInputMetadata<Metadata>(name: 'business')),
|
||||||
metadata: FormInputMetadata<Metadata>(export: false, extra: blue)),
|
FormInput(formFieldHidden, const Boolean.pure(),
|
||||||
|
metadata:
|
||||||
|
const FormInputMetadata<Metadata>(export: false, extra: blue)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<FormInput> getBusinessEntries() {
|
static List<FormInput> getBusinessEntries() {
|
||||||
const entries = [
|
final entries = [
|
||||||
FormInput(formFieldSiren, Siren.pure()),
|
FormInput(formFieldPhone, const Phone.pure(),
|
||||||
FormInput(formFieldIban, Iban.pure()),
|
metadata: const FormInputMetadata<Metadata>(extra: red)),
|
||||||
];
|
];
|
||||||
return getNormalEntries() + entries;
|
return getNormalEntries() + entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FormData getNormalFormData() {
|
static WyattForm getNormalFormData() {
|
||||||
return FormData(getNormalEntries());
|
return WyattFormImpl(getNormalEntries());
|
||||||
}
|
}
|
||||||
|
|
||||||
static FormData getProFormData() {
|
static WyattForm getProFormData() {
|
||||||
return FormData(getBusinessEntries());
|
return WyattFormImpl(getBusinessEntries());
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
FormDataCubit formCubit = CustomFormCubit(inputs: getNormalFormData());
|
SimpleCustomFormCubit formCubit = SimpleCustomFormCubit(getNormalFormData());
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider<SimpleCustomFormCubit>(
|
||||||
create: (context) => formCubit,
|
create: (context) => formCubit,
|
||||||
child: const WidgetTree(),
|
child: const WidgetTree(),
|
||||||
);
|
);
|
||||||
|
@ -28,7 +28,5 @@ class Metadata {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() => 'Metadata(category: $category)';
|
||||||
return category.toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,6 @@
|
|||||||
const String formFieldName = 'name';
|
const String formFieldName = 'name';
|
||||||
const String formFieldPhone = 'phone';
|
const String formFieldPhone = 'phone';
|
||||||
const String formFieldEmail = 'email';
|
const String formFieldEmail = 'email';
|
||||||
const String formFieldSiren = 'siren';
|
|
||||||
const String formFieldIban = 'iban';
|
|
||||||
const String formFieldList = 'list';
|
const String formFieldList = 'list';
|
||||||
const String formFieldRadio = 'radio';
|
const String formFieldRadio = 'radio';
|
||||||
const String formFieldHidden = 'hidden';
|
const String formFieldHidden = 'hidden';
|
||||||
|
@ -14,39 +14,33 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:form_bloc_example/app/app.dart';
|
import 'package:form_bloc_example/app/app.dart';
|
||||||
import 'package:form_bloc_example/app/metadata.dart';
|
import 'package:form_bloc_example/app/metadata.dart';
|
||||||
import 'package:form_bloc_example/constants.dart';
|
import 'package:form_bloc_example/constants.dart';
|
||||||
|
import 'package:form_bloc_example/simple_custom_form_cubit/simple_custom_form_cubit.dart';
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
|
|
||||||
class CategoryIndicator extends StatelessWidget {
|
Color computeColor(Metadata? meta) {
|
||||||
const CategoryIndicator(
|
switch (meta?.category) {
|
||||||
{Key? key, required this.field, required this.builder})
|
case Category.perso:
|
||||||
: super(key: key);
|
return Colors.blue;
|
||||||
|
case Category.business:
|
||||||
final String field;
|
return Colors.red;
|
||||||
final Function(BuildContext context, FormDataState state) builder;
|
case null:
|
||||||
|
return Colors.green;
|
||||||
Color computeColor(Metadata meta) {
|
|
||||||
switch (meta.category) {
|
|
||||||
case Category.perso:
|
|
||||||
return Colors.blue;
|
|
||||||
case Category.business:
|
|
||||||
return Colors.red;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NameInput extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<FormDataCubit, FormDataState>(
|
return InputBuilderMetadata<SimpleCustomFormCubit, Metadata>(
|
||||||
builder: ((context, state) {
|
field: formFieldName,
|
||||||
final meta = state.data.metadataOf(field).extra as Metadata;
|
builder: (context, cubit, state, field, inputValid, metadata) {
|
||||||
|
final meta = state.form.metadataOf<Metadata>(field).extra;
|
||||||
final color = computeColor(meta);
|
final color = computeColor(meta);
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
@ -57,58 +51,24 @@ class CategoryIndicator extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20,),
|
const SizedBox(
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: MediaQuery.of(context).size.width - 45,
|
width: MediaQuery.of(context).size.width - 45,
|
||||||
child: builder(context, state),
|
child: TextField(
|
||||||
|
onChanged: (value) =>
|
||||||
|
cubit.dataChanged(field, Name.dirty(value)),
|
||||||
|
keyboardType: TextInputType.name,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'name',
|
||||||
|
helperText: '',
|
||||||
|
errorText: !inputValid ? 'invalid name' : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _NameInput extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return CategoryIndicator(
|
|
||||||
field: formFieldName,
|
|
||||||
builder: (context, state) {
|
|
||||||
return TextField(
|
|
||||||
onChanged: (name) => context
|
|
||||||
.read<FormDataCubit>()
|
|
||||||
.dataChanged(formFieldName, Name.dirty(name)),
|
|
||||||
keyboardType: TextInputType.name,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: 'name',
|
|
||||||
helperText: '',
|
|
||||||
errorText:
|
|
||||||
state.data.isNotValid(formFieldName) ? 'invalid name' : null,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _EmailInput extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return CategoryIndicator(
|
|
||||||
field: formFieldEmail,
|
|
||||||
builder: (context, state) {
|
|
||||||
return TextField(
|
|
||||||
onChanged: (email) => context
|
|
||||||
.read<FormDataCubit>()
|
|
||||||
.dataChanged(formFieldEmail, Email.dirty(email)),
|
|
||||||
keyboardType: TextInputType.emailAddress,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: 'email',
|
|
||||||
helperText: '',
|
|
||||||
errorText:
|
|
||||||
state.data.isNotValid(formFieldEmail) ? 'invalid email' : null,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -117,67 +77,58 @@ class _EmailInput extends StatelessWidget {
|
|||||||
class _PhoneInput extends StatelessWidget {
|
class _PhoneInput extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CategoryIndicator(
|
return InputBuilderMetadata<SimpleCustomFormCubit, Metadata>(
|
||||||
field: formFieldPhone,
|
field: formFieldPhone,
|
||||||
builder: (context, state) {
|
builder: (context, cubit, state, field, inputValid, metadata) {
|
||||||
return TextField(
|
final meta = state.form.metadataOf<Metadata>(field).extra;
|
||||||
onChanged: (phone) => context
|
final color = computeColor(meta);
|
||||||
.read<FormDataCubit>()
|
return Row(
|
||||||
.dataChanged(formFieldPhone, Phone.dirty(phone)),
|
children: [
|
||||||
keyboardType: TextInputType.phone,
|
Container(
|
||||||
decoration: InputDecoration(
|
height: 8,
|
||||||
labelText: 'phone',
|
width: 8,
|
||||||
helperText: '',
|
decoration: BoxDecoration(
|
||||||
errorText:
|
color: color,
|
||||||
state.data.isNotValid(formFieldPhone) ? 'invalid phone' : null,
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width - 45,
|
||||||
|
child: TextField(
|
||||||
|
onChanged: (value) =>
|
||||||
|
cubit.dataChanged(field, Phone.dirty(value)),
|
||||||
|
keyboardType: TextInputType.phone,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'phone',
|
||||||
|
helperText: '',
|
||||||
|
errorText: !inputValid ? 'invalid phone' : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SirenInput extends StatelessWidget {
|
class _EmailInput extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CategoryIndicator(
|
return InputBuilder<SimpleCustomFormCubit>(
|
||||||
field: formFieldName,
|
field: formFieldEmail,
|
||||||
builder: (context, state) {
|
builder: (context, cubit, state, field, inputValid) => TextField(
|
||||||
return TextField(
|
onChanged: (value) => cubit.dataChanged(field, Email.dirty(value)),
|
||||||
onChanged: (siren) => context
|
keyboardType: TextInputType.emailAddress,
|
||||||
.read<FormDataCubit>()
|
decoration: InputDecoration(
|
||||||
.dataChanged(formFieldSiren, Siren.dirty(siren)),
|
labelText: 'email',
|
||||||
keyboardType: TextInputType.number,
|
helperText: '',
|
||||||
decoration: InputDecoration(
|
errorText: !inputValid ? 'invalid email' : null,
|
||||||
labelText: 'siren',
|
),
|
||||||
helperText: '',
|
),
|
||||||
errorText:
|
|
||||||
state.data.isNotValid(formFieldSiren) ? 'invalid SIREN' : null,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _IbanInput extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocBuilder<FormDataCubit, FormDataState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
return TextField(
|
|
||||||
onChanged: (iban) => context
|
|
||||||
.read<FormDataCubit>()
|
|
||||||
.dataChanged(formFieldIban, Iban.dirty(iban)),
|
|
||||||
keyboardType: TextInputType.text,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: 'iban',
|
|
||||||
helperText: '',
|
|
||||||
errorText:
|
|
||||||
state.data.isNotValid(formFieldIban) ? 'invalid IBAN' : null,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,11 +136,11 @@ class _IbanInput extends StatelessWidget {
|
|||||||
class _CheckListInput extends StatelessWidget {
|
class _CheckListInput extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<FormDataCubit, FormDataState>(
|
return InputBuilder<SimpleCustomFormCubit>(
|
||||||
builder: (context, state) {
|
field: formFieldList,
|
||||||
final input =
|
builder: (context, cubit, state, field, inputValid) {
|
||||||
state.data.validatorOf<ListOption<String>>(formFieldList);
|
final input = state.form.validatorOf<ListOption<String>>(field);
|
||||||
final options = input.value;
|
final choices = ['c1', 'c2', 'c3'];
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@ -197,34 +148,34 @@ class _CheckListInput extends StatelessWidget {
|
|||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Checkbox1'),
|
title: const Text('Checkbox1'),
|
||||||
trailing: Checkbox(
|
trailing: Checkbox(
|
||||||
value: options.contains('checkbox1'),
|
value: input.value == choices[0],
|
||||||
onChanged: (_) {
|
onChanged: (_) {
|
||||||
context.read<FormDataCubit>().dataChanged(
|
cubit.dataChanged(
|
||||||
formFieldList,
|
field,
|
||||||
input.select('checkbox1'),
|
ListOption.dirty(choices: choices, value: choices[0]),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Checkbox2'),
|
title: const Text('Checkbox2'),
|
||||||
trailing: Checkbox(
|
trailing: Checkbox(
|
||||||
value: options.contains('checkbox2'),
|
value: input.value == choices[1],
|
||||||
onChanged: (_) {
|
onChanged: (_) {
|
||||||
context.read<FormDataCubit>().dataChanged(
|
cubit.dataChanged(
|
||||||
formFieldList,
|
field,
|
||||||
input.select('checkbox2'),
|
ListOption.dirty(choices: choices, value: choices[1]),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Checkbox3 (default)'),
|
title: const Text('Checkbox3 (default)'),
|
||||||
trailing: Checkbox(
|
trailing: Checkbox(
|
||||||
value: options.contains('checkbox3'),
|
value: input.value == choices[2],
|
||||||
onChanged: (_) {
|
onChanged: (_) {
|
||||||
context.read<FormDataCubit>().dataChanged(
|
cubit.dataChanged(
|
||||||
formFieldList,
|
field,
|
||||||
input.select('checkbox3'),
|
ListOption.dirty(choices: choices, value: choices[2]),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -237,9 +188,10 @@ class _CheckListInput extends StatelessWidget {
|
|||||||
class _RadioListInput extends StatelessWidget {
|
class _RadioListInput extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<FormDataCubit, FormDataState>(
|
return InputBuilder<SimpleCustomFormCubit>(
|
||||||
builder: (context, state) {
|
field: formFieldRadio,
|
||||||
final input = state.data.validatorOf<TextString>(formFieldRadio);
|
builder: ((context, cubit, state, field, inputValid) {
|
||||||
|
final input = state.form.validatorOf<TextString>(field);
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@ -250,10 +202,10 @@ class _RadioListInput extends StatelessWidget {
|
|||||||
groupValue: true,
|
groupValue: true,
|
||||||
value: input.value == 'radio1',
|
value: input.value == 'radio1',
|
||||||
onChanged: (_) {
|
onChanged: (_) {
|
||||||
context.read<FormDataCubit>().dataChanged(
|
cubit.dataChanged(
|
||||||
formFieldRadio,
|
field,
|
||||||
const TextString.dirty('radio1'),
|
const TextString.dirty('radio1'),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
@ -262,10 +214,10 @@ class _RadioListInput extends StatelessWidget {
|
|||||||
groupValue: true,
|
groupValue: true,
|
||||||
value: input.value == 'radio2',
|
value: input.value == 'radio2',
|
||||||
onChanged: (_) {
|
onChanged: (_) {
|
||||||
context.read<FormDataCubit>().dataChanged(
|
cubit.dataChanged(
|
||||||
formFieldRadio,
|
field,
|
||||||
const TextString.dirty('radio2'),
|
const TextString.dirty('radio2'),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
@ -274,15 +226,15 @@ class _RadioListInput extends StatelessWidget {
|
|||||||
groupValue: true,
|
groupValue: true,
|
||||||
value: input.value == 'radio3',
|
value: input.value == 'radio3',
|
||||||
onChanged: (_) {
|
onChanged: (_) {
|
||||||
context.read<FormDataCubit>().dataChanged(
|
cubit.dataChanged(
|
||||||
formFieldRadio,
|
field,
|
||||||
const TextString.dirty('radio3'),
|
const TextString.dirty('radio3'),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,17 +244,18 @@ class _CheckHiddenInput extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: const Text('This input is not exported'),
|
title: const Text('This input is not exported'),
|
||||||
trailing: BlocBuilder<FormDataCubit, FormDataState>(
|
trailing: InputBuilder<SimpleCustomFormCubit>(
|
||||||
builder: (context, state) {
|
field: formFieldHidden,
|
||||||
|
builder: (context, cubit, state, field, inputValid) {
|
||||||
return Checkbox(
|
return Checkbox(
|
||||||
value: state.data.validatorOf<Boolean>(formFieldHidden).value,
|
value: state.form.validatorOf<Boolean>(field).value,
|
||||||
onChanged: (v) {
|
onChanged: (v) {
|
||||||
final value = v!; // state is false, so value can't be null
|
final value = v!; // state is false, so value can't be null
|
||||||
|
|
||||||
context.read<FormDataCubit>().dataChanged(
|
cubit.dataChanged(
|
||||||
formFieldHidden,
|
field,
|
||||||
Boolean.dirty(value: value),
|
Boolean.dirty(value: value),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -315,25 +268,24 @@ class _CheckIsProInput extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: const Text('Are you a pro?'),
|
title: const Text('Are you a pro?'),
|
||||||
trailing: BlocBuilder<FormDataCubit, FormDataState>(
|
trailing: InputBuilder<SimpleCustomFormCubit>(
|
||||||
builder: (context, state) {
|
field: formFieldPro,
|
||||||
|
builder: (context, cubit, state, field, inputValid) {
|
||||||
return Checkbox(
|
return Checkbox(
|
||||||
value: state.data.validatorOf<Boolean>(formFieldPro).value,
|
value: state.form.validatorOf<Boolean>(field).value,
|
||||||
onChanged: (isPro) {
|
onChanged: (v) {
|
||||||
final value = isPro!; // state is false, so value can't be null
|
final value = v!; // state is false, so value can't be null
|
||||||
|
|
||||||
context.read<FormDataCubit>().dataChanged(
|
cubit.dataChanged(
|
||||||
formFieldPro,
|
field,
|
||||||
Boolean.dirty(value: value),
|
Boolean.dirty(value: value),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
context.read<FormDataCubit>().updateFormData(
|
cubit.update(App.getProFormData(),
|
||||||
App.getProFormData(),
|
|
||||||
operation: SetOperation.union);
|
operation: SetOperation.union);
|
||||||
} else {
|
} else {
|
||||||
context.read<FormDataCubit>().updateFormData(
|
cubit.update(App.getNormalFormData(),
|
||||||
App.getNormalFormData(),
|
|
||||||
operation: SetOperation.intersection);
|
operation: SetOperation.intersection);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -346,49 +298,28 @@ class _CheckIsProInput extends StatelessWidget {
|
|||||||
class _SignUpButton extends StatelessWidget {
|
class _SignUpButton extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<FormDataCubit, FormDataState>(
|
return SubmitBuilder<SimpleCustomFormCubit>(
|
||||||
buildWhen: (previous, current) => previous.status != current.status,
|
builder: (context, cubit, status) {
|
||||||
builder: (context, state) {
|
return status.isSubmissionInProgress
|
||||||
return state.status.isSubmissionInProgress
|
? const CircularProgressIndicator()
|
||||||
? const CircularProgressIndicator()
|
: ElevatedButton(
|
||||||
: ElevatedButton(
|
onPressed: status.isValidated ? () => cubit.submit() : null,
|
||||||
onPressed: state.status.isValidated
|
child: const Text('SIGN UP'),
|
||||||
? () => context.read<FormDataCubit>().submitForm()
|
);
|
||||||
: null,
|
});
|
||||||
child: const Text('SIGN UP'),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _DebugButton extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocBuilder<FormDataCubit, FormDataState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
log(state.toString());
|
|
||||||
},
|
|
||||||
child: const Text('DEBUG'),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ResetButton extends StatelessWidget {
|
class _ResetButton extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<FormDataCubit, FormDataState>(
|
return SubmitBuilder<SimpleCustomFormCubit>(
|
||||||
builder: (context, state) {
|
builder: (context, cubit, status) {
|
||||||
return ElevatedButton(
|
return ElevatedButton(
|
||||||
onPressed: () => context.read<FormDataCubit>().resetForm(),
|
onPressed: () => cubit.reset(),
|
||||||
child: const Text('RESET'),
|
child: const Text('RESET'),
|
||||||
);
|
);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,7 +328,7 @@ class SignUpForm extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocListener<FormDataCubit, FormDataState>(
|
return BlocListener<SimpleCustomFormCubit, FormDataState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
if (state.status.isSubmissionSuccess) {
|
if (state.status.isSubmissionSuccess) {
|
||||||
Navigator.of(context).pop(); // Never happens here
|
Navigator.of(context).pop(); // Never happens here
|
||||||
@ -418,8 +349,6 @@ class SignUpForm extends StatelessWidget {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_EmailInput(),
|
_EmailInput(),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_PhoneInput(),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
_CheckListInput(),
|
_CheckListInput(),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_RadioListInput(),
|
_RadioListInput(),
|
||||||
@ -428,13 +357,12 @@ class SignUpForm extends StatelessWidget {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_CheckIsProInput(),
|
_CheckIsProInput(),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
BlocBuilder<FormDataCubit, FormDataState>(
|
BlocBuilder<SimpleCustomFormCubit, FormDataState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.data.validatorOf<Boolean>(formFieldPro).value) {
|
if (state.form.validatorOf<Boolean>(formFieldPro).value ??
|
||||||
|
false) {
|
||||||
return Column(children: [
|
return Column(children: [
|
||||||
_SirenInput(),
|
_PhoneInput(),
|
||||||
const SizedBox(height: 8),
|
|
||||||
_IbanInput(),
|
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -444,8 +372,6 @@ class SignUpForm extends StatelessWidget {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_SignUpButton(),
|
_SignUpButton(),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_DebugButton(),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
_ResetButton(),
|
_ResetButton(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -18,12 +18,13 @@ import 'dart:developer';
|
|||||||
|
|
||||||
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
import 'package:wyatt_form_bloc/wyatt_form_bloc.dart';
|
||||||
|
|
||||||
class CustomFormCubit extends FormDataCubit {
|
class SimpleCustomFormCubit extends FormDataCubitImpl {
|
||||||
CustomFormCubit({required FormData inputs}) : super(inputs: inputs);
|
SimpleCustomFormCubit(super.form) : super();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> submitForm() {
|
Future<void> submit() {
|
||||||
log(state.data.toMap().toString());
|
final value = FormJsonEncoder().encode(state.form);
|
||||||
|
log(value);
|
||||||
|
|
||||||
return Future.value();
|
return Future.value();
|
||||||
}
|
}
|
@ -14,17 +14,4 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export 'form/every_input_validator.dart';
|
export 'enums/enums.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';
|
|
@ -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 {
|
enum ValidationStandardError implements ValidationError {
|
||||||
invalid,
|
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();
|
|
||||||
}
|
|
34
packages/wyatt_form_bloc/lib/src/data/data.dart
Normal file
34
packages/wyatt_form_bloc/lib/src/data/data.dart
Normal file
@ -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';
|
136
packages/wyatt_form_bloc/lib/src/data/form/wyatt_form_impl.dart
Normal file
136
packages/wyatt_form_bloc/lib/src/data/form/wyatt_form_impl.dart
Normal file
@ -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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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';
|
class FormReplace extends FormOperation {
|
||||||
import 'package:wyatt_form_bloc/src/enums/form_input_status.dart';
|
const FormReplace();
|
||||||
import 'package:wyatt_form_bloc/src/enums/form_status.dart';
|
|
||||||
import 'package:wyatt_form_bloc/src/enums/validation_error.dart';
|
|
||||||
|
|
||||||
part 'form_data.dart';
|
@override
|
||||||
part 'form_input.dart';
|
WyattForm call(WyattForm a, WyattForm b) => b;
|
||||||
part 'form_input_metadata.dart';
|
}
|
||||||
part 'form_input_validator.dart';
|
|
||||||
part 'form_validator.dart';
|
|
@ -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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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}
|
/// {@template every}
|
||||||
/// Check and validate every input of a form
|
/// Check and validate every input of a form
|
||||||
@ -24,18 +27,13 @@ class EveryInputValidator extends FormValidator {
|
|||||||
const EveryInputValidator() : super();
|
const EveryInputValidator() : super();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FormStatus validate(FormData form) {
|
FormStatus validate(WyattForm form) {
|
||||||
if (isPure(form)) {
|
if (isPure(form)) {
|
||||||
return FormStatus.pure;
|
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)) {
|
if (validators.any((validator) => validator.valid == false)) {
|
||||||
return FormStatus.invalid;
|
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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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/core/enums/validation_error.dart';
|
||||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
|
||||||
|
|
||||||
/// {@template boolean}
|
/// {@template boolean}
|
||||||
/// Form input for a bool input
|
/// Form input for a bool input
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
class Boolean extends FormInputValidator<bool, ValidationStandardError> {
|
class Boolean extends NullableValidator<bool, ValidationStandardError> {
|
||||||
/// {@macro boolean}
|
/// {@macro boolean}
|
||||||
const Boolean.pure({bool? defaultValue = false})
|
const Boolean.pure({bool? defaultValue = false})
|
||||||
: super.pure(defaultValue ?? false);
|
: super.pure(defaultValue ?? false);
|
||||||
|
|
||||||
/// {@macro boolean}
|
/// {@macro boolean}
|
||||||
const Boolean.dirty({bool value = false}) : super.dirty(value);
|
const Boolean.dirty({bool value = false}) : super.dirty(value);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ValidationStandardError get onNull => ValidationStandardError.invalid;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ValidationStandardError? validator(bool? value) =>
|
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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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/core/enums/validation_error.dart';
|
||||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
|
||||||
|
|
||||||
/// {@template confirmed_password}
|
/// {@template confirmed_password}
|
||||||
/// Form input for a confirmed password input.
|
/// Form input for a confirmed password input.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
class ConfirmedPassword
|
class ConfirmedPassword
|
||||||
extends FormInputValidator<String, ValidationStandardError> {
|
extends EqualityValidator<String, ValidationStandardError> {
|
||||||
/// {@macro confirmed_password}
|
/// {@macro confirmed_password}
|
||||||
const ConfirmedPassword.pure({this.password = ''}) : super.pure('');
|
const ConfirmedPassword.pure({this.password = '', String? defaultValue})
|
||||||
|
: super.pure(defaultValue);
|
||||||
|
|
||||||
/// {@macro confirmed_password}
|
/// {@macro confirmed_password}
|
||||||
const ConfirmedPassword.dirty({required this.password, String value = ''})
|
const ConfirmedPassword.dirty({required this.password, String? value})
|
||||||
: super.dirty(value);
|
: super.dirty(value);
|
||||||
|
|
||||||
/// The original password.
|
/// The original password.
|
||||||
final String password;
|
final String password;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ValidationStandardError? validator(String? value) =>
|
String get another => password;
|
||||||
password == value ? null : ValidationStandardError.invalid;
|
|
||||||
|
@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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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/core/enums/validation_error.dart';
|
||||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
|
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
|
||||||
|
|
||||||
/// {@template email}
|
/// {@template email}
|
||||||
/// Form input for an email input.
|
/// Form input for an email input.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
class Email extends RegexValidator<ValidationStandardError> {
|
class Email extends RegexValidator<ValidationStandardError> {
|
||||||
/// {@macro email}
|
/// {@macro email}
|
||||||
const Email.pure() : super.pure();
|
const Email.pure([super.value]) : super.pure();
|
||||||
|
|
||||||
/// {@macro email}
|
/// {@macro email}
|
||||||
const Email.dirty([super.value = '']) : super.dirty();
|
const Email.dirty([super.value = '']) : super.dirty();
|
@ -14,24 +14,27 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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/core/enums/validation_error.dart';
|
||||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
|
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
|
||||||
|
|
||||||
/// {@template siren}
|
class EnumOption<T> extends AnyValidator<T, List<T>, ValidationError> {
|
||||||
/// Form input for a SIREN input.
|
const EnumOption.pure({this.enums = const [], T? defaultValue})
|
||||||
/// {@endtemplate}
|
: super.pure(defaultValue);
|
||||||
class Siren extends RegexValidator<ValidationStandardError> {
|
|
||||||
/// {@macro siren}
|
|
||||||
const Siren.pure() : super.pure();
|
|
||||||
|
|
||||||
/// {@macro siren}
|
const EnumOption.dirty({required this.enums, T? value})
|
||||||
const Siren.dirty([super.value = '']) : super.dirty();
|
: super.dirty(value);
|
||||||
|
|
||||||
|
final List<T> enums;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
List<T> get allChoices => enums;
|
||||||
@override
|
|
||||||
ValidationStandardError get onError => ValidationStandardError.invalid;
|
|
||||||
|
|
||||||
@override
|
@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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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/core/enums/validation_error.dart';
|
||||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
|
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
|
||||||
|
|
||||||
/// {@template name}
|
/// {@template name}
|
||||||
/// Form input for a name input.
|
/// Form input for a name input.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
class Name extends RegexValidator<ValidationStandardError> {
|
class Name extends RegexValidator<ValidationStandardError> {
|
||||||
/// {@macro name}
|
/// {@macro name}
|
||||||
const Name.pure() : super.pure();
|
const Name.pure([super.value]) : super.pure();
|
||||||
|
|
||||||
/// {@macro name}
|
/// {@macro name}
|
||||||
const Name.dirty([super.value = '']) : super.dirty();
|
const Name.dirty([super.value = '']) : super.dirty();
|
@ -14,18 +14,18 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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/core/enums/validation_error.dart';
|
||||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
|
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
|
||||||
|
|
||||||
/// {@template password}
|
/// {@template password}
|
||||||
/// Form input for a password input.
|
/// Form input for a password input.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
class Password extends RegexValidator<ValidationStandardError> {
|
class Password extends RegexValidator<ValidationStandardError> {
|
||||||
/// {@macro password}
|
/// {@macro password}
|
||||||
const Password.pure() : super.pure();
|
const Password.pure([super.value]) : super.pure();
|
||||||
|
|
||||||
/// {@macro password}
|
/// {@macro password}
|
||||||
const Password.dirty([super.value = '']) : super.dirty();
|
const Password.dirty([super.value]) : super.dirty();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
@ -14,15 +14,15 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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/core/enums/validation_error.dart';
|
||||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/regex_validator.dart';
|
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
|
||||||
|
|
||||||
/// {@template phone}
|
/// {@template phone}
|
||||||
/// Form input for a phone input.
|
/// Form input for a phone input.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
class Phone extends RegexValidator<ValidationStandardError> {
|
class Phone extends RegexValidator<ValidationStandardError> {
|
||||||
/// {@macro phone}
|
/// {@macro phone}
|
||||||
const Phone.pure() : super.pure();
|
const Phone.pure([super.value]) : super.pure();
|
||||||
|
|
||||||
/// {@macro phone}
|
/// {@macro phone}
|
||||||
const Phone.dirty([super.value = '']) : super.dirty();
|
const Phone.dirty([super.value = '']) : super.dirty();
|
@ -14,15 +14,15 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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/core/enums/validation_error.dart';
|
||||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/text_validator.dart';
|
import 'package:wyatt_form_bloc/src/domain/input_validators/form_input_validator.dart';
|
||||||
|
|
||||||
/// {@template text_string}
|
/// {@template text_string}
|
||||||
/// Form input for a text input
|
/// Form input for a text input
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
class TextString extends TextValidator<ValidationStandardError> {
|
class TextString extends TextValidator<ValidationStandardError> {
|
||||||
/// {@macro text_string}
|
/// {@macro text_string}
|
||||||
const TextString.pure() : super.pure();
|
const TextString.pure([super.value]) : super.pure();
|
||||||
|
|
||||||
/// {@macro text_string}
|
/// {@macro text_string}
|
||||||
const TextString.dirty([super.value = '']) : super.dirty();
|
const TextString.dirty([super.value = '']) : super.dirty();
|
23
packages/wyatt_form_bloc/lib/src/domain/domain.dart
Normal file
23
packages/wyatt_form_bloc/lib/src/domain/domain.dart
Normal file
@ -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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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>>
|
// ignore: must_be_immutable
|
||||||
extends Equatable {
|
class FormInput<
|
||||||
|
Value,
|
||||||
|
Validator extends FormInputValidator<Value, ValidationError>,
|
||||||
|
Extra> extends Equatable implements Entity {
|
||||||
final String key;
|
final String key;
|
||||||
final Validator validator;
|
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.key,
|
||||||
this.validator, {
|
this.validator, {
|
||||||
// ignore: avoid_redundant_argument_values
|
// 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,
|
String? key,
|
||||||
Validator? validator,
|
Validator? validator,
|
||||||
FormInputMetadata? metadata,
|
FormInputMetadata<Extra>? metadata,
|
||||||
}) =>
|
}) =>
|
||||||
FormInput(
|
FormInput(
|
||||||
key ?? this.key,
|
key ?? this.key,
|
||||||
@ -43,11 +52,12 @@ class FormInput<Validator extends FormInputValidator<dynamic, ValidationError>>
|
|||||||
metadata: metadata ?? this.metadata,
|
metadata: metadata ?? this.metadata,
|
||||||
);
|
);
|
||||||
|
|
||||||
FormInput clone() => copyWith(
|
FormInput<Value, Validator, Extra> clone() => copyWith(
|
||||||
key: key,
|
key: key,
|
||||||
validator: validator,
|
validator: validator,
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool? get stringify => true;
|
bool? get stringify => true;
|
||||||
|
|
@ -15,33 +15,35 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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 bool export;
|
||||||
final String? _name;
|
final String? name;
|
||||||
final T? extra;
|
final Extra? extra;
|
||||||
|
|
||||||
const FormInputMetadata({
|
const FormInputMetadata({
|
||||||
this.export = true,
|
this.export = true,
|
||||||
|
this.name,
|
||||||
this.extra,
|
this.extra,
|
||||||
String? name,
|
});
|
||||||
}) : _name = name;
|
|
||||||
|
|
||||||
FormInputMetadata<T> copyWith({
|
FormInputMetadata<Extra> copyWith({
|
||||||
bool? export,
|
bool? export,
|
||||||
String? name,
|
String? name,
|
||||||
T? extra,
|
Extra? extra,
|
||||||
}) =>
|
}) =>
|
||||||
FormInputMetadata<T>(
|
FormInputMetadata<Extra>(
|
||||||
export: export ?? this.export,
|
export: export ?? this.export,
|
||||||
name: name ?? _name,
|
name: name ?? this.name,
|
||||||
extra: extra ?? this.extra,
|
extra: extra ?? this.extra,
|
||||||
);
|
);
|
||||||
|
|
||||||
FormInputMetadata<T> clone() => copyWith(
|
FormInputMetadata<Extra> clone() => copyWith(
|
||||||
export: export,
|
export: export,
|
||||||
name: _name,
|
name: name,
|
||||||
extra: extra,
|
extra: extra,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -49,5 +51,5 @@ class FormInputMetadata<T extends Object?> extends Equatable {
|
|||||||
bool? get stringify => true;
|
bool? get stringify => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [export, _name, extra];
|
List<Object?> get props => [export, name, extra];
|
||||||
}
|
}
|
60
packages/wyatt_form_bloc/lib/src/domain/form/wyatt_form.dart
Normal file
60
packages/wyatt_form_bloc/lib/src/domain/form/wyatt_form.dart
Normal file
@ -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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
enum SetOperation {
|
import 'package:wyatt_form_bloc/src/domain/form/wyatt_form.dart';
|
||||||
/// Replace entire set with new set.
|
|
||||||
replace,
|
// ignore: one_member_abstracts
|
||||||
|
abstract class FormEncoder<Output> {
|
||||||
/// Keep common elements between sets.
|
Output encode(WyattForm form);
|
||||||
intersection,
|
|
||||||
|
|
||||||
/// Remove common elements between sets.
|
|
||||||
difference,
|
|
||||||
|
|
||||||
/// Add new elements to set.
|
|
||||||
union
|
|
||||||
}
|
}
|
@ -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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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}
|
/// {@template form_validator}
|
||||||
/// A [FormValidator] represents the global validaton state of a Form.
|
/// A [FormValidator] represents the global validaton state of a Form.
|
||||||
@ -23,13 +25,9 @@ abstract class FormValidator {
|
|||||||
/// {@macro form_validator}
|
/// {@macro form_validator}
|
||||||
const FormValidator();
|
const FormValidator();
|
||||||
|
|
||||||
bool isPure(FormData form) => form
|
bool isPure(WyattForm form) => form
|
||||||
.validators<dynamic, ValidationError>()
|
.asValidatorList<dynamic, ValidationError>()
|
||||||
.every((validator) => validator.pure);
|
.every((validator) => validator.pure);
|
||||||
|
|
||||||
FormStatus validate(FormData form);
|
FormStatus validate(WyattForm form);
|
||||||
|
|
||||||
FormStatus rawValidate(
|
|
||||||
List<FormInputValidator<dynamic, ValidationError>> validators,
|
|
||||||
);
|
|
||||||
}
|
}
|
@ -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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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}
|
/// {@template form_input_validator}
|
||||||
/// A [FormInputValidator] represents the value of a single form input field.
|
/// A [FormInputValidator] represents the value of a single form input field.
|
||||||
@ -39,21 +47,21 @@ part of 'form.dart';
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
abstract class FormInputValidator<V, E extends ValidationError>
|
abstract class FormInputValidator<Value, Error extends ValidationError>
|
||||||
extends Equatable {
|
extends Equatable {
|
||||||
const FormInputValidator._(this.value, [this.pure = true]);
|
const FormInputValidator._(this.value, [this.pure = true]);
|
||||||
|
|
||||||
/// Constructor which create a `pure` [FormInputValidator] with a given value.
|
/// 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
|
/// Constructor which create a `dirty` [FormInputValidator] with a
|
||||||
/// given value.
|
/// given value.
|
||||||
const FormInputValidator.dirty(V value) : this._(value, false);
|
const FormInputValidator.dirty(Value value) : this._(value, false);
|
||||||
|
|
||||||
/// The value of the given [FormInputValidator].
|
/// The value of the given [FormInputValidator].
|
||||||
/// For example, if you have a `FormInputValidator` for `FirstName`,
|
/// For example, if you have a `FormInputValidator` for `FirstName`,
|
||||||
/// the value could be 'Joe'.
|
/// the value could be 'Joe'.
|
||||||
final V value;
|
final Value? value;
|
||||||
|
|
||||||
/// If the [FormInputValidator] is pure (has been touched/modified).
|
/// If the [FormInputValidator] is pure (has been touched/modified).
|
||||||
/// Typically when the `FormInputValidator` is initially created,
|
/// 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 a validation error if the [FormInputValidator] is invalid.
|
||||||
/// Returns `null` if the [FormInputValidator] is valid.
|
/// 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
|
/// Whether the [FormInputValidator] value is valid according to the
|
||||||
/// overridden `validator`.
|
/// overridden `validator`.
|
||||||
@ -96,7 +104,7 @@ abstract class FormInputValidator<V, E extends ValidationError>
|
|||||||
|
|
||||||
/// A function that must return a validation error if the provided
|
/// A function that must return a validation error if the provided
|
||||||
/// [value] is invalid and `null` otherwise.
|
/// [value] is invalid and `null` otherwise.
|
||||||
E? validator(V value);
|
Error? validator(Value? value);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool? get stringify => true;
|
bool? get stringify => true;
|
@ -14,19 +14,24 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import 'package:wyatt_form_bloc/src/enums/validation_error.dart';
|
part of 'form_input_validator.dart';
|
||||||
import 'package:wyatt_form_bloc/src/validators/inputs/base/text_validator.dart';
|
|
||||||
|
|
||||||
class EnumValidator<E> extends TextValidator<ValidationStandardError> {
|
/// {@template nullable_validator}
|
||||||
/// {@macro text_string}
|
/// Abstract nullable validator not validating null values.
|
||||||
const EnumValidator.pure() : super.pure();
|
/// {@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}
|
/// If value is null.
|
||||||
EnumValidator.dirty(E value) : super.dirty(value.toString());
|
E get onNull;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ValidationStandardError get onEmpty => ValidationStandardError.empty;
|
E? validator(O? value) {
|
||||||
|
if (value == null) {
|
||||||
@override
|
return onNull;
|
||||||
ValidationStandardError get onNull => ValidationStandardError.invalid;
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
@ -14,20 +14,21 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import 'package:wyatt_form_bloc/src/enums/validation_error.dart';
|
part of 'form_input_validator.dart';
|
||||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
|
||||||
|
|
||||||
/// {@template regex_validator}
|
/// {@template regex_validator}
|
||||||
/// Abstract regex validator for form input.
|
/// Abstract regex validator for form input.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
abstract class RegexValidator<E extends ValidationError>
|
abstract class RegexValidator<E extends ValidationError>
|
||||||
extends FormInputValidator<String, E> {
|
extends FormInputValidator<String?, E> {
|
||||||
const RegexValidator.pure() : super.pure('');
|
const RegexValidator.pure(super.value) : super.pure();
|
||||||
const RegexValidator.dirty([super.value = '']) : super.dirty();
|
const RegexValidator.dirty(super.value) : super.dirty();
|
||||||
|
|
||||||
RegExp get regex;
|
RegExp get regex;
|
||||||
|
|
||||||
/// If the value is **not** null, but empty.
|
/// If the value is **not** null, but empty.
|
||||||
E get onEmpty;
|
E get onEmpty;
|
||||||
|
|
||||||
/// If value does not conform to regex.
|
/// If value does not conform to regex.
|
||||||
E get onError;
|
E get onError;
|
||||||
|
|
@ -14,13 +14,12 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import 'package:wyatt_form_bloc/src/enums/validation_error.dart';
|
part of 'form_input_validator.dart';
|
||||||
import 'package:wyatt_form_bloc/src/form/form.dart';
|
|
||||||
|
|
||||||
abstract class TextValidator<E extends ValidationError>
|
abstract class TextValidator<E extends ValidationError>
|
||||||
extends FormInputValidator<String, E> {
|
extends FormInputValidator<String?, E> {
|
||||||
const TextValidator.pure() : super.pure('');
|
const TextValidator.pure(super.value) : super.pure();
|
||||||
const TextValidator.dirty([super.value = '']) : super.dirty();
|
const TextValidator.dirty(super.value) : super.dirty();
|
||||||
|
|
||||||
/// If the value is **not** null, but empty.
|
/// If the value is **not** null, but empty.
|
||||||
E get onEmpty;
|
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';
|
part of 'form_data_cubit.dart';
|
||||||
|
|
||||||
class FormDataState extends Equatable {
|
abstract class FormDataState extends Equatable {
|
||||||
/// Global status of a form.
|
/// Global status of a form.
|
||||||
final FormStatus status;
|
final FormStatus status;
|
||||||
|
|
||||||
/// FormData with all inputs, and associated metadata.
|
/// FormData with all inputs, and associated metadata.
|
||||||
final FormData data;
|
final WyattForm form;
|
||||||
|
|
||||||
/// Optional error message.
|
/// Optional error message.
|
||||||
final String? errorMessage;
|
final String? errorMessage;
|
||||||
|
|
||||||
const FormDataState({
|
const FormDataState({
|
||||||
required this.data,
|
required this.form,
|
||||||
this.status = FormStatus.pure,
|
this.status = FormStatus.pure,
|
||||||
this.errorMessage,
|
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';
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export 'cubit/form_data_cubit.dart';
|
export 'core/core.dart';
|
||||||
export 'enums/enums.dart';
|
export 'data/data.dart';
|
||||||
export 'form/form.dart';
|
export 'domain/domain.dart';
|
||||||
export 'validators/validators.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;
|
|
||||||
}
|
|
@ -3,15 +3,33 @@ description: Manage forms in Dart & Flutter with Bloc
|
|||||||
repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_form_bloc
|
repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_form_bloc
|
||||||
version: 0.0.6
|
version: 0.0.6
|
||||||
|
|
||||||
|
publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.17.2 <3.0.0'
|
sdk: ">=2.17.2 <3.0.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
bloc: ^8.1.0
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
flutter_bloc: ^8.1.0
|
||||||
equatable: ^2.0.5
|
equatable: ^2.0.5
|
||||||
|
|
||||||
|
wyatt_architecture:
|
||||||
|
git:
|
||||||
|
url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages
|
||||||
|
ref: wyatt_architecture-v0.0.2-dev.0
|
||||||
|
path: packages/wyatt_architecture
|
||||||
|
|
||||||
|
wyatt_type_utils:
|
||||||
|
git:
|
||||||
|
url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages
|
||||||
|
ref: wyatt_type_utils-v0.0.3+1
|
||||||
|
path: packages/wyatt_type_utils
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
test: ^1.21.4
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
wyatt_analysis:
|
wyatt_analysis:
|
||||||
git:
|
git:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user