From 898073bc5e4e8783a5d5bf8e3f5ea57adeb8289f Mon Sep 17 00:00:00 2001 From: Michael Aziz Date: Wed, 28 May 2025 11:52:01 +0300 Subject: [PATCH] [SYNC] Doing the initial Values thing. --- lib/src/form/src/controller.dart | 152 +++++++++++++----- .../src/helpers/controller_states.helper.dart | 16 -- .../src/helpers/controller_values.helper.dart | 0 ...ups.helper.dart => form_group_helper.dart} | 0 .../models/form_group_structure.model.dart | 21 +-- .../initial_form_group_values.model.dart | 80 +++++++++ .../form/src/models/initial_values.model.dart | 78 +++++++++ 7 files changed, 274 insertions(+), 73 deletions(-) delete mode 100644 lib/src/form/src/helpers/controller_states.helper.dart delete mode 100644 lib/src/form/src/helpers/controller_values.helper.dart rename lib/src/form/src/helpers/{controller_groups.helper.dart => form_group_helper.dart} (100%) create mode 100644 lib/src/form/src/models/initial_form_group_values.model.dart create mode 100644 lib/src/form/src/models/initial_values.model.dart diff --git a/lib/src/form/src/controller.dart b/lib/src/form/src/controller.dart index 0c45c73..e4ceb19 100644 --- a/lib/src/form/src/controller.dart +++ b/lib/src/form/src/controller.dart @@ -15,20 +15,43 @@ import 'enums/enums.exports.dart'; import 'models/form_group_instance.model.dart'; import 'models/form_group_structure.model.dart'; import 'models/form_group_value.model.dart'; +import 'models/initial_form_group_values.model.dart'; +import 'models/initial_values.model.dart'; //s1 Exports -part './helpers/controller_states.helper.dart'; - /// A specialized form controller to handle form states, class AstromicFormController extends FormController { AstromicFormController({ - Map? initialValues, - Map? initialHostedValues, + AstromicFormInitialValues? initialValues, this.errorStream, - }) : super(initialValues) { - // Add states and messages based on initial controllers. - _addInitialControllers(initialValues); - _addInitialHostedValues(initialHostedValues); + }) : super(null) { + if (initialValues != null) { + // Take in the initials and proceed to fill: + //1. Field Values + if (initialValues.fieldValues != null && initialValues.fieldValues!.isNotEmpty) { + for (MapEntry fieldValueEntry in initialValues.fieldValues!.entries) { + String k = fieldValueEntry.key; + String v = fieldValueEntry.value ?? ''; + bool isObs = initialValues.fieldObscurityValues != null && initialValues.fieldObscurityValues!.containsKey(k) && initialValues.fieldObscurityValues![k]!; + // + controller(k, initialText: v, isObscure: isObs); + } + } + //2. Hosted Values + if (initialValues.hostedValues != null && initialValues.hostedValues!.isNotEmpty) { + for (MapEntry hostedValueEntry in initialValues.hostedValues!.entries) { + String k = hostedValueEntry.key; + dynamic v = hostedValueEntry.value.$1; + dynamic isReq = hostedValueEntry.value.$2; + // + setValue(k, v, isRequired: isReq); + } + } + //3. Form Group Values + if (initialValues.groupValues != null && initialValues.groupValues!.isNotEmpty) { + _initializeFormGroups(initialValues.groupValues!); + } + } } //SECTION - Overrides @@ -74,12 +97,26 @@ class AstromicFormController extends FormController { final Stream>? errorStream; //S1 - Methods - + /// 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 _hostedValues = {}; + final Map _hostedValues = {}; //S1 - Streams static final StreamController<(String, bool)> _hostedValueValidationStreamController = StreamController<(String id, bool)>.broadcast(); @@ -140,6 +177,7 @@ class AstromicFormController extends FormController { //S1 - State Variables final List _formGroups = []; //S1 - Methods + /// Does the controller has a field group with this ID. bool hasFieldGroup(String formGroupID) => getGroupStructure(formGroupID) != null; @@ -245,21 +283,12 @@ class AstromicFormController extends FormController { for (final String fieldID in structure.fields) { final String fullID = standeredGroupFormat(baseID, index.toString(), fieldID); - String? preFilled; - if (structure.preFields?.containsKey(fieldID) ?? false) { - preFilled = structure.preFields![fieldID]; - } - controller(fullID, initialText: preFilled); + controller(fullID); } for (final String valueID in structure.values ?? []) { final String fullID = standeredGroupFormat(baseID, index.toString(), valueID); - (String, dynamic)? preFilled; - if (structure.preValues?.containsKey(valueID) ?? false) { - preFilled = structure.preValues![valueID]; - } - controller(fullID, initialText: preFilled?.$1); - setValue(valueID, preFilled?.$2); + controller(fullID); } } @@ -533,26 +562,71 @@ class AstromicFormController extends FormController { //SECTION - Helper Methods String standeredGroupFormat(String groupID, String groupIndex, String? secondaryID) => '$groupID-#$groupIndex${secondaryID == null ? "" : "-$secondaryID"}'; - void _addInitialControllers(Map? initialValues) { - if (initialValues != null) { - // Add in the initial field states... - fieldStates.addEntries(initialValues.entries.map((MapEntry e) => MapEntry( - e.key, // controller ID - AstromicFieldState.idle, // Initial state of any new controller is Idle - ))); + // void _addInitialControllers(Map? initialValues) { + // if (initialValues != null) { + // // Add in the initial field states... + // fieldStates.addEntries(initialValues.entries.map((MapEntry e) => MapEntry( + // e.key, // controller ID + // AstromicFieldState.idle, // Initial state of any new controller is Idle + // ))); - // Add in the initial field messages... - fieldMessages.addEntries(initialValues.entries.toList().map((MapEntry e) => MapEntry( - e.key, // Controller ID - null, // The initial message it has which is Null - ))); - } - } + // // Add in the initial field messages... + // fieldMessages.addEntries(initialValues.entries.toList().map((MapEntry e) => MapEntry( + // e.key, // Controller ID + // null, // The initial message it has which is Null + // ))); + // } + // } - void _addInitialHostedValues(Map? initialValues) { - if (initialValues != null) { - for (MapEntry vEntry in initialValues.entries) { - setValue(vEntry.key, vEntry.value.$1, isRequired: vEntry.value.$2); + // void _addInitialHostedValues(Map? initialValues) { + // if (initialValues != null) { + // for (MapEntry vEntry in initialValues.entries) { + // setValue(vEntry.key, vEntry.value.$1, isRequired: vEntry.value.$2); + // } + // } + // } + _initializeFormGroups(Map initVals, {Map? parents}) { + for (MapEntry groupValueEntry in initVals.entries) { + String groupID = groupValueEntry.key; + InitialFormGroupValue groupValue = groupValueEntry.value; + + for (int i = 0; i < groupValue.instancesCount; i++) { + int currentGroupIndex = i; + // Check for the subgroups + if (groupValueEntry.value.subGroups != null && groupValueEntry.value.subGroups!.isNotEmpty) { + // There are subgroups. + _initializeFormGroups(groupValueEntry.value.subGroups!, parents: {...?parents, groupID: currentGroupIndex}); + } + + String? prefix = parents?.entries.map((MapEntry parentEntry) => standeredGroupFormat(parentEntry.key, parentEntry.value.toString(), null)).join('-'); + + // Fields + if (groupValue.fieldValues != null) { + for (MapEntry> fve in groupValue.fieldValues!.entries) { + assert(fve.value.length == groupValue.instancesCount, 'Your supplied list of `${fve.key}` is not `${groupValue.instancesCount}` as stated..'); + if (groupValue.fieldObscurityValues != null) { + assert(groupValue.fieldObscurityValues!.length == groupValue.instancesCount, 'Your supplied obscurity list of `${fve.key}` is not `${groupValue.instancesCount}` as stated..'); + } + String fieldKey = fve.key; + String fID = standeredGroupFormat((prefix != null ? '$prefix-' : '') + groupID, i.toString(), fieldKey); + String? fieldValue = fve.value[i] ?? ''; + bool obscValue = groupValue.fieldObscurityValues?[fieldKey]?[i] ?? false; + controller(fID, initialText: fieldValue, isObscure: obscValue); + } + } + + // Values + if (groupValue.hostedValues != null) { + for (MapEntry> hve in groupValue.hostedValues!.entries) { + assert(hve.value.length == groupValue.instancesCount, 'Your supplied list of `${hve.key}` is not `${groupValue.instancesCount}` as stated..'); + String fieldKey = hve.key; + String fID = standeredGroupFormat((prefix != null ? '$prefix-' : '') + groupID, i.toString(), fieldKey); + dynamic fieldValue = hve.value[i].$1; + bool isReq = hve.value[i].$2; + + setValue(fID, fieldValue, isRequired: isReq); + } + } } } } diff --git a/lib/src/form/src/helpers/controller_states.helper.dart b/lib/src/form/src/helpers/controller_states.helper.dart deleted file mode 100644 index 79f017b..0000000 --- a/lib/src/form/src/helpers/controller_states.helper.dart +++ /dev/null @@ -1,16 +0,0 @@ -part of '../controller.dart'; -/// 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); \ No newline at end of file diff --git a/lib/src/form/src/helpers/controller_values.helper.dart b/lib/src/form/src/helpers/controller_values.helper.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/src/form/src/helpers/controller_groups.helper.dart b/lib/src/form/src/helpers/form_group_helper.dart similarity index 100% rename from lib/src/form/src/helpers/controller_groups.helper.dart rename to lib/src/form/src/helpers/form_group_helper.dart diff --git a/lib/src/form/src/models/form_group_structure.model.dart b/lib/src/form/src/models/form_group_structure.model.dart index 22b6604..7d89e84 100644 --- a/lib/src/form/src/models/form_group_structure.model.dart +++ b/lib/src/form/src/models/form_group_structure.model.dart @@ -5,16 +5,12 @@ import 'package:flutter/foundation.dart'; class FormGroupStructure { final String id; final List fields; - final Map? preFields; final List? values; - final Map? preValues; final List<(int initialCount, FormGroupStructure structure)>? subGroups; FormGroupStructure({ required this.id, required this.fields, this.values, - this.preFields, - this.preValues, this.subGroups, }); @@ -30,8 +26,6 @@ class FormGroupStructure { id: id ?? this.id, fields: fields ?? this.fields, values: values ?? this.values, - preFields: preFields ?? this.preFields, - preValues: preValues ?? this.preValues, subGroups: subGroups ?? this.subGroups, ); } @@ -41,8 +35,6 @@ class FormGroupStructure { 'id': id, 'fields': fields, 'values': values, - 'preFields': preFields, - 'preValues': preValues, 'subGroups': subGroups?.map(((int initialCount, FormGroupStructure structure) x) => {'structure': x.$2.toMap(), 'initialCount': x.$1}).toList(), }; } @@ -52,8 +44,6 @@ class FormGroupStructure { id: map['id'] as String, fields: List.from(map['fields'] as List), values: map['values'] != null ? List.from(map['values'] as List) : null, - preFields: map['preFields'] != null ? map['preFields'] as Map : null, - preValues: map['preValues'] != null ? map['preValues'] as Map: null, subGroups: map['subGroups'] != null ? (map['subGroups'] as List>).map((Map map) => (int.tryParse(map['initialCount']) ?? 0, FormGroupStructure.fromMap(map['structure']))).toList() : null, @@ -66,23 +56,18 @@ class FormGroupStructure { @override String toString() { - return 'FormGroupStructure(id: $id, fields: $fields, values: $values, preFields: $preFields, preValues: $preValues, subGroups: $subGroups)'; + return 'FormGroupStructure(id: $id, fields: $fields, values: $values, subGroups: $subGroups)'; } @override bool operator ==(covariant FormGroupStructure other) { if (identical(this, other)) return true; - return other.id == id && - listEquals(other.fields, fields) && - listEquals(other.values, values) && - mapEquals(other.preFields, preFields) && - mapEquals(other.preValues, preValues) && - listEquals(other.subGroups, subGroups); + return other.id == id && listEquals(other.fields, fields) && listEquals(other.values, values) && listEquals(other.subGroups, subGroups); } @override int get hashCode { - return id.hashCode ^ fields.hashCode ^ values.hashCode ^ preFields.hashCode ^ preValues.hashCode ^ subGroups.hashCode; + return id.hashCode ^ fields.hashCode ^ values.hashCode ^ subGroups.hashCode; } } diff --git a/lib/src/form/src/models/initial_form_group_values.model.dart b/lib/src/form/src/models/initial_form_group_values.model.dart new file mode 100644 index 0000000..0d8fd76 --- /dev/null +++ b/lib/src/form/src/models/initial_form_group_values.model.dart @@ -0,0 +1,80 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; + +class InitialFormGroupValue { + final int instancesCount; + final Map>? fieldValues; + final Map>? fieldObscurityValues; + final Map>? hostedValues; + final Map? subGroups; + InitialFormGroupValue({ + required this.instancesCount, + this.fieldValues, + this.fieldObscurityValues, + this.hostedValues, + this.subGroups, + }); + + InitialFormGroupValue copyWith({ + int? instancesCount, + Map>? fieldValues, + Map>? fieldObscurityValues, + Map>? hostedValues, + Map? subGroups, + }) { + return InitialFormGroupValue( + instancesCount: instancesCount ?? this.instancesCount, + fieldValues: fieldValues ?? this.fieldValues, + fieldObscurityValues: fieldObscurityValues ?? this.fieldObscurityValues, + hostedValues: hostedValues ?? this.hostedValues, + subGroups: subGroups ?? this.subGroups, + ); + } + + Map toMap() { + return { + 'instancesCount': instancesCount, + 'fieldValues': fieldValues, + 'fieldObscurityValues': fieldObscurityValues, + 'hostedValues': hostedValues, + 'subGroups': subGroups, + }; + } + + factory InitialFormGroupValue.fromMap(Map map) { + return InitialFormGroupValue( + instancesCount: map['instancesCount'] as int, + fieldValues: map['fieldValues'] != null ? Map>.from(map['fieldValues'] as Map>) : null, + fieldObscurityValues: map['fieldObscurityValues'] != null ? Map>.from(map['fieldObscurityValues'] as Map>) : null, + hostedValues: map['hostedValues'] != null ? Map>.from(map['hostedValues'] as Map>) : null, + subGroups: map['subGroups'] != null ? Map.from(map['subGroups'] as Map) : null, + ); + } + + String toJson() => json.encode(toMap()); + + factory InitialFormGroupValue.fromJson(String source) => InitialFormGroupValue.fromMap(json.decode(source) as Map); + + @override + String toString() { + return 'InitialFormGroupValue(instancesCount: $instancesCount, fieldValues: $fieldValues, fieldObscurityValues: $fieldObscurityValues, hostedValues: $hostedValues, subGroups: $subGroups)'; + } + + @override + bool operator ==(covariant InitialFormGroupValue other) { + if (identical(this, other)) return true; + + return other.instancesCount == instancesCount && + mapEquals(other.fieldValues, fieldValues) && + mapEquals(other.fieldObscurityValues, fieldObscurityValues) && + mapEquals(other.hostedValues, hostedValues) && + mapEquals(other.subGroups, subGroups); + } + + @override + int get hashCode { + return instancesCount.hashCode ^ fieldValues.hashCode ^ fieldObscurityValues.hashCode ^ hostedValues.hashCode ^ subGroups.hashCode; + } +} diff --git a/lib/src/form/src/models/initial_values.model.dart b/lib/src/form/src/models/initial_values.model.dart new file mode 100644 index 0000000..b5f5498 --- /dev/null +++ b/lib/src/form/src/models/initial_values.model.dart @@ -0,0 +1,78 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; + +import 'initial_form_group_values.model.dart'; + +class AstromicFormInitialValues { + // Field Values + final Map? fieldValues; + final Map? fieldObscurityValues; + // Hosted Values + final Map? hostedValues; + // Form Groups + final Map? groupValues; + AstromicFormInitialValues({ + this.fieldValues, + this.fieldObscurityValues, + this.hostedValues, + this.groupValues, + }); + + AstromicFormInitialValues copyWith({ + Map? fieldValues, + Map? fieldObscurityValues, + Map? hostedValues, + Map? groupValues, + }) { + return AstromicFormInitialValues( + fieldValues: fieldValues ?? this.fieldValues, + fieldObscurityValues: fieldObscurityValues ?? this.fieldObscurityValues, + hostedValues: hostedValues ?? this.hostedValues, + groupValues: groupValues ?? this.groupValues, + ); + } + + Map toMap() { + return { + 'fieldValues': fieldValues, + 'fieldObscurityValues': fieldObscurityValues, + 'hostedValues': hostedValues, + 'groupValues': groupValues, + }; + } + + factory AstromicFormInitialValues.fromMap(Map map) { + return AstromicFormInitialValues( + fieldValues: map['fieldValues'] != null ? Map.from(map['fieldValues'] as Map) : null, + fieldObscurityValues: map['fieldObscurityValues'] != null ? Map.from(map['fieldObscurityValues'] as Map) : null, + hostedValues: map['hostedValues'] != null ? Map.from(map['hostedValues'] as Map) : null, + groupValues: map['groupValues'] != null ? Map.from(map['groupValues'] as Map) : null, + ); + } + + String toJson() => json.encode(toMap()); + + factory AstromicFormInitialValues.fromJson(String source) => AstromicFormInitialValues.fromMap(json.decode(source) as Map); + + @override + String toString() { + return 'AstromicFormInitialValues(fieldValues: $fieldValues, fieldObscurityValues: $fieldObscurityValues, hostedValues: $hostedValues, groupValues: $groupValues)'; + } + + @override + bool operator ==(covariant AstromicFormInitialValues other) { + if (identical(this, other)) return true; + + return mapEquals(other.fieldValues, fieldValues) && + mapEquals(other.fieldObscurityValues, fieldObscurityValues) && + mapEquals(other.hostedValues, hostedValues) && + mapEquals(other.groupValues, groupValues); + } + + @override + int get hashCode { + return fieldValues.hashCode ^ fieldObscurityValues.hashCode ^ hostedValues.hashCode ^ groupValues.hashCode; + } +}