Merge branch 'master' of https://git.micazi.dev/micazi/astromic_helpers
This commit is contained in:
@@ -21,10 +21,12 @@ import 'models/form_group_value.model.dart';
|
|||||||
class AstromicFormController extends FormController {
|
class AstromicFormController extends FormController {
|
||||||
AstromicFormController({
|
AstromicFormController({
|
||||||
Map<String, (String initialText, bool initialObscurity)>? initialValues,
|
Map<String, (String initialText, bool initialObscurity)>? initialValues,
|
||||||
|
Map<String, (dynamic, bool)>? initialHostedValues,
|
||||||
this.errorStream,
|
this.errorStream,
|
||||||
}) : super(initialValues) {
|
}) : super(initialValues) {
|
||||||
// Add states and messages based on initial controller.
|
// Add states and messages based on initial controllers.
|
||||||
_addInitialControllers(initialValues);
|
_addInitialControllers(initialValues);
|
||||||
|
_addInitialHostedValues(initialHostedValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
//SECTION - Overrides
|
//SECTION - Overrides
|
||||||
@@ -254,12 +256,21 @@ class AstromicFormController extends FormController {
|
|||||||
|
|
||||||
for (final String fieldID in structure.fields) {
|
for (final String fieldID in structure.fields) {
|
||||||
final String fullID = standeredGroupFormat(baseID, index.toString(), fieldID);
|
final String fullID = standeredGroupFormat(baseID, index.toString(), fieldID);
|
||||||
controller(fullID);
|
String? preFilled;
|
||||||
|
if (structure.preFields?.containsKey(fieldID) ?? false) {
|
||||||
|
preFilled = structure.preFields![fieldID];
|
||||||
|
}
|
||||||
|
controller(fullID, initialText: preFilled);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final String valueID in structure.values ?? <String>[]) {
|
for (final String valueID in structure.values ?? <String>[]) {
|
||||||
final String fullID = standeredGroupFormat(baseID, index.toString(), valueID);
|
final String fullID = standeredGroupFormat(baseID, index.toString(), valueID);
|
||||||
controller(fullID);
|
(String, dynamic)? preFilled;
|
||||||
|
if (structure.preValues?.containsKey(valueID) ?? false) {
|
||||||
|
preFilled = structure.preValues![valueID];
|
||||||
|
}
|
||||||
|
controller(fullID, initialText: preFilled?.$1);
|
||||||
|
setValue(valueID, preFilled?.$2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,5 +559,13 @@ class AstromicFormController extends FormController {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _addInitialHostedValues(Map<String, (dynamic, bool)>? initialValues) {
|
||||||
|
if (initialValues != null) {
|
||||||
|
for (MapEntry<String, (dynamic, bool)> vEntry in initialValues.entries) {
|
||||||
|
setValue(vEntry.key, vEntry.value.$1, isRequired: vEntry.value.$2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
//!SECTION
|
//!SECTION
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,25 +5,33 @@ import 'package:flutter/foundation.dart';
|
|||||||
class FormGroupStructure {
|
class FormGroupStructure {
|
||||||
final String id;
|
final String id;
|
||||||
final List<String> fields;
|
final List<String> fields;
|
||||||
|
final Map<String, String>? preFields;
|
||||||
final List<String>? values;
|
final List<String>? values;
|
||||||
|
final Map<String, (String, dynamic)>? preValues;
|
||||||
final List<(int initialCount, FormGroupStructure structure)>? subGroups;
|
final List<(int initialCount, FormGroupStructure structure)>? subGroups;
|
||||||
FormGroupStructure({
|
FormGroupStructure({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.fields,
|
required this.fields,
|
||||||
this.values,
|
this.values,
|
||||||
|
this.preFields,
|
||||||
|
this.preValues,
|
||||||
this.subGroups,
|
this.subGroups,
|
||||||
});
|
});
|
||||||
|
|
||||||
FormGroupStructure copyWith({
|
FormGroupStructure copyWith({
|
||||||
String? id,
|
String? id,
|
||||||
List<String>? fields,
|
List<String>? fields,
|
||||||
|
Map<String, String>? preFields,
|
||||||
List<String>? values,
|
List<String>? values,
|
||||||
|
Map<String, (String, dynamic)>? preValues,
|
||||||
List<(int initialCount, FormGroupStructure structure)>? subGroups,
|
List<(int initialCount, FormGroupStructure structure)>? subGroups,
|
||||||
}) {
|
}) {
|
||||||
return FormGroupStructure(
|
return FormGroupStructure(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
fields: fields ?? this.fields,
|
fields: fields ?? this.fields,
|
||||||
values: values ?? this.values,
|
values: values ?? this.values,
|
||||||
|
preFields: preFields ?? this.preFields,
|
||||||
|
preValues: preValues ?? this.preValues,
|
||||||
subGroups: subGroups ?? this.subGroups,
|
subGroups: subGroups ?? this.subGroups,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -33,6 +41,8 @@ class FormGroupStructure {
|
|||||||
'id': id,
|
'id': id,
|
||||||
'fields': fields,
|
'fields': fields,
|
||||||
'values': values,
|
'values': values,
|
||||||
|
'preFields': preFields,
|
||||||
|
'preValues': preValues,
|
||||||
'subGroups': subGroups?.map(((int initialCount, FormGroupStructure structure) x) => <String, dynamic>{'structure': x.$2.toMap(), 'initialCount': x.$1}).toList(),
|
'subGroups': subGroups?.map(((int initialCount, FormGroupStructure structure) x) => <String, dynamic>{'structure': x.$2.toMap(), 'initialCount': x.$1}).toList(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -42,6 +52,8 @@ 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,
|
||||||
|
preFields: map['preFields'] != null ? map['preFields'] as Map<String,String> : null,
|
||||||
|
preValues: map['preValues'] != null ? map['preValues'] as Map<String,(String,dynamic)>: null,
|
||||||
subGroups: map['subGroups'] != null
|
subGroups: map['subGroups'] != null
|
||||||
? (map['subGroups'] as List<Map<String, dynamic>>).map((Map<String, dynamic> map) => (int.tryParse(map['initialCount']) ?? 0, FormGroupStructure.fromMap(map['structure']))).toList()
|
? (map['subGroups'] as List<Map<String, dynamic>>).map((Map<String, dynamic> map) => (int.tryParse(map['initialCount']) ?? 0, FormGroupStructure.fromMap(map['structure']))).toList()
|
||||||
: null,
|
: null,
|
||||||
@@ -54,18 +66,23 @@ class FormGroupStructure {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'FormGroupStructure(id: $id, fields: $fields, values: $values, subGroups: $subGroups)';
|
return 'FormGroupStructure(id: $id, fields: $fields, values: $values, preFields: $preFields, preValues: $preValues, subGroups: $subGroups)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@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 other.id == id && listEquals(other.fields, fields) && listEquals(other.values, values) && listEquals(other.subGroups, subGroups);
|
return other.id == id &&
|
||||||
|
listEquals(other.fields, fields) &&
|
||||||
|
listEquals(other.values, values) &&
|
||||||
|
mapEquals(other.preFields, preFields) &&
|
||||||
|
mapEquals(other.preValues, preValues) &&
|
||||||
|
listEquals(other.subGroups, subGroups);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
return id.hashCode ^ fields.hashCode ^ values.hashCode ^ subGroups.hashCode;
|
return id.hashCode ^ fields.hashCode ^ values.hashCode ^ preFields.hashCode ^ preValues.hashCode ^ subGroups.hashCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class AstromicFuturePresenter<T> extends StatefulWidget {
|
|||||||
//SECTION - Widget Arguments
|
//SECTION - Widget Arguments
|
||||||
final AstromicPresenterController controller;
|
final AstromicPresenterController controller;
|
||||||
final String id;
|
final String id;
|
||||||
|
final Map<String,dynamic>? neededArguments;
|
||||||
//
|
//
|
||||||
final Map<AstromicPresenterState, Widget Function(PresenterReturnModel<T?>? r)> stateBuilder;
|
final Map<AstromicPresenterState, Widget Function(PresenterReturnModel<T?>? r)> stateBuilder;
|
||||||
final AstromicPresenterConfiguration? configuration;
|
final AstromicPresenterConfiguration? configuration;
|
||||||
@@ -32,6 +33,8 @@ class AstromicFuturePresenter<T> extends StatefulWidget {
|
|||||||
required this.id,
|
required this.id,
|
||||||
required this.stateBuilder,
|
required this.stateBuilder,
|
||||||
this.configuration,
|
this.configuration,
|
||||||
|
this.neededArguments,
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -62,8 +65,8 @@ class _AstromicFuturePresenterState<T> extends State<AstromicFuturePresenter<T>>
|
|||||||
//s1 --State
|
//s1 --State
|
||||||
//
|
//
|
||||||
//s1 --Controllers & Listeners
|
//s1 --Controllers & Listeners
|
||||||
widget.controller.getRefreshStream(widget.id).listen((_) {
|
widget.controller.getRefreshStream(widget.id).listen((uA) {
|
||||||
_refreshFuture(); // Force future recreation on refresh
|
_refreshFuture(updatedArgs: uA); // Force future recreation on refresh
|
||||||
});
|
});
|
||||||
//s1 --Controllers & Listeners
|
//s1 --Controllers & Listeners
|
||||||
//
|
//
|
||||||
@@ -120,16 +123,17 @@ class _AstromicFuturePresenterState<T> extends State<AstromicFuturePresenter<T>>
|
|||||||
}
|
}
|
||||||
|
|
||||||
//S1 -- Method to reinitialize or update `_future` with a new instance
|
//S1 -- Method to reinitialize or update `_future` with a new instance
|
||||||
void _refreshFuture() {
|
void _refreshFuture({Map<String,dynamic>? updatedArgs}) {
|
||||||
// Increment the refresh key to ensure a unique future instance
|
// Increment the refresh key to ensure a unique future instance
|
||||||
_refreshKey++;
|
_refreshKey++;
|
||||||
setState(() {
|
setState(() {
|
||||||
_initializeFuture();
|
_initializeFuture(updatedArgs: updatedArgs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//S1 -- Method to reinitialize or update `_future` with a new instance
|
//S1 -- Method to reinitialize or update `_future` with a new instance
|
||||||
void _initializeFuture() {
|
void _initializeFuture({Map<String,dynamic>? updatedArgs}) {
|
||||||
|
widget.controller.setProvidedArguments(updatedArgs ?? widget.neededArguments ?? <String,dynamic>{});
|
||||||
_future = widget.controller.getFuture(widget.id)?.then((dynamic result) => result as T?);
|
_future = widget.controller.getFuture(widget.id)?.then((dynamic result) => result as T?);
|
||||||
}
|
}
|
||||||
//!SECTION
|
//!SECTION
|
||||||
|
|||||||
@@ -3,17 +3,17 @@ import 'dart:async';
|
|||||||
|
|
||||||
/// A contrller used to control Futures/Streams to present them effeciantly.
|
/// A contrller used to control Futures/Streams to present them effeciantly.
|
||||||
class AstromicPresenterController {
|
class AstromicPresenterController {
|
||||||
late final Map<String, (Future Function()? fetch, int c)> _futures;
|
late final Map<String, (Future Function(Map<String, dynamic> args)? fetch, int c)> _futures;
|
||||||
late final Map<String, Stream Function(Map<String, dynamic> args)?> _streams;
|
late final Map<String, Stream Function(Map<String, dynamic> args)?> _streams;
|
||||||
late final Map<String, StreamController<void>> _futureRefreshers;
|
late final Map<String, StreamController<Map<String,dynamic>?>> _futureRefreshers;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AstromicPresenterController({
|
AstromicPresenterController({
|
||||||
Map<String, (Future Function()? fetch, int startCycle)> futures = const {},
|
Map<String, (Future Function(Map<String, dynamic> args)? fetch, int startCycle)> futures = const {},
|
||||||
Map<String, Stream Function(Map<String, dynamic> args)?> streams = const {},
|
Map<String, Stream Function(Map<String, dynamic> args)?> streams = const {},
|
||||||
}) : _futures = futures.map((k, v) => MapEntry(k, (v.$1, v.$2))),
|
}) : _futures = futures.map((k, v) => MapEntry(k, (v.$1, v.$2))),
|
||||||
_futureRefreshers = futures.map((k, v) => MapEntry(k, StreamController<void>.broadcast())),
|
_futureRefreshers = futures.map((k, v) => MapEntry(k, StreamController<Map<String,dynamic>?>.broadcast())),
|
||||||
_streams = streams;
|
_streams = streams;
|
||||||
|
|
||||||
Map<String,dynamic> providedArguments = {};
|
Map<String,dynamic> providedArguments = {};
|
||||||
@@ -35,7 +35,7 @@ class AstromicPresenterController {
|
|||||||
Future<T?>? getFuture<T>(String id) {
|
Future<T?>? getFuture<T>(String id) {
|
||||||
assert(_futures.containsKey(id), 'did you add a future with this id?');
|
assert(_futures.containsKey(id), 'did you add a future with this id?');
|
||||||
|
|
||||||
return _futures[id]!.$1!() as Future<T?>?;
|
return _futures[id]!.$1!(getProvidedArguments()) as Future<T?>?;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the stream using it's ID.
|
/// Get the stream using it's ID.
|
||||||
@@ -46,7 +46,7 @@ class AstromicPresenterController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the refresh stream of a future using it's ID.
|
/// Get the refresh stream of a future using it's ID.
|
||||||
Stream<void> getRefreshStream<T>(String id) {
|
Stream<Map<String,dynamic>?> getRefreshStream<T>(String id) {
|
||||||
assert(_futures.containsKey(id), 'did you add a future with this id?');
|
assert(_futures.containsKey(id), 'did you add a future with this id?');
|
||||||
|
|
||||||
return _futureRefreshers[id]!.stream;
|
return _futureRefreshers[id]!.stream;
|
||||||
@@ -60,10 +60,10 @@ class AstromicPresenterController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Refresh a future using it's ID.
|
/// Refresh a future using it's ID.
|
||||||
void refreshFuture(String id) {
|
void refreshFuture(String id, {Map<String,dynamic>? updatedArgs}) {
|
||||||
assert(_futures.containsKey(id), 'did you add a future with this id?');
|
assert(_futures.containsKey(id), 'did you add a future with this id?');
|
||||||
|
|
||||||
_futureRefreshers[id]!.add(null);
|
_futureRefreshers[id]!.add(updatedArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispose of a future using it's ID.
|
/// Dispose of a future using it's ID.
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class AstromicSheetHelper {
|
|||||||
radius: sheetStyle.radius,
|
radius: sheetStyle.radius,
|
||||||
//
|
//
|
||||||
child: ChangeNotifierProvider<SheetStore>(
|
child: ChangeNotifierProvider<SheetStore>(
|
||||||
create: (BuildContext c) => SheetStore(),
|
create: (BuildContext c) => store,
|
||||||
child: BaseSheetWidget<T?>(
|
child: BaseSheetWidget<T?>(
|
||||||
sheetType: SheetType.form,
|
sheetType: SheetType.form,
|
||||||
//
|
//
|
||||||
@@ -202,7 +202,7 @@ class AstromicSheetHelper {
|
|||||||
// s2 -- Child
|
// s2 -- Child
|
||||||
builder: (BuildContext context, ScrollController scrollController, ScrollPhysics scrollPhysics, int stop) {
|
builder: (BuildContext context, ScrollController scrollController, ScrollPhysics scrollPhysics, int stop) {
|
||||||
return ChangeNotifierProvider<SheetStore>(
|
return ChangeNotifierProvider<SheetStore>(
|
||||||
create: (BuildContext c) => SheetStore(),
|
create: (BuildContext c) => store,
|
||||||
child: BaseSheetWidget<T?>(
|
child: BaseSheetWidget<T?>(
|
||||||
sheetType: SheetType.scroller,
|
sheetType: SheetType.scroller,
|
||||||
sheetConfiguration: sheetConfigs,
|
sheetConfiguration: sheetConfigs,
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// ignore_for_file: close_sinks
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
@@ -9,6 +12,24 @@ class SheetStore extends ChangeNotifier {
|
|||||||
/// An unmodifiable view of the items in the store.
|
/// An unmodifiable view of the items in the store.
|
||||||
UnmodifiableMapView<String, dynamic> get items => UnmodifiableMapView<String, dynamic>(_items);
|
UnmodifiableMapView<String, dynamic> get items => UnmodifiableMapView<String, dynamic>(_items);
|
||||||
|
|
||||||
|
static final StreamController<UnmodifiableMapView<String, dynamic>> _stateStreamController = StreamController<UnmodifiableMapView<String, dynamic>>.broadcast();
|
||||||
|
final Stream<UnmodifiableMapView<String, dynamic>> stateStream = _stateStreamController.stream;
|
||||||
|
|
||||||
|
/// Adds [item] to store.
|
||||||
|
dynamic get(String itemID) {
|
||||||
|
if (!_items.containsKey(itemID)) {
|
||||||
|
throw Exception('No item with the ID $itemID exist in the SheetStore, Are you sure you added it?');
|
||||||
|
}
|
||||||
|
return _items[itemID];
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic tryGet(String itemID) {
|
||||||
|
if (!_items.containsKey(itemID)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return _items[itemID];
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds [item] to store.
|
/// Adds [item] to store.
|
||||||
void add(String itemID, dynamic value) {
|
void add(String itemID, dynamic value) {
|
||||||
_items.addEntries(<MapEntry<String, dynamic>>[MapEntry<String, dynamic>(itemID, value)]);
|
_items.addEntries(<MapEntry<String, dynamic>>[MapEntry<String, dynamic>(itemID, value)]);
|
||||||
@@ -17,21 +38,25 @@ class SheetStore extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Updates [item] in the store.
|
/// Updates [item] in the store.
|
||||||
void update(String itemID, dynamic value) {
|
void update(String itemID, dynamic value, {bool addIfAbsent = false}) {
|
||||||
if (!_items.containsKey(itemID)) {
|
if (!_items.containsKey(itemID)) {
|
||||||
|
if (addIfAbsent) {
|
||||||
|
add(itemID, value);
|
||||||
|
} else {
|
||||||
throw Exception('No item with the ID $itemID exist in the SheetStore, Are you sure you added it?');
|
throw Exception('No item with the ID $itemID exist in the SheetStore, Are you sure you added it?');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
_items[itemID] = value;
|
_items[itemID] = value;
|
||||||
|
}
|
||||||
// This call tells the widgets that are listening to this store to rebuild.
|
// This call tells the widgets that are listening to this store to rebuild.
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes [item] from the store.
|
/// Removes [item] from the store.
|
||||||
void remove(String itemID, dynamic value) {
|
void remove(String itemID, dynamic value) {
|
||||||
if (!_items.containsKey(itemID)) {
|
if (_items.containsKey(itemID)) {
|
||||||
throw Exception('No item with the ID $itemID exist in the SheetStore, Are you sure you added it?');
|
|
||||||
}
|
|
||||||
_items.remove(itemID);
|
_items.remove(itemID);
|
||||||
|
}
|
||||||
// This call tells the widgets that are listening to this store to rebuild.
|
// This call tells the widgets that are listening to this store to rebuild.
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user