This commit is contained in:
2025-04-01 14:39:38 +02:00
parent 5553ded528
commit 1eb18a8982
4 changed files with 156 additions and 57 deletions

View File

@@ -21,8 +21,8 @@ class AstromicFormController extends FormController {
final Map<String, AstromicFieldState> fieldStates = <String, AstromicFieldState>{};
final Map<String, String?> fieldMessages = <String, String?>{};
final Map<String, (dynamic, bool)> _hostedValues = <String, (dynamic, bool)>{};
// final Map<String, Map<String, String>>? streamedErrorMaps; // fieldId: {errorCode: errorMessage}
final Stream<List<(String internalCode, String? message)>>? errorStream;
// State Stream Variables
static final StreamController<(String, AstromicFieldState)> _stateStreamController = StreamController<(String id, AstromicFieldState)>.broadcast();
final Stream<(String id, AstromicFieldState)> stateStream = _stateStreamController.stream;
@@ -32,35 +32,23 @@ class AstromicFormController extends FormController {
final Stream<(String id, bool isValidationErrored)> hostedValueValidationStream = _hostedValueValidationStreamController.stream;
AstromicFormController({
Map<String, (String initialText, bool initialObscurity)>? extraControllers,
// this.streamedErrorMaps,
Map<String, (String initialText, bool initialObscurity)>? initialValues,
this.errorStream,
}) : super(controllers: extraControllers) {
}) : super(initialValues) {
// Add states and messages based on initial controller.
_addInitialControllers();
_addInitialControllers(initialValues ?? <String, (String, bool)>{});
}
/// Get all the available controllers with their current values
Map<String, String> get allControllers => Map<String, String>.fromEntries(<String, (String?, bool)>{
...?controllers,
...?super.controllers,
}.entries.map((MapEntry<String, (String?, bool)> entry) => MapEntry<String, String>(entry.key, value(entry.key))).toList());
bool hasKey(String id) => allControllers.containsKey(id);
/// 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) {
if (fieldStates.containsKey(fieldId)) {
return (fieldStates[fieldId]!, fieldMessages[fieldId]);
} else {
return null;
}
}
(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 FlutterError('Field ID $fieldId does not exist.');
throw Exception('Field ID $fieldId does not exist.');
}
fieldStates[fieldId] = state;
fieldMessages[fieldId] = message;
@@ -68,10 +56,9 @@ class AstromicFormController extends FormController {
}
/// Reset the state of a specific field using it's ID.
resetState(String fieldId) {
setState(fieldId, AstromicFieldState.idle);
}
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) {
@@ -90,13 +77,6 @@ class AstromicFormController extends FormController {
}
}
/// 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));
}
/// Get the value of a hosted state variable using it's ID.
T? getValue<T>(String id) {
prepareValue(id, false);
@@ -104,48 +84,46 @@ class AstromicFormController extends FormController {
if (_hostedValues[id]?.$1 is T?) {
return _hostedValues[id]?.$1;
} else {
throw FlutterError('Value found but is not of the type $T, it\'s of type ${_hostedValues[id]?.$1.runtimeType}');
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
TextEditingController controller(String id, {String? initialText, bool isObscure = false}) {
if (super.controllers == null || !super.controllers!.keys.toList().contains(id)) {
TextEditingController ret = super.controller(id, initialText: initialText, isObscure: isObscure);
//
if (!hasKey(id)) {
fieldStates.addEntries(<MapEntry<String, AstromicFieldState>>[MapEntry<String, AstromicFieldState>(id, AstromicFieldState.idle)]);
fieldMessages.addEntries(<MapEntry<String, String?>>[MapEntry<String, String?>(id, null)]);
}
TextEditingController ret = super.controller(id, initialText: initialText, isObscure: isObscure);
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
if (ret.text.isEmpty) {
ret.text = initialText ?? '';
}
});
super.controllers?.addEntries(<MapEntry<String, (String, bool)>>[MapEntry<String, (String, bool)>(id, (ret.text, isObscure))]);
return ret;
}
@override
Future<void> dispose() async {
// _stateStreamController.close();
super.dispose();
}
//SECTION - Helper Methods
_addInitialControllers() {
_addInitialControllers(Map<String, (String, bool)> initialValues) {
// Add in the initial field states...
fieldStates.addEntries(super.controllers?.entries.toList().map((MapEntry<String, (String, bool)> e) => MapEntry<String, AstromicFieldState>(
e.key, // controller ID
AstromicFieldState.idle, // Initial state of any new controller is Idle
)) ??
<MapEntry<String, AstromicFieldState>>{});
fieldStates.addEntries(initialValues.entries.toList().map((MapEntry<String, (String, bool)> e) => MapEntry<String, AstromicFieldState>(
e.key, // controller ID
AstromicFieldState.idle, // Initial state of any new controller is Idle
)));
// Add in the initial field messages...
fieldMessages.addEntries(super.controllers?.entries.toList().map((MapEntry<String, (String, bool)> e) => MapEntry<String, String?>(
e.key, // Controller ID
null, // The initial message it has which is Null
)) ??
<MapEntry<String, String?>>{});
fieldMessages.addEntries(initialValues.entries.toList().map((MapEntry<String, (String, bool)> e) => MapEntry<String, String?>(
e.key, // Controller ID
null, // The initial message it has which is Null
)));
}
//!SECTION
}

View File

@@ -0,0 +1,117 @@
// //s1 Imports
// //s2 Packages
// //s3 Core Packages
// import 'package:flutter/material.dart';
// import '../../sheet/sheet_helper.astromic.dart';
// //s3 Internal Packages
// //s3 3rd-party Packages
// //s2 Utility
// //s3 Configs
// //s3 Misc
// //s2 Domain
// //s3 Entities
// //s3 Usecases
// //s2 Presentation
// //s3 Design
// //s3 Presenters
// //s3 Widgets
// //s1 Exports
// class FormGroupWrapper extends StatefulWidget {
// //SECTION - Widget Arguments
// final AstromicFormController formController;
// final String identifier;
// //!SECTION
// //
// const FormGroupWrapper({
// super.key,
// required this.formController,
// required this
// });
// @override
// State<FormGroupWrapper> createState() => _FormGroupWrapperState();
// }
// class _FormGroupWrapperState extends State<FormGroupWrapper> {
// //
// //SECTION - State Variables
// //s1 --State
// //s1 --State
// //
// //s1 --Controllers
// //late AstromicFormController _formController;
// //s1 --Controllers
// //
// //s1 --Constants
// //s1 --Constants
// //!SECTION
// @override
// void initState() {
// super.initState();
// //
// //SECTION - State Variables initializations & Listeners
// //s1 --State
// //s1 --State
// //
// //s1 --Controllers & Listeners
// // _formController = AstromicFormController();
// //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 const Scaffold(
// body: Center(child:Text(FormGroupWrapper)),
// );
// //!SECTION
// }
// @override
// void dispose() {
// //SECTION - Disposable variables
// //!SECTION
// super.dispose();
// }
// }