mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-10-31 13:33:28 +01:00 
			
		
		
		
	Broke GeneratedFormItem into sub-types
Prep for "chips" input type
This commit is contained in:
		| @@ -1,39 +1,90 @@ | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
|  | ||||
| enum FormItemType { string, bool } | ||||
|  | ||||
| typedef OnValueChanges = void Function( | ||||
|     Map<String, String> values, bool valid, bool isBuilding); | ||||
|  | ||||
| class GeneratedFormItem { | ||||
| abstract class GeneratedFormItem { | ||||
|   late String key; | ||||
|   late String label; | ||||
|   late FormItemType type; | ||||
|   late bool required; | ||||
|   late int max; | ||||
|   late List<String? Function(String? value)> additionalValidators; | ||||
|   late List<Widget> belowWidgets; | ||||
|   late String? hint; | ||||
|   late List<MapEntry<String, String>>? opts; | ||||
|   late String? defaultValue; | ||||
|   late dynamic defaultValue; | ||||
|   List<dynamic> additionalValidators; | ||||
|   dynamic ensureType(dynamic val); | ||||
|  | ||||
|   GeneratedFormItem(this.key, | ||||
|       {this.label = 'Input', | ||||
|       this.type = FormItemType.string, | ||||
|       this.belowWidgets = const [], | ||||
|       this.defaultValue, | ||||
|       this.additionalValidators = const []}); | ||||
| } | ||||
|  | ||||
| class GeneratedFormTextField extends GeneratedFormItem { | ||||
|   late bool required; | ||||
|   late int max; | ||||
|   late String? hint; | ||||
|  | ||||
|   GeneratedFormTextField(String key, | ||||
|       {String label = 'Input', | ||||
|       List<Widget> belowWidgets = const [], | ||||
|       String defaultValue = '', | ||||
|       List<String? Function(String? value)> additionalValidators = const [], | ||||
|       this.required = true, | ||||
|       this.max = 1, | ||||
|       this.additionalValidators = const [], | ||||
|       this.belowWidgets = const [], | ||||
|       this.hint, | ||||
|       this.opts, | ||||
|       this.defaultValue}) { | ||||
|     if (type != FormItemType.string) { | ||||
|       required = false; | ||||
|     } | ||||
|       this.hint}) | ||||
|       : super(key, | ||||
|             label: label, | ||||
|             belowWidgets: belowWidgets, | ||||
|             defaultValue: defaultValue, | ||||
|             additionalValidators: additionalValidators); | ||||
|  | ||||
|   @override | ||||
|   String ensureType(val) { | ||||
|     return val.toString(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class GeneratedFormDropdown extends GeneratedFormItem { | ||||
|   late List<MapEntry<String, String>>? opts; | ||||
|  | ||||
|   GeneratedFormDropdown( | ||||
|     String key, | ||||
|     this.opts, { | ||||
|     String label = 'Input', | ||||
|     List<Widget> belowWidgets = const [], | ||||
|     String defaultValue = '', | ||||
|     List<String? Function(String? value)> additionalValidators = const [], | ||||
|   }) : super(key, | ||||
|             label: label, | ||||
|             belowWidgets: belowWidgets, | ||||
|             defaultValue: defaultValue, | ||||
|             additionalValidators: additionalValidators); | ||||
|  | ||||
|   @override | ||||
|   String ensureType(val) { | ||||
|     return val.toString(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class GeneratedFormSwitch extends GeneratedFormItem { | ||||
|   GeneratedFormSwitch( | ||||
|     String key, { | ||||
|     String label = 'Input', | ||||
|     List<Widget> belowWidgets = const [], | ||||
|     bool defaultValue = false, | ||||
|     List<String? Function(bool value)> additionalValidators = const [], | ||||
|   }) : super(key, | ||||
|             label: label, | ||||
|             belowWidgets: belowWidgets, | ||||
|             defaultValue: defaultValue, | ||||
|             additionalValidators: additionalValidators); | ||||
|  | ||||
|   @override | ||||
|   bool ensureType(val) { | ||||
|     return val == true || val == 'true'; | ||||
|   } | ||||
| } | ||||
|  | ||||
| typedef OnValueChanges = void Function( | ||||
|     Map<String, dynamic> values, bool valid, bool isBuilding); | ||||
|  | ||||
| class GeneratedForm extends StatefulWidget { | ||||
|   const GeneratedForm( | ||||
|       {super.key, required this.items, required this.onValueChanges}); | ||||
| @@ -47,18 +98,16 @@ class GeneratedForm extends StatefulWidget { | ||||
|  | ||||
| class _GeneratedFormState extends State<GeneratedForm> { | ||||
|   final _formKey = GlobalKey<FormState>(); | ||||
|   Map<String, String> values = {}; | ||||
|   Map<String, dynamic> values = {}; | ||||
|   late List<List<Widget>> formInputs; | ||||
|   List<List<Widget>> rows = []; | ||||
|  | ||||
|   // If any value changes, call this to update the parent with value and validity | ||||
|   void someValueChanged({bool isBuilding = false}) { | ||||
|     Map<String, String> returnValues = {}; | ||||
|     Map<String, dynamic> returnValues = values; | ||||
|     var valid = true; | ||||
|     for (int r = 0; r < widget.items.length; r++) { | ||||
|       for (int i = 0; i < widget.items[r].length; i++) { | ||||
|         returnValues[widget.items[r][i].key] = | ||||
|             values[widget.items[r][i].key] ?? ''; | ||||
|         if (formInputs[r][i] is TextFormField) { | ||||
|           valid = valid && | ||||
|               ((formInputs[r][i].key as GlobalKey<FormFieldState>) | ||||
| @@ -80,35 +129,37 @@ class _GeneratedFormState extends State<GeneratedForm> { | ||||
|     int j = 0; | ||||
|     for (var row in widget.items) { | ||||
|       for (var e in row) { | ||||
|         values[e.key] = e.defaultValue ?? e.opts?.first.key ?? ''; | ||||
|         values[e.key] = e.defaultValue; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Dynamically create form inputs | ||||
|     formInputs = widget.items.asMap().entries.map((row) { | ||||
|       return row.value.asMap().entries.map((e) { | ||||
|         if (e.value.type == FormItemType.string && e.value.opts == null) { | ||||
|         var formItem = e.value; | ||||
|         if (formItem is GeneratedFormTextField) { | ||||
|           final formFieldKey = GlobalKey<FormFieldState>(); | ||||
|           return TextFormField( | ||||
|             key: formFieldKey, | ||||
|             initialValue: values[e.value.key], | ||||
|             initialValue: values[formItem.key], | ||||
|             autovalidateMode: AutovalidateMode.onUserInteraction, | ||||
|             onChanged: (value) { | ||||
|               setState(() { | ||||
|                 values[e.value.key] = value; | ||||
|                 values[formItem.key] = value; | ||||
|                 someValueChanged(); | ||||
|               }); | ||||
|             }, | ||||
|             decoration: InputDecoration( | ||||
|                 helperText: e.value.label + (e.value.required ? ' *' : ''), | ||||
|                 hintText: e.value.hint), | ||||
|             minLines: e.value.max <= 1 ? null : e.value.max, | ||||
|             maxLines: e.value.max <= 1 ? 1 : e.value.max, | ||||
|                 helperText: formItem.label + (formItem.required ? ' *' : ''), | ||||
|                 hintText: formItem.hint), | ||||
|             minLines: formItem.max <= 1 ? null : formItem.max, | ||||
|             maxLines: formItem.max <= 1 ? 1 : formItem.max, | ||||
|             validator: (value) { | ||||
|               if (e.value.required && (value == null || value.trim().isEmpty)) { | ||||
|                 return '${e.value.label} ${tr('requiredInBrackets')}'; | ||||
|               if (formItem.required && | ||||
|                   (value == null || value.trim().isEmpty)) { | ||||
|                 return '${formItem.label} ${tr('requiredInBrackets')}'; | ||||
|               } | ||||
|               for (var validator in e.value.additionalValidators) { | ||||
|               for (var validator in formItem.additionalValidators) { | ||||
|                 String? result = validator(value); | ||||
|                 if (result != null) { | ||||
|                   return result; | ||||
| @@ -117,21 +168,20 @@ class _GeneratedFormState extends State<GeneratedForm> { | ||||
|               return null; | ||||
|             }, | ||||
|           ); | ||||
|         } else if (e.value.type == FormItemType.string && | ||||
|             e.value.opts != null) { | ||||
|           if (e.value.opts!.isEmpty) { | ||||
|         } else if (formItem is GeneratedFormDropdown) { | ||||
|           if (formItem.opts!.isEmpty) { | ||||
|             return Text(tr('dropdownNoOptsError')); | ||||
|           } | ||||
|           return DropdownButtonFormField( | ||||
|               decoration: InputDecoration(labelText: e.value.label), | ||||
|               value: values[e.value.key], | ||||
|               items: e.value.opts! | ||||
|                   .map((e) => | ||||
|                       DropdownMenuItem(value: e.key, child: Text(e.value))) | ||||
|               decoration: InputDecoration(labelText: formItem.label), | ||||
|               value: values[formItem.key], | ||||
|               items: formItem.opts! | ||||
|                   .map((e2) => | ||||
|                       DropdownMenuItem(value: e2.key, child: Text(e2.value))) | ||||
|                   .toList(), | ||||
|               onChanged: (value) { | ||||
|                 setState(() { | ||||
|                   values[e.value.key] = value ?? e.value.opts!.first.key; | ||||
|                   values[formItem.key] = value ?? formItem.opts!.first.key; | ||||
|                   someValueChanged(); | ||||
|                 }); | ||||
|               }); | ||||
| @@ -147,16 +197,16 @@ class _GeneratedFormState extends State<GeneratedForm> { | ||||
|   Widget build(BuildContext context) { | ||||
|     for (var r = 0; r < formInputs.length; r++) { | ||||
|       for (var e = 0; e < formInputs[r].length; e++) { | ||||
|         if (widget.items[r][e].type == FormItemType.bool) { | ||||
|         if (widget.items[r][e] is GeneratedFormSwitch) { | ||||
|           formInputs[r][e] = Row( | ||||
|             mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|             children: [ | ||||
|               Text(widget.items[r][e].label), | ||||
|               Switch( | ||||
|                   value: values[widget.items[r][e].key] == 'true', | ||||
|                   value: values[widget.items[r][e].key], | ||||
|                   onChanged: (value) { | ||||
|                     setState(() { | ||||
|                       values[widget.items[r][e].key] = value ? 'true' : ''; | ||||
|                       values[widget.items[r][e].key] = value; | ||||
|                       someValueChanged(); | ||||
|                     }); | ||||
|                   }) | ||||
| @@ -171,9 +221,8 @@ class _GeneratedFormState extends State<GeneratedForm> { | ||||
|       if (rowInputs.key > 0) { | ||||
|         rows.add([ | ||||
|           SizedBox( | ||||
|             height: widget.items[rowInputs.key][0].type == FormItemType.bool && | ||||
|                     widget.items[rowInputs.key - 1][0].type == | ||||
|                         FormItemType.string | ||||
|             height: widget.items[rowInputs.key][0] is GeneratedFormSwitch && | ||||
|                     widget.items[rowInputs.key - 1][0] is! GeneratedFormSwitch | ||||
|                 ? 25 | ||||
|                 : 8, | ||||
|           ) | ||||
|   | ||||
| @@ -21,7 +21,7 @@ class GeneratedFormModal extends StatefulWidget { | ||||
| } | ||||
|  | ||||
| class _GeneratedFormModalState extends State<GeneratedFormModal> { | ||||
|   Map<String, String> values = {}; | ||||
|   Map<String, dynamic> values = {}; | ||||
|   bool valid = false; | ||||
|  | ||||
|   @override | ||||
|   | ||||
		Reference in New Issue
	
	Block a user