auth/wyatt_arch_migration #25
| @ -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