[SYNC]
This commit is contained in:
@@ -19,21 +19,6 @@ import 'models/form_group_value.model.dart';
|
|||||||
|
|
||||||
/// A specialized form controller to handle form states,
|
/// A specialized form controller to handle form states,
|
||||||
class AstromicFormController extends FormController {
|
class AstromicFormController extends FormController {
|
||||||
// State Variables
|
|
||||||
final Map<String, AstromicFieldState> fieldStates = <String, AstromicFieldState>{};
|
|
||||||
final Map<String, String?> fieldMessages = <String, String?>{};
|
|
||||||
final Map<String, (dynamic, bool)> _hostedValues = <String, (dynamic, bool)>{};
|
|
||||||
final Stream<List<(String internalCode, String? message)>>? errorStream;
|
|
||||||
final List<FormGroupStructure> _formGroups = <FormGroupStructure>[];
|
|
||||||
|
|
||||||
// State Stream Variables
|
|
||||||
static final StreamController<(String, AstromicFieldState)> _stateStreamController = StreamController<(String id, AstromicFieldState)>.broadcast();
|
|
||||||
final Stream<(String id, AstromicFieldState)> stateStream = _stateStreamController.stream;
|
|
||||||
|
|
||||||
// Hosted Value Validation Stream Variables
|
|
||||||
static final StreamController<(String, bool)> _hostedValueValidationStreamController = StreamController<(String id, bool)>.broadcast();
|
|
||||||
final Stream<(String id, bool isValidationErrored)> hostedValueValidationStream = _hostedValueValidationStreamController.stream;
|
|
||||||
|
|
||||||
AstromicFormController({
|
AstromicFormController({
|
||||||
Map<String, (String initialText, bool initialObscurity)>? initialValues,
|
Map<String, (String initialText, bool initialObscurity)>? initialValues,
|
||||||
this.errorStream,
|
this.errorStream,
|
||||||
@@ -42,338 +27,7 @@ class AstromicFormController extends FormController {
|
|||||||
_addInitialControllers(initialValues);
|
_addInitialControllers(initialValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
get i => null;
|
//SECTION - Overrides
|
||||||
|
|
||||||
/// Does the controller has a field with this ID.
|
|
||||||
bool hasKey(String id) => controllers.containsKey(id);
|
|
||||||
|
|
||||||
/* some-group: {
|
|
||||||
some-group-0 : null,
|
|
||||||
some-group-1 : null,
|
|
||||||
some-group-2: null,
|
|
||||||
some-group-3: {
|
|
||||||
some-group-3-a: null,
|
|
||||||
some-group-3-b: null,
|
|
||||||
some-group-3-c: null,
|
|
||||||
some-group-3-d: null,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
// At the start of a screen?
|
|
||||||
void initializeFormGroup(FormGroupStructure groupStructure, {int initialCount = 1}) {
|
|
||||||
if (groupStructure.fields.isEmpty) {
|
|
||||||
throw Exception('Group Fields should NOT be empty.');
|
|
||||||
}
|
|
||||||
_formGroups.add(groupStructure);
|
|
||||||
|
|
||||||
// Add the controllers and values.
|
|
||||||
for (int i = 0; i < initialCount; i++) {
|
|
||||||
for (String fieldID in groupStructure.fields) {
|
|
||||||
String finalFieldID = '${groupStructure.id}-#$i-$fieldID';
|
|
||||||
controller(finalFieldID);
|
|
||||||
}
|
|
||||||
if (groupStructure.values != null && groupStructure.values!.isNotEmpty) {
|
|
||||||
for (String valueID in groupStructure.values!) {
|
|
||||||
String finalFieldID = '${groupStructure.id}-#$i-$valueID';
|
|
||||||
controller(finalFieldID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*{
|
|
||||||
{
|
|
||||||
0: {
|
|
||||||
field1: something,
|
|
||||||
field2: something else
|
|
||||||
field3: somethin another,
|
|
||||||
sub-group: {
|
|
||||||
0:
|
|
||||||
{
|
|
||||||
sub-field1: someValue,
|
|
||||||
sub-field2: someOtherValue,
|
|
||||||
}
|
|
||||||
1:
|
|
||||||
2:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1:
|
|
||||||
2:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
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;
|
|
||||||
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?');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
print('Got the structure: $groupStructure');
|
|
||||||
|
|
||||||
// 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(),
|
|
||||||
);
|
|
||||||
|
|
||||||
print('First set of fields: $firstSetOfFieldsWithID');
|
|
||||||
// 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');
|
|
||||||
|
|
||||||
// get the subGroups
|
|
||||||
List<FormGroupValue> subValues = <FormGroupValue>[];
|
|
||||||
if (groupStructure.subGroups != null && groupStructure.subGroups!.isNotEmpty) {
|
|
||||||
subValues = groupStructure.subGroups!.map((FormGroupStructure s) => getFormGroupValue(s.id, isSubGroup: true)).nonNulls.toList();
|
|
||||||
}
|
|
||||||
print('subValues: $subValues');
|
|
||||||
|
|
||||||
List<FormGroupInstance> instances = <FormGroupInstance>[];
|
|
||||||
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>{},
|
|
||||||
subGroups: subValues,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
FormGroupValue groupValue = FormGroupValue(groupID: formGroupID, instancesCount: firstSetOfFieldsWithID.length, instances: instances);
|
|
||||||
return groupValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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+]-' + groupStructure!.fields.first).hasMatch(c.key)).nonNulls.toList(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// 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}-';
|
|
||||||
}
|
|
||||||
|
|
||||||
void 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 (indexToRemove >= 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 (indexToRemove == (firstSetOfFieldsWithID.length - 1)) {
|
|
||||||
// Remove the last item
|
|
||||||
for (String fieldID in groupStructure.fields) {
|
|
||||||
removeController('${groupStructure.id}-#$indexToRemove-$fieldID');
|
|
||||||
}
|
|
||||||
if (groupStructure.values != null && groupStructure.values!.isNotEmpty) {
|
|
||||||
for (String valueID in groupStructure.values!) {
|
|
||||||
removeController('${groupStructure.id}-#$indexToRemove-$valueID');
|
|
||||||
_hostedValues.remove('${groupStructure.id}-#$indexToRemove-$valueID');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Switch and remove
|
|
||||||
int nextIndex = indexToRemove + 1;
|
|
||||||
for (String fieldID in groupStructure.fields) {
|
|
||||||
set('${groupStructure.id}-#$indexToRemove-$fieldID', value('${groupStructure.id}-#$nextIndex-$fieldID'));
|
|
||||||
removeController('${groupStructure.id}-#$nextIndex-$fieldID');
|
|
||||||
}
|
|
||||||
if (groupStructure.values != null && groupStructure.values!.isNotEmpty) {
|
|
||||||
for (String valueID in groupStructure.values!) {
|
|
||||||
_hostedValues.remove('${groupStructure.id}-#$indexToRemove-$valueID');
|
|
||||||
set('${groupStructure.id}-#$indexToRemove-$valueID', value('${groupStructure.id}-#$nextIndex-$valueID'));
|
|
||||||
setValue('${groupStructure.id}-#$indexToRemove-$valueID', getValue('${groupStructure.id}-#$nextIndex-$valueID'));
|
|
||||||
removeController('${groupStructure.id}-#$nextIndex-$valueID');
|
|
||||||
_hostedValues.remove('${groupStructure.id}-#$nextIndex-$valueID');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Remove last instance
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// void removeFromFormGroup(String formGroupID, int index) {
|
|
||||||
// // Get all the groups with the same ID
|
|
||||||
// List<FormGroupStructure> groupsWithSameID = _formGroups.where((FormGroupStructure f) => f.id == formGroupID).nonNulls.toList();
|
|
||||||
// if (groupsWithSameID.isEmpty) {
|
|
||||||
// throw Exception('The group ID $formGroupID doesn\'t have any elements. Did you initialize the group?');
|
|
||||||
// }
|
|
||||||
// _formGroups.removeAt(groupsWithSameID.first);
|
|
||||||
// for (MapEntry<String, bool> fieldEntry in groupsWithSameID.first.fields.entries) {
|
|
||||||
// String fieldID = '$formGroupID-${groupsWithSameID.length}-${fieldEntry.key}';
|
|
||||||
// controller(fieldID);
|
|
||||||
// if (fieldEntry.value) {
|
|
||||||
// // Is a value field
|
|
||||||
// } else {
|
|
||||||
// // Is a text field
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Map<String,Map<String,dynamic>> getFormGroup(String groupID){}
|
|
||||||
|
|
||||||
/// Get the field state and message of a specific field using it's ID.
|
|
||||||
(AstromicFieldState, String? message)? getState(String fieldId) => (fieldStates.containsKey(fieldId)) ? (fieldStates[fieldId]!, fieldMessages[fieldId]) : null;
|
|
||||||
|
|
||||||
/// Set the field state and message of a specific field using it's ID.
|
|
||||||
void setState(String fieldId, AstromicFieldState state, {String? message}) {
|
|
||||||
if (!fieldStates.containsKey(fieldId)) {
|
|
||||||
throw Exception('The state of the field ID $fieldId does not exist.');
|
|
||||||
}
|
|
||||||
fieldStates[fieldId] = state;
|
|
||||||
fieldMessages[fieldId] = message;
|
|
||||||
_stateStreamController.add((fieldId, state));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reset the state of a specific field using it's ID.
|
|
||||||
void resetState(String fieldId) => setState(fieldId, AstromicFieldState.idle);
|
|
||||||
|
|
||||||
/// Validate hosted values.
|
|
||||||
bool validateValues(List<String> valueIDs) {
|
|
||||||
for (String hostedValueID in valueIDs) {
|
|
||||||
if (_hostedValues.containsKey(hostedValueID) && _hostedValues[hostedValueID]!.$2 && _hostedValues[hostedValueID]!.$1 == null) {
|
|
||||||
// Validation Error!
|
|
||||||
_hostedValueValidationStreamController.add((hostedValueID, true));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prepare a hosted value.
|
|
||||||
void prepareValue<T>(String id, bool isRequired) {
|
|
||||||
if (!_hostedValues.keys.toList().contains(id)) {
|
|
||||||
return _hostedValues.addEntries(<MapEntry<String, (T?, bool)>>[MapEntry<String, (T?, bool)>(id, (null, isRequired))]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the value of a hosted state variable using it's ID.
|
|
||||||
T? getValue<T>(String id) {
|
|
||||||
prepareValue(id, false);
|
|
||||||
|
|
||||||
if (_hostedValues[id]?.$1 is T?) {
|
|
||||||
return _hostedValues[id]?.$1;
|
|
||||||
} else {
|
|
||||||
throw Exception('Value found but is not of the type $T, it\'s of type ${_hostedValues[id]?.$1.runtimeType}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the value of a hosted state variable using it's ID.
|
|
||||||
void setValue<T>(String id, T data, {bool isRequired = false}) {
|
|
||||||
prepareValue(id, isRequired);
|
|
||||||
_hostedValues[id] = (data, isRequired);
|
|
||||||
_hostedValueValidationStreamController.add((id, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
TextEditingController controller(String id, {String? initialText, bool isObscure = false}) {
|
TextEditingController controller(String id, {String? initialText, bool isObscure = false}) {
|
||||||
TextEditingController ret = super.controller(id, initialText: initialText, isObscure: isObscure);
|
TextEditingController ret = super.controller(id, initialText: initialText, isObscure: isObscure);
|
||||||
@@ -400,8 +54,545 @@ class AstromicFormController extends FormController {
|
|||||||
fieldMessages.remove(id);
|
fieldMessages.remove(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//!SECTION
|
||||||
|
|
||||||
|
//SECTION - Field State
|
||||||
|
//S1 - State Variables
|
||||||
|
final Map<String, AstromicFieldState> fieldStates = <String, AstromicFieldState>{};
|
||||||
|
final Map<String, String?> fieldMessages = <String, String?>{};
|
||||||
|
//S1 - Streams
|
||||||
|
static final StreamController<(String, AstromicFieldState)> _stateStreamController = StreamController<(String id, AstromicFieldState)>.broadcast();
|
||||||
|
final Stream<(String id, AstromicFieldState)> stateStream = _stateStreamController.stream;
|
||||||
|
final Stream<List<(String internalCode, String? message)>>? errorStream;
|
||||||
|
//S1 - Methods
|
||||||
|
|
||||||
|
/// Does the controller has a field with this ID.
|
||||||
|
bool hasKey(String id) => controllers.containsKey(id);
|
||||||
|
|
||||||
|
/// Get the field state and message of a specific field using it's ID.
|
||||||
|
(AstromicFieldState, String? message)? getState(String fieldId) => (fieldStates.containsKey(fieldId)) ? (fieldStates[fieldId]!, fieldMessages[fieldId]) : null;
|
||||||
|
|
||||||
|
/// Set the field state and message of a specific field using it's ID.
|
||||||
|
void setState(String fieldId, AstromicFieldState state, {String? message}) {
|
||||||
|
if (!fieldStates.containsKey(fieldId)) {
|
||||||
|
throw Exception('The state of the field ID $fieldId does not exist.');
|
||||||
|
}
|
||||||
|
fieldStates[fieldId] = state;
|
||||||
|
fieldMessages[fieldId] = message;
|
||||||
|
_stateStreamController.add((fieldId, state));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset the state of a specific field using it's ID.
|
||||||
|
void resetState(String fieldId) => setState(fieldId, AstromicFieldState.idle);
|
||||||
|
//!SECTION
|
||||||
|
|
||||||
|
//SECTION - Hosted Values
|
||||||
|
//S1 - State Variables
|
||||||
|
final Map<String, (dynamic, bool)> _hostedValues = <String, (dynamic, bool)>{};
|
||||||
|
|
||||||
|
//S1 - Streams
|
||||||
|
static final StreamController<(String, bool)> _hostedValueValidationStreamController = StreamController<(String id, bool)>.broadcast();
|
||||||
|
final Stream<(String id, bool isValidationErrored)> hostedValueValidationStream = _hostedValueValidationStreamController.stream;
|
||||||
|
|
||||||
|
//S1 - Methods
|
||||||
|
|
||||||
|
/// Prepare a hosted value.
|
||||||
|
void prepareValue<T>(String id, bool isRequired) {
|
||||||
|
if (!_hostedValues.keys.toList().contains(id)) {
|
||||||
|
return _hostedValues.addEntries(<MapEntry<String, (T?, bool)>>[MapEntry<String, (T?, bool)>(id, (null, isRequired))]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the value of a hosted state variable using it's ID.
|
||||||
|
T? getValue<T>(String id) {
|
||||||
|
prepareValue(id, false);
|
||||||
|
|
||||||
|
if (_hostedValues[id]?.$1 is T?) {
|
||||||
|
return _hostedValues[id]?.$1;
|
||||||
|
} else {
|
||||||
|
throw Exception('Value found but is not of the type $T, it\'s of type ${_hostedValues[id]?.$1.runtimeType}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the value of a hosted state variable using it's ID.
|
||||||
|
void setValue<T>(String id, T data, {bool isRequired = false}) {
|
||||||
|
prepareValue(id, isRequired);
|
||||||
|
_hostedValues[id] = (data, isRequired);
|
||||||
|
_hostedValueValidationStreamController.add((id, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validate hosted values.
|
||||||
|
bool validateValues(List<String> valueIDs) {
|
||||||
|
for (String hostedValueID in valueIDs) {
|
||||||
|
if (_hostedValues.containsKey(hostedValueID) && _hostedValues[hostedValueID]!.$2 && _hostedValues[hostedValueID]!.$1 == null) {
|
||||||
|
// Validation Error!
|
||||||
|
_hostedValueValidationStreamController.add((hostedValueID, true));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//!SECTION
|
||||||
|
|
||||||
|
//SECTION - Form Groups
|
||||||
|
//S1 - State Variables
|
||||||
|
final List<FormGroupStructure> _formGroups = <FormGroupStructure>[];
|
||||||
|
//S1 - Methods
|
||||||
|
|
||||||
|
/// Recursively returns the full path of the group ID.
|
||||||
|
String? getFullPathOfGroup(String targetGroupID, {List<FormGroupStructure>? formGroups, String currentPath = ''}) {
|
||||||
|
// Loop through each FormGroupStructure
|
||||||
|
for (final FormGroupStructure group in (formGroups ?? _formGroups)) {
|
||||||
|
// If the group ID matches, return the current path
|
||||||
|
if (group.id == targetGroupID) return '$currentPath${group.id}';
|
||||||
|
|
||||||
|
// Otherwise, check in its subgroups recursively
|
||||||
|
for (final (FormGroupStructure, int) subGroup in group.subGroups ?? <(FormGroupStructure, int)>[]) {
|
||||||
|
final String? subGroupPath = getFullPathOfGroup(targetGroupID, formGroups: <FormGroupStructure>[subGroup.$1], currentPath: '$currentPath${group.id}->');
|
||||||
|
// Return the path if found
|
||||||
|
if (subGroupPath != null) {
|
||||||
|
return subGroupPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an empty string if the group ID is not found
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// _formController.initializeFormGroup(
|
||||||
|
// FormGroupStructure(
|
||||||
|
// id: 'mainGroup',
|
||||||
|
// fields: [
|
||||||
|
// 'title',
|
||||||
|
// 'description',
|
||||||
|
// ],
|
||||||
|
// values: [
|
||||||
|
// 'media',
|
||||||
|
// ],
|
||||||
|
// subGroups: [
|
||||||
|
// (FormGroupStructure(
|
||||||
|
// id: 'variations',
|
||||||
|
// fields: ['title'],
|
||||||
|
// values: ['media'],
|
||||||
|
// ),3),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// initialCount: 2,
|
||||||
|
// );
|
||||||
|
/// Does the controller has a field group with this ID.
|
||||||
|
// bool hasFieldGroup(String formGroupID, {bool isSubGroup = false}) => _getGroupStructure(formGroupID, isSubGroup: isSubGroup) != null;
|
||||||
|
|
||||||
|
/// Get the formGroupStructure of this groupId
|
||||||
|
// String? findGroupPath(String groupID, List<FormGroupStructure>? groups) {
|
||||||
|
// if ((groups ?? _formGroups).map((FormGroupStructure a) => a.id).contains(groupID)) return groupID;
|
||||||
|
// findGroupPath(
|
||||||
|
// groupID,
|
||||||
|
// (groups ?? _formGroups)
|
||||||
|
// .map((FormGroupStructure f) => f.subGroups?.map(((FormGroupStructure, int) aa) => aa.$1).toList())
|
||||||
|
// .toList()
|
||||||
|
// .reduce((List<FormGroupStructure>? a, List<FormGroupStructure>? b) => <FormGroupStructure>[...?a, ...?b])
|
||||||
|
// ?.toList() ??
|
||||||
|
// <FormGroupStructure>[],
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// Get the formGroupStructure of this groupId
|
||||||
|
FormGroupStructure? getGroupStructure(String groupID) {
|
||||||
|
// Get the full path of the group
|
||||||
|
final String? fullPath = getFullPathOfGroup(groupID, formGroups: _formGroups);
|
||||||
|
|
||||||
|
// If no path is found, return null
|
||||||
|
if (fullPath == null) return null;
|
||||||
|
|
||||||
|
// Split the path into segments
|
||||||
|
final List<String> pathSegments = fullPath.split('->');
|
||||||
|
|
||||||
|
// We start with the root group (the first segment in the path)
|
||||||
|
FormGroupStructure? currentGroup = _formGroups.where((FormGroupStructure group) => group.id == pathSegments.first).firstOrNull;
|
||||||
|
|
||||||
|
// If the root group is not found, return null
|
||||||
|
if (currentGroup == null) return null;
|
||||||
|
|
||||||
|
// Traverse through the path segments to find the group or subgroup
|
||||||
|
for (int i = 1; i < pathSegments.length; i++) {
|
||||||
|
final String segment = pathSegments[i];
|
||||||
|
|
||||||
|
// Search for the subgroup within the current group
|
||||||
|
final (FormGroupStructure, int)? subGroup = currentGroup?.subGroups?.where(((FormGroupStructure, int) subGroup) => subGroup.$1.id == segment).firstOrNull;
|
||||||
|
|
||||||
|
// If a subgroup is found, update currentGroup to the subgroup
|
||||||
|
if (subGroup != null) {
|
||||||
|
currentGroup = subGroup.$1;
|
||||||
|
} else {
|
||||||
|
// If no subgroup is found at this level, return null
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormGroupStructure? _getGroupStructure(String formGroupID, {bool isSubGroup = false}) {
|
||||||
|
// FormGroupStructure? groupStructure;
|
||||||
|
// if (isSubGroup) {
|
||||||
|
// FormGroupStructure? parentGroup =
|
||||||
|
// _formGroups.where((FormGroupStructure f) => (f.subGroups?.map(((FormGroupStructure, int) ss) => ss.$1.id).contains(formGroupID) ?? false)).nonNulls.toList().firstOrNull;
|
||||||
|
// if (parentGroup != null && parentGroup.subGroups != null && parentGroup.subGroups!.map(((FormGroupStructure, int) i) => i.$1.id).contains(formGroupID)) {
|
||||||
|
// assert(parentGroup.subGroups!.where(((FormGroupStructure, int) f) => f.$1.id == formGroupID).nonNulls.toList().length == 1, 'Seems there are multible subgroups with this ID!');
|
||||||
|
// groupStructure = parentGroup.subGroups!.where(((FormGroupStructure, int) f) => f.$1.id == formGroupID).nonNulls.toList().firstOrNull?.$1;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// groupStructure = _formGroups.where((FormGroupStructure f) => f.id == formGroupID).nonNulls.toList().firstOrNull;
|
||||||
|
// }
|
||||||
|
// //
|
||||||
|
// return groupStructure;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// Get current Instance count of this formGroup
|
||||||
|
// int formGroupInstancesLength(String formGroupID, {bool isSubGroup = false}) {
|
||||||
|
// // Get the group structure with the same ID
|
||||||
|
// FormGroupStructure? structure = _getGroupStructure(formGroupID, isSubGroup: isSubGroup);
|
||||||
|
// assert(structure != null, 'The ${isSubGroup ? "SUBGroup" : "Group"} $formGroupID doesn\'t seem to be found, are you sure you initialized it?');
|
||||||
|
|
||||||
|
// 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(),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// Prepare the groupStructure.
|
||||||
|
// void _addFieldsToGroup(String structureID, List<String> fields, List<String>? values, int index) {
|
||||||
|
// for (String fieldID in fields) {
|
||||||
|
// controller(standeredGroupFormat(structureID, index, fieldID));
|
||||||
|
// }
|
||||||
|
// if (values != null && values.isNotEmpty) {
|
||||||
|
// for (String valueID in values) {
|
||||||
|
// controller(standeredGroupFormat(structureID, index, valueID));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
void _addGroupControllers(FormGroupStructure structure, int index, {String? parentPrefix}) {
|
||||||
|
final String baseID = parentPrefix ?? structure.id;
|
||||||
|
|
||||||
|
for (final String fieldID in structure.fields) {
|
||||||
|
final String fullID = standeredGroupFormat(baseID, index, fieldID);
|
||||||
|
controller(fullID);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final String valueID in structure.values ?? <String>[]) {
|
||||||
|
final String fullID = standeredGroupFormat(baseID, index, valueID);
|
||||||
|
controller(fullID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize the formGroup Structure.
|
||||||
|
void initializeFormGroup(FormGroupStructure groupStructure, {int initialCount = 1}) {
|
||||||
|
assert(groupStructure.fields.isNotEmpty, '${groupStructure.id}: Group fields should NOT be empty.');
|
||||||
|
|
||||||
|
// Validate subgroups (if any)
|
||||||
|
groupStructure.subGroups?.map(((FormGroupStructure, int) a) => a.$1).forEach(((FormGroupStructure subGroup) {
|
||||||
|
assert(subGroup.fields.isNotEmpty, '${subGroup.id}: Subgroup fields should NOT be empty.');
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Add structure to registry
|
||||||
|
_formGroups.add(groupStructure);
|
||||||
|
|
||||||
|
for (int groupIndex = 0; groupIndex < initialCount; groupIndex++) {
|
||||||
|
// Add main group fields/values
|
||||||
|
_addGroupControllers(groupStructure, groupIndex);
|
||||||
|
|
||||||
|
// Add subgroup fields/values
|
||||||
|
if (groupStructure.subGroups != null && groupStructure.subGroups!.isNotEmpty) {
|
||||||
|
for (final (FormGroupStructure subGroup, int subgroupInitialCount) in groupStructure.subGroups!) {
|
||||||
|
for (int subIndex = 0; subIndex < subgroupInitialCount; subIndex++) {
|
||||||
|
final String nestedID = standeredGroupFormat(groupStructure.id, groupIndex, subGroup.id);
|
||||||
|
_addGroupControllers(subGroup, subIndex, parentPrefix: nestedID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// void initializeFormGroup(FormGroupStructure groupStructure, {int initialCount = 1}) {
|
||||||
|
// assert(groupStructure.fields.isNotEmpty, '$groupStructure: Group Fields should NOT be empty.');
|
||||||
|
// if (groupStructure.subGroups != null && groupStructure.subGroups!.isNotEmpty) {
|
||||||
|
// assert(!groupStructure.subGroups!.any(((FormGroupStructure, int) a) => a.$1.fields.isEmpty), '$groupStructure: Subgroup Fields should NOT be empty.');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Add the group.
|
||||||
|
// _formGroups.add(groupStructure);
|
||||||
|
|
||||||
|
// // Add the controllers and values.
|
||||||
|
// for (int groupInstanceIndex = 0; groupInstanceIndex < initialCount; groupInstanceIndex++) {
|
||||||
|
// _addFieldsToGroup(groupStructure.id, groupStructure.fields, groupStructure.values, groupInstanceIndex);
|
||||||
|
|
||||||
|
// // Add subGroup data if non null
|
||||||
|
// if (groupStructure.subGroups != null && groupStructure.subGroups!.isNotEmpty) {
|
||||||
|
// for ((FormGroupStructure, int) subGroupStructure in groupStructure.subGroups!) {
|
||||||
|
// for (int subgroupInstanceIndex = 0; subgroupInstanceIndex < subGroupStructure.$2; subgroupInstanceIndex++) {
|
||||||
|
// _addFieldsToGroup(standeredGroupFormat(groupStructure.id, groupInstanceIndex, subGroupStructure.$1.id), subGroupStructure.$1.fields, subGroupStructure.$1.values, subgroupInstanceIndex);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// String addInstanceToFormGroup(String formGroupID, {bool isSubGroup = false}) {
|
||||||
|
// // Get the group structure with the same ID
|
||||||
|
// FormGroupStructure? structure = _getGroupStructure(formGroupID);
|
||||||
|
// assert(structure != null, 'The ${isSubGroup ? "SUBGroup" : "Group"} $formGroupID doesn\'t seem to be found, are you sure you initialized it?');
|
||||||
|
|
||||||
|
// // 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(),
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // 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}-';
|
||||||
|
// }
|
||||||
|
|
||||||
|
// FormGroupValue getFormGroupValue(String groupID) {
|
||||||
|
// final FormGroupStructure structure = _formGroups.firstWhere(
|
||||||
|
// (FormGroupStructure group) => group.id == groupID,
|
||||||
|
// orElse: () => throw Exception("Group '$groupID' not initialized."),
|
||||||
|
// );
|
||||||
|
|
||||||
|
// final List<FormGroupInstance> instances = <FormGroupInstance>[];
|
||||||
|
|
||||||
|
// for (int index = 0; index < structure.count; index++) {
|
||||||
|
// final Map<String, dynamic> values = {};
|
||||||
|
// final Map<String, TextEditingController> fields = {};
|
||||||
|
|
||||||
|
// // Fields (Text)
|
||||||
|
// for (final fieldID in structure.fields) {
|
||||||
|
// final fullID = standeredGroupFormat(groupID, index, fieldID);
|
||||||
|
// fields[fieldID] = controller(fullID);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Values (Dynamic)
|
||||||
|
// for (final valueID in structure.values ?? []) {
|
||||||
|
// final fullID = standeredGroupFormat(groupID, index, valueID);
|
||||||
|
// values[valueID] = controller(fullID).value;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // SubGroups
|
||||||
|
// final Map<String, FormGroupValue> subGroups = {};
|
||||||
|
|
||||||
|
// if (structure.subGroups != null && structure.subGroups!.isNotEmpty) {
|
||||||
|
// for ((FormGroupStructure subGroup, int subCount) in structure.subGroups!) {
|
||||||
|
// final nestedID = standeredGroupFormat(groupID, index, subGroup.id);
|
||||||
|
|
||||||
|
// final List<FormGroupInstance> subInstances = [];
|
||||||
|
|
||||||
|
// for (int subIndex = 0; subIndex < subCount; subIndex++) {
|
||||||
|
// final Map<String, dynamic> subValues = {};
|
||||||
|
// final Map<String, TextEditingController> subFields = {};
|
||||||
|
|
||||||
|
// for (final fieldID in subGroup.fields) {
|
||||||
|
// final subFullID = standeredGroupFormat(nestedID, subIndex, fieldID);
|
||||||
|
// subFields[fieldID] = controller(subFullID);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for (final valueID in subGroup.values ?? []) {
|
||||||
|
// final subFullID = standeredGroupFormat(nestedID, subIndex, valueID);
|
||||||
|
// subValues[valueID] = controller(subFullID).value;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// subInstances.add(FormGroupInstance(
|
||||||
|
// fields: subFields,
|
||||||
|
// values: subValues,
|
||||||
|
// subGroups: const {}, // deeper nesting unsupported (for now)
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// subGroups[subGroup.id] = FormGroupValue(
|
||||||
|
// groupID: subGroup.id,
|
||||||
|
// instancesCount: subCount,
|
||||||
|
// instances: subInstances,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// instances.add(FormGroupInstance(
|
||||||
|
// fields: fields,
|
||||||
|
// values: values,
|
||||||
|
// subGroups: subGroups,
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return FormGroupValue(
|
||||||
|
// groupID: groupID,
|
||||||
|
// instancesCount: structure.count,
|
||||||
|
// instances: instances,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
int getInstanceCount(String targetGroupID) {
|
||||||
|
// Helper method to check if a controller key matches the target group
|
||||||
|
bool isControllerForGroup(String controllerKey, String groupID) {
|
||||||
|
final RegExp regExp = RegExp(r'^' + RegExp.escape(groupID) + r'-#\d+-');
|
||||||
|
return regExp.hasMatch(controllerKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursive helper function to find instances of a group and its subgroups
|
||||||
|
int countInstancesRecursively(FormGroupStructure groupStructure, List<String> controllersKeys) {
|
||||||
|
// Start with the base count (for the current group itself)
|
||||||
|
int instanceCount = controllersKeys.where((String key) => isControllerForGroup(key, groupStructure.id)).length;
|
||||||
|
|
||||||
|
// Recursively count instances in subgroups
|
||||||
|
if (groupStructure.subGroups != null) {
|
||||||
|
for ((FormGroupStructure, int) subGroup in groupStructure.subGroups!) {
|
||||||
|
instanceCount += countInstancesRecursively(subGroup.$1, controllersKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return instanceCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flatten all controller keys into a list
|
||||||
|
final List<String> controllerKeys = controllers.keys.toList();
|
||||||
|
|
||||||
|
// Find the group structure for the target group
|
||||||
|
final FormGroupStructure? groupStructure = getGroupStructure(targetGroupID);
|
||||||
|
if (groupStructure == null) return 0;
|
||||||
|
|
||||||
|
// Use the recursive function to count instances for the target group
|
||||||
|
return countInstancesRecursively(groupStructure, controllerKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
FormGroupValue? getFormGroupValue(String formGroupID, {bool isSubGroup = false}) {
|
||||||
|
// Get the group structure with the ID
|
||||||
|
FormGroupStructure? groupStructure = getGroupStructure(formGroupID);
|
||||||
|
|
||||||
|
print('Got the structure: $groupStructure');
|
||||||
|
|
||||||
|
// Get the current fields with this ID
|
||||||
|
int instancesCount = getInstanceCount(formGroupID);
|
||||||
|
print('Got the instancesCount: $instancesCount');
|
||||||
|
// 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(),
|
||||||
|
// );
|
||||||
|
|
||||||
|
// print('First set of fields: $firstSetOfFieldsWithID');
|
||||||
|
// 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');
|
||||||
|
|
||||||
|
// get the subGroups
|
||||||
|
List<FormGroupValue> subValues = <FormGroupValue>[];
|
||||||
|
if (groupStructure.subGroups != null && groupStructure.subGroups!.isNotEmpty) {
|
||||||
|
subValues = groupStructure.subGroups!.map(((FormGroupStructure, int) s) => getFormGroupValue(s.$1.id, isSubGroup: true)).nonNulls.toList();
|
||||||
|
}
|
||||||
|
print('subValues: $subValues');
|
||||||
|
|
||||||
|
List<FormGroupInstance> instances = <FormGroupInstance>[];
|
||||||
|
for (int i = 0; i < instancesCount; 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>{},
|
||||||
|
subGroups: subValues,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FormGroupValue groupValue = FormGroupValue(groupID: formGroupID, instancesCount: instancesCount, instances: instances);
|
||||||
|
return groupValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// void 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 (indexToRemove >= 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 (indexToRemove == (firstSetOfFieldsWithID.length - 1)) {
|
||||||
|
// // Remove the last item
|
||||||
|
// for (String fieldID in groupStructure.fields) {
|
||||||
|
// removeController('${groupStructure.id}-#$indexToRemove-$fieldID');
|
||||||
|
// }
|
||||||
|
// if (groupStructure.values != null && groupStructure.values!.isNotEmpty) {
|
||||||
|
// for (String valueID in groupStructure.values!) {
|
||||||
|
// removeController('${groupStructure.id}-#$indexToRemove-$valueID');
|
||||||
|
// _hostedValues.remove('${groupStructure.id}-#$indexToRemove-$valueID');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // Switch and remove
|
||||||
|
// int nextIndex = indexToRemove + 1;
|
||||||
|
// for (String fieldID in groupStructure.fields) {
|
||||||
|
// set('${groupStructure.id}-#$indexToRemove-$fieldID', value('${groupStructure.id}-#$nextIndex-$fieldID'));
|
||||||
|
// removeController('${groupStructure.id}-#$nextIndex-$fieldID');
|
||||||
|
// }
|
||||||
|
// if (groupStructure.values != null && groupStructure.values!.isNotEmpty) {
|
||||||
|
// for (String valueID in groupStructure.values!) {
|
||||||
|
// _hostedValues.remove('${groupStructure.id}-#$indexToRemove-$valueID');
|
||||||
|
// set('${groupStructure.id}-#$indexToRemove-$valueID', value('${groupStructure.id}-#$nextIndex-$valueID'));
|
||||||
|
// setValue('${groupStructure.id}-#$indexToRemove-$valueID', getValue('${groupStructure.id}-#$nextIndex-$valueID'));
|
||||||
|
// removeController('${groupStructure.id}-#$nextIndex-$valueID');
|
||||||
|
// _hostedValues.remove('${groupStructure.id}-#$nextIndex-$valueID');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // Remove last instance
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//!SECTION
|
||||||
|
|
||||||
//SECTION - Helper Methods
|
//SECTION - Helper Methods
|
||||||
|
String standeredGroupFormat(String groupID, int groupIndex, String? fieldID) => '$groupID-#$groupIndex-${fieldID ?? ""}';
|
||||||
|
|
||||||
void _addInitialControllers(Map<String, (String, bool)>? initialValues) {
|
void _addInitialControllers(Map<String, (String, bool)>? initialValues) {
|
||||||
if (initialValues != null) {
|
if (initialValues != null) {
|
||||||
// Add in the initial field states...
|
// Add in the initial field states...
|
||||||
|
|||||||
@@ -105,8 +105,8 @@ class _FormGroupWrapperState extends State<FormGroupWrapper> {
|
|||||||
() {
|
() {
|
||||||
String id = '';
|
String id = '';
|
||||||
setState(() {
|
setState(() {
|
||||||
id = widget.formController.addInstanceToFormGroup(widget.groupID,isSubGroup: widget.isSubGroup);
|
// id = widget.formController.addInstanceToFormGroup(widget.groupID,isSubGroup: widget.isSubGroup);
|
||||||
instances = widget.formController.getFormGroupValue(widget.groupID,isSubGroup: widget.isSubGroup)!.instances;
|
// instances = widget.formController.getFormGroupValue(widget.groupID,isSubGroup: widget.isSubGroup)!.instances;
|
||||||
});
|
});
|
||||||
return id;
|
return id;
|
||||||
},
|
},
|
||||||
@@ -118,8 +118,8 @@ class _FormGroupWrapperState extends State<FormGroupWrapper> {
|
|||||||
|
|
||||||
void _removeItem(int i) {
|
void _removeItem(int i) {
|
||||||
setState(() {
|
setState(() {
|
||||||
widget.formController.removeInstanceFromFormGroup(widget.groupID, i,isSubGroup: widget.isSubGroup);
|
// widget.formController.removeInstanceFromFormGroup(widget.groupID, i,isSubGroup: widget.isSubGroup);
|
||||||
instances = widget.formController.getFormGroupValue(widget.groupID,isSubGroup: widget.isSubGroup)!.instances;
|
// instances = widget.formController.getFormGroupValue(widget.groupID,isSubGroup: widget.isSubGroup)!.instances;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ class FormGroupStructure {
|
|||||||
final String id;
|
final String id;
|
||||||
final List<String> fields;
|
final List<String> fields;
|
||||||
final List<String>? values;
|
final List<String>? values;
|
||||||
final List<FormGroupStructure>? subGroups;
|
final List<(FormGroupStructure structure, int initialCount)>? subGroups;
|
||||||
FormGroupStructure({
|
FormGroupStructure({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.fields,
|
required this.fields,
|
||||||
@@ -18,7 +18,7 @@ class FormGroupStructure {
|
|||||||
String? id,
|
String? id,
|
||||||
List<String>? fields,
|
List<String>? fields,
|
||||||
List<String>? values,
|
List<String>? values,
|
||||||
List<FormGroupStructure>? subGroups,
|
List<(FormGroupStructure structure, int initialCount)>? subGroups,
|
||||||
}) {
|
}) {
|
||||||
return FormGroupStructure(
|
return FormGroupStructure(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
@@ -33,7 +33,7 @@ class FormGroupStructure {
|
|||||||
'id': id,
|
'id': id,
|
||||||
'fields': fields,
|
'fields': fields,
|
||||||
'values': values,
|
'values': values,
|
||||||
'subGroups': subGroups?.map((FormGroupStructure x) => x.toMap()).toList(),
|
'subGroups': subGroups?.map(((FormGroupStructure structure, int initialCount) x) => <String, dynamic>{'structure': x.$1.toMap(), 'initialCount': x.$2}).toList(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +42,9 @@ class FormGroupStructure {
|
|||||||
id: map['id'] as String,
|
id: map['id'] as String,
|
||||||
fields: List<String>.from(map['fields'] as List<String>),
|
fields: List<String>.from(map['fields'] as List<String>),
|
||||||
values: map['values'] != null ? List<String>.from(map['values'] as List<String>) : null,
|
values: map['values'] != null ? List<String>.from(map['values'] as List<String>) : null,
|
||||||
subGroups: map['subGroups'] != null ? (map['subGroups'] as List<Map<String, dynamic>>).map((Map<String, dynamic> f) => FormGroupStructure.fromMap(f)).toList() : null,
|
subGroups: map['subGroups'] != null
|
||||||
|
? (map['subGroups'] as List<Map<String, dynamic>>).map((Map<String, dynamic> map) => (FormGroupStructure.fromMap(map['structure']), int.tryParse(map['initialCount']) ?? 0)).toList()
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,19 +60,12 @@ class FormGroupStructure {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(covariant FormGroupStructure other) {
|
bool operator ==(covariant FormGroupStructure other) {
|
||||||
if (identical(this, other)) return true;
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
return
|
return other.id == id && listEquals(other.fields, fields) && listEquals(other.values, values) && listEquals(other.subGroups, subGroups);
|
||||||
other.id == id &&
|
|
||||||
listEquals(other.fields, fields) &&
|
|
||||||
listEquals(other.values, values) &&
|
|
||||||
listEquals(other.subGroups, subGroups);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
return id.hashCode ^
|
return id.hashCode ^ fields.hashCode ^ values.hashCode ^ subGroups.hashCode;
|
||||||
fields.hashCode ^
|
|
||||||
values.hashCode ^
|
|
||||||
subGroups.hashCode;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user