diff --git a/examples/stac_gallery/assets/json/home_screen.json b/examples/stac_gallery/assets/json/home_screen.json index 7170a978..8a0c4080 100644 --- a/examples/stac_gallery/assets/json/home_screen.json +++ b/examples/stac_gallery/assets/json/home_screen.json @@ -1351,5 +1351,27 @@ "assetPath": "assets/json/dropdown_menu_view_example.json" } } + }, + { + "type": "listTile", + "leading": { + "type": "icon", + "icon": "category" + }, + "title": { + "type": "text", + "data": "Stac Variable" + }, + "subtitle": { + "type": "text", + "data": "Use variables to store and access values" + }, + "onTap": { + "actionType": "navigate", + "widgetJson": { + "type": "exampleScreen", + "assetPath": "assets/json/variable_example.json" + } + } } ] \ No newline at end of file diff --git a/examples/stac_gallery/assets/json/variable_example.json b/examples/stac_gallery/assets/json/variable_example.json new file mode 100644 index 00000000..dab9fa6b --- /dev/null +++ b/examples/stac_gallery/assets/json/variable_example.json @@ -0,0 +1,70 @@ +{ + "type": "setValue", + "values": [ + { + "key": "name", + "value": "John Doe" + }, + { + "key": "age", + "value": 30 + }, + { + "key": "city", + "value": "New York" + }, + { + "key": "country", + "value": "USA" + } + ], + "child": { + "type": "scaffold", + "body": { + "type": "center", + "child": { + "type": "column", + "mainAxisAlignment": "center", + "children": [ + { + "type": "text", + "data": "{{name}}" + }, + { + "type": "text", + "data": "{{age}}" + }, + { + "type": "text", + "data": "{{city}}", + "children": [ + { + "data": "{{country}}" + } + ] + } + ] + } + }, + "floatingActionButton": { + "type": "floatingActionButton", + "child": { + "type": "icon", + "icon": "add" + }, + "onPressed": { + "actionType": "setValue", + "values": [ + { + "key": "phone", + "value": "1234567890" + } + ], + "action": { + "actionType": "navigate", + "assetPath": "assets/json/variable_navigate_example.json" + } + } + } + } +} \ No newline at end of file diff --git a/examples/stac_gallery/assets/json/variable_navigate_example.json b/examples/stac_gallery/assets/json/variable_navigate_example.json new file mode 100644 index 00000000..fdcaf60b --- /dev/null +++ b/examples/stac_gallery/assets/json/variable_navigate_example.json @@ -0,0 +1,33 @@ +{ + "type": "scaffold", + "body": { + "type": "center", + "child": { + "type": "column", + "mainAxisAlignment": "center", + "children": [ + { + "type": "text", + "data": "{{name}}" + }, + { + "type": "text", + "data": "{{age}}" + }, + { + "type": "text", + "data": "{{city}} ", + "children": [ + { + "data": "{{country}}" + } + ] + }, + { + "type": "text", + "data": "phone: {{phone}}" + } + ] + } + } +} \ No newline at end of file diff --git a/examples/stac_gallery/lib/main.dart b/examples/stac_gallery/lib/main.dart index 89ea1acf..15a5c4e6 100644 --- a/examples/stac_gallery/lib/main.dart +++ b/examples/stac_gallery/lib/main.dart @@ -43,7 +43,7 @@ class MyApp extends StatelessWidget { theme: state.lightTheme, darkTheme: state.darkTheme, themeMode: state.themeMode, - homeBuilder: (context) => const HomeScreen(), + homeBuilder: (context) => HomeScreen(), title: 'Stac Gallery', routes: { '/homeScreen': (context) => const HomeScreen(), diff --git a/packages/stac/lib/src/framework/stac.dart b/packages/stac/lib/src/framework/stac.dart index 029ab39f..79b56a7c 100644 --- a/packages/stac/lib/src/framework/stac.dart +++ b/packages/stac/lib/src/framework/stac.dart @@ -7,9 +7,12 @@ import 'package:flutter/services.dart'; import 'package:stac/src/framework/stac_registry.dart'; import 'package:stac/src/parsers/actions/stac_network_request/stac_network_request_parser.dart'; import 'package:stac/src/parsers/parsers.dart'; +import 'package:stac/src/parsers/widgets/stac_set_value/stac_set_value_parser.dart'; import 'package:stac/src/parsers/widgets/stac_inkwell/stac_inkwell_parser.dart'; import 'package:stac/src/services/stac_network_service.dart'; import 'package:stac/src/utils/log.dart'; +import 'package:stac/src/utils/variable_resolver.dart'; +import 'package:stac/src/utils/widget_type.dart'; import 'package:stac_framework/stac_framework.dart'; typedef ErrorWidgetBuilder = Widget Function( @@ -101,6 +104,7 @@ class Stac { const StacClipRRectParser(), const StacClipOvalParser(), const StacGestureDetectorParser(), + const StacSetValueParser(), const StacInkwellParser(), ]; @@ -113,6 +117,7 @@ class Stac { const StacGetFormValueParser(), const StacFormValidateParser(), const StacSnackBarParser(), + const StacSetValueActionParser(), ]; static Future initialize({ @@ -134,7 +139,15 @@ class Stac { String widgetType = json['type']; StacParser? stacParser = StacRegistry.instance.getParser(widgetType); if (stacParser != null) { - final model = stacParser.getModel(json); + Map resolvedJson; + if (widgetType == WidgetType.setValue.name) { + resolvedJson = json; + } else { + resolvedJson = resolveVariablesInJson(json, StacRegistry.instance); + } + + final model = stacParser.getModel(resolvedJson); + return stacParser.parse(context, model); } else { Log.w('Widget type [$widgetType] not supported'); diff --git a/packages/stac/lib/src/framework/stac_registry.dart b/packages/stac/lib/src/framework/stac_registry.dart index 5c1d8125..f393554e 100644 --- a/packages/stac/lib/src/framework/stac_registry.dart +++ b/packages/stac/lib/src/framework/stac_registry.dart @@ -14,6 +14,8 @@ class StacRegistry { static final _stacActionParsers = {}; + static final Map _variables = {}; + bool register(StacParser parser, [bool override = false]) { final String type = parser.type; if (_stacParsers.containsKey(type)) { @@ -75,4 +77,20 @@ class StacRegistry { StacActionParser? getActionParser(String type) { return _stacActionParsers[type]; } + + dynamic setValue(String key, dynamic value) { + if (value == null) { + removeValue(key); + } else { + _variables[key] = value; + } + } + + dynamic removeValue(String key) { + return _variables.remove(key); + } + + dynamic getValue(String key) { + return _variables[key]; + } } diff --git a/packages/stac/lib/src/parsers/actions/actions.dart b/packages/stac/lib/src/parsers/actions/actions.dart index 79c628a5..288fc73e 100644 --- a/packages/stac/lib/src/parsers/actions/actions.dart +++ b/packages/stac/lib/src/parsers/actions/actions.dart @@ -5,4 +5,5 @@ export 'package:stac/src/parsers/actions/stac_modal_bottom_sheet_action/stac_mod export 'package:stac/src/parsers/actions/stac_navigate_action/stac_navigate_action_parser.dart'; export 'package:stac/src/parsers/actions/stac_network_request/stac_network_request.dart'; export 'package:stac/src/parsers/actions/stac_none_action/stac_none_action_parser.dart'; +export 'package:stac/src/parsers/actions/stac_set_value/stac_set_value_action_parser.dart'; export 'package:stac/src/parsers/actions/stac_snack_bar/stac_snack_bar.dart'; diff --git a/packages/stac/lib/src/parsers/actions/stac_navigate_action/stac_navigate_action_parser.dart b/packages/stac/lib/src/parsers/actions/stac_navigate_action/stac_navigate_action_parser.dart index 2e34a5b0..ab02998f 100644 --- a/packages/stac/lib/src/parsers/actions/stac_navigate_action/stac_navigate_action_parser.dart +++ b/packages/stac/lib/src/parsers/actions/stac_navigate_action/stac_navigate_action_parser.dart @@ -1,8 +1,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:stac/src/parsers/actions/stac_navigate_action/stac_navigate_action.dart'; import 'package:stac/src/framework/framework.dart'; +import 'package:stac/src/parsers/actions/stac_navigate_action/stac_navigate_action.dart'; import 'package:stac/src/utils/action_type.dart'; import 'package:stac_framework/stac_framework.dart'; diff --git a/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action.dart b/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action.dart new file mode 100644 index 00000000..0de736d7 --- /dev/null +++ b/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:stac_framework/stac_framework.dart'; + +part 'stac_set_value_action.freezed.dart'; +part 'stac_set_value_action.g.dart'; + +@freezed +abstract class StacSetValueAction with _$StacSetValueAction { + const factory StacSetValueAction({ + @Default([]) List> values, + StacAction? action, + }) = _StacSetValueAction; + + factory StacSetValueAction.fromJson(Map json) => + _$StacSetValueActionFromJson(json); +} diff --git a/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action.freezed.dart b/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action.freezed.dart new file mode 100644 index 00000000..9e8a6de1 --- /dev/null +++ b/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action.freezed.dart @@ -0,0 +1,199 @@ +// dart format width=80 +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'stac_set_value_action.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$StacSetValueAction { + List> get values; + StacAction? get action; + + /// Create a copy of StacSetValueAction + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + $StacSetValueActionCopyWith get copyWith => + _$StacSetValueActionCopyWithImpl( + this as StacSetValueAction, _$identity); + + /// Serializes this StacSetValueAction to a JSON map. + Map toJson(); + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is StacSetValueAction && + const DeepCollectionEquality().equals(other.values, values) && + const DeepCollectionEquality().equals(other.action, action)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(values), + const DeepCollectionEquality().hash(action)); + + @override + String toString() { + return 'StacSetValueAction(values: $values, action: $action)'; + } +} + +/// @nodoc +abstract mixin class $StacSetValueActionCopyWith<$Res> { + factory $StacSetValueActionCopyWith( + StacSetValueAction value, $Res Function(StacSetValueAction) _then) = + _$StacSetValueActionCopyWithImpl; + @useResult + $Res call({List> values, StacAction? action}); +} + +/// @nodoc +class _$StacSetValueActionCopyWithImpl<$Res> + implements $StacSetValueActionCopyWith<$Res> { + _$StacSetValueActionCopyWithImpl(this._self, this._then); + + final StacSetValueAction _self; + final $Res Function(StacSetValueAction) _then; + + /// Create a copy of StacSetValueAction + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? values = null, + Object? action = freezed, + }) { + return _then(_self.copyWith( + values: null == values + ? _self.values + : values // ignore: cast_nullable_to_non_nullable + as List>, + action: freezed == action + ? _self.action + : action // ignore: cast_nullable_to_non_nullable + as StacAction?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _StacSetValueAction implements StacSetValueAction { + const _StacSetValueAction( + {final List> values = const [], + final StacAction? action}) + : _values = values, + _action = action; + factory _StacSetValueAction.fromJson(Map json) => + _$StacSetValueActionFromJson(json); + + final List> _values; + @override + @JsonKey() + List> get values { + if (_values is EqualUnmodifiableListView) return _values; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_values); + } + + final StacAction? _action; + @override + StacAction? get action { + final value = _action; + if (value == null) return null; + if (_action is EqualUnmodifiableMapView) return _action; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(value); + } + + /// Create a copy of StacSetValueAction + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + _$StacSetValueActionCopyWith<_StacSetValueAction> get copyWith => + __$StacSetValueActionCopyWithImpl<_StacSetValueAction>(this, _$identity); + + @override + Map toJson() { + return _$StacSetValueActionToJson( + this, + ); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _StacSetValueAction && + const DeepCollectionEquality().equals(other._values, _values) && + const DeepCollectionEquality().equals(other._action, _action)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_values), + const DeepCollectionEquality().hash(_action)); + + @override + String toString() { + return 'StacSetValueAction(values: $values, action: $action)'; + } +} + +/// @nodoc +abstract mixin class _$StacSetValueActionCopyWith<$Res> + implements $StacSetValueActionCopyWith<$Res> { + factory _$StacSetValueActionCopyWith( + _StacSetValueAction value, $Res Function(_StacSetValueAction) _then) = + __$StacSetValueActionCopyWithImpl; + @override + @useResult + $Res call({List> values, StacAction? action}); +} + +/// @nodoc +class __$StacSetValueActionCopyWithImpl<$Res> + implements _$StacSetValueActionCopyWith<$Res> { + __$StacSetValueActionCopyWithImpl(this._self, this._then); + + final _StacSetValueAction _self; + final $Res Function(_StacSetValueAction) _then; + + /// Create a copy of StacSetValueAction + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $Res call({ + Object? values = null, + Object? action = freezed, + }) { + return _then(_StacSetValueAction( + values: null == values + ? _self._values + : values // ignore: cast_nullable_to_non_nullable + as List>, + action: freezed == action + ? _self._action + : action // ignore: cast_nullable_to_non_nullable + as StacAction?, + )); + } +} + +// dart format on diff --git a/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action.g.dart b/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action.g.dart new file mode 100644 index 00000000..0606d6c1 --- /dev/null +++ b/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action.g.dart @@ -0,0 +1,22 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'stac_set_value_action.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_StacSetValueAction _$StacSetValueActionFromJson(Map json) => + _StacSetValueAction( + values: (json['values'] as List?) + ?.map((e) => e as Map) + .toList() ?? + const [], + action: json['action'] as Map?, + ); + +Map _$StacSetValueActionToJson(_StacSetValueAction instance) => + { + 'values': instance.values, + 'action': instance.action, + }; diff --git a/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action_parser.dart b/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action_parser.dart new file mode 100644 index 00000000..5ce3a49e --- /dev/null +++ b/packages/stac/lib/src/parsers/actions/stac_set_value/stac_set_value_action_parser.dart @@ -0,0 +1,28 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:stac/src/parsers/actions/stac_set_value/stac_set_value_action.dart'; +import 'package:stac/src/utils/action_type.dart'; +import 'package:stac/stac.dart'; + +class StacSetValueActionParser extends StacActionParser { + const StacSetValueActionParser(); + + @override + String get actionType => ActionType.setValue.name; + + @override + StacSetValueAction getModel(StacAction json) => + StacSetValueAction.fromJson(json); + + @override + FutureOr onCall( + BuildContext context, + StacSetValueAction model, + ) async { + for (final value in model.values) { + StacRegistry.instance.setValue(value['key'] as String, value['value']); + } + return Stac.onCallFromJson(model.action, context); + } +} diff --git a/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value.dart b/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value.dart new file mode 100644 index 00000000..b1fdd81d --- /dev/null +++ b/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:stac_framework/stac_framework.dart'; + +part 'stac_set_value.freezed.dart'; +part 'stac_set_value.g.dart'; + +@freezed +abstract class StacSetValue with _$StacSetValue { + const factory StacSetValue({ + @Default([]) List> values, + StacWidget? child, + }) = _StacSetValue; + + factory StacSetValue.fromJson(Map json) => + _$StacSetValueFromJson(json); +} diff --git a/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value.freezed.dart b/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value.freezed.dart new file mode 100644 index 00000000..d48574a7 --- /dev/null +++ b/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value.freezed.dart @@ -0,0 +1,198 @@ +// dart format width=80 +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'stac_set_value.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$StacSetValue { + List> get values; + StacWidget? get child; + + /// Create a copy of StacSetValue + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + $StacSetValueCopyWith get copyWith => + _$StacSetValueCopyWithImpl( + this as StacSetValue, _$identity); + + /// Serializes this StacSetValue to a JSON map. + Map toJson(); + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is StacSetValue && + const DeepCollectionEquality().equals(other.values, values) && + const DeepCollectionEquality().equals(other.child, child)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(values), + const DeepCollectionEquality().hash(child)); + + @override + String toString() { + return 'StacSetValue(values: $values, child: $child)'; + } +} + +/// @nodoc +abstract mixin class $StacSetValueCopyWith<$Res> { + factory $StacSetValueCopyWith( + StacSetValue value, $Res Function(StacSetValue) _then) = + _$StacSetValueCopyWithImpl; + @useResult + $Res call({List> values, StacWidget? child}); +} + +/// @nodoc +class _$StacSetValueCopyWithImpl<$Res> implements $StacSetValueCopyWith<$Res> { + _$StacSetValueCopyWithImpl(this._self, this._then); + + final StacSetValue _self; + final $Res Function(StacSetValue) _then; + + /// Create a copy of StacSetValue + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? values = null, + Object? child = freezed, + }) { + return _then(_self.copyWith( + values: null == values + ? _self.values + : values // ignore: cast_nullable_to_non_nullable + as List>, + child: freezed == child + ? _self.child + : child // ignore: cast_nullable_to_non_nullable + as StacWidget?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _StacSetValue implements StacSetValue { + const _StacSetValue( + {final List> values = const [], + final StacWidget? child}) + : _values = values, + _child = child; + factory _StacSetValue.fromJson(Map json) => + _$StacSetValueFromJson(json); + + final List> _values; + @override + @JsonKey() + List> get values { + if (_values is EqualUnmodifiableListView) return _values; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_values); + } + + final StacWidget? _child; + @override + StacWidget? get child { + final value = _child; + if (value == null) return null; + if (_child is EqualUnmodifiableMapView) return _child; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(value); + } + + /// Create a copy of StacSetValue + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + _$StacSetValueCopyWith<_StacSetValue> get copyWith => + __$StacSetValueCopyWithImpl<_StacSetValue>(this, _$identity); + + @override + Map toJson() { + return _$StacSetValueToJson( + this, + ); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _StacSetValue && + const DeepCollectionEquality().equals(other._values, _values) && + const DeepCollectionEquality().equals(other._child, _child)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_values), + const DeepCollectionEquality().hash(_child)); + + @override + String toString() { + return 'StacSetValue(values: $values, child: $child)'; + } +} + +/// @nodoc +abstract mixin class _$StacSetValueCopyWith<$Res> + implements $StacSetValueCopyWith<$Res> { + factory _$StacSetValueCopyWith( + _StacSetValue value, $Res Function(_StacSetValue) _then) = + __$StacSetValueCopyWithImpl; + @override + @useResult + $Res call({List> values, StacWidget? child}); +} + +/// @nodoc +class __$StacSetValueCopyWithImpl<$Res> + implements _$StacSetValueCopyWith<$Res> { + __$StacSetValueCopyWithImpl(this._self, this._then); + + final _StacSetValue _self; + final $Res Function(_StacSetValue) _then; + + /// Create a copy of StacSetValue + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $Res call({ + Object? values = null, + Object? child = freezed, + }) { + return _then(_StacSetValue( + values: null == values + ? _self._values + : values // ignore: cast_nullable_to_non_nullable + as List>, + child: freezed == child + ? _self._child + : child // ignore: cast_nullable_to_non_nullable + as StacWidget?, + )); + } +} + +// dart format on diff --git a/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value.g.dart b/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value.g.dart new file mode 100644 index 00000000..99aab0d8 --- /dev/null +++ b/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value.g.dart @@ -0,0 +1,22 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'stac_set_value.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_StacSetValue _$StacSetValueFromJson(Map json) => + _StacSetValue( + values: (json['values'] as List?) + ?.map((e) => e as Map) + .toList() ?? + const [], + child: json['child'] as Map?, + ); + +Map _$StacSetValueToJson(_StacSetValue instance) => + { + 'values': instance.values, + 'child': instance.child, + }; diff --git a/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value_parser.dart b/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value_parser.dart new file mode 100644 index 00000000..e33c8dd0 --- /dev/null +++ b/packages/stac/lib/src/parsers/widgets/stac_set_value/stac_set_value_parser.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:stac/src/framework/framework.dart'; +import 'package:stac/src/utils/variable_resolver.dart'; +import 'package:stac/src/utils/widget_type.dart'; +import 'package:stac_framework/stac_framework.dart'; + +import 'stac_set_value.dart'; + +class StacSetValueParser extends StacParser { + const StacSetValueParser(); + + @override + String get type => WidgetType.setValue.name; + + @override + StacSetValue getModel(Map json) => + StacSetValue.fromJson(json); + + @override + Widget parse(BuildContext context, StacSetValue model) { + return _SetValueWidget(model: model); + } +} + +class _SetValueWidget extends StatefulWidget { + const _SetValueWidget({required this.model}); + + final StacSetValue model; + + @override + State<_SetValueWidget> createState() => _SetValueWidgetState(); +} + +class _SetValueWidgetState extends State<_SetValueWidget> { + final StacRegistry _stacRegistry = StacRegistry.instance; + + @override + void initState() { + super.initState(); + + for (final value in widget.model.values) { + _stacRegistry.setValue(value['key'] as String, value['value']); + } + } + + @override + void dispose() { + for (final value in widget.model.values) { + _stacRegistry.removeValue(value['key'] as String); + } + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final resolvedJson = resolveVariablesInJson( + widget.model.child, + _stacRegistry, + ); + + return Stac.fromJson(resolvedJson, context) ?? const SizedBox(); + } +} diff --git a/packages/stac/lib/src/parsers/widgets/widgets.dart b/packages/stac/lib/src/parsers/widgets/widgets.dart index 76fcc22b..44c40039 100644 --- a/packages/stac/lib/src/parsers/widgets/widgets.dart +++ b/packages/stac/lib/src/parsers/widgets/widgets.dart @@ -75,6 +75,7 @@ export 'package:stac/src/parsers/widgets/stac_refresh_indicator/stac_refresh_ind export 'package:stac/src/parsers/widgets/stac_row/stac_row.dart'; export 'package:stac/src/parsers/widgets/stac_safe_area/stac_safe_area.dart'; export 'package:stac/src/parsers/widgets/stac_scaffold/stac_scaffold.dart'; +export 'package:stac/src/parsers/widgets/stac_set_value/stac_set_value.dart'; export 'package:stac/src/parsers/widgets/stac_shape_border/stac_shape_border.dart'; export 'package:stac/src/parsers/widgets/stac_single_child_scroll_view/stac_single_child_scroll_view.dart'; export 'package:stac/src/parsers/widgets/stac_sized_box/stac_sized_box.dart'; diff --git a/packages/stac/lib/src/utils/action_type.dart b/packages/stac/lib/src/utils/action_type.dart index cf7fd4ef..9d66cd03 100644 --- a/packages/stac/lib/src/utils/action_type.dart +++ b/packages/stac/lib/src/utils/action_type.dart @@ -7,4 +7,5 @@ enum ActionType { getFormValue, validateForm, showSnackBar, + setValue, } diff --git a/packages/stac/lib/src/utils/variable_resolver.dart b/packages/stac/lib/src/utils/variable_resolver.dart new file mode 100644 index 00000000..96ade855 --- /dev/null +++ b/packages/stac/lib/src/utils/variable_resolver.dart @@ -0,0 +1,17 @@ +import 'package:stac/src/framework/stac_registry.dart'; + +dynamic resolveVariablesInJson(dynamic json, StacRegistry registry) { + if (json is String) { + // Replace all {{variable_name}} with their values from registry + return json.replaceAllMapped(RegExp(r'{{(.*?)}}'), (match) { + final variableName = match.group(1)?.trim(); + return registry.getValue(variableName ?? '')?.toString() ?? ''; + }); + } else if (json is Map) { + return json.map( + (key, value) => MapEntry(key, resolveVariablesInJson(value, registry))); + } else if (json is List) { + return json.map((item) => resolveVariablesInJson(item, registry)).toList(); + } + return json; +} diff --git a/packages/stac/lib/src/utils/widget_type.dart b/packages/stac/lib/src/utils/widget_type.dart index 80994d5f..e4870a6a 100644 --- a/packages/stac/lib/src/utils/widget_type.dart +++ b/packages/stac/lib/src/utils/widget_type.dart @@ -57,6 +57,7 @@ enum WidgetType { row, safeArea, scaffold, + setValue, singleChildScrollView, sizedBox, slider, diff --git a/packages/stac_framework/lib/src/stac_action_parser.dart b/packages/stac_framework/lib/src/stac_action_parser.dart index 0d22e38a..ae9c572a 100644 --- a/packages/stac_framework/lib/src/stac_action_parser.dart +++ b/packages/stac_framework/lib/src/stac_action_parser.dart @@ -2,6 +2,8 @@ import 'dart:async'; import 'package:flutter/widgets.dart'; +typedef StacAction = Map; + /// [StacActionParser] is an abstract class that is used to parse a JSON object into /// a model and then handle an action based on the model. /// @@ -19,7 +21,7 @@ abstract class StacActionParser { /// This method should be implemented to parse a JSON object into a model. /// The JSON object is typically a part of the STAC action. /// The model [T] should contain all the necessary data to handle the action. - T getModel(Map json); + T getModel(StacAction json); /// Handles the action based on the model [T]. /// diff --git a/packages/stac_framework/lib/src/stac_parser.dart b/packages/stac_framework/lib/src/stac_parser.dart index fb37ce2e..368f0839 100644 --- a/packages/stac_framework/lib/src/stac_parser.dart +++ b/packages/stac_framework/lib/src/stac_parser.dart @@ -1,5 +1,7 @@ import 'package:flutter/widgets.dart'; +typedef StacWidget = Map; + /// [StacParser] is an abstract class that is used to parse a JSON object into /// a model and then parse the model into a widget. /// @@ -19,7 +21,7 @@ abstract class StacParser { /// This method should be implemented to parse a JSON object into a model. /// The JSON object is typically a part of the STAC widget. /// The model [T] should contain all the necessary data to build a widget. - T getModel(Map json); + T getModel(StacWidget json); /// Parses a model [T] into a [Widget]. ///