This commit is contained in:
2025-03-23 15:46:57 +02:00
parent 0a08c573f4
commit e25b3b811e
3 changed files with 153 additions and 30 deletions

View File

@@ -1,4 +1,5 @@
export 'package:form_controller/form_controller.dart'; export 'package:form_controller/form_controller.dart';
export 'src/controller.dart'; export 'src/controller.dart';
export 'src/form_field.dart'; export 'src/form_field.dart';
export 'src/form_value_wrapper.dart';
export 'src/enums/enums.exports.dart'; export 'src/enums/enums.exports.dart';

View File

@@ -1,5 +1,7 @@
//s1 Imports //s1 Imports
//s2 Core Package Imports //s2 Core Package Imports
// ignore_for_file: close_sinks
import 'dart:async'; import 'dart:async';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
@@ -18,13 +20,17 @@ class AstromicFormController extends FormController {
// State Variables // State Variables
final Map<String, AstromicFieldState> fieldStates = <String, AstromicFieldState>{}; final Map<String, AstromicFieldState> fieldStates = <String, AstromicFieldState>{};
final Map<String, String?> fieldMessages = <String, String?>{}; final Map<String, String?> fieldMessages = <String, String?>{};
final Map<String, dynamic> _hostedValues = <String, dynamic>{}; final Map<String, (dynamic, bool)> _hostedValues = <String, (dynamic, bool)>{};
// final Map<String, Map<String, String>>? streamedErrorMaps; // fieldId: {errorCode: errorMessage} // final Map<String, Map<String, String>>? streamedErrorMaps; // fieldId: {errorCode: errorMessage}
final Stream<List<(String internalCode, String? message)>>? errorStream; final Stream<List<(String internalCode, String? message)>>? errorStream;
// State Stream Variables // State Stream Variables
static final StreamController<(String, AstromicFieldState)> _stateStreamController = StreamController<(String id, AstromicFieldState)>.broadcast(); static final StreamController<(String, AstromicFieldState)> _stateStreamController = StreamController<(String id, AstromicFieldState)>.broadcast();
final Stream<(String id, AstromicFieldState)> stateStream = _stateStreamController.stream; 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)>? extraControllers, Map<String, (String initialText, bool initialObscurity)>? extraControllers,
// this.streamedErrorMaps, // this.streamedErrorMaps,
@@ -63,20 +69,32 @@ class AstromicFormController extends FormController {
setState(fieldId, AstromicFieldState.idle); setState(fieldId, AstromicFieldState.idle);
} }
/// Set the value of a hosted state variable using it's ID. bool validateValues(List<String> valueIDs) {
void setValue<T>(String id, T data) { for (String hostedValueID in valueIDs) {
if (_hostedValues.keys.toList().contains(id)) { if (_hostedValues.containsKey(hostedValueID) && _hostedValues[hostedValueID]!.$2 && _hostedValues[hostedValueID]!.$1 == null) {
_hostedValues[id] = data; // Validation Error!
} else { _hostedValueValidationStreamController.add((hostedValueID, true));
_hostedValues.addEntries(<MapEntry<String, dynamic>>[MapEntry<String, dynamic>(id, data)]); return false;
} }
} }
return true;
}
/// Set the value of a hosted state variable using it's ID.
void setValue<T>(String id, T data, {bool isRequired = false}) {
if (_hostedValues.keys.toList().contains(id)) {
_hostedValues[id] = (data, isRequired);
} else {
_hostedValues.addEntries(<MapEntry<String, (dynamic, bool)>>[MapEntry<String, (dynamic, bool)>(id, (data, isRequired))]);
}
_hostedValueValidationStreamController.add((id, false));
}
/// Get the value of a hosted state variable using it's ID. /// Get the value of a hosted state variable using it's ID.
T? getValue<T>(String id) { T? getValue<T>(String id) {
if (_hostedValues.keys.toList().contains(id)) { if (_hostedValues.keys.toList().contains(id)) {
if (_hostedValues[id] is T) { if (_hostedValues[id] is (T?, bool)) {
return _hostedValues[id]; return _hostedValues[id]?.$1;
} else { } else {
throw FlutterError('Value found but is not of the type $T'); throw FlutterError('Value found but is not of the type $T');
} }
@@ -123,24 +141,5 @@ class AstromicFormController extends FormController {
)) ?? )) ??
<MapEntry<String, String?>>{}); <MapEntry<String, String?>>{});
} }
// _handleErrorStream() {
// errorStream!.distinct().listen((List<String> errorCodes) {
// if (streamedErrorMaps != null && streamedErrorMaps!.isNotEmpty) {
// for (String errorMapId in streamedErrorMaps!.keys.toList()) {
// if (super.controllers != null && super.controllers!.containsKey(errorMapId)) {
// if (streamedErrorMaps![errorMapId] != null &&
// streamedErrorMaps![errorMapId]!.isNotEmpty &&
// streamedErrorMaps![errorMapId]!.keys.toList().where((String k) => errorCodes.contains(k)).toList().isNotEmpty) {
// for (String eC in streamedErrorMaps![errorMapId]!.keys.toList().where((String k) => errorCodes.contains(k)).toList()) {
// String? m = streamedErrorMaps![errorMapId]![eC];
// setState(errorMapId, AstromicFieldState.withError, message: m ?? 'Error Message was not set!');
// }
// }
// }
// }
// }
// });
// }
//!SECTION //!SECTION
} }

View File

@@ -0,0 +1,123 @@
//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 FormValueWrapper<T extends Object?> extends StatefulWidget {
//SECTION - Widget Arguments
final AstromicFormController controller;
final String id;
final Widget Function(T? value, bool isErroredForValidation, void Function(T value, bool isRequired) valueSetter) builder;
//!SECTION
//
const FormValueWrapper({
super.key,
required this.controller,
required this.id,
required this.builder,
});
@override
State<FormValueWrapper<T>> createState() => _FormValueWrapperState<T>();
}
class _FormValueWrapperState<T> extends State<FormValueWrapper<T>> {
//
//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 = widget.controller;
//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 StreamBuilder<(String, bool)>(
stream: widget.controller.hostedValueValidationStream,
builder: (BuildContext context, AsyncSnapshot<(String, bool)> validationSnapshot) {
return widget.builder(widget.controller.getValue(widget.id),
validationSnapshot.hasData && validationSnapshot.data != null && validationSnapshot.data!.$1 == widget.id && validationSnapshot.data!.$2 ? true : false, (T newValue, bool isRequired) {
return widget.controller.setValue(widget.id, (newValue, isRequired));
});
});
//!SECTION
}
@override
void dispose() {
//SECTION - Disposable variables
//!SECTION
super.dispose();
}
}