From 51cfbec60ee15b48013aaee2fcaedf711a1b342e Mon Sep 17 00:00:00 2001 From: Sudhi S Date: Mon, 24 Apr 2023 15:26:49 +0530 Subject: [PATCH] doc: Documentations updated --- README.md | 11 + example/assets/app.json | 6 +- example/assets/full.json | 19 +- example/ios/Flutter/Debug.xcconfig | 1 + example/ios/Flutter/Release.xcconfig | 1 + example/ios/Podfile | 41 ++++ example/lib/main.dart | 8 +- example/macos/Flutter/Flutter-Debug.xcconfig | 2 +- .../macos/Flutter/Flutter-Release.xcconfig | 1 + example/macos/Podfile | 40 ++++ lib/src/formstack.dart | 208 +++++++++--------- lib/src/input_types.dart | 2 +- lib/src/result/result_format.dart | 16 ++ lib/src/step/question_step.dart | 1 - lib/src/ui/views/base_step_view.dart | 5 +- .../input/factory/common_input_factory.dart | 4 + lib/src/utils/parser.dart | 100 +++++++++ 17 files changed, 343 insertions(+), 123 deletions(-) create mode 100644 example/ios/Podfile create mode 100644 example/macos/Podfile create mode 100644 lib/src/ui/views/input/factory/common_input_factory.dart create mode 100644 lib/src/utils/parser.dart diff --git a/README.md b/README.md index a78778f..2eb79b1 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,17 @@ Overall, FormStack is a powerful tool for creating dynamic user interfaces in Fl } +``` +### Load single json file from assets folder +``` dart + await FormStack.api() .loadFromAsset('assets/app.json'); + +``` +### Load Mutiple json file from assets folder +``` dart + await FormStack.api() + .loadFromAssets(['assets/app.json', 'assets/full.json']); + ``` ### Read json file from assets to FormStack diff --git a/example/assets/app.json b/example/assets/app.json index 94b404a..8d70588 100644 --- a/example/assets/app.json +++ b/example/assets/app.json @@ -13,12 +13,14 @@ "options":[ {"key":"AUTISM_M_CHAT_R","text":"Screenig Tool For Autism In Child M-CHAT-R"}, {"key":"CALL_DRIVER","text":"Call Driver Now"}, - {"key":"FULL_QUESTIONS","text":"Full Components"} + {"key":"FULL_QUESTIONS","text":"Full Components"}, + {"key":"NEW_COMPONENTS","text":"New Components"} ], "id":"CHOICE", "relevantConditions":[{"id":"CALL_DRIVER","expression":"IN CALL_DRIVER"}, {"id":"AUTISM_QUESTIONS","expression":"IN AUTISM_M_CHAT_R" ,"formName":"formOne"}, - {"id":"FULL_QUESTIONS_START","expression":"IN FULL_QUESTIONS" ,"formName":"full"} + {"id":"FULL_QUESTIONS_START","expression":"IN FULL_QUESTIONS" ,"formName":"full"}, + {"id":"","expression":"IN NEW_COMPONENTS" ,"formName":"new_form"} ] },{ "type": "QuestionStep", diff --git a/example/assets/full.json b/example/assets/full.json index 16d9da2..cfa3e8c 100644 --- a/example/assets/full.json +++ b/example/assets/full.json @@ -1,5 +1,6 @@ { + "full": { "steps":[ @@ -27,12 +28,14 @@ },{ "type": "QuestionStep", "title":"Full Questions - Email", - "inputType":"email" + "inputType":"email", + "isOptional":true }, { "type": "QuestionStep", "title":"Full Questions - Name", - "inputType":"name" + "inputType":"name", + "isOptional":true }, { "type": "QuestionStep", @@ -42,22 +45,26 @@ { "type": "QuestionStep", "title":"Full Questions - Date", - "inputType":"date" + "inputType":"date", + "isOptional":true }, { "type": "QuestionStep", "title":"Full Questions - DateTime", - "inputType":"dateTime" + "inputType":"dateTime", + "isOptional":true }, { "type": "QuestionStep", "title":"Full Questions - Time", - "inputType":"time" + "inputType":"time", + "isOptional":true }, { "type": "QuestionStep", "title":"Full Questions - Number", - "inputType":"number" + "inputType":"number", + "isOptional":true }, { "type": "QuestionStep", diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 0000000..88359b2 --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '11.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/example/lib/main.dart b/example/lib/main.dart index 41a73b8..4c6ded3 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:formstack/formstack.dart'; @@ -58,10 +56,8 @@ class HomeScreen extends StatelessWidget { trailing: const Icon(Icons.arrow_forward_ios_outlined), onTap: () async { FormStack.clearForms(); - await FormStack.api().buildFormFromJson(await json - .decode(await rootBundle.loadString('assets/app.json'))); - await FormStack.api().buildFormFromJson(await json - .decode(await rootBundle.loadString('assets/full.json'))); + await FormStack.api() + .loadFromAssets(['assets/app.json', 'assets/full.json']); // ignore: use_build_context_synchronously Navigator.push( context, diff --git a/example/macos/Flutter/Flutter-Debug.xcconfig b/example/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b..20ca87d 100644 --- a/example/macos/Flutter/Flutter-Debug.xcconfig +++ b/example/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1 @@ -#include "ephemeral/Flutter-Generated.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" diff --git a/example/macos/Flutter/Flutter-Release.xcconfig b/example/macos/Flutter/Flutter-Release.xcconfig index c2efd0b..5caa9d1 100644 --- a/example/macos/Flutter/Flutter-Release.xcconfig +++ b/example/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/example/macos/Podfile b/example/macos/Podfile new file mode 100644 index 0000000..049abe2 --- /dev/null +++ b/example/macos/Podfile @@ -0,0 +1,40 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/lib/src/formstack.dart b/lib/src/formstack.dart index 5f28b39..13b5147 100644 --- a/lib/src/formstack.dart +++ b/lib/src/formstack.dart @@ -1,13 +1,47 @@ import 'dart:collection'; import 'dart:convert'; - import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:formstack/formstack.dart'; -import 'package:formstack/src/relevant/expression_relevant_condition.dart'; -import 'package:formstack/src/relevant/relevant_condition.dart'; import 'package:formstack/src/ui/views/formstack_view.dart'; -import 'package:formstack/src/utils/alignment.dart'; - +import 'package:formstack/src/utils/parser.dart'; + +/// +/// +/// FormStack - Comprehensive Library for Creating Dynamic Form +/// +/// FormStack is a library designed to help developers create dynamic user interfaces in Flutter. +/// Specifically, the library is focused on creating forms and surveys using a JSON or Dart language model. +/// +/// The primary goal of FormStack is to make it easy for developers to create dynamic UIs without having to write a lot of code. +/// By using a JSON or Dart model to define the structure of a form or survey, developers can quickly create UIs that are easy to customize and update. +/// +///While the library was initially created to help developers create survey UIs, the focus has expanded to include any type of dynamic application UI. +/// With FormStack, developers can create UIs that are responsive and adaptable to different devices and screen sizes. +/// +///Overall, FormStack is a powerful tool for creating dynamic user interfaces in Flutter. +///It offers a flexible and customizable approach to UI design, allowing developers to create UIs that are easy to use and maintain. +/// +///```dart +/// +/// await FormStack.api().loadFromAsset('assets/app.json'); +/// +/// +/// class SampleScreen extends StatelessWidget { +/// const SampleScreen({super.key}); +/// +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// body: FormStack.api().render(), +/// ); +/// } +/// } +/// +///``` +/// +/// +/// class FormStack { // Ensures end-users cannot initialize the class. FormStack._(); @@ -16,6 +50,10 @@ class FormStack { final Map _forms = {}; + /// + ///Create the instnce for the app + /// name - instance name. + /// static FormStack api({String name = "default"}) { if (!_delegate.containsKey(name)) { _delegate.putIfAbsent(name, () => FormStack._()); @@ -23,6 +61,7 @@ class FormStack { return _delegate[name]!; } + /// Get the purticular from from different instance. static FormStackForm? formByInstaceAndName( {String name = "default", String formName = "default"}) { return api(name: name)._forms[formName]; @@ -34,22 +73,49 @@ class FormStack { _delegate.clear(); } - ///Clear forms. - ///Clear Forms only. + ///Clear forms from instance name . static void clearForms({String name = "default"}) { if (_delegate.containsKey(name)) { _delegate.remove(name); } } - FormStack form({ - String name = "default", - String? googleMapAPIKey, - GeoLocationResult? initialPosition, - String? backgroundAnimationFile, - Alignment? backgroundAlignment, - required List steps, - }) { + /// Load the form from dart language model + /// + ///```dart + ///FormStack.api().form(steps: [ + /// InstructionStep( + /// id: GenericIdentifier(id: "IS_STARTED"), + /// title: "Example Survey", + /// text: "Simple survey example using dart model", + /// cancellable: false), + /// QuestionStep( + /// title: "Name", + /// text: "Your name", + /// inputType: InputType.name, + /// id: GenericIdentifier(id: "NAME"), + /// ) + /// CompletionStep( + /// id: GenericIdentifier(id: "IS_COMPLETED"), + /// title: "Survey Completed", + /// text: "ENd Of ", + /// onFinish: (result) { + /// debugPrint("Completed With Result : $result"); + /// }, + /// ), + /// ]); + /// + ///```` + /// + /// + /// + FormStack form( + {String name = "default", + String? googleMapAPIKey, + GeoLocationResult? initialPosition, + String? backgroundAnimationFile, + Alignment? backgroundAlignment, + required List steps}) { var list = LinkedList(); list.addAll(steps); FormWizard form = FormWizard(list, @@ -61,102 +127,29 @@ class FormStack { return this; } + ///Load single json file from assets folder + Future loadFromAsset(String path) async { + return loadFromAssets([path]); + } + + ///Import and parse multiple JSON files located in the assets folder. + Future loadFromAssets(List files) async { + for (var element in files) { + String data = await rootBundle.loadString(element); + Parser.buildFormFromJson(this, json.decode(data)); + } + return this; + } + + /// Build the form from the JSON content Future buildFormFromJsonString(String data) async { Map? body = await json.decode(data); return buildFormFromJson(body); } + /// Build the from from Map (JSON) Future buildFormFromJson(Map? body) async { - if (body != null) { - body.forEach((key, value) { - List formStep = []; - List? tsteps = value?["steps"] ?? []; - tsteps?.forEach((element) { - List relevantConditions = []; - cast(element?["relevantConditions"])?.forEach((el) { - relevantConditions.add(ExpressionRelevant( - expression: el?["expression"], - formName: el?["formName"] ?? "", - identifier: GenericIdentifier(id: el?["id"]))); - }); - - if (element["type"] == "QuestionStep") { - List options = []; - cast(element?["options"])?.forEach((el) { - options.add(Options(el?["key"], el?["text"])); - }); - InputType inputType = InputType.values - .firstWhere((e) => e.name == element?["inputType"]); - QuestionStep step = QuestionStep( - inputType: inputType, - options: options, - relevantConditions: relevantConditions, - cancellable: element?["cancellable"], - autoTrigger: element?["autoTrigger"] ?? false, - backButtonText: element?["backButtonText"], - cancelButtonText: element?["cancelButtonText"], - isOptional: element?["isOptional"], - nextButtonText: element?["nextButtonText"], - numberOfLines: element?["numberOfLines"], - text: element?["text"], - title: element?["title"], - titleIconAnimationFile: element?["titleIconAnimationFile"], - titleIconMaxWidth: element?["titleIconMaxWidth"], - id: GenericIdentifier(id: element?["id"])); - formStep.add(step); - } else if (element["type"] == "CompletionStep") { - CompletionStep step = CompletionStep( - display: element?["display"] != null - ? Display.values - .firstWhere((e) => e.name == element?["display"]) - : Display.normal, - cancellable: element?["cancellable"], - autoTrigger: element?["autoTrigger"] ?? false, - relevantConditions: relevantConditions, - backButtonText: element?["backButtonText"], - cancelButtonText: element?["cancelButtonText"], - isOptional: element?["isOptional"], - nextButtonText: element?["nextButtonText"], - text: element?["text"], - title: element?["title"], - titleIconAnimationFile: element?["titleIconAnimationFile"], - titleIconMaxWidth: element?["titleIconMaxWidth"], - id: GenericIdentifier(id: element?["id"])); - formStep.add(step); - } else if (element["type"] == "InstructionStep") { - InstructionStep step = InstructionStep( - display: element?["display"] != null - ? Display.values - .firstWhere((e) => e.name == element?["display"]) - : Display.normal, - cancellable: element?["cancellable"], - relevantConditions: relevantConditions, - backButtonText: element?["backButtonText"], - cancelButtonText: element?["cancelButtonText"], - isOptional: element?["isOptional"], - nextButtonText: element?["nextButtonText"], - text: element?["text"], - title: element?["title"], - titleIconAnimationFile: element?["titleIconAnimationFile"], - titleIconMaxWidth: element?["titleIconMaxWidth"], - id: GenericIdentifier(id: element?["id"])); - formStep.add(step); - } - }); - form( - steps: formStep, - name: key, - googleMapAPIKey: value?["googleMapAPIKey"], - backgroundAnimationFile: value?["backgroundAnimationFile"], - backgroundAlignment: - alignmentFromString(value?["backgroundAlignment"]), - initialPosition: value?["initialPosition"] != null - ? GeoLocationResult( - latitude: value?["initialPosition"]["latitude"], - longitude: value?["initialPosition"]["longitude"]) - : null); - }); - } + Parser.buildFormFromJson(this, body); return this; } @@ -173,6 +166,7 @@ class FormStack { return this; } + /// Add validation error listener FormStack addOnValidationError( Identifier identifier, Function(String)? onValidationError, {String? formName = "default"}) { @@ -189,6 +183,7 @@ class FormStack { return this; } + /// Prevent System back navigation or getting call back when the user click the system back button. FormStack systemBackNavigation( bool disabled, VoidCallback onBackNavigationClick, {String? formName = "default"}) { @@ -200,6 +195,7 @@ class FormStack { return this; } + /// Add the completion handler to add you logic when the form finish FormStack addCompletionCallback( Identifier identifier, { String? formName = "default", @@ -220,6 +216,8 @@ class FormStack { return this; } + /// Render the form to the UI + /// Primary method to implement in you Widget tree. Widget render({String name = "default"}) { return FormStackView(_forms[name]!); } diff --git a/lib/src/input_types.dart b/lib/src/input_types.dart index c219267..4c027bc 100644 --- a/lib/src/input_types.dart +++ b/lib/src/input_types.dart @@ -9,5 +9,5 @@ enum InputType { number, smile, singleChoice, - multipleChoice, + multipleChoice } diff --git a/lib/src/result/result_format.dart b/lib/src/result/result_format.dart index bd898ba..88273ae 100644 --- a/lib/src/result/result_format.dart +++ b/lib/src/result/result_format.dart @@ -3,6 +3,7 @@ T? cast(x) => x is T ? x : null; abstract class ResultFormat { ResultFormat._(); factory ResultFormat.none() = _NoneResultType; + factory ResultFormat.notNull(String errorMsg) = _NotNullResultType; factory ResultFormat.email(String errorMsg) = _EmailResultType; factory ResultFormat.smile(String errorMsg) = _SmileResultType; factory ResultFormat.name(String errorMsg) = _NameResultType; @@ -34,6 +35,21 @@ class DateResultType extends ResultFormat { } } +class _NotNullResultType extends ResultFormat { + final String errorMsg; + _NotNullResultType(this.errorMsg) : super._(); + + @override + bool isValid(dynamic input) { + return input != null; + } + + @override + String error() { + return errorMsg; + } +} + class _NoneResultType extends ResultFormat { _NoneResultType() : super._(); diff --git a/lib/src/step/question_step.dart b/lib/src/step/question_step.dart index 60a1b64..c27e43d 100644 --- a/lib/src/step/question_step.dart +++ b/lib/src/step/question_step.dart @@ -93,7 +93,6 @@ class QuestionStep extends FormStep { resultFormat ?? ResultFormat.multipleChoice("Please select any."); return ChoiceInputWidget.multiple( this, formKitForm, text, resultFormat!, title, options); - default: } throw UnimplementedError(); diff --git a/lib/src/ui/views/base_step_view.dart b/lib/src/ui/views/base_step_view.dart index b06dbb3..54f7932 100644 --- a/lib/src/ui/views/base_step_view.dart +++ b/lib/src/ui/views/base_step_view.dart @@ -186,7 +186,10 @@ abstract class BaseStepView extends FormStepView { @override void onNext() { - if (isValid()) { + if (formStep.isOptional ?? false) { + clearFocus(); + formKitForm.nextStep(formStep); + } else if (isValid()) { clearFocus(); formKitForm.nextStep(formStep); } else { diff --git a/lib/src/ui/views/input/factory/common_input_factory.dart b/lib/src/ui/views/input/factory/common_input_factory.dart new file mode 100644 index 0000000..5a9c035 --- /dev/null +++ b/lib/src/ui/views/input/factory/common_input_factory.dart @@ -0,0 +1,4 @@ +// ignore: must_be_immutable + +// ignore: must_be_immutable +class CommonInputWidget {} diff --git a/lib/src/utils/parser.dart b/lib/src/utils/parser.dart new file mode 100644 index 0000000..c5ec4b4 --- /dev/null +++ b/lib/src/utils/parser.dart @@ -0,0 +1,100 @@ +import 'package:formstack/formstack.dart'; +import 'package:formstack/src/relevant/expression_relevant_condition.dart'; +import 'package:formstack/src/relevant/relevant_condition.dart'; +import 'package:formstack/src/utils/alignment.dart'; + +class Parser { + static void buildFormFromJson( + FormStack formStack, Map? body) async { + if (body != null) { + body.forEach((key, value) { + List formStep = []; + List? tsteps = value?["steps"] ?? []; + tsteps?.forEach((element) { + List relevantConditions = []; + cast(element?["relevantConditions"])?.forEach((el) { + relevantConditions.add(ExpressionRelevant( + expression: el?["expression"], + formName: el?["formName"] ?? "", + identifier: GenericIdentifier(id: el?["id"]))); + }); + + if (element["type"] == "QuestionStep") { + List options = []; + cast(element?["options"])?.forEach((el) { + options.add(Options(el?["key"], el?["text"])); + }); + InputType inputType = InputType.values + .firstWhere((e) => e.name == element?["inputType"]); + QuestionStep step = QuestionStep( + inputType: inputType, + options: options, + relevantConditions: relevantConditions, + cancellable: element?["cancellable"], + autoTrigger: element?["autoTrigger"] ?? false, + backButtonText: element?["backButtonText"], + cancelButtonText: element?["cancelButtonText"], + isOptional: element?["isOptional"], + nextButtonText: element?["nextButtonText"], + numberOfLines: element?["numberOfLines"], + text: element?["text"], + title: element?["title"], + titleIconAnimationFile: element?["titleIconAnimationFile"], + titleIconMaxWidth: element?["titleIconMaxWidth"], + id: GenericIdentifier(id: element?["id"])); + formStep.add(step); + } else if (element["type"] == "CompletionStep") { + CompletionStep step = CompletionStep( + display: element?["display"] != null + ? Display.values + .firstWhere((e) => e.name == element?["display"]) + : Display.normal, + cancellable: element?["cancellable"], + autoTrigger: element?["autoTrigger"] ?? false, + relevantConditions: relevantConditions, + backButtonText: element?["backButtonText"], + cancelButtonText: element?["cancelButtonText"], + isOptional: element?["isOptional"], + nextButtonText: element?["nextButtonText"], + text: element?["text"], + title: element?["title"], + titleIconAnimationFile: element?["titleIconAnimationFile"], + titleIconMaxWidth: element?["titleIconMaxWidth"], + id: GenericIdentifier(id: element?["id"])); + formStep.add(step); + } else if (element["type"] == "InstructionStep") { + InstructionStep step = InstructionStep( + display: element?["display"] != null + ? Display.values + .firstWhere((e) => e.name == element?["display"]) + : Display.normal, + cancellable: element?["cancellable"], + relevantConditions: relevantConditions, + backButtonText: element?["backButtonText"], + cancelButtonText: element?["cancelButtonText"], + isOptional: element?["isOptional"], + nextButtonText: element?["nextButtonText"], + text: element?["text"], + title: element?["title"], + titleIconAnimationFile: element?["titleIconAnimationFile"], + titleIconMaxWidth: element?["titleIconMaxWidth"], + id: GenericIdentifier(id: element?["id"])); + formStep.add(step); + } + }); + formStack.form( + steps: formStep, + name: key, + googleMapAPIKey: value?["googleMapAPIKey"], + backgroundAnimationFile: value?["backgroundAnimationFile"], + backgroundAlignment: + alignmentFromString(value?["backgroundAlignment"]), + initialPosition: value?["initialPosition"] != null + ? GeoLocationResult( + latitude: value?["initialPosition"]["latitude"], + longitude: value?["initialPosition"]["longitude"]) + : null); + }); + } + } +}