This commit is contained in:
2025-04-08 11:42:30 +02:00
parent 4a664288d7
commit bb1dfb8f9a
4 changed files with 283 additions and 25 deletions

View File

@@ -2,5 +2,6 @@ export 'package:form_controller/form_controller.dart';
export 'src/controller.dart';
export 'src/form_field.dart';
export 'src/form_value_wrapper.dart';
export 'src/form_group_wrapper.dart';
export 'src/enums/enums.exports.dart';
export 'src/models/models.exports.dart';

View File

@@ -105,6 +105,35 @@ class AstromicFormController extends FormController {
}
*/
bool hasGroup(String formGroupID, {bool isSubGroup = false}) {
FormGroupStructure? groupStructure;
if (isSubGroup) {
FormGroupStructure? parentGroup = _formGroups.where((FormGroupStructure f) => (f.subGroups?.map((FormGroupStructure ss) => ss.id).contains(formGroupID) ?? false)).nonNulls.toList().firstOrNull;
if (parentGroup != null && parentGroup.subGroups != null && parentGroup.subGroups!.map((FormGroupStructure i) => i.id).contains(formGroupID)) {
groupStructure = parentGroup.subGroups!.where((FormGroupStructure f) => f.id == formGroupID).nonNulls.toList().firstOrNull;
}
} else {
groupStructure = _formGroups.where((FormGroupStructure f) => f.id == formGroupID).nonNulls.toList().firstOrNull;
}
//
return groupStructure != null;
}
FormGroupStructure? getGroupStructure(String formGroupID, {bool isSubGroup = false}) {
// Get the group structure with the same ID
FormGroupStructure? groupStructure;
if (isSubGroup) {
FormGroupStructure? parentGroup = _formGroups.where((FormGroupStructure f) => (f.subGroups?.map((FormGroupStructure ss) => ss.id).contains(formGroupID) ?? false)).nonNulls.toList().firstOrNull;
if (parentGroup != null && parentGroup.subGroups != null && parentGroup.subGroups!.map((FormGroupStructure i) => i.id).contains(formGroupID)) {
groupStructure = parentGroup.subGroups!.where((FormGroupStructure f) => f.id == formGroupID).nonNulls.toList().firstOrNull;
}
} else {
groupStructure = _formGroups.where((FormGroupStructure f) => f.id == formGroupID).nonNulls.toList().firstOrNull;
}
//
return groupStructure;
}
FormGroupValue? getFormGroupValue(String formGroupID, {bool isSubGroup = false}) {
// Get the group structure with the same ID
FormGroupStructure? groupStructure;
@@ -148,8 +177,11 @@ class AstromicFormController extends FormController {
for (int i = 0; i < firstSetOfFieldsWithID.length; i++) {
instances.add(
FormGroupInstance(
composedID: '$formGroupID-#$i-',
fields: Map<String, String>.fromEntries(fieldsIDs.map((String id) => MapEntry<String, String>('$formGroupID-#$i-$id', value('$formGroupID-#$i-$id'))).toList()),
values: valuesIDs.isNotEmpty? Map<String, dynamic>.fromEntries(valuesIDs.map((String a) => MapEntry<String, dynamic>('$formGroupID-#$i-$a', getValue<dynamic>('$formGroupID-#$i-$a'))).toList()) : <String, dynamic>{},
values: valuesIDs.isNotEmpty
? Map<String, dynamic>.fromEntries(valuesIDs.map((String a) => MapEntry<String, dynamic>('$formGroupID-#$i-$a', getValue<dynamic>('$formGroupID-#$i-$a'))).toList())
: <String, dynamic>{},
subGroups: subValues,
),
);
@@ -159,28 +191,112 @@ class AstromicFormController extends FormController {
return groupValue;
}
// void addToFormGroup(String formGroupID) {
// // Get the group structure with the same ID
// FormGroupStructure? groupWithSameID = _formGroups.where((FormGroupStructure f) => f.id == formGroupID).nonNulls.toList().firstOrNull;
// if (groupWithSameID == null) {
// throw Exception('The group ID $formGroupID doesn\'t have any elements. Did you initialize the group?');
// }
String addInstanceToFormGroup(String formGroupID, {bool isSubGroup = false}) {
// Get the group structure with the same ID
FormGroupStructure? groupStructure;
if (isSubGroup) {
FormGroupStructure? parentGroup = _formGroups.where((FormGroupStructure f) => (f.subGroups?.map((FormGroupStructure ss) => ss.id).contains(formGroupID) ?? false)).nonNulls.toList().firstOrNull;
if (parentGroup != null && parentGroup.subGroups != null && parentGroup.subGroups!.map((FormGroupStructure i) => i.id).contains(formGroupID)) {
groupStructure = parentGroup.subGroups!.where((FormGroupStructure f) => f.id == formGroupID).nonNulls.toList().firstOrNull;
} else {
throw Exception('The group ID $formGroupID doesn\'t have any elements. Did you initialize the group?');
}
} else {
groupStructure = _formGroups.where((FormGroupStructure f) => f.id == formGroupID).nonNulls.toList().firstOrNull;
if (groupStructure == null) {
throw Exception('The group ID $formGroupID doesn\'t have any elements. Did you initialize the group?');
}
}
// // Get the current fields with this ID
// Map<String, String> firstSetOfFieldsWithID = Map<String, String>.fromEntries(
// controllers.entries.where((MapEntry<String, String> c) => RegExp(formGroupID + r'-#[\d+]-' + groupWithSameID.fields.entries.first.key).hasMatch(c.key)).nonNulls.toList(),
// );
// Get the current fields with this ID
Map<String, String> firstSetOfFieldsWithID = Map<String, String>.fromEntries(
controllers.entries.where((MapEntry<String, String> c) => RegExp(formGroupID + r'-#[\d+]-' + groupStructure!.fields.first).hasMatch(c.key)).nonNulls.toList(),
);
// for (MapEntry<String, bool> fieldEntry in groupWithSameID.fields.entries) {
// String fieldID = '$formGroupID-${firstSetOfFieldsWithID.length}-${fieldEntry.key}';
// controller(fieldID);
// if (fieldEntry.value) {
// // Is a value field
// } else {
// // Is a text field
// }
// }
// }
// get the fields IDs
List<String> fieldsIDs = groupStructure!.fields.nonNulls.toList();
print('fieldIDs: $fieldsIDs');
// get the values IDs
List<String> valuesIDs = groupStructure.values?.nonNulls.toList() ?? <String>[];
print('valueIDs: $valuesIDs');
// Add the controllers and values.
for (String fieldID in groupStructure.fields) {
String finalFieldID = '${groupStructure.id}-#${firstSetOfFieldsWithID.length}-$fieldID';
controller(finalFieldID);
}
if (groupStructure.values != null && groupStructure.values!.isNotEmpty) {
for (String valueID in groupStructure.values!) {
String finalFieldID = '${groupStructure.id}-#${firstSetOfFieldsWithID.length}-$valueID';
controller(finalFieldID);
}
}
return '${groupStructure.id}-#${firstSetOfFieldsWithID.length}-';
}
String removeInstanceFromFormGroup(String formGroupID, int indexToRemove, {bool isSubGroup = false}) {
// Get the group structure with the same ID
FormGroupStructure? groupStructure;
if (isSubGroup) {
FormGroupStructure? parentGroup = _formGroups.where((FormGroupStructure f) => (f.subGroups?.map((FormGroupStructure ss) => ss.id).contains(formGroupID) ?? false)).nonNulls.toList().firstOrNull;
if (parentGroup != null && parentGroup.subGroups != null && parentGroup.subGroups!.map((FormGroupStructure i) => i.id).contains(formGroupID)) {
groupStructure = parentGroup.subGroups!.where((FormGroupStructure f) => f.id == formGroupID).nonNulls.toList().firstOrNull;
} else {
throw Exception('The group ID $formGroupID doesn\'t have any elements. Did you initialize the group?');
}
} else {
groupStructure = _formGroups.where((FormGroupStructure f) => f.id == formGroupID).nonNulls.toList().firstOrNull;
if (groupStructure == null) {
throw Exception('The group ID $formGroupID doesn\'t have any elements. Did you initialize the group?');
}
}
// Get the current fields with this ID
Map<String, String> firstSetOfFieldsWithID = Map<String, String>.fromEntries(
controllers.entries.where((MapEntry<String, String> c) => RegExp(formGroupID + r'-#[\d+]-' + groupStructure!.fields.first).hasMatch(c.key)).nonNulls.toList(),
);
if (i >= firstSetOfFieldsWithID.length) {
throw Exception('The index to remove is larger than the whole instances count.');
} else {
// get the fields IDs
List<String> fieldsIDs = groupStructure!.fields.nonNulls.toList();
print('fieldIDs: $fieldsIDs');
// get the values IDs
List<String> valuesIDs = groupStructure.values?.nonNulls.toList() ?? <String>[];
print('valueIDs: $valuesIDs');
if (i == (firstSetOfFieldsWithID.length - 1)) {
// Remove the last item
for (String fieldID in groupStructure.fields) {
removeController('${groupStructure.id}-#$i-$fieldID');
}
if (groupStructure.values != null && groupStructure.values!.isNotEmpty) {
for (String valueID in groupStructure.values!) {
removeController('${groupStructure.id}-#$i-$valueID');
}
}
} else {
// Switch and remove
int nextIndex = i + 1;
for (String fieldID in groupStructure.fields) {
set('${groupStructure.id}-#$i-$fieldID', value('${groupStructure.id}-#$nextIndex-$fieldID'));
removeController('${groupStructure.id}-#$nextIndex-$fieldID');
}
if (groupStructure.values != null && groupStructure.values!.isNotEmpty) {
for (String valueID in groupStructure.values!) {
set('${groupStructure.id}-#$i-$valueID', value('${groupStructure.id}-#$nextIndex-$valueID'));
removeController('${groupStructure.id}-#$nextIndex-$valueID');
}
}
}
}
// Remove the controllers and values.
return '${groupStructure.id}-#${firstSetOfFieldsWithID.length}-';
}
// void removeFromFormGroup(String formGroupID, int index) {
// // Get all the groups with the same ID

View File

@@ -0,0 +1,136 @@
//s1 Imports
//s2 Packages
//s3 Core Packages
import 'package:flutter/material.dart';
import '../../../astromic_helpers.dart';
//s3 Internal Packages
// import 'package:astromic_elements/astromic_elements.dart';
//s3 3rd-party Packages
//s2 Utility
//s3 Configs
// import '../../../../../core/configs/routing/routing.config.dart';
//s3 Misc
//s2 Domain
//s3 Entities
//s3 Usecases
//s2 Presentation
//s3 Design
// import '../../../../design-system/design_system.dart';
//s3 Presenters
//s3 Widgets
//s1 Exports
class FormGroupWrapper extends StatefulWidget {
//SECTION - Widget Arguments
final AstromicFormController formController;
final String groupID;
final Widget Function(List<Widget> children, String Function() addItem, void Function(int) removeItem) groupBuilder;
final Widget Function(int index, String composedID, VoidCallback removeItem) itemBuilder;
final int startLength;
//!SECTION
//
const FormGroupWrapper({
super.key,
required this.formController,
required this.groupID,
required this.groupBuilder,
required this.itemBuilder,
this.startLength = 0,
});
@override
State<FormGroupWrapper> createState() => _FormGroupWrapperState();
}
class _FormGroupWrapperState extends State<FormGroupWrapper> {
//
//SECTION - State Variables
//s1 --State
late List<FormGroupInstance> instances;
//s1 --State
//
//s1 --Controllers
//s1 --Controllers
//
//s1 --Constants
//s1 --Constants
//!SECTION
@override
void initState() {
super.initState();
//
//SECTION - State Variables initializations & Listeners
//s1 --State
//s1 --State
//
//s1 --Controllers & Listeners
instances = widget.formController.getFormGroupValue(widget.groupID)!.instances;
//s1 --Controllers & Listeners
//
//s1 --Late & Async Initializers
//s1 --Late & Async Initializers
//!SECTION
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//
//SECTION - State Variables initializations & Listeners
//s1 --State
//s1 --State
//
//s1 --Controllers & Listeners
//s1 --Controllers & Listeners
//
//!SECTION
}
//SECTION - Dumb Widgets
//!SECTION
//SECTION - Stateless functions
//!SECTION
//SECTION - Action Callbacks
//!SECTION
@override
Widget build(BuildContext context) {
//SECTION - Build Setup
//s1 --Values
//double w = MediaQuery.of(context).size.width;
//double h = MediaQuery.of(context).size.height;
//s1 --Values
//
//s1 --Contexted Widgets
//s1 --Contexted Widgets
//!SECTION
//SECTION - Build Return
return widget.groupBuilder(
// Children
List<Widget>.generate(instances.length, (int i) => widget.itemBuilder(i, instances[i].composedID, () => _removeItem(i))),
// Add Callback
() {
return widget.formController.addInstanceToFormGroup(widget.groupID);
},
// Remove Callback
(int i) => _removeItem(i),
);
//!SECTION
}
void _removeItem(int i) {
widget.formController.removeInstanceFromFormGroup(widget.groupID, i);
}
@override
void dispose() {
//SECTION - Disposable variables
//!SECTION
super.dispose();
}
}

View File

@@ -5,21 +5,25 @@ import 'package:flutter/foundation.dart';
import 'form_group_value.model.dart';
class FormGroupInstance {
String composedID;
Map<String, String> fields;
Map<String, dynamic> values;
List<FormGroupValue>? subGroups;
FormGroupInstance({
required this.composedID,
required this.fields,
required this.values,
this.subGroups,
});
FormGroupInstance copyWith({
String? composedID,
Map<String, String>? fields,
Map<String, dynamic>? values,
List<FormGroupValue>? subGroups,
}) {
return FormGroupInstance(
composedID: composedID ?? this.composedID,
fields: fields ?? this.fields,
values: values ?? this.values,
subGroups: subGroups ?? this.subGroups,
@@ -28,6 +32,7 @@ class FormGroupInstance {
Map<String, dynamic> toMap() {
return <String, dynamic>{
'composedID': composedID,
'fields': fields,
'values': values,
'subGroups': subGroups?.map((FormGroupValue x) => x.toMap()).toList(),
@@ -36,6 +41,7 @@ class FormGroupInstance {
factory FormGroupInstance.fromMap(Map<String, dynamic> map) {
return FormGroupInstance(
composedID: map['composedID'],
fields: Map<String, String>.from(map['fields'] as Map<String, String>),
values: Map<String, dynamic>.from(map['values'] as Map<String, dynamic>),
subGroups: map['subGroups'] != null
@@ -53,16 +59,15 @@ class FormGroupInstance {
factory FormGroupInstance.fromJson(String source) => FormGroupInstance.fromMap(json.decode(source) as Map<String, dynamic>);
@override
String toString() => 'FormGroupInstance(fields: $fields, values: $values, subGroups: $subGroups)';
String toString() => 'FormGroupInstance(composedID: $composedID, fields: $fields, values: $values, subGroups: $subGroups)';
@override
bool operator ==(covariant FormGroupInstance other) {
if (identical(this, other)) return true;
return mapEquals(other.fields, fields) && mapEquals(other.values, values) && listEquals(other.subGroups, subGroups);
return mapEquals(other.fields, fields) && mapEquals(other.values, values) && listEquals(other.subGroups, subGroups) && composedID == other.composedID;
}
@override
int get hashCode => fields.hashCode ^ values.hashCode ^ subGroups.hashCode;
int get hashCode => composedID.hashCode ^ fields.hashCode ^ values.hashCode ^ subGroups.hashCode;
}