From b436501c0b937c6d2d1b0cdb8d2fdcd92520eaa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Ma=CC=88rz?= Date: Thu, 15 Dec 2022 08:27:42 +0100 Subject: [PATCH 001/108] feat/add dynamic steps --- analysis_option.yaml | 233 ------- analysis_options.yaml | 189 ++++++ .../plugins/GeneratedPluginRegistrant.java | 31 - example/integration_test/app_test.dart | 16 - example/ios/Podfile.lock | 12 + example/lib/main.dart | 51 +- example/macos/.gitignore | 6 - example/macos/Flutter/Flutter-Debug.xcconfig | 2 - .../macos/Flutter/Flutter-Release.xcconfig | 2 - .../Flutter/GeneratedPluginRegistrant.swift | 10 - example/macos/Podfile | 40 -- example/macos/Podfile.lock | 16 - .../macos/Runner.xcodeproj/project.pbxproj | 614 ------------------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 89 --- .../contents.xcworkspacedata | 10 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - example/macos/Runner/AppDelegate.swift | 9 - .../AppIcon.appiconset/Contents.json | 68 -- .../AppIcon.appiconset/app_icon_1024.png | Bin 46993 -> 0 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 3276 -> 0 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 1429 -> 0 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 5933 -> 0 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 1243 -> 0 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 14800 -> 0 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 1874 -> 0 bytes example/macos/Runner/Base.lproj/MainMenu.xib | 339 ---------- example/macos/Runner/Configs/AppInfo.xcconfig | 14 - example/macos/Runner/Configs/Debug.xcconfig | 2 - example/macos/Runner/Configs/Release.xcconfig | 2 - .../macos/Runner/Configs/Warnings.xcconfig | 13 - .../macos/Runner/DebugProfile.entitlements | 12 - example/macos/Runner/Info.plist | 32 - example/macos/Runner/MainFlutterWindow.swift | 15 - example/macos/Runner/Release.entitlements | 8 - example/pubspec.lock | 173 ++++- lib/src/answer_format/answer_format.dart | 6 +- .../answer_format/boolean_answer_format.dart | 1 + lib/src/answer_format/date_answer_format.dart | 28 +- .../answer_format/double_answer_format.dart | 1 + .../answer_format/image_answer_format.dart | 1 + .../answer_format/image_answer_format.g.dart | 6 +- .../answer_format/integer_answer_format.dart | 1 + lib/src/answer_format/multi_double.dart | 5 +- .../multiple_choice_answer_format.dart | 3 +- ...le_choice_auto_complete_answer_format.dart | 8 +- .../multiple_double_answer_format.dart | 3 +- .../answer_format/scale_answer_format.dart | 1 + .../single_choice_answer_format.dart | 1 + lib/src/answer_format/text_answer_format.dart | 5 +- lib/src/answer_format/text_choice.dart | 4 +- .../answer_format/time_answer_formart.dart | 1 + lib/src/controller/survey_controller.dart | 13 +- .../navigator/navigable_task_navigator.dart | 27 +- .../rules/conditional_navigation_rule.dart | 7 +- .../rules/direct_navigation_rule.dart | 1 + lib/src/navigator/rules/navigation_rule.dart | 4 +- lib/src/navigator/task_navigator.dart | 2 +- lib/src/presenter/survey_state.dart | 22 + .../question/boolean_question_result.dart | 7 +- .../result/question/date_question_result.dart | 5 +- .../question/double_question_result.dart | 7 +- .../question/image_question_result.dart | 4 +- .../question/image_question_result.g.dart | 4 +- .../question/integer_question_result.dart | 7 +- .../multiple_choice_question_result.dart | 7 +- .../multiple_double_question_result.dart | 7 +- .../question/scale_question_result.dart | 7 +- .../single_choice_question_result.dart | 7 +- .../result/question/text_question_result.dart | 7 +- .../result/question/time_question_result.dart | 14 +- lib/src/result/question_result.dart | 2 +- lib/src/result/result.dart | 2 +- .../result/step/completion_step_result.dart | 9 +- .../result/step/instruction_step_result.dart | 7 +- lib/src/result/step/video_step_result.dart | 13 +- lib/src/result/step_result.dart | 21 +- lib/src/result/survey/survey_result.dart | 5 +- lib/src/steps/cms_steps/audio_cms_step.dart | 26 + lib/src/steps/cms_steps/audio_cms_step.g.dart | 16 + lib/src/steps/cms_steps/cms_content_step.dart | 7 + .../steps/cms_steps/markdown_cms_step.dart | 26 + .../steps/cms_steps/markdown_cms_step.g.dart | 17 + lib/src/steps/cms_steps/video_cms_step.dart | 26 + lib/src/steps/cms_steps/video_cms_step.g.dart | 16 + lib/src/steps/identifier/identifier.dart | 6 +- lib/src/steps/identifier/step_identifier.dart | 5 +- lib/src/steps/predefined_steps/cms_step.dart | 28 + .../predefined_steps/completion_step.dart | 11 +- .../predefined_steps/instruction_step.dart | 9 +- .../steps/predefined_steps/question_step.dart | 7 +- lib/src/steps/step.dart | 16 +- lib/src/survey_configuration.dart | 34 + lib/src/survey_kit.dart | 59 +- ...r.dart => survey_presenter_inherited.dart} | 125 ++-- lib/src/task/identifier/task_identifier.dart | 1 + lib/src/task/navigable_task.dart | 33 +- lib/src/task/ordered_task.dart | 5 +- lib/src/task/task.dart | 10 +- lib/src/views/boolean_answer_view.dart | 4 +- lib/src/views/cms_step_view.dart | 29 + lib/src/views/completion_view.dart | 30 +- lib/src/views/date_answer_view.dart | 12 +- .../views/decoration/input_decoration.dart | 8 +- lib/src/views/double_answer_view.dart | 8 +- lib/src/views/image_answer_view.dart | 36 +- lib/src/views/instruction_view.dart | 5 +- lib/src/views/integer_answer_view.dart | 8 +- .../multiple_auto_complete_answer_view.dart | 26 +- .../views/multiple_choice_answer_view.dart | 9 +- .../views/multiple_double_answer_view.dart | 36 +- lib/src/views/scale_answer_view.dart | 6 +- lib/src/views/single_choice_answer_view.dart | 4 +- lib/src/views/text_answer_view.dart | 8 +- lib/src/views/widget/selection_list_tile.dart | 2 +- lib/src/views/widget/step_view.dart | 7 +- lib/src/views/widget/survey_app_bar.dart | 15 +- lib/src/views/widget/time_picker_widget.dart | 411 ++++++------ lib/src/widget/survey_kit_audio_player.dart | 56 ++ lib/src/widget/survey_kit_markdown.dart | 19 + lib/src/widget/survey_kit_video_player.dart | 67 ++ lib/src/widget/survey_progress.dart | 102 +-- .../widget/survey_progress_configuration.dart | 2 +- lib/survey_kit.dart | 7 +- pubspec.lock | 158 ++++- pubspec.yaml | 5 +- .../multiple_choice_question_result_test.dart | 2 +- .../question/single_choice_result_test.dart | 2 +- .../question/time_question_result_test.dart | 2 +- .../result/step/video_step_result_test.dart | 2 +- test/src/survey/survey_result_test.dart | 4 +- test/steps/identifier/identifier_test.dart | 5 +- test/steps/step_test.dart | 20 +- test/surveykit_flutter_test.dart | 8 +- test/task/navigable_task_test.dart | 11 +- test/task/ordered_task_test.dart | 5 +- 136 files changed, 1671 insertions(+), 2270 deletions(-) delete mode 100644 analysis_option.yaml create mode 100644 analysis_options.yaml delete mode 100644 android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java delete mode 100644 example/integration_test/app_test.dart delete mode 100644 example/macos/.gitignore delete mode 100644 example/macos/Flutter/Flutter-Debug.xcconfig delete mode 100644 example/macos/Flutter/Flutter-Release.xcconfig delete mode 100644 example/macos/Flutter/GeneratedPluginRegistrant.swift delete mode 100644 example/macos/Podfile delete mode 100644 example/macos/Podfile.lock delete mode 100644 example/macos/Runner.xcodeproj/project.pbxproj delete mode 100644 example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 example/macos/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 example/macos/Runner/AppDelegate.swift delete mode 100644 example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png delete mode 100644 example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png delete mode 100644 example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png delete mode 100644 example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png delete mode 100644 example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png delete mode 100644 example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png delete mode 100644 example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png delete mode 100644 example/macos/Runner/Base.lproj/MainMenu.xib delete mode 100644 example/macos/Runner/Configs/AppInfo.xcconfig delete mode 100644 example/macos/Runner/Configs/Debug.xcconfig delete mode 100644 example/macos/Runner/Configs/Release.xcconfig delete mode 100644 example/macos/Runner/Configs/Warnings.xcconfig delete mode 100644 example/macos/Runner/DebugProfile.entitlements delete mode 100644 example/macos/Runner/Info.plist delete mode 100644 example/macos/Runner/MainFlutterWindow.swift delete mode 100644 example/macos/Runner/Release.entitlements create mode 100644 lib/src/steps/cms_steps/audio_cms_step.dart create mode 100644 lib/src/steps/cms_steps/audio_cms_step.g.dart create mode 100644 lib/src/steps/cms_steps/cms_content_step.dart create mode 100644 lib/src/steps/cms_steps/markdown_cms_step.dart create mode 100644 lib/src/steps/cms_steps/markdown_cms_step.g.dart create mode 100644 lib/src/steps/cms_steps/video_cms_step.dart create mode 100644 lib/src/steps/cms_steps/video_cms_step.g.dart create mode 100644 lib/src/steps/predefined_steps/cms_step.dart create mode 100644 lib/src/survey_configuration.dart rename lib/src/{presenter/survey_presenter.dart => survey_presenter_inherited.dart} (65%) create mode 100644 lib/src/views/cms_step_view.dart create mode 100644 lib/src/widget/survey_kit_audio_player.dart create mode 100644 lib/src/widget/survey_kit_markdown.dart create mode 100644 lib/src/widget/survey_kit_video_player.dart diff --git a/analysis_option.yaml b/analysis_option.yaml deleted file mode 100644 index 7febab12..00000000 --- a/analysis_option.yaml +++ /dev/null @@ -1,233 +0,0 @@ -# Specify analysis options. -# -# Until there are meta linter rules, each desired lint must be explicitly enabled. -# See: https://github.com/dart-lang/linter/issues/288 -# -# For a list of lints, see: http://dart-lang.github.io/linter/lints/ -# See the configuration guide for more -# https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer -# -# There are other similar analysis options files in the flutter repos, -# which should be kept in sync with this file: -# -# - analysis_options.yaml (this file) -# - packages/flutter/lib/analysis_options_user.yaml -# - https://github.com/flutter/plugins/blob/master/analysis_options.yaml -# - https://github.com/flutter/engine/blob/master/analysis_options.yaml -# -# This file contains the analysis options used by Flutter tools, such as IntelliJ, -# Android Studio, and the `flutter analyze` command. -include: package:extra_pedantic/analysis_options.yaml - -exclude: - - "**/*.g.dart" - -analyzer: - strong-mode: - implicit-casts: false - implicit-dynamic: false - errors: - # treat missing required parameters as a warning (not a hint) - missing_required_param: warning - # treat missing returns as a warning (not a hint) - missing_return: warning - # allow having TODOs in the code - todo: ignore - # allow self-reference to deprecated members (we do this because otherwise we have - # to annotate every member in every test, assert, etc, when we deprecate something) - deprecated_member_use_from_same_package: ignore - # Ignore analyzer hints for updating pubspecs when using Future or - # Stream and not importing dart:async - # Please see https://github.com/flutter/flutter/pull/24528 for details. - sdk_version_async_exported_from_core: ignore - exclude: - - "bin/cache/**" - # the following two are relative to the stocks example and the flutter package respectively - # see https://github.com/dart-lang/sdk/issues/28463 - - "lib/i18n/messages_*.dart" - - "lib/src/http/**" - - "test_fixes/**" - -linter: - rules: - # these rules are documented on and in the same order as - # the Dart Lint rules page to make maintenance easier - # https://github.com/dart-lang/linter/blob/master/example/all.yaml - - always_declare_return_types - - always_put_control_body_on_new_line - # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 - - always_require_non_null_named_parameters - - always_specify_types - # - always_use_package_imports # we do this commonly - - annotate_overrides - # - avoid_annotating_with_dynamic # conflicts with always_specify_types - # - avoid_as # required for implicit-casts: true - - avoid_bool_literals_in_conditional_expressions - # - avoid_catches_without_on_clauses # we do this commonly - # - avoid_catching_errors # we do this commonly - - avoid_classes_with_only_static_members - # - avoid_double_and_int_checks # only useful when targeting JS runtime - - avoid_empty_else - - avoid_equals_and_hash_code_on_mutable_classes - # - avoid_escaping_inner_quotes # not yet tested - - avoid_field_initializers_in_const_classes - - avoid_function_literals_in_foreach_calls - # - avoid_implementing_value_types # not yet tested - - avoid_init_to_null - # - avoid_js_rounded_ints # only useful when targeting JS runtime - - avoid_null_checks_in_equality_operators - # - avoid_positional_boolean_parameters # not yet tested - # - avoid_print # not yet tested - # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) - # - avoid_redundant_argument_values # not yet tested - - avoid_relative_lib_imports - - avoid_renaming_method_parameters - - avoid_return_types_on_setters - # - avoid_returning_null # there are plenty of valid reasons to return null - # - avoid_returning_null_for_future # not yet tested - - avoid_returning_null_for_void - # - avoid_returning_this # there are plenty of valid reasons to return this - # - avoid_setters_without_getters # not yet tested - - avoid_shadowing_type_parameters - - avoid_single_cascade_in_expression_statements - - avoid_slow_async_io - # - avoid_type_to_string # we do this commonly - - avoid_types_as_parameter_names - # - avoid_types_on_closure_parameters # conflicts with always_specify_types - # - avoid_unnecessary_containers # not yet tested - - avoid_unused_constructor_parameters - - avoid_void_async - # - avoid_web_libraries_in_flutter # not yet tested - - await_only_futures - - camel_case_extensions - - camel_case_types - - cancel_subscriptions - # - cascade_invocations # not yet tested - - cast_nullable_to_non_nullable - # - close_sinks # not reliable enough - # - comment_references # blocked on https://github.com/flutter/flutter/issues/20765 - # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 - - control_flow_in_finally - # - curly_braces_in_flow_control_structures # not required by flutter style - # - diagnostic_describe_all_properties # not yet tested - - directives_ordering - # - do_not_use_environment # we do this commonly - - empty_catches - - empty_constructor_bodies - - empty_statements - - exhaustive_cases - # - file_names # not yet tested - - flutter_style_todos - - hash_and_equals - - implementation_imports - # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 - - iterable_contains_unrelated_type - # - join_return_with_assignment # not required by flutter style - - leading_newlines_in_multiline_strings - - library_names - - library_prefixes - # - lines_longer_than_80_chars # not required by flutter style - - list_remove_unrelated_type - # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181 - # - missing_whitespace_between_adjacent_strings # not yet tested - - no_adjacent_strings_in_list - # - no_default_cases # too many false positives - - no_duplicate_case_values - - no_logic_in_create_state - # - no_runtimeType_toString # ok in tests; we enable this only in packages/ - - non_constant_identifier_names - - null_check_on_nullable_type_parameter - # - null_closures # not required by flutter style - # - omit_local_variable_types # opposite of always_specify_types - # - one_member_abstracts # too many false positives - # - only_throw_errors # https://github.com/flutter/flutter/issues/5792 - - overridden_fields - - package_api_docs - # - package_names # non conforming packages in sdk - - package_prefixed_library_names - # - parameter_assignments # we do this commonly - - prefer_adjacent_string_concatenation - - prefer_asserts_in_initializer_lists - # - prefer_asserts_with_message # not required by flutter style - - prefer_collection_literals - - prefer_conditional_assignment - - prefer_const_constructors - - prefer_const_constructors_in_immutables - - prefer_const_declarations - - prefer_const_literals_to_create_immutables - # - prefer_constructors_over_static_methods # far too many false positives - - prefer_contains - # - prefer_double_quotes # opposite of prefer_single_quotes - - prefer_equal_for_default_values - # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods - - prefer_final_fields - - prefer_final_in_for_each - - prefer_final_locals - - prefer_for_elements_to_map_fromIterable - - prefer_foreach - # - prefer_function_declarations_over_variables # not yet tested - - prefer_generic_function_type_aliases - - prefer_if_elements_to_conditional_expressions - - prefer_if_null_operators - - prefer_initializing_formals - - prefer_inlined_adds - # - prefer_int_literals # not yet tested - # - prefer_interpolation_to_compose_strings # not yet tested - - prefer_is_empty - - prefer_is_not_empty - - prefer_is_not_operator - - prefer_iterable_whereType - # - prefer_mixin # https://github.com/dart-lang/language/issues/32 - # - prefer_null_aware_operators # disable until NNBD, see https://github.com/flutter/flutter/pull/32711#issuecomment-492930932 - # - prefer_relative_imports # not yet tested - - prefer_single_quotes - - prefer_spread_collections - - prefer_typing_uninitialized_variables - - prefer_void_to_null - # - provide_deprecation_message # not yet tested - # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml - - recursive_getters - # - sized_box_for_whitespace # not yet tested - - slash_for_doc_comments - # - sort_child_properties_last # not yet tested - - sort_constructors_first - # - sort_pub_dependencies # prevents separating pinned transitive dependencies - - sort_unnamed_constructors_first - - test_types_in_equals - - throw_in_finally - - tighten_type_of_initializing_formals - # - type_annotate_public_apis # subset of always_specify_types - - type_init_formals - # - unawaited_futures # too many false positives - # - unnecessary_await_in_return # not yet tested - - unnecessary_brace_in_string_interps - - unnecessary_const - # - unnecessary_final # conflicts with prefer_final_locals - - unnecessary_getters_setters - # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 - - unnecessary_new - - unnecessary_null_aware_assignments - # - unnecessary_null_checks # not yet tested - - unnecessary_null_in_if_null_operators - - unnecessary_nullable_for_final_variable_declarations - - unnecessary_overrides - - unnecessary_parenthesis - # - unnecessary_raw_strings # not yet tested - - unnecessary_statements - - unnecessary_string_escapes - - unnecessary_string_interpolations - - unnecessary_this - - unrelated_type_equality_checks - # - unsafe_html # not yet tested - - use_full_hex_values_for_flutter_colors - # - use_function_type_syntax_for_parameters # not yet tested - - use_is_even_rather_than_modulo - # - use_key_in_widget_constructors # not yet tested - - use_late_for_private_fields_and_variables - - use_raw_strings - - use_rethrow_when_possible - # - use_setters_to_change_properties # not yet tested - # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 - # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review - - valid_regexps - - void_checks \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 00000000..d4b479d7 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,189 @@ +analyzer: + strong-mode: + implicit-casts: false + implicit-dynamic: false + + errors: + close_sinks: ignore + missing_required_param: error + missing_return: error + # Ignored because of freezed and JsonKey (https://github.com/rrousselGit/freezed/issues/488) + invalid_annotation_target: ignore + body_might_complete_normally_nullable: ignore + + exclude: + - test/.test_coverage.dart + - lib/generated_plugin_registrant.dart + - packages/** + - "**/*.g.dart" + - "**/*.freezed.dart" + +linter: + rules: + - always_declare_return_types + - always_require_non_null_named_parameters + - always_use_package_imports + - annotate_overrides + - avoid_bool_literals_in_conditional_expressions + - avoid_catching_errors + - avoid_double_and_int_checks + - avoid_dynamic_calls + - avoid_empty_else + - avoid_equals_and_hash_code_on_mutable_classes + - avoid_escaping_inner_quotes + - avoid_field_initializers_in_const_classes + - avoid_function_literals_in_foreach_calls + - avoid_init_to_null + - avoid_js_rounded_ints + - avoid_null_checks_in_equality_operators + - avoid_positional_boolean_parameters + - avoid_print + # - avoid_private_typedef_functions + # - avoid_redundant_argument_values + - avoid_relative_lib_imports + - avoid_renaming_method_parameters + - avoid_return_types_on_setters + - avoid_returning_null + - avoid_returning_null_for_future + - avoid_returning_null_for_void + - avoid_returning_this + - avoid_setters_without_getters + - avoid_shadowing_type_parameters + - avoid_single_cascade_in_expression_statements + - avoid_slow_async_io + - avoid_type_to_string + - avoid_types_as_parameter_names + - avoid_unnecessary_containers + - avoid_unused_constructor_parameters + - avoid_void_async + - avoid_web_libraries_in_flutter + - await_only_futures + - camel_case_extensions + - camel_case_types + - cancel_subscriptions + - cascade_invocations + - cast_nullable_to_non_nullable + - comment_references + - constant_identifier_names + - control_flow_in_finally + - curly_braces_in_flow_control_structures + - deprecated_consistency + - directives_ordering + - empty_catches + - empty_constructor_bodies + - empty_statements + # - eol_at_end_of_file + - exhaustive_cases + - file_names + - flutter_style_todos + - hash_and_equals + - implementation_imports + - invariant_booleans + - iterable_contains_unrelated_type + - join_return_with_assignment + - leading_newlines_in_multiline_strings + - library_names + - library_prefixes + # - library_private_types_in_public_api + # - lines_longer_than_80_chars + - list_remove_unrelated_type + - literal_only_boolean_expressions + - missing_whitespace_between_adjacent_strings + - no_adjacent_strings_in_list + - no_default_cases + - no_duplicate_case_values + - no_logic_in_create_state + - no_runtimeType_toString + - non_constant_identifier_names + # - noop_primitive_operations + - null_check_on_nullable_type_parameter + - null_closures + - omit_local_variable_types + - only_throw_errors + - overridden_fields + - package_api_docs + - package_names + - package_prefixed_library_names + - parameter_assignments + - prefer_adjacent_string_concatenation + - prefer_asserts_in_initializer_lists + - prefer_asserts_with_message + - prefer_collection_literals + - prefer_conditional_assignment + - prefer_const_constructors + - prefer_const_constructors_in_immutables + - prefer_const_declarations + - prefer_const_literals_to_create_immutables + - prefer_constructors_over_static_methods + - prefer_contains + - prefer_equal_for_default_values + - prefer_final_fields + - prefer_final_in_for_each + - prefer_final_locals + - prefer_for_elements_to_map_fromIterable + - prefer_function_declarations_over_variables + - prefer_generic_function_type_aliases + - prefer_if_elements_to_conditional_expressions + - prefer_if_null_operators + - prefer_initializing_formals + - prefer_inlined_adds + # - prefer_int_literals + - prefer_interpolation_to_compose_strings + - prefer_is_empty + - prefer_is_not_empty + - prefer_is_not_operator + - prefer_iterable_whereType + - prefer_null_aware_operators + # - prefer_null_aware_method_calls + - prefer_single_quotes + - prefer_spread_collections + - prefer_typing_uninitialized_variables + - prefer_void_to_null + - provide_deprecation_message + # - public_member_api_docs + - recursive_getters + - require_trailing_commas + # - sized_box_for_whitespace //To error prone + - slash_for_doc_comments + - sort_child_properties_last + # - sort_constructors_first + - sort_pub_dependencies + - sort_unnamed_constructors_first + - test_types_in_equals + - throw_in_finally + - tighten_type_of_initializing_formals + - type_annotate_public_apis + - type_init_formals + - unawaited_futures + - unnecessary_await_in_return + - unnecessary_brace_in_string_interps + - unnecessary_const + - unnecessary_getters_setters + - unnecessary_lambdas + - unnecessary_new + - unnecessary_null_aware_assignments + - unnecessary_null_checks + - unnecessary_null_in_if_null_operators + - unnecessary_nullable_for_final_variable_declarations + - unnecessary_overrides + - unnecessary_parenthesis + - unnecessary_raw_strings + - unnecessary_statements + - unnecessary_string_escapes + - unnecessary_string_interpolations + - unnecessary_this + - unrelated_type_equality_checks + # - use_build_context_synchronously + - use_full_hex_values_for_flutter_colors + - use_function_type_syntax_for_parameters + - use_is_even_rather_than_modulo + - use_key_in_widget_constructors + - use_late_for_private_fields_and_variables + - use_named_constants + - use_raw_strings + - use_rethrow_when_possible + - use_setters_to_change_properties + - use_string_buffers + - use_to_and_as_if_applicable + - valid_regexps + - void_checks \ No newline at end of file diff --git a/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java deleted file mode 100644 index 6aa3b529..00000000 --- a/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.flutter.plugins; - -import io.flutter.plugin.common.PluginRegistry; -import io.flutter.plugins.camera.CameraPlugin; -import io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin; -import io.flutter.plugins.imagepicker.ImagePickerPlugin; -import io.flutter.plugins.videoplayer.VideoPlayerPlugin; - -/** - * Generated file. Do not edit. - */ -public final class GeneratedPluginRegistrant { - public static void registerWith(PluginRegistry registry) { - if (alreadyRegisteredWith(registry)) { - return; - } - CameraPlugin.registerWith(registry.registrarFor("io.flutter.plugins.camera.CameraPlugin")); - FlutterAndroidLifecyclePlugin.registerWith(registry.registrarFor("io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin")); - ImagePickerPlugin.registerWith(registry.registrarFor("io.flutter.plugins.imagepicker.ImagePickerPlugin")); - VideoPlayerPlugin.registerWith(registry.registrarFor("io.flutter.plugins.videoplayer.VideoPlayerPlugin")); - } - - private static boolean alreadyRegisteredWith(PluginRegistry registry) { - final String key = GeneratedPluginRegistrant.class.getCanonicalName(); - if (registry.hasPlugin(key)) { - return true; - } - registry.registrarFor(key); - return false; - } -} diff --git a/example/integration_test/app_test.dart b/example/integration_test/app_test.dart deleted file mode 100644 index b0498d63..00000000 --- a/example/integration_test/app_test.dart +++ /dev/null @@ -1,16 +0,0 @@ -// This is a basic Flutter integration test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter_test/flutter_test.dart'; - -void main() => run(_testMain); - -run(void Function() testMain) {} - -void _testMain() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async {}); -} diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index b318a7d7..806ae991 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,32 +1,44 @@ PODS: + - audioplayers_darwin (0.0.1): + - Flutter - camera_avfoundation (0.0.1): - Flutter - Flutter (1.0.0) - image_picker_ios (0.0.1): - Flutter + - path_provider_ios (0.0.1): + - Flutter - video_player_avfoundation (0.0.1): - Flutter DEPENDENCIES: + - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`) - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) - Flutter (from `Flutter`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) EXTERNAL SOURCES: + audioplayers_darwin: + :path: ".symlinks/plugins/audioplayers_darwin/ios" camera_avfoundation: :path: ".symlinks/plugins/camera_avfoundation/ios" Flutter: :path: Flutter image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" + path_provider_ios: + :path: ".symlinks/plugins/path_provider_ios/ios" video_player_avfoundation: :path: ".symlinks/plugins/video_player_avfoundation/ios" SPEC CHECKSUMS: + audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40 camera_avfoundation: 07c77549ea54ad95d8581be86617c094a46280d9 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb + path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 diff --git a/example/lib/main.dart b/example/lib/main.dart index a2ff6a37..1c6998fc 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -6,10 +7,12 @@ import 'package:flutter/services.dart'; import 'package:survey_kit/survey_kit.dart'; void main() { - runApp(MyApp()); + runApp(const MyApp()); } class MyApp extends StatefulWidget { + const MyApp({Key? key}) : super(key: key); + @override _MyAppState createState() => _MyAppState(); } @@ -32,12 +35,12 @@ class _MyAppState extends State { final task = snapshot.data!; return SurveyKit( onResult: (SurveyResult result) { - print(result.finishReason); + log(result.finishReason.toString()); Navigator.pushNamed(context, '/'); }, task: task, showProgress: true, - localizations: { + localizations: const { 'cancel': 'Cancel', 'next': 'Next', }, @@ -61,27 +64,27 @@ class _MyAppState extends State { iconTheme: const IconThemeData( color: Colors.cyan, ), - textSelectionTheme: TextSelectionThemeData( + textSelectionTheme: const TextSelectionThemeData( cursorColor: Colors.cyan, selectionColor: Colors.cyan, selectionHandleColor: Colors.cyan, ), - cupertinoOverrideTheme: CupertinoThemeData( + cupertinoOverrideTheme: const CupertinoThemeData( primaryColor: Colors.cyan, ), outlinedButtonTheme: OutlinedButtonThemeData( style: ButtonStyle( minimumSize: MaterialStateProperty.all( - Size(150.0, 60.0), + const Size(150.0, 60.0), ), side: MaterialStateProperty.resolveWith( (Set state) { if (state.contains(MaterialState.disabled)) { - return BorderSide( + return const BorderSide( color: Colors.grey, ); } - return BorderSide( + return const BorderSide( color: Colors.cyan, ); }, @@ -120,7 +123,7 @@ class _MyAppState extends State { ), ), ), - textTheme: TextTheme( + textTheme: const TextTheme( headline2: TextStyle( fontSize: 28.0, color: Colors.black, @@ -138,7 +141,7 @@ class _MyAppState extends State { color: Colors.black, ), ), - inputDecorationTheme: InputDecorationTheme( + inputDecorationTheme: const InputDecorationTheme( labelStyle: TextStyle( color: Colors.black, ), @@ -149,7 +152,7 @@ class _MyAppState extends State { ), ); } - return CircularProgressIndicator.adaptive(); + return const CircularProgressIndicator.adaptive(); }, ), ), @@ -159,17 +162,17 @@ class _MyAppState extends State { } Future getSampleTask() { - var task = NavigableTask( + final task = NavigableTask( id: TaskIdentifier(), steps: [ InstructionStep( title: 'Welcome to the\nQuickBird Studios\nHealth Survey', text: 'Get ready for a bunch of super random questions!', - buttonText: 'Let\'s go!', + buttonText: "Let's go!", ), QuestionStep( title: 'How old are you?', - answerFormat: IntegerAnswerFormat( + answerFormat: const IntegerAnswerFormat( defaultValue: 25, hint: 'Please enter your age', ), @@ -178,7 +181,7 @@ class _MyAppState extends State { QuestionStep( title: 'Medication?', text: 'Are you using any medication', - answerFormat: BooleanAnswerFormat( + answerFormat: const BooleanAnswerFormat( positiveAnswer: 'Yes', negativeAnswer: 'No', result: BooleanResult.POSITIVE, @@ -188,14 +191,14 @@ class _MyAppState extends State { title: 'Tell us about you', text: 'Tell us about yourself and why you want to improve your health.', - answerFormat: TextAnswerFormat( + answerFormat: const TextAnswerFormat( maxLines: 5, - validationRegEx: "^(?!\s*\$).+", + validationRegEx: r'^(?!s*$).+', ), ), QuestionStep( title: 'Select your body type', - answerFormat: ScaleAnswerFormat( + answerFormat: const ScaleAnswerFormat( step: 1, minimumValue: 1, maximumValue: 5, @@ -208,7 +211,7 @@ class _MyAppState extends State { title: 'Known allergies', text: 'Do you have any allergies that we should be aware of?', isOptional: false, - answerFormat: MultipleChoiceAnswerFormat( + answerFormat: const MultipleChoiceAnswerFormat( textChoices: [ TextChoice(text: 'Penicillin', value: 'Penicillin'), TextChoice(text: 'Latex', value: 'Latex'), @@ -221,7 +224,7 @@ class _MyAppState extends State { title: 'Done?', text: 'We are done, do you mind to tell us more about yourself?', isOptional: true, - answerFormat: SingleChoiceAnswerFormat( + answerFormat: const SingleChoiceAnswerFormat( textChoices: [ TextChoice(text: 'Yes', value: 'Yes'), TextChoice(text: 'No', value: 'No'), @@ -231,7 +234,7 @@ class _MyAppState extends State { ), QuestionStep( title: 'When did you wake up?', - answerFormat: TimeAnswerFormat( + answerFormat: const TimeAnswerFormat( defaultValue: TimeOfDay( hour: 12, minute: 0, @@ -259,9 +262,9 @@ class _MyAppState extends State { navigationRule: ConditionalNavigationRule( resultToStepIdentifierMapper: (input) { switch (input) { - case "Yes": + case 'Yes': return task.steps[0].stepIdentifier; - case "No": + case 'No': return task.steps[7].stepIdentifier; default: return null; @@ -274,7 +277,7 @@ class _MyAppState extends State { Future getJsonTask() async { final taskJson = await rootBundle.loadString('assets/example_json.json'); - final taskMap = json.decode(taskJson); + final taskMap = json.decode(taskJson) as Map; return Task.fromJson(taskMap); } diff --git a/example/macos/.gitignore b/example/macos/.gitignore deleted file mode 100644 index d2fd3772..00000000 --- a/example/macos/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/xcuserdata/ diff --git a/example/macos/Flutter/Flutter-Debug.xcconfig b/example/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index 4b81f9b2..00000000 --- a/example/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/example/macos/Flutter/Flutter-Release.xcconfig b/example/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index 5caa9d15..00000000 --- a/example/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift deleted file mode 100644 index cccf817a..00000000 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ /dev/null @@ -1,10 +0,0 @@ -// -// Generated file. Do not edit. -// - -import FlutterMacOS -import Foundation - - -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { -} diff --git a/example/macos/Podfile b/example/macos/Podfile deleted file mode 100644 index dade8dfa..00000000 --- a/example/macos/Podfile +++ /dev/null @@ -1,40 +0,0 @@ -platform :osx, '10.11' - -# 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/example/macos/Podfile.lock b/example/macos/Podfile.lock deleted file mode 100644 index 2dd77155..00000000 --- a/example/macos/Podfile.lock +++ /dev/null @@ -1,16 +0,0 @@ -PODS: - - FlutterMacOS (1.0.0) - -DEPENDENCIES: - - FlutterMacOS (from `Flutter/ephemeral`) - -EXTERNAL SOURCES: - FlutterMacOS: - :path: Flutter/ephemeral - -SPEC CHECKSUMS: - FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 - -PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c - -COCOAPODS: 1.11.3 diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index a31182c3..00000000 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,614 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 51; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - C5BB841EF34C16EF07BD72CE /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C254C71D972CDB96BB6F010C /* Pods_Runner.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 5C3D665D84BB6CA50895E54B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - C254C71D972CDB96BB6F010C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - CCC23E51A2CC6CF47FB99A62 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - D650CBEC706CEB2A77FC2CE5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C5BB841EF34C16EF07BD72CE /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 1EC9F9E8DBD9F3AA83B6D500 /* Pods */ = { - isa = PBXGroup; - children = ( - CCC23E51A2CC6CF47FB99A62 /* Pods-Runner.debug.xcconfig */, - D650CBEC706CEB2A77FC2CE5 /* Pods-Runner.release.xcconfig */, - 5C3D665D84BB6CA50895E54B /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - 1EC9F9E8DBD9F3AA83B6D500 /* Pods */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* example.app */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - C254C71D972CDB96BB6F010C /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 7BED113BE35462C766540B52 /* [CP] Check Pods Manifest.lock */, - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* example.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 0930; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; - 7BED113BE35462C766540B52 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index ae8ff59d..00000000 --- a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/example/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14..00000000 --- a/example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/example/macos/Runner/AppDelegate.swift b/example/macos/Runner/AppDelegate.swift deleted file mode 100644 index d53ef643..00000000 --- a/example/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Cocoa -import FlutterMacOS - -@NSApplicationMain -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } -} diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f1..00000000 --- a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 3c4935a7ca84f0976aca34b7f2895d65fb94d1ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46993 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 diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index ed4cc16421680a50164ba74381b4b35ceaa0ccfc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3276 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 N;OXk;vd$@?2>?>Ex^Vyi diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png deleted file mode 100644 index bcbf36df2f2aaaa0a63c7dabc94e600184229d0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5933 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 f$KZHO*s&vt|9^w-6P?|#0pRK8NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!ItFh?!xdN1Q+aGJ{c&& zS>O>_%)r1c48n{Iv*t(u1=&kHeO=ifbFy+6aSK)V_AxLppYn8Z42d|rc6w}vOsL55 z`t&mC&y2@JTEyg!eDiFX^k#CC!jq%>erB=yHqUP0XcDOTw6ko}L zX;EmMrq(fKk*eygEuA616;0)>@A{TK|55PV@70 z$OfzS*(VJxQev3J?yY?O=ul(v`fp}?u9z`JK3ugibK>)DyCwImZOF4d{xK%%Ks1*} zv$oa)9anR%lXIBUqYnhLmT>VOzHfNP?ZwJNZ!5$s9M08RynIvaXw>@G^T9@r9^KH1 zVy??F&uuk)bH9Y4pQY!hP58i_H6 znl-NcuCpLV6ZWU;4C zu@9exF&OZi`Bovq_m%T+WhU2kvkz@^_LpycBvqm3bMpLw8X-Or5sL>0AKE1$(k_L=_Zc=CUq#=x1-QZf)G7nHu@fmsQ1eN_N3+nTEz`4HI4Z6uVlE zJH+X&det8JU?tO?upcM4Z=cV!JV;yF>FfL5Q$M|W_2Z!P`S=}Wzp|_1^#d%e?_H`> zV@%vA$+bFVqhw9`U;TfP|5|PD{||OiYdor8P*i??|NJcb%kzT_73*7WE?Ua5hAnR2 z=7WE=PhTlJ#ZeRznjTUb;`E(wkMZrj4e|Hilz-mK>9cZHQY**5TUPw~u}k;u73KI}xAx!0m-)GVia|x^d3p~s_9gh83jA&Ra<8rM%`>U3x69t&NzbwWY}7Ar?)FK#IZ0z|d0H0EkRO w3{9;}4Xg|ebq&m|3=9_N6z8I7$jwj5OsmAL;bP(Gi$Dzwp00i_>zopr02+f8CIA2c diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png deleted file mode 100644 index e71a726136a47ed24125c7efc79d68a4a01961b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14800 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/macos/Runner/Configs/AppInfo.xcconfig b/example/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index 4c9e0861..00000000 --- a/example/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = example - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.quickbirdstudios.example - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2021 com.quickbirdstudios. All rights reserved. diff --git a/example/macos/Runner/Configs/Debug.xcconfig b/example/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd94..00000000 --- a/example/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/example/macos/Runner/Configs/Release.xcconfig b/example/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f495..00000000 --- a/example/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/example/macos/Runner/Configs/Warnings.xcconfig b/example/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf47..00000000 --- a/example/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/example/macos/Runner/DebugProfile.entitlements b/example/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index dddb8a30..00000000 --- a/example/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - diff --git a/example/macos/Runner/Info.plist b/example/macos/Runner/Info.plist deleted file mode 100644 index 4789daa6..00000000 --- a/example/macos/Runner/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/example/macos/Runner/MainFlutterWindow.swift b/example/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 2722837e..00000000 --- a/example/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController.init() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/example/macos/Runner/Release.entitlements b/example/macos/Runner/Release.entitlements deleted file mode 100644 index 852fa1a4..00000000 --- a/example/macos/Runner/Release.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.security.app-sandbox - - - diff --git a/example/pubspec.lock b/example/pubspec.lock index a350003a..2119a098 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -8,6 +8,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.3.0" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" async: dependency: transitive description: @@ -15,6 +22,55 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.9.0" + audioplayers: + dependency: transitive + description: + name: audioplayers + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + audioplayers_android: + dependency: transitive + description: + name: audioplayers_android + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + audioplayers_darwin: + dependency: transitive + description: + name: audioplayers_darwin + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + audioplayers_linux: + dependency: transitive + description: + name: audioplayers_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + audioplayers_platform_interface: + dependency: transitive + description: + name: audioplayers_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + audioplayers_web: + dependency: transitive + description: + name: audioplayers_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + audioplayers_windows: + dependency: transitive + description: + name: audioplayers_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" bloc: dependency: transitive description: @@ -127,6 +183,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.4" flutter: dependency: "direct main" description: flutter @@ -139,6 +209,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "8.0.1" + flutter_markdown: + dependency: transitive + description: + name: flutter_markdown + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.13" flutter_platform_widgets: dependency: transitive description: @@ -163,13 +240,6 @@ packages: description: flutter source: sdk version: "0.0.0" - go_router: - dependency: transitive - description: - name: go_router - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.0" html: dependency: transitive description: @@ -247,20 +317,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.5.0" - logging: + lottie: dependency: transitive description: - name: logging + name: lottie url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" - lottie: + version: "1.3.0" + markdown: dependency: transitive description: - name: lottie + name: markdown url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "6.0.1" matcher: dependency: transitive description: @@ -296,6 +366,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.2" + path_provider: + dependency: transitive + description: + name: path_provider + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.22" + path_provider_ios: + dependency: transitive + description: + name: path_provider_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.7" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.6" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" plugin_platform_interface: dependency: transitive description: @@ -303,6 +429,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + process: + dependency: transitive + description: + name: process + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.4" provider: dependency: transitive description: @@ -434,6 +567,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.10" + win32: + dependency: transitive + description: + name: win32 + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.2" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0+2" sdks: dart: ">=2.18.0 <3.0.0" flutter: ">=3.0.0" diff --git a/lib/src/answer_format/answer_format.dart b/lib/src/answer_format/answer_format.dart index 97042128..ac83fca2 100644 --- a/lib/src/answer_format/answer_format.dart +++ b/lib/src/answer_format/answer_format.dart @@ -3,11 +3,11 @@ import 'package:survey_kit/src/answer_format/boolean_answer_format.dart'; import 'package:survey_kit/src/answer_format/date_answer_format.dart'; import 'package:survey_kit/src/answer_format/double_answer_format.dart'; -import 'package:survey_kit/src/answer_format/multiple_choice_auto_complete_answer_format.dart'; -import 'package:survey_kit/src/answer_format/multiple_double_answer_format.dart'; import 'package:survey_kit/src/answer_format/image_answer_format.dart'; import 'package:survey_kit/src/answer_format/integer_answer_format.dart'; import 'package:survey_kit/src/answer_format/multiple_choice_answer_format.dart'; +import 'package:survey_kit/src/answer_format/multiple_choice_auto_complete_answer_format.dart'; +import 'package:survey_kit/src/answer_format/multiple_double_answer_format.dart'; import 'package:survey_kit/src/answer_format/scale_answer_format.dart'; import 'package:survey_kit/src/answer_format/single_choice_answer_format.dart'; import 'package:survey_kit/src/answer_format/text_answer_format.dart'; @@ -44,7 +44,7 @@ abstract class AnswerFormat { case 'file': return ImageAnswerFormat.fromJson(json); default: - throw AnswerFormatNotDefinedException(); + throw const AnswerFormatNotDefinedException(); } } Map toJson(); diff --git a/lib/src/answer_format/boolean_answer_format.dart b/lib/src/answer_format/boolean_answer_format.dart index c41a0468..39d01434 100644 --- a/lib/src/answer_format/boolean_answer_format.dart +++ b/lib/src/answer_format/boolean_answer_format.dart @@ -17,6 +17,7 @@ class BooleanAnswerFormat implements AnswerFormat { factory BooleanAnswerFormat.fromJson(Map json) => _$BooleanAnswerFormatFromJson(json); + @override Map toJson() => _$BooleanAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/date_answer_format.dart b/lib/src/answer_format/date_answer_format.dart index afd4ca3e..ddced727 100644 --- a/lib/src/answer_format/date_answer_format.dart +++ b/lib/src/answer_format/date_answer_format.dart @@ -18,18 +18,28 @@ class DateAnswerFormat implements AnswerFormat { this.defaultDate, this.minDate, this.maxDate, - }) : assert(minDate == null || maxDate == null || minDate.isBefore(maxDate)), - assert(defaultDate == null || - minDate == null || - defaultDate.isAtSameMomentAs(minDate) || - defaultDate.isAfter(minDate)), - assert(defaultDate == null || - maxDate == null || - defaultDate.isAtSameMomentAs(maxDate) || - defaultDate.isBefore(maxDate)), + }) : assert( + minDate == null || maxDate == null || minDate.isBefore(maxDate), + 'mindate must be before maxdate', + ), + assert( + defaultDate == null || + minDate == null || + defaultDate.isAtSameMomentAs(minDate) || + defaultDate.isAfter(minDate), + 'defaultDate must be after minDate', + ), + assert( + defaultDate == null || + maxDate == null || + defaultDate.isAtSameMomentAs(maxDate) || + defaultDate.isBefore(maxDate), + 'defaultDate must be before maxDate', + ), super(); factory DateAnswerFormat.fromJson(Map json) => _$DateAnswerFormatFromJson(json); + @override Map toJson() => _$DateAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/double_answer_format.dart b/lib/src/answer_format/double_answer_format.dart index f3f52cb6..ac55edf6 100644 --- a/lib/src/answer_format/double_answer_format.dart +++ b/lib/src/answer_format/double_answer_format.dart @@ -17,5 +17,6 @@ class DoubleAnswerFormat implements AnswerFormat { factory DoubleAnswerFormat.fromJson(Map json) => _$DoubleAnswerFormatFromJson(json); + @override Map toJson() => _$DoubleAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/image_answer_format.dart b/lib/src/answer_format/image_answer_format.dart index fea9a510..db89b22d 100644 --- a/lib/src/answer_format/image_answer_format.dart +++ b/lib/src/answer_format/image_answer_format.dart @@ -16,5 +16,6 @@ class ImageAnswerFormat implements AnswerFormat { factory ImageAnswerFormat.fromJson(Map json) => _$ImageAnswerFormatFromJson(json); + @override Map toJson() => _$ImageAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/image_answer_format.g.dart b/lib/src/answer_format/image_answer_format.g.dart index 756387d8..cfe5d228 100644 --- a/lib/src/answer_format/image_answer_format.g.dart +++ b/lib/src/answer_format/image_answer_format.g.dart @@ -8,12 +8,12 @@ part of 'image_answer_format.dart'; ImageAnswerFormat _$ImageAnswerFormatFromJson(Map json) => ImageAnswerFormat( - defaultValue: json['defaulValue'] as String?, - buttonText: json['hint'] as String? ?? '', + defaultValue: json['defaultValue'] as String?, + buttonText: json['buttonText'] as String? ?? 'Image: ', ); Map _$ImageAnswerFormatToJson(ImageAnswerFormat instance) => { 'defaultValue': instance.defaultValue, - 'hint': instance.buttonText, + 'buttonText': instance.buttonText, }; diff --git a/lib/src/answer_format/integer_answer_format.dart b/lib/src/answer_format/integer_answer_format.dart index ff939bfc..7969c122 100644 --- a/lib/src/answer_format/integer_answer_format.dart +++ b/lib/src/answer_format/integer_answer_format.dart @@ -15,5 +15,6 @@ class IntegerAnswerFormat implements AnswerFormat { factory IntegerAnswerFormat.fromJson(Map json) => _$IntegerAnswerFormatFromJson(json); + @override Map toJson() => _$IntegerAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/multi_double.dart b/lib/src/answer_format/multi_double.dart index bff53b12..e6696334 100644 --- a/lib/src/answer_format/multi_double.dart +++ b/lib/src/answer_format/multi_double.dart @@ -16,6 +16,9 @@ class MultiDouble { _$MultiDoubleFromJson(json); Map toJson() => _$MultiDoubleToJson(this); - bool operator ==(o) => o is MultiDouble && text == o.text && value == o.value; + @override + bool operator ==(Object other) => + other is MultiDouble && text == other.text && value == other.value; + @override int get hashCode => text.hashCode ^ value.hashCode; } diff --git a/lib/src/answer_format/multiple_choice_answer_format.dart b/lib/src/answer_format/multiple_choice_answer_format.dart index 413eea41..af2f1f3f 100644 --- a/lib/src/answer_format/multiple_choice_answer_format.dart +++ b/lib/src/answer_format/multiple_choice_answer_format.dart @@ -7,7 +7,7 @@ part 'multiple_choice_answer_format.g.dart'; @JsonSerializable() class MultipleChoiceAnswerFormat implements AnswerFormat { final List textChoices; - @JsonKey(defaultValue: const []) + @JsonKey(defaultValue: []) final List defaultSelection; @JsonKey(defaultValue: false) final bool otherField; @@ -20,5 +20,6 @@ class MultipleChoiceAnswerFormat implements AnswerFormat { factory MultipleChoiceAnswerFormat.fromJson(Map json) => _$MultipleChoiceAnswerFormatFromJson(json); + @override Map toJson() => _$MultipleChoiceAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/multiple_choice_auto_complete_answer_format.dart b/lib/src/answer_format/multiple_choice_auto_complete_answer_format.dart index a0400631..d19f5df6 100644 --- a/lib/src/answer_format/multiple_choice_auto_complete_answer_format.dart +++ b/lib/src/answer_format/multiple_choice_auto_complete_answer_format.dart @@ -7,9 +7,9 @@ part 'multiple_choice_auto_complete_answer_format.g.dart'; @JsonSerializable() class MultipleChoiceAutoCompleteAnswerFormat implements AnswerFormat { final List textChoices; - @JsonKey(defaultValue: const []) + @JsonKey(defaultValue: []) final List defaultSelection; - @JsonKey(defaultValue: const []) + @JsonKey(defaultValue: []) final List suggestions; @JsonKey(defaultValue: false) final bool otherField; @@ -22,8 +22,10 @@ class MultipleChoiceAutoCompleteAnswerFormat implements AnswerFormat { }) : super(); factory MultipleChoiceAutoCompleteAnswerFormat.fromJson( - Map json) => + Map json, + ) => _$MultipleChoiceAutoCompleteAnswerFormatFromJson(json); + @override Map toJson() => _$MultipleChoiceAutoCompleteAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/multiple_double_answer_format.dart b/lib/src/answer_format/multiple_double_answer_format.dart index 3e4395d2..583c439f 100644 --- a/lib/src/answer_format/multiple_double_answer_format.dart +++ b/lib/src/answer_format/multiple_double_answer_format.dart @@ -7,7 +7,7 @@ part 'multiple_double_answer_format.g.dart'; @JsonSerializable() class MultipleDoubleAnswerFormat implements AnswerFormat { final List? defaultValues; - @JsonKey(defaultValue: const []) + @JsonKey(defaultValue: []) final List hints; const MultipleDoubleAnswerFormat({ @@ -17,5 +17,6 @@ class MultipleDoubleAnswerFormat implements AnswerFormat { factory MultipleDoubleAnswerFormat.fromJson(Map json) => _$MultipleDoubleAnswerFormatFromJson(json); + @override Map toJson() => _$MultipleDoubleAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/scale_answer_format.dart b/lib/src/answer_format/scale_answer_format.dart index eff60f38..b8b118c3 100644 --- a/lib/src/answer_format/scale_answer_format.dart +++ b/lib/src/answer_format/scale_answer_format.dart @@ -23,5 +23,6 @@ class ScaleAnswerFormat implements AnswerFormat { factory ScaleAnswerFormat.fromJson(Map json) => _$ScaleAnswerFormatFromJson(json); + @override Map toJson() => _$ScaleAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/single_choice_answer_format.dart b/lib/src/answer_format/single_choice_answer_format.dart index f1a1055a..4380f8ef 100644 --- a/lib/src/answer_format/single_choice_answer_format.dart +++ b/lib/src/answer_format/single_choice_answer_format.dart @@ -16,5 +16,6 @@ class SingleChoiceAnswerFormat implements AnswerFormat { factory SingleChoiceAnswerFormat.fromJson(Map json) => _$SingleChoiceAnswerFormatFromJson(json); + @override Map toJson() => _$SingleChoiceAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/text_answer_format.dart b/lib/src/answer_format/text_answer_format.dart index 89b362a9..a0775b8d 100644 --- a/lib/src/answer_format/text_answer_format.dart +++ b/lib/src/answer_format/text_answer_format.dart @@ -14,16 +14,17 @@ class TextAnswerFormat implements AnswerFormat { /// to allow any type of an answer including an empty one; /// set it explicitly to null. /// - @JsonKey(defaultValue: '^(?!\s*\$).+') + @JsonKey(defaultValue: r'^(?!s*$).+') final String? validationRegEx; const TextAnswerFormat({ this.maxLines, this.hint = '', - this.validationRegEx = '^(?!\s*\$).+', + this.validationRegEx = r'^(?!s*$).+', }) : super(); factory TextAnswerFormat.fromJson(Map json) => _$TextAnswerFormatFromJson(json); + @override Map toJson() => _$TextAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/text_choice.dart b/lib/src/answer_format/text_choice.dart index f9b56c8a..e3bc43e8 100644 --- a/lib/src/answer_format/text_choice.dart +++ b/lib/src/answer_format/text_choice.dart @@ -16,6 +16,8 @@ class TextChoice { _$TextChoiceFromJson(json); Map toJson() => _$TextChoiceToJson(this); - bool operator ==(o) => o is TextChoice && text == o.text && value == o.value; + @override + bool operator ==(Object o) => o is TextChoice && text == o.text && value == o.value; + @override int get hashCode => text.hashCode ^ value.hashCode; } diff --git a/lib/src/answer_format/time_answer_formart.dart b/lib/src/answer_format/time_answer_formart.dart index 5516568c..95b47fd7 100644 --- a/lib/src/answer_format/time_answer_formart.dart +++ b/lib/src/answer_format/time_answer_formart.dart @@ -15,6 +15,7 @@ class TimeAnswerFormat implements AnswerFormat { factory TimeAnswerFormat.fromJson(Map json) => _$TimeAnswerFormatFromJson(json); + @override Map toJson() => _$TimeAnswerFormatToJson(this); } diff --git a/lib/src/controller/survey_controller.dart b/lib/src/controller/survey_controller.dart index 38e6c531..22886de0 100644 --- a/lib/src/controller/survey_controller.dart +++ b/lib/src/controller/survey_controller.dart @@ -1,8 +1,7 @@ import 'package:flutter/widgets.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:survey_kit/src/presenter/survey_event.dart'; -import 'package:survey_kit/src/presenter/survey_presenter.dart'; import 'package:survey_kit/src/result/question_result.dart'; +import 'package:survey_kit/src/survey_presenter_inherited.dart'; class SurveyController { /// Defines what should happen if the next step is called @@ -61,7 +60,7 @@ class SurveyController { onNextStep!(context, resultFunction); return; } - BlocProvider.of(context).add( + SurveyPresenterInherited.of(context).onEvent( NextStep( resultFunction.call(), ), @@ -76,9 +75,9 @@ class SurveyController { onStepBack!(context, resultFunction); return; } - BlocProvider.of(context).add( + SurveyPresenterInherited.of(context).onEvent( StepBack( - resultFunction != null ? resultFunction.call() : null, + resultFunction?.call(), ), ); } @@ -91,9 +90,9 @@ class SurveyController { onCloseSurvey!(context, resultFunction); return; } - BlocProvider.of(context).add( + SurveyPresenterInherited.of(context).onEvent( CloseSurvey( - resultFunction != null ? resultFunction.call() : null, + resultFunction?.call(), ), ); } diff --git a/lib/src/navigator/navigable_task_navigator.dart b/lib/src/navigator/navigable_task_navigator.dart index 60cd97da..c234bb6e 100644 --- a/lib/src/navigator/navigable_task_navigator.dart +++ b/lib/src/navigator/navigable_task_navigator.dart @@ -1,6 +1,6 @@ +import 'package:survey_kit/src/answer_format/text_choice.dart'; import 'package:survey_kit/src/navigator/rules/conditional_navigation_rule.dart'; import 'package:survey_kit/src/navigator/rules/direct_navigation_rule.dart'; -import 'package:survey_kit/src/navigator/rules/navigation_rule.dart'; import 'package:survey_kit/src/navigator/task_navigator.dart'; import 'package:survey_kit/src/result/question_result.dart'; import 'package:survey_kit/src/steps/step.dart'; @@ -14,19 +14,23 @@ class NavigableTaskNavigator extends TaskNavigator { Step? nextStep({required Step step, QuestionResult? questionResult}) { record(step); final navigableTask = task as NavigableTask; - NavigationRule? rule = - navigableTask.getRuleByStepIdentifier(step.stepIdentifier); + final rule = navigableTask.getRuleByStepIdentifier(step.stepIdentifier); if (rule == null) { return nextInList(step); } switch (rule.runtimeType) { case DirectNavigationRule: - return task.steps.firstWhere((element) => - element.stepIdentifier == - (rule as DirectNavigationRule).destinationStepIdentifier); + return task.steps.firstWhere( + (element) => + element.stepIdentifier == + (rule as DirectNavigationRule).destinationStepIdentifier, + ); case ConditionalNavigationRule: return evaluateNextStep( - step, rule as ConditionalNavigationRule, questionResult); + step, + rule as ConditionalNavigationRule, + questionResult, + ); } return nextInList(step); } @@ -39,12 +43,15 @@ class NavigableTaskNavigator extends TaskNavigator { return history.removeLast(); } - Step? evaluateNextStep(Step? step, ConditionalNavigationRule rule, - QuestionResult? questionResult) { + Step? evaluateNextStep( + Step? step, + ConditionalNavigationRule rule, + QuestionResult? questionResult, + ) { if (questionResult == null) { return nextInList(step); } - final result = questionResult.result; + final result = questionResult.result as List?; if (result == null) { return nextInList(step); } diff --git a/lib/src/navigator/rules/conditional_navigation_rule.dart b/lib/src/navigator/rules/conditional_navigation_rule.dart index 3236a05e..699b1ef8 100644 --- a/lib/src/navigator/rules/conditional_navigation_rule.dart +++ b/lib/src/navigator/rules/conditional_navigation_rule.dart @@ -12,7 +12,7 @@ class ConditionalNavigationRule implements NavigationRule { resultToStepIdentifierMapper: (input) { for (final MapEntry entry in inputValues.entries) { if (entry.key == input) { - return StepIdentifier(id: entry.value); + return StepIdentifier(id: entry.value as String); } } return null; @@ -20,5 +20,8 @@ class ConditionalNavigationRule implements NavigationRule { ); } - Map toJson() => {'values': {}}; + @override + Map toJson() => { + 'values': {}, + }; } diff --git a/lib/src/navigator/rules/direct_navigation_rule.dart b/lib/src/navigator/rules/direct_navigation_rule.dart index 07eed500..c01f8901 100644 --- a/lib/src/navigator/rules/direct_navigation_rule.dart +++ b/lib/src/navigator/rules/direct_navigation_rule.dart @@ -12,5 +12,6 @@ class DirectNavigationRule implements NavigationRule { factory DirectNavigationRule.fromJson(Map json) => _$DirectNavigationRuleFromJson(json); + @override Map toJson() => _$DirectNavigationRuleToJson(this); } diff --git a/lib/src/navigator/rules/navigation_rule.dart b/lib/src/navigator/rules/navigation_rule.dart index 0d882099..2a6d0dc0 100644 --- a/lib/src/navigator/rules/navigation_rule.dart +++ b/lib/src/navigator/rules/navigation_rule.dart @@ -6,13 +6,13 @@ abstract class NavigationRule { const NavigationRule(); factory NavigationRule.fromJson(Map json) { - final type = json['type']; + final type = json['type'] as String; if (type == 'conditional') { return ConditionalNavigationRule.fromJson(json); } else if (type == 'direct') { return DirectNavigationRule.fromJson(json); } - throw RuleNotDefinedException(); + throw const RuleNotDefinedException(); } Map toJson(); } diff --git a/lib/src/navigator/task_navigator.dart b/lib/src/navigator/task_navigator.dart index 5f0706bf..6a5166d5 100644 --- a/lib/src/navigator/task_navigator.dart +++ b/lib/src/navigator/task_navigator.dart @@ -16,7 +16,7 @@ abstract class TaskNavigator { Step? nextInList(Step? step) { final currentIndex = task.steps.indexWhere( - (element) => element.stepIdentifier == step?.stepIdentifier); + (element) => element.stepIdentifier == step?.stepIdentifier,); return (currentIndex + 1 > task.steps.length - 1) ? null : task.steps[currentIndex + 1]; diff --git a/lib/src/presenter/survey_state.dart b/lib/src/presenter/survey_state.dart index 602c9703..4c543237 100644 --- a/lib/src/presenter/survey_state.dart +++ b/lib/src/presenter/survey_state.dart @@ -29,6 +29,28 @@ class PresentingSurveyState extends SurveyState { this.currentStepIndex = 0, this.isPreviousStep = false, }); + + @override + bool operator ==(Object other) => + other is PresentingSurveyState && + other.stepCount == stepCount && + other.appBarConfiguration == appBarConfiguration && + other.currentStep == currentStep && + other.steps == steps && + other.questionResults == questionResults && + other.result == result && + other.currentStepIndex == currentStepIndex && + other.isPreviousStep == isPreviousStep; + @override + int get hashCode => + stepCount.hashCode ^ + appBarConfiguration.hashCode ^ + currentStep.hashCode ^ + steps.hashCode ^ + questionResults.hashCode ^ + result.hashCode ^ + currentStepIndex.hashCode ^ + isPreviousStep.hashCode; } class SurveyResultState extends SurveyState { diff --git a/lib/src/result/question/boolean_question_result.dart b/lib/src/result/question/boolean_question_result.dart index 3ff59f4d..ec377a14 100644 --- a/lib/src/result/question/boolean_question_result.dart +++ b/lib/src/result/question/boolean_question_result.dart @@ -1,14 +1,13 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/answer_format/boolean_answer_format.dart'; -import 'package:survey_kit/src/steps/identifier/identifier.dart'; import 'package:survey_kit/src/result/question_result.dart'; - -import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/steps/identifier/identifier.dart'; part 'boolean_question_result.g.dart'; @JsonSerializable(explicitToJson: true) class BooleanQuestionResult extends QuestionResult { - BooleanQuestionResult({ + const BooleanQuestionResult({ required Identifier id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/result/question/date_question_result.dart b/lib/src/result/question/date_question_result.dart index 6f9e2fef..78a77ff9 100644 --- a/lib/src/result/question/date_question_result.dart +++ b/lib/src/result/question/date_question_result.dart @@ -1,13 +1,12 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/result/question_result.dart'; import 'package:survey_kit/src/steps/identifier/identifier.dart'; -import 'package:json_annotation/json_annotation.dart'; - part 'date_question_result.g.dart'; @JsonSerializable(explicitToJson: true) class DateQuestionResult extends QuestionResult { - DateQuestionResult({ + const DateQuestionResult({ required Identifier id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/result/question/double_question_result.dart b/lib/src/result/question/double_question_result.dart index c63b1e79..82b4cc72 100644 --- a/lib/src/result/question/double_question_result.dart +++ b/lib/src/result/question/double_question_result.dart @@ -1,13 +1,12 @@ -import 'package:survey_kit/src/steps/identifier/identifier.dart'; -import 'package:survey_kit/src/result/question_result.dart'; - import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/result/question_result.dart'; +import 'package:survey_kit/src/steps/identifier/identifier.dart'; part 'double_question_result.g.dart'; @JsonSerializable(explicitToJson: true) class DoubleQuestionResult extends QuestionResult { - DoubleQuestionResult({ + const DoubleQuestionResult({ required Identifier id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/result/question/image_question_result.dart b/lib/src/result/question/image_question_result.dart index 5b67637a..3630c773 100644 --- a/lib/src/result/question/image_question_result.dart +++ b/lib/src/result/question/image_question_result.dart @@ -1,10 +1,12 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/result/question_result.dart'; import 'package:survey_kit/src/steps/identifier/identifier.dart'; part 'image_question_result.g.dart'; +@JsonSerializable() class ImageQuestionResult extends QuestionResult { - ImageQuestionResult({ + const ImageQuestionResult({ required Identifier id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/result/question/image_question_result.g.dart b/lib/src/result/question/image_question_result.g.dart index 704afed2..8350dd80 100644 --- a/lib/src/result/question/image_question_result.g.dart +++ b/lib/src/result/question/image_question_result.g.dart @@ -18,9 +18,9 @@ ImageQuestionResult _$ImageQuestionResultFromJson(Map json) => Map _$ImageQuestionResultToJson( ImageQuestionResult instance) => { - 'id': instance.id?.toJson(), + 'id': instance.id, 'startDate': instance.startDate.toIso8601String(), 'endDate': instance.endDate.toIso8601String(), - 'valueIdentifier': instance.valueIdentifier, 'result': instance.result, + 'valueIdentifier': instance.valueIdentifier, }; diff --git a/lib/src/result/question/integer_question_result.dart b/lib/src/result/question/integer_question_result.dart index b6b858f9..8bf65140 100644 --- a/lib/src/result/question/integer_question_result.dart +++ b/lib/src/result/question/integer_question_result.dart @@ -1,13 +1,12 @@ -import 'package:survey_kit/src/steps/identifier/identifier.dart'; -import 'package:survey_kit/src/result/question_result.dart'; - import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/result/question_result.dart'; +import 'package:survey_kit/src/steps/identifier/identifier.dart'; part 'integer_question_result.g.dart'; @JsonSerializable(explicitToJson: true) class IntegerQuestionResult extends QuestionResult { - IntegerQuestionResult({ + const IntegerQuestionResult({ required Identifier id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/result/question/multiple_choice_question_result.dart b/lib/src/result/question/multiple_choice_question_result.dart index 79762405..2bc39e2b 100644 --- a/lib/src/result/question/multiple_choice_question_result.dart +++ b/lib/src/result/question/multiple_choice_question_result.dart @@ -1,14 +1,13 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/answer_format/text_choice.dart'; -import 'package:survey_kit/src/steps/identifier/identifier.dart'; import 'package:survey_kit/src/result/question_result.dart'; - -import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/steps/identifier/identifier.dart'; part 'multiple_choice_question_result.g.dart'; @JsonSerializable(explicitToJson: true) class MultipleChoiceQuestionResult extends QuestionResult?> { - MultipleChoiceQuestionResult({ + const MultipleChoiceQuestionResult({ required Identifier id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/result/question/multiple_double_question_result.dart b/lib/src/result/question/multiple_double_question_result.dart index 72ccc8f8..779fdd24 100644 --- a/lib/src/result/question/multiple_double_question_result.dart +++ b/lib/src/result/question/multiple_double_question_result.dart @@ -1,14 +1,13 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/answer_format/multi_double.dart'; -import 'package:survey_kit/src/steps/identifier/identifier.dart'; import 'package:survey_kit/src/result/question_result.dart'; - -import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/steps/identifier/identifier.dart'; part 'multiple_double_question_result.g.dart'; @JsonSerializable(explicitToJson: true) class MultipleDoubleQuestionResult extends QuestionResult?> { - MultipleDoubleQuestionResult({ + const MultipleDoubleQuestionResult({ required Identifier id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/result/question/scale_question_result.dart b/lib/src/result/question/scale_question_result.dart index ec67a251..ae5fb4e4 100644 --- a/lib/src/result/question/scale_question_result.dart +++ b/lib/src/result/question/scale_question_result.dart @@ -1,13 +1,12 @@ -import 'package:survey_kit/src/steps/identifier/identifier.dart'; -import 'package:survey_kit/src/result/question_result.dart'; - import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/result/question_result.dart'; +import 'package:survey_kit/src/steps/identifier/identifier.dart'; part 'scale_question_result.g.dart'; @JsonSerializable(explicitToJson: true) class ScaleQuestionResult extends QuestionResult { - ScaleQuestionResult({ + const ScaleQuestionResult({ required Identifier id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/result/question/single_choice_question_result.dart b/lib/src/result/question/single_choice_question_result.dart index 9c8386b1..012aa290 100644 --- a/lib/src/result/question/single_choice_question_result.dart +++ b/lib/src/result/question/single_choice_question_result.dart @@ -1,14 +1,13 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/answer_format/text_choice.dart'; -import 'package:survey_kit/src/steps/identifier/identifier.dart'; import 'package:survey_kit/src/result/question_result.dart'; - -import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/steps/identifier/identifier.dart'; part 'single_choice_question_result.g.dart'; @JsonSerializable(explicitToJson: true) class SingleChoiceQuestionResult extends QuestionResult { - SingleChoiceQuestionResult({ + const SingleChoiceQuestionResult({ required Identifier id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/result/question/text_question_result.dart b/lib/src/result/question/text_question_result.dart index 59cea508..ddaf2447 100644 --- a/lib/src/result/question/text_question_result.dart +++ b/lib/src/result/question/text_question_result.dart @@ -1,13 +1,12 @@ -import 'package:survey_kit/src/steps/identifier/identifier.dart'; -import 'package:survey_kit/src/result/question_result.dart'; - import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/result/question_result.dart'; +import 'package:survey_kit/src/steps/identifier/identifier.dart'; part 'text_question_result.g.dart'; @JsonSerializable(explicitToJson: true) class TextQuestionResult extends QuestionResult { - TextQuestionResult({ + const TextQuestionResult({ required Identifier id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/result/question/time_question_result.dart b/lib/src/result/question/time_question_result.dart index 71a0cbdd..48b7fb3d 100644 --- a/lib/src/result/question/time_question_result.dart +++ b/lib/src/result/question/time_question_result.dart @@ -1,15 +1,14 @@ import 'package:flutter/material.dart'; -import 'package:survey_kit/src/steps/identifier/identifier.dart'; -import 'package:survey_kit/src/result/question_result.dart'; - import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/result/question_result.dart'; +import 'package:survey_kit/src/steps/identifier/identifier.dart'; part 'time_question_result.g.dart'; @JsonSerializable(explicitToJson: true) @TimeOfDayConverter() class TimeQuestionResult extends QuestionResult { - TimeQuestionResult({ + const TimeQuestionResult({ required Identifier id, required DateTime startDate, required DateTime endDate, @@ -71,13 +70,14 @@ class TimeOfDayConverter extends JsonConverter { } String _addLeadingZeroIfNeeded(int value) { - if (value < 10) + if (value < 10) { return '0$value'; + } return value.toString(); } - final String hourLabel = _addLeadingZeroIfNeeded(object.hour); - final String minuteLabel = _addLeadingZeroIfNeeded(object.minute); + final hourLabel = _addLeadingZeroIfNeeded(object.hour); + final minuteLabel = _addLeadingZeroIfNeeded(object.minute); return '$hourLabel:$minuteLabel'; } diff --git a/lib/src/result/question_result.dart b/lib/src/result/question_result.dart index bef898cf..648f68f5 100644 --- a/lib/src/result/question_result.dart +++ b/lib/src/result/question_result.dart @@ -4,7 +4,7 @@ import 'package:survey_kit/src/steps/identifier/identifier.dart'; abstract class QuestionResult extends Result { final T? result; final String? valueIdentifier; - QuestionResult({ + const QuestionResult({ required Identifier? id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/result/result.dart b/lib/src/result/result.dart index ca0fc1c8..7949f1b3 100644 --- a/lib/src/result/result.dart +++ b/lib/src/result/result.dart @@ -6,7 +6,7 @@ abstract class Result extends Equatable { final DateTime startDate; final DateTime endDate; - Result({ + const Result({ required this.id, required this.startDate, required this.endDate, diff --git a/lib/src/result/step/completion_step_result.dart b/lib/src/result/step/completion_step_result.dart index 62d603ea..c5897dd2 100644 --- a/lib/src/result/step/completion_step_result.dart +++ b/lib/src/result/step/completion_step_result.dart @@ -1,13 +1,12 @@ -import 'package:survey_kit/src/steps/identifier/identifier.dart'; -import 'package:survey_kit/src/result/question_result.dart'; - import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/result/question_result.dart'; +import 'package:survey_kit/src/steps/identifier/identifier.dart'; part 'completion_step_result.g.dart'; @JsonSerializable(explicitToJson: true) -class CompletionStepResult extends QuestionResult { - CompletionStepResult( +class CompletionStepResult extends QuestionResult { + const CompletionStepResult( Identifier id, DateTime startDate, DateTime endDate, diff --git a/lib/src/result/step/instruction_step_result.dart b/lib/src/result/step/instruction_step_result.dart index 9b82e03b..189acf83 100644 --- a/lib/src/result/step/instruction_step_result.dart +++ b/lib/src/result/step/instruction_step_result.dart @@ -1,13 +1,12 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/result/question_result.dart'; import 'package:survey_kit/src/steps/identifier/identifier.dart'; -import 'package:json_annotation/json_annotation.dart'; - part 'instruction_step_result.g.dart'; @JsonSerializable(explicitToJson: true) -class InstructionStepResult extends QuestionResult { - InstructionStepResult( +class InstructionStepResult extends QuestionResult { + const InstructionStepResult( Identifier id, DateTime startDate, DateTime endDate, diff --git a/lib/src/result/step/video_step_result.dart b/lib/src/result/step/video_step_result.dart index d6f72fba..da764e2d 100644 --- a/lib/src/result/step/video_step_result.dart +++ b/lib/src/result/step/video_step_result.dart @@ -1,8 +1,7 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/result/question_result.dart'; import 'package:survey_kit/src/steps/identifier/identifier.dart'; -import 'package:json_annotation/json_annotation.dart'; - part 'video_step_result.g.dart'; @JsonSerializable(explicitToJson: true) @@ -33,14 +32,14 @@ class VideoResult { final Duration leftVideoAt; final DateTime stayedInVideo; - factory VideoResult.fromJson(Map json) => - _$VideoResultFromJson(json); - - Map toJson() => _$VideoResultToJson(this); - const VideoResult({ required this.leftVideoAt, required this.stayedInVideo, }); + + factory VideoResult.fromJson(Map json) => + _$VideoResultFromJson(json); + + Map toJson() => _$VideoResultToJson(this); } diff --git a/lib/src/result/step_result.dart b/lib/src/result/step_result.dart index e9360be1..b31646f0 100644 --- a/lib/src/result/step_result.dart +++ b/lib/src/result/step_result.dart @@ -1,3 +1,4 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/result/question/boolean_question_result.dart'; import 'package:survey_kit/src/result/question/date_question_result.dart'; import 'package:survey_kit/src/result/question/double_question_result.dart'; @@ -8,14 +9,12 @@ import 'package:survey_kit/src/result/question/scale_question_result.dart'; import 'package:survey_kit/src/result/question/single_choice_question_result.dart'; import 'package:survey_kit/src/result/question/text_question_result.dart'; import 'package:survey_kit/src/result/question/time_question_result.dart'; +import 'package:survey_kit/src/result/question_result.dart'; import 'package:survey_kit/src/result/result.dart'; import 'package:survey_kit/src/result/step/completion_step_result.dart'; import 'package:survey_kit/src/result/step/instruction_step_result.dart'; import 'package:survey_kit/src/result/step/video_step_result.dart'; import 'package:survey_kit/src/steps/identifier/identifier.dart'; -import 'package:survey_kit/src/result/question_result.dart'; - -import 'package:json_annotation/json_annotation.dart'; part 'step_result.g.dart'; @@ -24,11 +23,11 @@ class StepResult extends Result { @_Converter() final List results; - StepResult( + const StepResult( {required Identifier? id, required DateTime startDate, required DateTime endDate, - required this.results}) + required this.results,}) : super(id: id, startDate: startDate, endDate: endDate); factory StepResult.fromQuestion({required QuestionResult questionResult}) { @@ -54,9 +53,9 @@ class _Converter implements JsonConverter, Object> { @override Object toJson(List questionResults) { - List> allQuestionResultsEncoded = []; + final allQuestionResultsEncoded = >[]; - for (QuestionResult qr in questionResults) { + for (final qr in questionResults) { if (qr is BooleanQuestionResult) { final qrJson = qr.toJson(); qrJson['type'] = (BooleanQuestionResult).toString(); @@ -114,7 +113,7 @@ class _Converter implements JsonConverter, Object> { qrJson['type'] = (VideoStepResult).toString(); allQuestionResultsEncoded.add(qrJson); } else { - throw ('Unhandled Question Result Type'); + throw 'Unhandled Question Result Type'; } } @@ -123,8 +122,8 @@ class _Converter implements JsonConverter, Object> { @override List fromJson(Object json) { - final List results = []; - for (var element in json as List) { + final results = []; + for (final element in json as List) { final qData = element as Map; final qType = qData['type'] as String; @@ -155,7 +154,7 @@ class _Converter implements JsonConverter, Object> { } else if (qType == (VideoStepResult).toString()) { results.add(VideoStepResult.fromJson(qData)); } else { - throw ('Unhandled Question Result Type'); + throw 'Unhandled Question Result Type'; } } diff --git a/lib/src/result/survey/survey_result.dart b/lib/src/result/survey/survey_result.dart index ef0b5367..564cdbca 100644 --- a/lib/src/result/survey/survey_result.dart +++ b/lib/src/result/survey/survey_result.dart @@ -1,9 +1,8 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/result/result.dart'; import 'package:survey_kit/src/result/step_result.dart'; import 'package:survey_kit/src/steps/identifier/identifier.dart'; -import 'package:json_annotation/json_annotation.dart'; - part 'survey_result.g.dart'; @JsonSerializable(explicitToJson: true) @@ -11,7 +10,7 @@ class SurveyResult extends Result { final FinishReason finishReason; final List results; - SurveyResult({ + const SurveyResult({ required Identifier? id, required DateTime startDate, required DateTime endDate, diff --git a/lib/src/steps/cms_steps/audio_cms_step.dart b/lib/src/steps/cms_steps/audio_cms_step.dart new file mode 100644 index 00000000..df37f8e9 --- /dev/null +++ b/lib/src/steps/cms_steps/audio_cms_step.dart @@ -0,0 +1,26 @@ +import 'package:flutter/widgets.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/steps/cms_steps/cms_content_step.dart'; +import 'package:survey_kit/src/widget/survey_kit_audio_player.dart'; + +part 'audio_cms_step.g.dart'; + +@JsonSerializable(explicitToJson: true) +class AudioCMSStep extends Content { + final String audioUrl; + + AudioCMSStep({ + required this.audioUrl, + }); + + @override + Widget createView() { + return SurveyKitAudioPlayer( + audioUrl: audioUrl, + ); + } + + factory AudioCMSStep.fromJson(Map json) => + _$AudioCMSStepFromJson(json); + Map toJson() => _$AudioCMSStepToJson(this); +} diff --git a/lib/src/steps/cms_steps/audio_cms_step.g.dart b/lib/src/steps/cms_steps/audio_cms_step.g.dart new file mode 100644 index 00000000..89484ba3 --- /dev/null +++ b/lib/src/steps/cms_steps/audio_cms_step.g.dart @@ -0,0 +1,16 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'audio_cms_step.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +AudioCMSStep _$AudioCMSStepFromJson(Map json) => AudioCMSStep( + audioUrl: json['audioUrl'] as String, + ); + +Map _$AudioCMSStepToJson(AudioCMSStep instance) => + { + 'audioUrl': instance.audioUrl, + }; diff --git a/lib/src/steps/cms_steps/cms_content_step.dart b/lib/src/steps/cms_steps/cms_content_step.dart new file mode 100644 index 00000000..be06fc0b --- /dev/null +++ b/lib/src/steps/cms_steps/cms_content_step.dart @@ -0,0 +1,7 @@ +import 'package:flutter/material.dart'; +import 'package:json_annotation/json_annotation.dart'; + +@JsonSerializable(explicitToJson: true) +abstract class Content { + Widget createView(); +} diff --git a/lib/src/steps/cms_steps/markdown_cms_step.dart b/lib/src/steps/cms_steps/markdown_cms_step.dart new file mode 100644 index 00000000..9757f8be --- /dev/null +++ b/lib/src/steps/cms_steps/markdown_cms_step.dart @@ -0,0 +1,26 @@ +import 'package:flutter/widgets.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/steps/cms_steps/cms_content_step.dart'; +import 'package:survey_kit/src/widget/survey_kit_markdown.dart'; + +part 'markdown_cms_step.g.dart'; + +@JsonSerializable(explicitToJson: true) +class MarkdownCMSStep extends Content { + final String markdown; + + MarkdownCMSStep({ + required this.markdown, + }); + + @override + Widget createView() { + return SurveyKitMarkdown( + markdown: markdown, + ); + } + + factory MarkdownCMSStep.fromJson(Map json) => + _$MarkdownCMSStepFromJson(json); + Map toJson() => _$MarkdownCMSStepToJson(this); +} diff --git a/lib/src/steps/cms_steps/markdown_cms_step.g.dart b/lib/src/steps/cms_steps/markdown_cms_step.g.dart new file mode 100644 index 00000000..134e8450 --- /dev/null +++ b/lib/src/steps/cms_steps/markdown_cms_step.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'markdown_cms_step.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +MarkdownCMSStep _$MarkdownCMSStepFromJson(Map json) => + MarkdownCMSStep( + markdown: json['markdown'] as String, + ); + +Map _$MarkdownCMSStepToJson(MarkdownCMSStep instance) => + { + 'markdown': instance.markdown, + }; diff --git a/lib/src/steps/cms_steps/video_cms_step.dart b/lib/src/steps/cms_steps/video_cms_step.dart new file mode 100644 index 00000000..e6b009f1 --- /dev/null +++ b/lib/src/steps/cms_steps/video_cms_step.dart @@ -0,0 +1,26 @@ +import 'package:flutter/widgets.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/steps/cms_steps/cms_content_step.dart'; +import 'package:survey_kit/src/widget/survey_kit_video_player.dart'; + +part 'video_cms_step.g.dart'; + +@JsonSerializable(explicitToJson: true) +class VideoCMSStep extends Content { + final String videoUrl; + + VideoCMSStep({ + required this.videoUrl, + }); + + @override + Widget createView() { + return SurveyKitVideoPlayer( + videoUrl: videoUrl, + ); + } + + factory VideoCMSStep.fromJson(Map json) => + _$VideoCMSStepFromJson(json); + Map toJson() => _$VideoCMSStepToJson(this); +} diff --git a/lib/src/steps/cms_steps/video_cms_step.g.dart b/lib/src/steps/cms_steps/video_cms_step.g.dart new file mode 100644 index 00000000..ba1606c7 --- /dev/null +++ b/lib/src/steps/cms_steps/video_cms_step.g.dart @@ -0,0 +1,16 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'video_cms_step.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +VideoCMSStep _$VideoCMSStepFromJson(Map json) => VideoCMSStep( + videoUrl: json['videoUrl'] as String, + ); + +Map _$VideoCMSStepToJson(VideoCMSStep instance) => + { + 'videoUrl': instance.videoUrl, + }; diff --git a/lib/src/steps/identifier/identifier.dart b/lib/src/steps/identifier/identifier.dart index d58f23ea..3ae5bc84 100644 --- a/lib/src/steps/identifier/identifier.dart +++ b/lib/src/steps/identifier/identifier.dart @@ -7,12 +7,14 @@ part 'identifier.g.dart'; class Identifier { final String id; - Identifier({String? id}) : id = id ?? Uuid().v4(); + Identifier({String? id}) : id = id ?? const Uuid().v4(); factory Identifier.fromJson(Map json) => _$IdentifierFromJson(json); Map toJson() => _$IdentifierToJson(this); - bool operator ==(o) => o is Identifier && o.id == id; + @override + bool operator ==(Object o) => o is Identifier && o.id == id; + @override int get hashCode => id.hashCode; } diff --git a/lib/src/steps/identifier/step_identifier.dart b/lib/src/steps/identifier/step_identifier.dart index 94a6636b..7716bfde 100644 --- a/lib/src/steps/identifier/step_identifier.dart +++ b/lib/src/steps/identifier/step_identifier.dart @@ -9,8 +9,11 @@ class StepIdentifier extends Identifier { factory StepIdentifier.fromJson(Map json) => _$StepIdentifierFromJson(json); + @override Map toJson() => _$StepIdentifierToJson(this); - bool operator ==(o) => o is StepIdentifier && id == o.id; + @override + bool operator ==(Object o) => o is StepIdentifier && id == o.id; + @override int get hashCode => id.hashCode; } diff --git a/lib/src/steps/predefined_steps/cms_step.dart b/lib/src/steps/predefined_steps/cms_step.dart new file mode 100644 index 00000000..3d926681 --- /dev/null +++ b/lib/src/steps/predefined_steps/cms_step.dart @@ -0,0 +1,28 @@ +import 'package:flutter/widgets.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/steps/cms_steps/cms_content_step.dart'; +import 'package:survey_kit/src/views/cms_step_view.dart'; + +@JsonSerializable() +class CMSStep { + final List contextSteps; + CMSStep({ + required this.contextSteps, + }); + + Widget createView() { + return CMSStepView( + cmsStep: this, + ); + } + + @override + bool operator ==(Object o) => super == o && o is CMSStep; + + @override + // TODO: implement hashCode + int get hashCode => super.hashCode; + + + +} diff --git a/lib/src/steps/predefined_steps/completion_step.dart b/lib/src/steps/predefined_steps/completion_step.dart index 735b24ba..d7a36b88 100644 --- a/lib/src/steps/predefined_steps/completion_step.dart +++ b/lib/src/steps/predefined_steps/completion_step.dart @@ -1,8 +1,8 @@ import 'package:flutter/widgets.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/result/question_result.dart'; -import 'package:survey_kit/src/steps/step.dart'; import 'package:survey_kit/src/steps/identifier/step_identifier.dart'; +import 'package:survey_kit/src/steps/step.dart'; import 'package:survey_kit/src/views/completion_view.dart'; part 'completion_step.g.dart'; @@ -20,7 +20,7 @@ class CompletionStep extends Step { bool showAppBar = true, required this.title, required this.text, - this.assetPath = "" + this.assetPath = '', }) : super( stepIdentifier: stepIdentifier, isOptional: isOptional, @@ -35,9 +35,12 @@ class CompletionStep extends Step { factory CompletionStep.fromJson(Map json) => _$CompletionStepFromJson(json); + @override Map toJson() => _$CompletionStepToJson(this); - bool operator ==(o) => - super == (o) && o is CompletionStep && o.title == title && o.text == text; + @override + bool operator ==(Object o) => + super == o && o is CompletionStep && o.title == title && o.text == text; + @override int get hashCode => super.hashCode ^ title.hashCode ^ text.hashCode; } diff --git a/lib/src/steps/predefined_steps/instruction_step.dart b/lib/src/steps/predefined_steps/instruction_step.dart index d767cfe0..6675050b 100644 --- a/lib/src/steps/predefined_steps/instruction_step.dart +++ b/lib/src/steps/predefined_steps/instruction_step.dart @@ -1,8 +1,8 @@ import 'package:flutter/widgets.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/result/question_result.dart'; -import 'package:survey_kit/src/steps/step.dart'; import 'package:survey_kit/src/steps/identifier/step_identifier.dart'; +import 'package:survey_kit/src/steps/step.dart'; import 'package:survey_kit/src/views/instruction_view.dart'; part 'instruction_step.g.dart'; @@ -39,12 +39,15 @@ class InstructionStep extends Step { factory InstructionStep.fromJson(Map json) => _$InstructionStepFromJson(json); + @override Map toJson() => _$InstructionStepToJson(this); - bool operator ==(o) => - super == (o) && + @override + bool operator ==(Object o) => + super == o && o is InstructionStep && o.title == title && o.text == text; + @override int get hashCode => super.hashCode ^ title.hashCode ^ text.hashCode; } diff --git a/lib/src/steps/predefined_steps/question_step.dart b/lib/src/steps/predefined_steps/question_step.dart index d2f8c85c..fe319306 100644 --- a/lib/src/steps/predefined_steps/question_step.dart +++ b/lib/src/steps/predefined_steps/question_step.dart @@ -31,9 +31,9 @@ import 'package:survey_kit/src/steps/step.dart'; import 'package:survey_kit/src/views/boolean_answer_view.dart'; import 'package:survey_kit/src/views/date_answer_view.dart'; import 'package:survey_kit/src/views/double_answer_view.dart'; -import 'package:survey_kit/src/views/multiple_auto_complete_answer_view.dart'; import 'package:survey_kit/src/views/image_answer_view.dart'; import 'package:survey_kit/src/views/integer_answer_view.dart'; +import 'package:survey_kit/src/views/multiple_auto_complete_answer_view.dart'; import 'package:survey_kit/src/views/multiple_choice_answer_view.dart'; import 'package:survey_kit/src/views/multiple_double_answer_view.dart'; import 'package:survey_kit/src/views/scale_answer_view.dart'; @@ -71,7 +71,7 @@ class QuestionStep extends Step { @override Widget createView({required QuestionResult? questionResult}) { - final key = ObjectKey(this.stepIdentifier.id); + final key = ObjectKey(stepIdentifier.id); switch (answerFormat.runtimeType) { case IntegerAnswerFormat: @@ -148,10 +148,11 @@ class QuestionStep extends Step { result: questionResult as ImageQuestionResult?, ); default: - throw AnswerFormatNotDefinedException(); + throw const AnswerFormatNotDefinedException(); } } factory QuestionStep.fromJson(Map json) => _$QuestionStepFromJson(json); + @override Map toJson() => _$QuestionStepToJson(this); } diff --git a/lib/src/steps/step.dart b/lib/src/steps/step.dart index 1b3dbceb..96189839 100644 --- a/lib/src/steps/step.dart +++ b/lib/src/steps/step.dart @@ -29,7 +29,7 @@ abstract class Step { Widget createView({required QuestionResult? questionResult}); factory Step.fromJson(Map json) { - final type = json['type']; + final type = json['type'] as String; if (type == 'intro') { return InstructionStep.fromJson(json); } else if (type == 'question') { @@ -37,16 +37,18 @@ abstract class Step { } else if (type == 'completion') { return CompletionStep.fromJson(json); } - throw StepNotDefinedException(); + throw const StepNotDefinedException(); } Map toJson(); - bool operator ==(o) => - o is Step && - o.stepIdentifier == stepIdentifier && - o.isOptional == isOptional && - o.buttonText == buttonText; + @override + bool operator ==(Object other) => + other is Step && + other.stepIdentifier == stepIdentifier && + other.isOptional == isOptional && + other.buttonText == buttonText; + @override int get hashCode => stepIdentifier.hashCode ^ isOptional.hashCode ^ buttonText.hashCode; } diff --git a/lib/src/survey_configuration.dart b/lib/src/survey_configuration.dart new file mode 100644 index 00000000..aa453403 --- /dev/null +++ b/lib/src/survey_configuration.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:survey_kit/src/controller/survey_controller.dart'; +import 'package:survey_kit/src/navigator/task_navigator.dart'; +import 'package:survey_kit/src/widget/survey_progress_configuration.dart'; + +class SurveyConfiguration extends InheritedWidget { + const SurveyConfiguration({ + super.key, + required this.surveyProgressConfiguration, + required this.showProgress, + required this.taskNavigator, + required this.surveyController, + required this.localizations, + required super.child, + }); + + final SurveyProgressConfiguration surveyProgressConfiguration; + final bool showProgress; + final TaskNavigator taskNavigator; + final SurveyController surveyController; + final Map? localizations; + + static SurveyConfiguration of(BuildContext context) { + final result = + context.dependOnInheritedWidgetOfExactType(); + assert(result != null, 'No SurveyConfiguration found in context'); + return result!; + } + + @override + bool updateShouldNotify(SurveyConfiguration old) => + surveyProgressConfiguration != old.surveyProgressConfiguration && + showProgress != old.showProgress; +} diff --git a/lib/src/survey_kit.dart b/lib/src/survey_kit.dart index 5dbaf0b3..b5635cdf 100644 --- a/lib/src/survey_kit.dart +++ b/lib/src/survey_kit.dart @@ -1,15 +1,14 @@ -import 'package:collection/collection.dart' show IterableExtension; +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:provider/provider.dart'; import 'package:survey_kit/src/configuration/app_bar_configuration.dart'; import 'package:survey_kit/src/controller/survey_controller.dart'; import 'package:survey_kit/src/navigator/navigable_task_navigator.dart'; import 'package:survey_kit/src/navigator/ordered_task_navigator.dart'; import 'package:survey_kit/src/navigator/task_navigator.dart'; -import 'package:survey_kit/src/presenter/survey_presenter.dart'; import 'package:survey_kit/src/presenter/survey_state.dart'; import 'package:survey_kit/src/result/survey/survey_result.dart'; +import 'package:survey_kit/src/survey_configuration.dart'; +import 'package:survey_kit/src/survey_presenter_inherited.dart'; import 'package:survey_kit/src/task/navigable_task.dart'; import 'package:survey_kit/src/task/ordered_task.dart'; import 'package:survey_kit/src/task/task.dart'; @@ -42,6 +41,7 @@ class SurveyKit extends StatefulWidget { final Map? localizations; const SurveyKit({ + super.key, required this.task, required this.onResult, this.themeData, @@ -83,25 +83,18 @@ class _SurveyKitState extends State { @override Widget build(BuildContext context) { - return Theme( - data: widget.themeData ?? Theme.of(context), - child: MultiProvider( - providers: [ - Provider.value(value: _taskNavigator), - Provider.value( - value: widget.surveyController ?? SurveyController()), - Provider.value(value: widget.showProgress ?? true), - Provider.value( - value: widget.surveyProgressbarConfiguration ?? - SurveyProgressConfiguration(), - ), - Provider?>.value(value: widget.localizations) - ], - child: BlocProvider( - create: (BuildContext context) => SurveyPresenter( - taskNavigator: _taskNavigator, - onResult: widget.onResult, - ), + return SurveyConfiguration( + showProgress: widget.showProgress ?? true, + surveyProgressConfiguration: widget.surveyProgressbarConfiguration ?? + SurveyProgressConfiguration(), + taskNavigator: _taskNavigator, + surveyController: widget.surveyController ?? SurveyController(), + localizations: widget.localizations, + child: Theme( + data: widget.themeData ?? Theme.of(context), + child: SurveyPresenterInherited( + taskNavigator: _taskNavigator, + onResult: widget.onResult, child: SurveyPage( length: widget.task.steps.length, onResult: widget.onResult, @@ -119,6 +112,7 @@ class SurveyPage extends StatefulWidget { final Function(SurveyResult) onResult; const SurveyPage({ + super.key, required this.length, required this.onResult, this.appBar, @@ -146,23 +140,24 @@ class _SurveyPageState extends State @override Widget build(BuildContext context) { - return BlocConsumer( - listenWhen: (previous, current) => previous != current, - listener: (context, state) async { + return StreamBuilder( + stream: SurveyPresenterInherited.of(context).surveyStateStream.stream, + builder: (_, __) { + final state = SurveyPresenterInherited.of(context).state; + if (state is SurveyResultState) { widget.onResult.call(state.result); } if (state is PresentingSurveyState) { tabController.animateTo(state.currentStepIndex); } - }, - builder: (BuildContext context, SurveyState state) { + if (state is PresentingSurveyState) { return Scaffold( backgroundColor: Colors.transparent, appBar: state.currentStep.showAppBar ? PreferredSize( - preferredSize: Size( + preferredSize: const Size( double.infinity, 70.0, ), @@ -174,7 +169,7 @@ class _SurveyPageState extends State ) : null, body: TabBarView( - physics: NeverScrollableScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), controller: tabController, children: state.steps .map( @@ -191,11 +186,11 @@ class _SurveyPageState extends State ), ); } else if (state is SurveyResultState && state.currentStep != null) { - return Center( + return const Center( child: CircularProgressIndicator(), ); } - return Center( + return const Center( child: CircularProgressIndicator(), ); }, diff --git a/lib/src/presenter/survey_presenter.dart b/lib/src/survey_presenter_inherited.dart similarity index 65% rename from lib/src/presenter/survey_presenter.dart rename to lib/src/survey_presenter_inherited.dart index f0390462..38d5dff2 100644 --- a/lib/src/presenter/survey_presenter.dart +++ b/lib/src/survey_presenter_inherited.dart @@ -1,5 +1,7 @@ -import 'package:collection/collection.dart' show IterableExtension; -import 'package:flutter_bloc/flutter_bloc.dart'; +import 'dart:async'; + +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart' hide Step; import 'package:survey_kit/src/configuration/app_bar_configuration.dart'; import 'package:survey_kit/src/navigator/task_navigator.dart'; import 'package:survey_kit/src/presenter/survey_event.dart'; @@ -7,57 +9,70 @@ import 'package:survey_kit/src/presenter/survey_state.dart'; import 'package:survey_kit/src/result/question_result.dart'; import 'package:survey_kit/src/result/step_result.dart'; import 'package:survey_kit/src/result/survey/survey_result.dart'; -import 'package:survey_kit/src/steps/step.dart'; import 'package:survey_kit/src/steps/identifier/step_identifier.dart'; +import 'package:survey_kit/src/steps/step.dart'; + +class SurveyPresenterInherited extends InheritedWidget { + SurveyPresenterInherited({ + super.key, + required this.taskNavigator, + required this.onResult, + required super.child, + }) : _state = LoadingSurveyState(), + startDate = DateTime.now() { + //TODO: Do somewhere else + onEvent(StartSurvey()); + } -//TO DO: Extract gathering of the results into another class -class SurveyPresenter extends Bloc { final TaskNavigator taskNavigator; final Function(SurveyResult) onResult; - Set results = {}; - late final DateTime startDate; + late SurveyState _state; + SurveyState get state => _state; + void updateState(SurveyState newState) { + _state = newState; + surveyStateStream.add(_state); + } - SurveyPresenter({ - required this.taskNavigator, - required this.onResult, - }) : super(LoadingSurveyState()) { + late StreamController surveyStateStream = + StreamController(); - on((event, emit){ - emit( - _handleInitialStep() - ); - }); + static SurveyPresenterInherited of(BuildContext context) { + final result = + context.dependOnInheritedWidgetOfExactType(); + assert(result != null, 'No SurveyPresenterInherited found in context'); + return result!; + } - on((event, emit){ - if (state is PresentingSurveyState){ - emit(_handleNextStep(event, state as PresentingSurveyState)); - } - }); + @override + bool updateShouldNotify(SurveyPresenterInherited oldWidget) => + taskNavigator != oldWidget.taskNavigator || + onResult != oldWidget.onResult || + _state != oldWidget._state; - on((event, emit){ - if (state is PresentingSurveyState){ - emit( - _handleStepBack(event, state as PresentingSurveyState) - ); - } - }); + Set results = {}; + late final DateTime startDate; - on((event, emit){ - if (state is PresentingSurveyState){ - emit( - _handleClose(event, state as PresentingSurveyState) - ); + void onEvent(SurveyEvent event) { + if (event is StartSurvey) { + updateState(_handleInitialStep()); + } else if (event is NextStep) { + if (state is PresentingSurveyState) { + updateState(_handleNextStep(event, state as PresentingSurveyState)); } - }); - - this.startDate = DateTime.now(); - add(StartSurvey()); + } else if (event is StepBack) { + if (state is PresentingSurveyState) { + updateState(_handleStepBack(event, state as PresentingSurveyState)); + } + } else if (event is CloseSurvey) { + if (state is PresentingSurveyState) { + updateState(_handleClose(event, state as PresentingSurveyState)); + } + } } - SurveyState _handleInitialStep() { - Step? step = taskNavigator.firstStep(); + final step = taskNavigator.firstStep(); if (step != null) { return PresentingSurveyState( currentStep: step, @@ -79,7 +94,7 @@ class SurveyPresenter extends Bloc { startDate: startDate, endDate: DateTime.now(), finishReason: FinishReason.COMPLETED, - results: [], + results: const [], ); return SurveyResultState( result: taskResult, @@ -88,17 +103,20 @@ class SurveyPresenter extends Bloc { } SurveyState _handleNextStep( - NextStep event, PresentingSurveyState currentState) { + NextStep event, + PresentingSurveyState currentState, + ) { _addResult(event.questionResult); - final Step? nextStep = taskNavigator.nextStep( - step: currentState.currentStep, questionResult: event.questionResult); + final nextStep = taskNavigator.nextStep( + step: currentState.currentStep, + questionResult: event.questionResult, + ); if (nextStep == null) { return _handleSurveyFinished(currentState); } - QuestionResult? questionResult = - _getResultByStepIdentifier(nextStep.stepIdentifier); + final questionResult = _getResultByStepIdentifier(nextStep.stepIdentifier); return PresentingSurveyState( currentStep: nextStep, @@ -115,13 +133,14 @@ class SurveyPresenter extends Bloc { } SurveyState _handleStepBack( - StepBack event, PresentingSurveyState currentState) { + StepBack event, + PresentingSurveyState currentState, + ) { _addResult(event.questionResult); - final Step? previousStep = - taskNavigator.previousInList(currentState.currentStep); + final previousStep = taskNavigator.previousInList(currentState.currentStep); if (previousStep != null) { - QuestionResult? questionResult = + final questionResult = _getResultByStepIdentifier(previousStep.stepIdentifier); return PresentingSurveyState( @@ -150,10 +169,12 @@ class SurveyPresenter extends Bloc { } SurveyState _handleClose( - CloseSurvey event, PresentingSurveyState currentState) { + CloseSurvey event, + PresentingSurveyState currentState, + ) { _addResult(event.questionResult); - List stepResults = + final stepResults = results.map((e) => StepResult.fromQuestion(questionResult: e)).toList(); final taskResult = SurveyResult( @@ -172,7 +193,7 @@ class SurveyPresenter extends Bloc { //Currently we are only handling one question per step SurveyState _handleSurveyFinished(PresentingSurveyState currentState) { - List stepResults = + final stepResults = results.map((e) => StepResult.fromQuestion(questionResult: e)).toList(); final taskResult = SurveyResult( id: taskNavigator.task.id, diff --git a/lib/src/task/identifier/task_identifier.dart b/lib/src/task/identifier/task_identifier.dart index 6c8d2591..25d16156 100644 --- a/lib/src/task/identifier/task_identifier.dart +++ b/lib/src/task/identifier/task_identifier.dart @@ -10,5 +10,6 @@ class TaskIdentifier extends Identifier { factory TaskIdentifier.fromJson(Map json) => _$TaskIdentifierFromJson(json); + @override Map toJson() => _$TaskIdentifierToJson(this); } diff --git a/lib/src/task/navigable_task.dart b/lib/src/task/navigable_task.dart index 40ba3bc4..83c7d074 100644 --- a/lib/src/task/navigable_task.dart +++ b/lib/src/task/navigable_task.dart @@ -1,8 +1,8 @@ import 'package:survey_kit/src/navigator/rules/navigation_rule.dart'; -import 'package:survey_kit/src/steps/step.dart'; import 'package:survey_kit/src/steps/identifier/step_identifier.dart'; -import 'package:survey_kit/src/task/task.dart'; +import 'package:survey_kit/src/steps/step.dart'; import 'package:survey_kit/src/task/identifier/task_identifier.dart'; +import 'package:survey_kit/src/task/task.dart'; /// Definition of task which can handle routing between [Tasks] /// @@ -17,7 +17,7 @@ class NavigableTask extends Task { List steps = const [], Step? initialStep, Map? navigationRules, - }) : this.navigationRules = navigationRules ?? {}, + }) : navigationRules = navigationRules ?? {}, super( id: id, steps: steps, @@ -27,9 +27,10 @@ class NavigableTask extends Task { /// Adds a [NavigationRule] to the [navigationRule] Map /// It only adds the [NavigationRule] if none is already set for the /// [StepIdentifier] - void addNavigationRule( - {required StepIdentifier forTriggerStepIdentifier, - required NavigationRule navigationRule}) { + void addNavigationRule({ + required StepIdentifier forTriggerStepIdentifier, + required NavigationRule navigationRule, + }) { navigationRules.putIfAbsent(forTriggerStepIdentifier, () => navigationRule); } @@ -40,29 +41,35 @@ class NavigableTask extends Task { } factory NavigableTask.fromJson(Map json) { - final Map navigationRules = {}; + final navigationRules = {}; if (json['rules'] != null) { final rules = json['rules'] as List; - rules.forEach((rule) { + for (final rule in rules) { navigationRules.putIfAbsent( - StepIdentifier.fromJson(rule['triggerStepIdentifier']), - () => NavigationRule.fromJson(rule as Map)); - }); + StepIdentifier.fromJson( + rule['triggerStepIdentifier'] as Map, + ), + () => NavigationRule.fromJson(rule as Map), + ); + } } return NavigableTask( id: TaskIdentifier.fromJson(json), steps: json['steps'] != null ? (json['steps'] as List) - .map((step) => Step.fromJson(step as Map)) + .map( + (dynamic step) => Step.fromJson(step as Map), + ) .toList() : [], navigationRules: navigationRules, ); } - Map toJson() => { + @override + Map toJson() => { 'id': id.toJson(), 'steps': steps.map((step) => step.toJson()).toList(), 'navigationRules': navigationRules, diff --git a/lib/src/task/ordered_task.dart b/lib/src/task/ordered_task.dart index e35b7d34..e6a7f8a9 100644 --- a/lib/src/task/ordered_task.dart +++ b/lib/src/task/ordered_task.dart @@ -1,7 +1,7 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/steps/step.dart'; -import 'package:survey_kit/src/task/task.dart'; import 'package:survey_kit/src/task/identifier/task_identifier.dart'; +import 'package:survey_kit/src/task/task.dart'; part 'ordered_task.g.dart'; @@ -22,10 +22,11 @@ class OrderedTask extends Task { id: TaskIdentifier.fromJson(json), steps: json['steps'] != null ? (json['steps'] as List>) - .map((step) => Step.fromJson(step)) + .map(Step.fromJson) .toList() : [], ); + @override Map toJson() => _$OrderedTaskToJson(this); } diff --git a/lib/src/task/task.dart b/lib/src/task/task.dart index 248e3b2e..4d494435 100644 --- a/lib/src/task/task.dart +++ b/lib/src/task/task.dart @@ -12,7 +12,7 @@ import 'package:survey_kit/src/task/task_not_defined_exception.dart'; /// * If you want to use JSON override [fromJson] and add your type abstract class Task { late final TaskIdentifier id; - @JsonKey(defaultValue: []) + @JsonKey(defaultValue: []) final List steps; final Step? initalStep; @@ -32,17 +32,19 @@ abstract class Task { /// either 'ordered' - [OrderedTask] or 'navigable' - [NavigableTask]. /// If not it will throw a [TaskNotDefinedException]. factory Task.fromJson(Map json) { - final type = json['type']; + final type = json['type'] as String; if (type == 'ordered') { return OrderedTask.fromJson(json); } else if (type == 'navigable') { return NavigableTask.fromJson(json); } - throw TaskNotDefinedException(); + throw const TaskNotDefinedException(); } Map toJson(); - bool operator ==(o) => o is Task && o.id == id; + @override + bool operator ==(Object other) => other is Task && other.id == id; + @override int get hashCode => id.hashCode ^ steps.hashCode; } diff --git a/lib/src/views/boolean_answer_view.dart b/lib/src/views/boolean_answer_view.dart index eb6c92a1..d2356edc 100644 --- a/lib/src/views/boolean_answer_view.dart +++ b/lib/src/views/boolean_answer_view.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:survey_kit/src/answer_format/boolean_answer_format.dart'; -import 'package:survey_kit/src/views/widget/selection_list_tile.dart'; import 'package:survey_kit/src/result/question/boolean_question_result.dart'; import 'package:survey_kit/src/steps/predefined_steps/question_step.dart'; +import 'package:survey_kit/src/views/widget/selection_list_tile.dart'; import 'package:survey_kit/src/views/widget/step_view.dart'; class BooleanAnswerView extends StatefulWidget { @@ -67,7 +67,7 @@ class _BooleanAnswerViewState extends State { ), Column( children: [ - Divider( + const Divider( color: Colors.grey, ), SelectionListTile( diff --git a/lib/src/views/cms_step_view.dart b/lib/src/views/cms_step_view.dart new file mode 100644 index 00000000..8748ffad --- /dev/null +++ b/lib/src/views/cms_step_view.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:survey_kit/src/steps/predefined_steps/cms_step.dart'; + +class CMSStepView extends StatelessWidget { + final CMSStep cmsStep; + final _startDate = DateTime.now(); + + CMSStepView({ + super.key, + required this.cmsStep, + }); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + ...cmsStep.contextSteps + .map( + (e) => Padding( + padding: + const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + child: e.createView(), + ), + ) + .toList(), + ], + ); + } +} diff --git a/lib/src/views/completion_view.dart b/lib/src/views/completion_view.dart index 34fedd50..c9e290c3 100644 --- a/lib/src/views/completion_view.dart +++ b/lib/src/views/completion_view.dart @@ -9,7 +9,11 @@ class CompletionView extends StatelessWidget { final DateTime _startDate = DateTime.now(); final String assetPath; - CompletionView({required this.completionStep, this.assetPath = ""}); + CompletionView({ + super.key, + required this.completionStep, + this.assetPath = '', + }); @override Widget build(BuildContext context) { @@ -20,8 +24,10 @@ class CompletionView extends StatelessWidget { _startDate, DateTime.now(), ), - title: Text(completionStep.title, - style: Theme.of(context).textTheme.headline2), + title: Text( + completionStep.title, + style: Theme.of(context).textTheme.headline2, + ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 64.0), child: Column( @@ -37,15 +43,15 @@ class CompletionView extends StatelessWidget { width: 150.0, height: 150.0, child: assetPath.isNotEmpty - ? Lottie.asset( - assetPath, - repeat: false, - ) - : Lottie.asset( - 'assets/fancy_checkmark.json', - package: 'survey_kit', - repeat: false, - ), + ? Lottie.asset( + assetPath, + repeat: false, + ) + : Lottie.asset( + 'assets/fancy_checkmark.json', + package: 'survey_kit', + repeat: false, + ), ), ) ], diff --git a/lib/src/views/date_answer_view.dart b/lib/src/views/date_answer_view.dart index 28f5981e..26352a68 100644 --- a/lib/src/views/date_answer_view.dart +++ b/lib/src/views/date_answer_view.dart @@ -99,7 +99,7 @@ class _DateAnswerViewState extends State { bottom: 8.0, child: Text( _dateFormat.format(_result!), - style: TextStyle( + style: const TextStyle( fontSize: 28.0, color: Colors.white, ), @@ -114,14 +114,14 @@ class _DateAnswerViewState extends State { child: CalendarDatePicker( firstDate: _dateAnswerFormat.minDate ?? DateTime.utc(1900), lastDate: _dateAnswerFormat.maxDate?.add( - Duration(hours: 1), + const Duration(hours: 1), ) ?? DateTime.now().add( - Duration(hours: 1), + const Duration(hours: 1), ), initialDate: _result ?? DateTime.now(), currentDate: _result, - onDateChanged: (DateTime value) => _handleDateChanged(value), + onDateChanged: _handleDateChanged, ), ), ], @@ -137,10 +137,10 @@ class _DateAnswerViewState extends State { minimumDate: _dateAnswerFormat.minDate, //We have to add an hour to to met the assert maxDate > initDate maximumDate: _dateAnswerFormat.maxDate?.add( - Duration(hours: 1), + const Duration(hours: 1), ) ?? DateTime.now().add( - Duration(hours: 1), + const Duration(hours: 1), ), initialDateTime: _dateAnswerFormat.defaultDate, onDateTimeChanged: (DateTime value) { diff --git a/lib/src/views/decoration/input_decoration.dart b/lib/src/views/decoration/input_decoration.dart index 35c65fe7..00bd3f15 100644 --- a/lib/src/views/decoration/input_decoration.dart +++ b/lib/src/views/decoration/input_decoration.dart @@ -8,17 +8,13 @@ InputDecoration textFieldInputDecoration({String hint = ''}) => InputDecoration( right: 10, ), focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.all( - Radius.zero, - ), + borderRadius: BorderRadius.zero, borderSide: BorderSide( color: Colors.black.withOpacity(0.2), ), ), enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.all( - Radius.zero, - ), + borderRadius: BorderRadius.zero, borderSide: BorderSide( color: Colors.black.withOpacity(0.2), ), diff --git a/lib/src/views/double_answer_view.dart b/lib/src/views/double_answer_view.dart index 9c81375d..334f66bd 100644 --- a/lib/src/views/double_answer_view.dart +++ b/lib/src/views/double_answer_view.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:survey_kit/src/answer_format/double_answer_format.dart'; -import 'package:survey_kit/src/views/decoration/input_decoration.dart'; import 'package:survey_kit/src/result/question/double_question_result.dart'; import 'package:survey_kit/src/steps/predefined_steps/question_step.dart'; +import 'package:survey_kit/src/views/decoration/input_decoration.dart'; import 'package:survey_kit/src/views/widget/step_view.dart'; class DoubleAnswerView extends StatefulWidget { @@ -57,7 +57,7 @@ class _DoubleAnswerViewState extends State { startDate: _startDate, endDate: DateTime.now(), valueIdentifier: _controller.text, - result: double.tryParse(_controller.text) ?? _doubleAnswerFormat.defaultValue ?? null, + result: double.tryParse(_controller.text) ?? _doubleAnswerFormat.defaultValue, ), isValid: _isValid || widget.questionStep.isOptional, title: widget.questionStep.title.isNotEmpty @@ -77,9 +77,7 @@ class _DoubleAnswerViewState extends State { hint: _doubleAnswerFormat.hint, ), controller: _controller, - onChanged: (String value) { - _checkValidation(value); - }, + onChanged: _checkValidation, keyboardType: TextInputType.number, textAlign: TextAlign.center, ), diff --git a/lib/src/views/image_answer_view.dart b/lib/src/views/image_answer_view.dart index 8078d3bf..19e0954e 100644 --- a/lib/src/views/image_answer_view.dart +++ b/lib/src/views/image_answer_view.dart @@ -23,7 +23,7 @@ class _ImageAnswerViewState extends State { late final ImageAnswerFormat _imageAnswerFormat; late final DateTime _startDate; - bool _isValid = false; + final bool _isValid = false; String filePath = ''; @override @@ -73,25 +73,21 @@ class _ImageAnswerViewState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ ElevatedButton( - onPressed: () { - _optionsDialogBox(); - }, + onPressed: _optionsDialogBox, child: Text(_imageAnswerFormat.buttonText), ), - filePath.isNotEmpty - ? Flexible( + if (filePath.isNotEmpty) Flexible( child: Padding( padding: const EdgeInsets.all(8.0), child: Text( filePath .split('/')[filePath.split('/').length - 1], - style: TextStyle( + style: const TextStyle( fontSize: 12, ), ), ), - ) - : SizedBox(), + ) else const SizedBox(), ], ), ), @@ -111,17 +107,13 @@ class _ImageAnswerViewState extends State { child: ListBody( children: [ GestureDetector( - child: Text('Take a picture'), - onTap: () { - _openCamera(); - }, + onTap: _openCamera, + child: const Text('Take a picture'), ), - Padding(padding: EdgeInsets.all(8.0)), + const Padding(padding: EdgeInsets.all(8.0)), GestureDetector( - child: Text('Select from Gallery'), - onTap: () { - _openGallery(); - }, + onTap: _openGallery, + child: const Text('Select from Gallery'), ), ], ), @@ -132,13 +124,13 @@ class _ImageAnswerViewState extends State { } Future _openCamera() async { - var picture = await ImagePicker().pickImage( + final picture = await ImagePicker().pickImage( source: ImageSource.camera, ); Navigator.pop(context); - picture?.readAsBytes().then((value) { + await picture?.readAsBytes().then((value) { setState(() { filePath = picture.path; }); @@ -146,13 +138,13 @@ class _ImageAnswerViewState extends State { } Future _openGallery() async { - var picture = await ImagePicker().pickImage( + final picture = await ImagePicker().pickImage( source: ImageSource.gallery, ); Navigator.pop(context); - picture?.readAsBytes().then((value) { + await picture?.readAsBytes().then((value) { setState(() { filePath = picture.path; }); diff --git a/lib/src/views/instruction_view.dart b/lib/src/views/instruction_view.dart index 5b622956..0aa5d2d5 100644 --- a/lib/src/views/instruction_view.dart +++ b/lib/src/views/instruction_view.dart @@ -7,7 +7,10 @@ class InstructionView extends StatelessWidget { final InstructionStep instructionStep; final DateTime _startDate = DateTime.now(); - InstructionView({required this.instructionStep}); + InstructionView({ + super.key, + required this.instructionStep, + }); @override Widget build(BuildContext context) { diff --git a/lib/src/views/integer_answer_view.dart b/lib/src/views/integer_answer_view.dart index ac53d239..22a86ecd 100644 --- a/lib/src/views/integer_answer_view.dart +++ b/lib/src/views/integer_answer_view.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:survey_kit/src/answer_format/integer_answer_format.dart'; -import 'package:survey_kit/src/views/decoration/input_decoration.dart'; import 'package:survey_kit/src/result/question/integer_question_result.dart'; import 'package:survey_kit/src/steps/predefined_steps/question_step.dart'; +import 'package:survey_kit/src/views/decoration/input_decoration.dart'; import 'package:survey_kit/src/views/widget/step_view.dart'; class IntegerAnswerView extends StatefulWidget { @@ -57,7 +57,7 @@ class _IntegerAnswerViewState extends State { startDate: _startDate, endDate: DateTime.now(), valueIdentifier: _controller.text, - result: int.tryParse(_controller.text) ?? _integerAnswerFormat.defaultValue ?? null, + result: int.tryParse(_controller.text) ?? _integerAnswerFormat.defaultValue, ), isValid: _isValid || widget.questionStep.isOptional, title: widget.questionStep.title.isNotEmpty @@ -78,9 +78,7 @@ class _IntegerAnswerViewState extends State { hint: _integerAnswerFormat.hint, ), controller: _controller, - onChanged: (String value) { - _checkValidation(value); - }, + onChanged: _checkValidation, keyboardType: TextInputType.number, textAlign: TextAlign.center, ), diff --git a/lib/src/views/multiple_auto_complete_answer_view.dart b/lib/src/views/multiple_auto_complete_answer_view.dart index 72ca954b..9fd552d8 100644 --- a/lib/src/views/multiple_auto_complete_answer_view.dart +++ b/lib/src/views/multiple_auto_complete_answer_view.dart @@ -75,10 +75,10 @@ class _MultipleChoiceAutoCompleteAnswerViewState onSelected: onChoiceSelected, selectedChoices: _selectedChoices, ), - SizedBox( + const SizedBox( height: 32, ), - Divider( + const Divider( color: Colors.grey, ), ..._multipleChoiceAnswer.textChoices @@ -92,7 +92,7 @@ class _MultipleChoiceAutoCompleteAnswerViewState .toList(), ..._selectedChoices .where((element) => - !_multipleChoiceAnswer.textChoices.contains(element)) + !_multipleChoiceAnswer.textChoices.contains(element),) .map( (TextChoice tc) => SelectionListTile( text: tc.text, @@ -143,7 +143,7 @@ class _MultipleChoiceAutoCompleteAnswerViewState ), ), ), - Divider( + const Divider( color: Colors.grey, ), ], @@ -189,16 +189,16 @@ class _AutoComplete extends StatelessWidget { controller: textEditingController, focusNode: focusNode, decoration: InputDecoration( - contentPadding: EdgeInsets.symmetric(horizontal: 32), + contentPadding: const EdgeInsets.symmetric(horizontal: 32), labelText: 'Search', hintText: 'Type here to search', suffixIcon: IconButton( padding: EdgeInsets.zero, - icon: Icon(Icons.clear), + icon: const Icon(Icons.clear), onPressed: () { textEditingController.clear(); }, - )), + ),), onSubmitted: (v) { onFieldSubmitted(); }, @@ -216,7 +216,7 @@ class _AutoComplete extends StatelessWidget { return suggestions.where((element) => element.text .toLowerCase() - .contains(textEditingValue.text.toLowerCase())); + .contains(textEditingValue.text.toLowerCase()),); }, onSelected: onSelected, ); @@ -241,7 +241,7 @@ class _OptionsViewBuilder extends StatelessWidget { elevation: 4.0, textStyle: Theme.of(context).textTheme.bodyText1, child: ConstrainedBox( - constraints: BoxConstraints(maxHeight: 200), + constraints: const BoxConstraints(maxHeight: 200), child: ListView.builder( padding: EdgeInsets.zero, shrinkWrap: true, @@ -253,7 +253,7 @@ class _OptionsViewBuilder extends StatelessWidget { onSelected(option); }, child: Builder(builder: (BuildContext context) { - final bool highlight = + final highlight = AutocompleteHighlightedOption.of(context) == index; if (highlight) { SchedulerBinding.instance @@ -264,16 +264,16 @@ class _OptionsViewBuilder extends StatelessWidget { return Container( color: highlight ? Theme.of(context).focusColor : null, padding: const EdgeInsets.all(16.0), - margin: EdgeInsets.only(right: 16), + margin: const EdgeInsets.only(right: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(option.text), - if (selectedChoices.contains(option)) Icon(Icons.done) + if (selectedChoices.contains(option)) const Icon(Icons.done) ], ), ); - }), + },), ); }, ), diff --git a/lib/src/views/multiple_choice_answer_view.dart b/lib/src/views/multiple_choice_answer_view.dart index 0716fef2..31d5b991 100644 --- a/lib/src/views/multiple_choice_answer_view.dart +++ b/lib/src/views/multiple_choice_answer_view.dart @@ -1,11 +1,11 @@ +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:survey_kit/src/answer_format/multiple_choice_answer_format.dart'; import 'package:survey_kit/src/answer_format/text_choice.dart'; -import 'package:survey_kit/src/views/widget/selection_list_tile.dart'; import 'package:survey_kit/src/result/question/multiple_choice_question_result.dart'; import 'package:survey_kit/src/steps/predefined_steps/question_step.dart'; +import 'package:survey_kit/src/views/widget/selection_list_tile.dart'; import 'package:survey_kit/src/views/widget/step_view.dart'; -import 'package:collection/collection.dart'; class MultipleChoiceAnswerView extends StatefulWidget { final QuestionStep questionStep; @@ -61,6 +61,7 @@ class _MultipleChoiceAnswerView extends State { padding: const EdgeInsets.symmetric(horizontal: 14.0), child: Column( children: [ + widget.questionStep.content, Padding( padding: const EdgeInsets.only(bottom: 32.0), child: Text( @@ -71,7 +72,7 @@ class _MultipleChoiceAnswerView extends State { ), Column( children: [ - Divider( + const Divider( color: Colors.grey, ), ..._multipleChoiceAnswer.textChoices @@ -135,7 +136,7 @@ class _MultipleChoiceAnswerView extends State { ), ), ), - Divider( + const Divider( color: Colors.grey, ), ], diff --git a/lib/src/views/multiple_double_answer_view.dart b/lib/src/views/multiple_double_answer_view.dart index a0bb5f82..212f8099 100644 --- a/lib/src/views/multiple_double_answer_view.dart +++ b/lib/src/views/multiple_double_answer_view.dart @@ -16,7 +16,8 @@ class MultipleDoubleAnswerView extends StatefulWidget { }) : super(key: key); @override - State createState() => _MultipleDoubleAnswerViewState(); + State createState() => + _MultipleDoubleAnswerViewState(); } class _MultipleDoubleAnswerViewState extends State { @@ -30,32 +31,34 @@ class _MultipleDoubleAnswerViewState extends State { @override void initState() { super.initState(); - _multipleDoubleAnswer = widget.questionStep.answerFormat as MultipleDoubleAnswerFormat; + _multipleDoubleAnswer = + widget.questionStep.answerFormat as MultipleDoubleAnswerFormat; _controller = _multipleDoubleAnswer.hints.map((e) { return TextEditingController(); }).toList(); - _controller.forEach((element) { - element = TextEditingController(); - element.text = widget.result?.result?.toString() ?? ''; + for (var element in _controller) { + element = TextEditingController() + ..text = widget.result?.result?.toString() ?? ''; _checkValidation(element.text); - }); + } _insertedValues = List.generate( - _multipleDoubleAnswer.hints.length, - (index) => MultiDouble( - text: '', - value: 0.0, - )); + _multipleDoubleAnswer.hints.length, + (index) => MultiDouble( + text: '', + value: 0.0, + ), + ); _startDate = DateTime.now(); } @override void dispose() { - _controller.forEach((element) { + for (final element in _controller) { element.dispose(); - }); + } super.dispose(); } @@ -98,10 +101,13 @@ class _MultipleDoubleAnswerViewState extends State { ), Column( children: [ - Divider( + const Divider( color: Colors.grey, ), - ..._multipleDoubleAnswer.hints.asMap().entries.map((MapEntry md) { + ..._multipleDoubleAnswer.hints + .asMap() + .entries + .map((MapEntry md) { return TextField( textInputAction: TextInputAction.next, autofocus: true, diff --git a/lib/src/views/scale_answer_view.dart b/lib/src/views/scale_answer_view.dart index efe273bb..30c26463 100644 --- a/lib/src/views/scale_answer_view.dart +++ b/lib/src/views/scale_answer_view.dart @@ -61,7 +61,7 @@ class _ScaleAnswerViewState extends State { ), ), Padding( - padding: EdgeInsets.all(14.0), + padding: const EdgeInsets.all(14.0), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, @@ -82,13 +82,13 @@ class _ScaleAnswerViewState extends State { children: [ Text( _scaleAnswerFormat.minimumValueDescription, - style: TextStyle( + style: const TextStyle( fontSize: 16.0, ), ), Text( _scaleAnswerFormat.maximumValueDescription, - style: TextStyle( + style: const TextStyle( fontSize: 16.0, ), ), diff --git a/lib/src/views/single_choice_answer_view.dart b/lib/src/views/single_choice_answer_view.dart index 41c7954f..ebcb7ae7 100644 --- a/lib/src/views/single_choice_answer_view.dart +++ b/lib/src/views/single_choice_answer_view.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:survey_kit/src/answer_format/single_choice_answer_format.dart'; import 'package:survey_kit/src/answer_format/text_choice.dart'; -import 'package:survey_kit/src/views/widget/selection_list_tile.dart'; import 'package:survey_kit/src/result/question/single_choice_question_result.dart'; import 'package:survey_kit/src/steps/predefined_steps/question_step.dart'; +import 'package:survey_kit/src/views/widget/selection_list_tile.dart'; import 'package:survey_kit/src/views/widget/step_view.dart'; class SingleChoiceAnswerView extends StatefulWidget { @@ -68,7 +68,7 @@ class _SingleChoiceAnswerViewState extends State { ), Column( children: [ - Divider( + const Divider( color: Colors.grey, ), ..._singleChoiceAnswerFormat.textChoices.map( diff --git a/lib/src/views/text_answer_view.dart b/lib/src/views/text_answer_view.dart index edeea9e1..20229068 100644 --- a/lib/src/views/text_answer_view.dart +++ b/lib/src/views/text_answer_view.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:survey_kit/src/answer_format/text_answer_format.dart'; -import 'package:survey_kit/src/views/decoration/input_decoration.dart'; import 'package:survey_kit/src/result/question/text_question_result.dart'; import 'package:survey_kit/src/steps/predefined_steps/question_step.dart'; +import 'package:survey_kit/src/views/decoration/input_decoration.dart'; import 'package:survey_kit/src/views/widget/step_view.dart'; class TextAnswerView extends StatefulWidget { @@ -39,7 +39,7 @@ class _TextAnswerViewState extends State { void _checkValidation(String text) { setState(() { if (_textAnswerFormat.validationRegEx != null) { - RegExp regExp = new RegExp(_textAnswerFormat.validationRegEx!); + final regExp = RegExp(_textAnswerFormat.validationRegEx!); _isValid = regExp.hasMatch(text); } else { _isValid = true; @@ -93,9 +93,7 @@ class _TextAnswerViewState extends State { ), controller: _controller, textAlign: TextAlign.center, - onChanged: (String text) { - _checkValidation(text); - }, + onChanged: _checkValidation, ), ), ], diff --git a/lib/src/views/widget/selection_list_tile.dart b/lib/src/views/widget/selection_list_tile.dart index b6149cc3..95bf5e06 100644 --- a/lib/src/views/widget/selection_list_tile.dart +++ b/lib/src/views/widget/selection_list_tile.dart @@ -42,7 +42,7 @@ class SelectionListTile extends StatelessWidget { onTap: () => onTap.call(), ), ), - Divider( + const Divider( color: Colors.grey, ), ], diff --git a/lib/src/views/widget/step_view.dart b/lib/src/views/widget/step_view.dart index 2f4827c0..47578602 100644 --- a/lib/src/views/widget/step_view.dart +++ b/lib/src/views/widget/step_view.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:survey_kit/src/controller/survey_controller.dart'; import 'package:survey_kit/src/result/question_result.dart'; import 'package:survey_kit/src/steps/step.dart' as surveystep; -import 'package:provider/provider.dart'; +import 'package:survey_kit/src/survey_configuration.dart'; class StepView extends StatelessWidget { final surveystep.Step step; @@ -13,6 +14,7 @@ class StepView extends StatelessWidget { final SurveyController? controller; const StepView({ + super.key, required this.step, required this.child, required this.title, @@ -23,7 +25,8 @@ class StepView extends StatelessWidget { @override Widget build(BuildContext context) { - final _surveyController = controller ?? context.read(); + final _surveyController = + controller ?? SurveyConfiguration.of(context).surveyController; return _content(_surveyController, context); } diff --git a/lib/src/views/widget/survey_app_bar.dart b/lib/src/views/widget/survey_app_bar.dart index 59cfe4c3..289621f8 100644 --- a/lib/src/views/widget/survey_app_bar.dart +++ b/lib/src/views/widget/survey_app_bar.dart @@ -1,25 +1,27 @@ import 'package:flutter/material.dart'; import 'package:survey_kit/src/configuration/app_bar_configuration.dart'; import 'package:survey_kit/src/controller/survey_controller.dart'; +import 'package:survey_kit/src/survey_configuration.dart'; import 'package:survey_kit/src/widget/survey_progress.dart'; -import 'package:provider/provider.dart'; class SurveyAppBar extends StatelessWidget { final AppBarConfiguration appBarConfiguration; final SurveyController? controller; const SurveyAppBar({ + super.key, required this.appBarConfiguration, this.controller, }); @override AppBar build(BuildContext context) { - final _showProgress = - appBarConfiguration.showProgress ?? context.read(); + final _showProgress = appBarConfiguration.showProgress ?? + SurveyConfiguration.of(context).showProgress; final _canGoBack = appBarConfiguration.canBack ?? true; - final surveyController = controller ?? context.read(); + final surveyController = + controller ?? SurveyConfiguration.of(context).surveyController; return AppBar( elevation: 0, leading: _canGoBack @@ -32,12 +34,13 @@ class SurveyAppBar extends StatelessWidget { }, ) : Container(), - title: _showProgress ? SurveyProgress() : SizedBox.shrink(), + title: _showProgress ? const SurveyProgress() : const SizedBox.shrink(), actions: [ TextButton( child: appBarConfiguration.trailing ?? Text( - context.read?>()?['cancel'] ?? 'Cancel', + SurveyConfiguration.of(context).localizations?['cancel'] ?? + 'Cancel', style: TextStyle( color: Theme.of(context).primaryColor, ), diff --git a/lib/src/views/widget/time_picker_widget.dart b/lib/src/views/widget/time_picker_widget.dart index f703a958..6091395e 100644 --- a/lib/src/views/widget/time_picker_widget.dart +++ b/lib/src/views/widget/time_picker_widget.dart @@ -7,6 +7,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// ignore_for_file: prefer_asserts_with_message, cascade_invocations + import 'dart:async'; import 'dart:math' as math; import 'dart:ui' as ui; @@ -109,14 +111,12 @@ class _TimePickerHeader extends StatelessWidget { @override Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); - final ThemeData themeData = Theme.of(context); - final TimeOfDayFormat timeOfDayFormat = - MaterialLocalizations.of(context).timeOfDayFormat( + final themeData = Theme.of(context); + final timeOfDayFormat = MaterialLocalizations.of(context).timeOfDayFormat( alwaysUse24HourFormat: MediaQuery.of(context).alwaysUse24HourFormat, ); - final _TimePickerFragmentContext fragmentContext = - _TimePickerFragmentContext( + final fragmentContext = _TimePickerFragmentContext( selectedTime: selectedTime, mode: mode, onTimeChange: onChanged, @@ -157,12 +157,14 @@ class _TimePickerHeader extends StatelessWidget { textDirection: TextDirection.ltr, children: [ Expanded( - child: - _HourControl(fragmentContext: fragmentContext)), + child: _HourControl(fragmentContext: fragmentContext), + ), _StringFragment(timeOfDayFormat: timeOfDayFormat), Expanded( - child: _MinuteControl( - fragmentContext: fragmentContext)), + child: _MinuteControl( + fragmentContext: fragmentContext, + ), + ), ], ), ), @@ -203,11 +205,12 @@ class _TimePickerHeader extends StatelessWidget { textDirection: TextDirection.ltr, children: [ Expanded( - child: _HourControl(fragmentContext: fragmentContext)), + child: _HourControl(fragmentContext: fragmentContext), + ), _StringFragment(timeOfDayFormat: timeOfDayFormat), Expanded( - child: - _MinuteControl(fragmentContext: fragmentContext)), + child: _MinuteControl(fragmentContext: fragmentContext), + ), ], ), ), @@ -259,26 +262,26 @@ class _HourMinuteControl extends StatelessWidget { @override Widget build(BuildContext context) { - final ThemeData themeData = Theme.of(context); - final TimePickerThemeData timePickerTheme = TimePickerTheme.of(context); - final bool isDark = themeData.colorScheme.brightness == Brightness.dark; - final Color textColor = timePickerTheme.hourMinuteTextColor ?? + final themeData = Theme.of(context); + final timePickerTheme = TimePickerTheme.of(context); + final isDark = themeData.colorScheme.brightness == Brightness.dark; + final textColor = timePickerTheme.hourMinuteTextColor ?? MaterialStateColor.resolveWith((Set states) { return states.contains(MaterialState.selected) ? themeData.colorScheme.primary : themeData.colorScheme.onSurface; }); - final Color backgroundColor = timePickerTheme.hourMinuteColor ?? + final backgroundColor = timePickerTheme.hourMinuteColor ?? MaterialStateColor.resolveWith((Set states) { return states.contains(MaterialState.selected) ? themeData.colorScheme.primary.withOpacity(isDark ? 0.24 : 0.12) : themeData.colorScheme.onSurface.withOpacity(0.12); }); - final TextStyle style = + final style = timePickerTheme.hourMinuteTextStyle ?? themeData.textTheme.headline2!; - final ShapeBorder shape = timePickerTheme.hourMinuteShape ?? _kDefaultShape; + final shape = timePickerTheme.hourMinuteShape ?? _kDefaultShape; - final Set states = isSelected + final states = isSelected ? {MaterialState.selected} : {}; return SizedBox( @@ -294,7 +297,8 @@ class _HourMinuteControl extends StatelessWidget { child: Text( text, style: style.copyWith( - color: MaterialStateProperty.resolveAs(textColor, states)), + color: MaterialStateProperty.resolveAs(textColor, states), + ), textScaleFactor: 1.0, ), ), @@ -317,38 +321,36 @@ class _HourControl extends StatelessWidget { @override Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); - final bool alwaysUse24HourFormat = - MediaQuery.of(context).alwaysUse24HourFormat; - final MaterialLocalizations localizations = - MaterialLocalizations.of(context); - final String formattedHour = localizations.formatHour( + final alwaysUse24HourFormat = MediaQuery.of(context).alwaysUse24HourFormat; + final localizations = MaterialLocalizations.of(context); + final formattedHour = localizations.formatHour( fragmentContext.selectedTime, alwaysUse24HourFormat: alwaysUse24HourFormat, ); TimeOfDay hoursFromSelected(int hoursToAdd) { if (fragmentContext.use24HourDials) { - final int selectedHour = fragmentContext.selectedTime.hour; + final selectedHour = fragmentContext.selectedTime.hour; return fragmentContext.selectedTime.replacing( hour: (selectedHour + hoursToAdd) % TimeOfDay.hoursPerDay, ); } else { // Cycle 1 through 12 without changing day period. - final int periodOffset = fragmentContext.selectedTime.periodOffset; - final int hours = fragmentContext.selectedTime.hourOfPeriod; + final periodOffset = fragmentContext.selectedTime.periodOffset; + final hours = fragmentContext.selectedTime.hourOfPeriod; return fragmentContext.selectedTime.replacing( hour: periodOffset + (hours + hoursToAdd) % TimeOfDay.hoursPerPeriod, ); } } - final TimeOfDay nextHour = hoursFromSelected(1); - final String formattedNextHour = localizations.formatHour( + final nextHour = hoursFromSelected(1); + final formattedNextHour = localizations.formatHour( nextHour, alwaysUse24HourFormat: alwaysUse24HourFormat, ); - final TimeOfDay previousHour = hoursFromSelected(-1); - final String formattedPreviousHour = localizations.formatHour( + final previousHour = hoursFromSelected(-1); + final formattedPreviousHour = localizations.formatHour( previousHour, alwaysUse24HourFormat: alwaysUse24HourFormat, ); @@ -368,7 +370,9 @@ class _HourControl extends StatelessWidget { isSelected: fragmentContext.mode == _TimePickerMode.hour, text: formattedHour, onTap: Feedback.wrapForTap( - () => fragmentContext.onModeChange(_TimePickerMode.hour), context)!, + () => fragmentContext.onModeChange(_TimePickerMode.hour), + context, + )!, onDoubleTap: fragmentContext.onHourDoubleTapped, ), ); @@ -399,11 +403,11 @@ class _StringFragment extends StatelessWidget { @override Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final TimePickerThemeData timePickerTheme = TimePickerTheme.of(context); - final TextStyle hourMinuteStyle = + final theme = Theme.of(context); + final timePickerTheme = TimePickerTheme.of(context); + final hourMinuteStyle = timePickerTheme.hourMinuteTextStyle ?? theme.textTheme.headline2!; - final Color textColor = + final textColor = timePickerTheme.hourMinuteTextColor ?? theme.colorScheme.onSurface; return ExcludeSemantics( @@ -413,8 +417,11 @@ class _StringFragment extends StatelessWidget { child: Text( _stringFragmentValue(timeOfDayFormat), style: hourMinuteStyle.apply( - color: MaterialStateProperty.resolveAs( - textColor, {})), + color: MaterialStateProperty.resolveAs( + textColor, + {}, + ), + ), textScaleFactor: 1.0, ), ), @@ -435,21 +442,19 @@ class _MinuteControl extends StatelessWidget { @override Widget build(BuildContext context) { - final MaterialLocalizations localizations = - MaterialLocalizations.of(context); - final String formattedMinute = + final localizations = MaterialLocalizations.of(context); + final formattedMinute = localizations.formatMinute(fragmentContext.selectedTime); - final TimeOfDay nextMinute = fragmentContext.selectedTime.replacing( + final nextMinute = fragmentContext.selectedTime.replacing( minute: (fragmentContext.selectedTime.minute + 1) % TimeOfDay.minutesPerHour, ); - final String formattedNextMinute = localizations.formatMinute(nextMinute); - final TimeOfDay previousMinute = fragmentContext.selectedTime.replacing( + final formattedNextMinute = localizations.formatMinute(nextMinute); + final previousMinute = fragmentContext.selectedTime.replacing( minute: (fragmentContext.selectedTime.minute - 1) % TimeOfDay.minutesPerHour, ); - final String formattedPreviousMinute = - localizations.formatMinute(previousMinute); + final formattedPreviousMinute = localizations.formatMinute(previousMinute); return Semantics( excludeSemantics: true, @@ -467,8 +472,9 @@ class _MinuteControl extends StatelessWidget { isSelected: fragmentContext.mode == _TimePickerMode.minute, text: formattedMinute, onTap: Feedback.wrapForTap( - () => fragmentContext.onModeChange(_TimePickerMode.minute), - context)!, + () => fragmentContext.onModeChange(_TimePickerMode.minute), + context, + )!, onDoubleTap: fragmentContext.onMinuteDoubleTapped, ), ); @@ -489,9 +495,9 @@ class _DayPeriodControl extends StatelessWidget { final ValueChanged onChanged; void _togglePeriod() { - final int newHour = + final newHour = (selectedTime.hour + TimeOfDay.hoursPerPeriod) % TimeOfDay.hoursPerDay; - final TimeOfDay newTime = selectedTime.replacing(hour: newHour); + final newTime = selectedTime.replacing(hour: newHour); onChanged(newTime); } @@ -504,8 +510,10 @@ class _DayPeriodControl extends StatelessWidget { case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - _announceToAccessibility(context, - MaterialLocalizations.of(context).anteMeridiemAbbreviation); + _announceToAccessibility( + context, + MaterialLocalizations.of(context).anteMeridiemAbbreviation, + ); break; case TargetPlatform.iOS: case TargetPlatform.macOS: @@ -523,8 +531,10 @@ class _DayPeriodControl extends StatelessWidget { case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - _announceToAccessibility(context, - MaterialLocalizations.of(context).postMeridiemAbbreviation); + _announceToAccessibility( + context, + MaterialLocalizations.of(context).postMeridiemAbbreviation, + ); break; case TargetPlatform.iOS: case TargetPlatform.macOS: @@ -535,18 +545,17 @@ class _DayPeriodControl extends StatelessWidget { @override Widget build(BuildContext context) { - final MaterialLocalizations materialLocalizations = - MaterialLocalizations.of(context); - final ColorScheme colorScheme = Theme.of(context).colorScheme; - final TimePickerThemeData timePickerTheme = TimePickerTheme.of(context); - final bool isDark = colorScheme.brightness == Brightness.dark; - final Color textColor = timePickerTheme.dayPeriodTextColor ?? + final materialLocalizations = MaterialLocalizations.of(context); + final colorScheme = Theme.of(context).colorScheme; + final timePickerTheme = TimePickerTheme.of(context); + final isDark = colorScheme.brightness == Brightness.dark; + final textColor = timePickerTheme.dayPeriodTextColor ?? MaterialStateColor.resolveWith((Set states) { return states.contains(MaterialState.selected) ? colorScheme.primary : colorScheme.onSurface.withOpacity(0.60); }); - final Color backgroundColor = timePickerTheme.dayPeriodColor ?? + final backgroundColor = timePickerTheme.dayPeriodColor ?? MaterialStateColor.resolveWith((Set states) { // The unselected day period should match the overall picker dialog // color. Making it transparent enables that without being redundant @@ -556,28 +565,30 @@ class _DayPeriodControl extends StatelessWidget { ? colorScheme.primary.withOpacity(isDark ? 0.24 : 0.12) : Colors.transparent; }); - final bool amSelected = selectedTime.period == DayPeriod.am; - final Set amStates = amSelected + final amSelected = selectedTime.period == DayPeriod.am; + final amStates = amSelected ? {MaterialState.selected} : {}; - final bool pmSelected = !amSelected; - final Set pmStates = pmSelected + final pmSelected = !amSelected; + final pmStates = pmSelected ? {MaterialState.selected} : {}; - final TextStyle textStyle = timePickerTheme.dayPeriodTextStyle ?? + final textStyle = timePickerTheme.dayPeriodTextStyle ?? Theme.of(context).textTheme.subtitle1!; - final TextStyle amStyle = textStyle.copyWith( + final amStyle = textStyle.copyWith( color: MaterialStateProperty.resolveAs(textColor, amStates), ); - final TextStyle pmStyle = textStyle.copyWith( + final pmStyle = textStyle.copyWith( color: MaterialStateProperty.resolveAs(textColor, pmStates), ); - OutlinedBorder shape = timePickerTheme.dayPeriodShape ?? + var shape = timePickerTheme.dayPeriodShape ?? const RoundedRectangleBorder(borderRadius: _kDefaultBorderRadius); - final BorderSide borderSide = timePickerTheme.dayPeriodBorderSide ?? + final borderSide = timePickerTheme.dayPeriodBorderSide ?? BorderSide( color: Color.alphaBlend( - colorScheme.onBackground.withOpacity(0.38), colorScheme.surface), + colorScheme.onBackground.withOpacity(0.38), + colorScheme.surface, + ), ); // Apply the custom borderSide. shape = shape.copyWith( @@ -628,7 +639,7 @@ class _DayPeriodControl extends StatelessWidget { final Widget result; switch (orientation) { case Orientation.portrait: - const double width = 52.0; + const width = 52.0; result = _DayPeriodInputPadding( minSize: const Size(width, kMinInteractiveDimension * 2), orientation: orientation, @@ -705,7 +716,9 @@ class _DayPeriodInputPadding extends SingleChildRenderObjectWidget { @override void updateRenderObject( - BuildContext context, covariant _RenderInputPadding renderObject) { + BuildContext context, + covariant _RenderInputPadding renderObject, + ) { renderObject.minSize = minSize; } } @@ -756,11 +769,12 @@ class _RenderInputPadding extends RenderShiftedBox { return 0.0; } - Size _computeSize( - {required BoxConstraints constraints, - required ChildLayouter layoutChild}) { + Size _computeSize({ + required BoxConstraints constraints, + required ChildLayouter layoutChild, + }) { if (child != null) { - final Size childSize = layoutChild(child!, constraints); + final childSize = layoutChild(child!, constraints); final double width = math.max(childSize.width, minSize.width); final double height = math.max(childSize.height, minSize.height); return constraints.constrain(Size(width, height)); @@ -783,7 +797,7 @@ class _RenderInputPadding extends RenderShiftedBox { layoutChild: ChildLayoutHelper.layoutChild, ); if (child != null) { - final BoxParentData childParentData = child!.parentData! as BoxParentData; + final childParentData = child!.parentData! as BoxParentData; childParentData.offset = Alignment.center.alongOffset(size - child!.size as Offset); } @@ -802,7 +816,7 @@ class _RenderInputPadding extends RenderShiftedBox { return false; } - Offset newPosition = child!.size.center(Offset.zero); + var newPosition = child!.size.center(Offset.zero); switch (orientation) { case Orientation.portrait: if (position.dy > newPosition.dy) { @@ -873,12 +887,12 @@ class _DialPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { - final double radius = size.shortestSide / 2.0; - final Offset center = Offset(size.width / 2.0, size.height / 2.0); - final Offset centerPoint = center; + final radius = size.shortestSide / 2.0; + final center = Offset(size.width / 2.0, size.height / 2.0); + final centerPoint = center; canvas.drawCircle(centerPoint, radius, Paint()..color = backgroundColor); - final double labelRadius = radius - _labelPadding; + final labelRadius = radius - _labelPadding; Offset getOffsetForTheta(double theta) { return center + Offset(labelRadius * math.cos(theta), -labelRadius * math.sin(theta)); @@ -886,12 +900,12 @@ class _DialPainter extends CustomPainter { void paintLabels(List<_TappableLabel>? labels) { if (labels == null) return; - final double labelThetaIncrement = -_kTwoPi / labels.length; - double labelTheta = math.pi / 2.0; + final labelThetaIncrement = -_kTwoPi / labels.length; + var labelTheta = math.pi / 2.0; - for (final _TappableLabel label in labels) { - final TextPainter labelPainter = label.painter; - final Offset labelOffset = + for (final label in labels) { + final labelPainter = label.painter; + final labelOffset = Offset(-labelPainter.width / 2.0, -labelPainter.height / 2.0); labelPainter.paint(canvas, getOffsetForTheta(labelTheta) + labelOffset); labelTheta += labelThetaIncrement; @@ -900,9 +914,9 @@ class _DialPainter extends CustomPainter { paintLabels(primaryLabels); - final Paint selectorPaint = Paint()..color = accentColor; - final Offset focusedPoint = getOffsetForTheta(theta); - const double focusedRadius = _labelPadding - 4.0; + final selectorPaint = Paint()..color = accentColor; + final focusedPoint = getOffsetForTheta(theta); + const focusedRadius = _labelPadding - 4.0; canvas.drawCircle(centerPoint, 4.0, selectorPaint); canvas.drawCircle(focusedPoint, focusedRadius, selectorPaint); selectorPaint.strokeWidth = 2.0; @@ -912,13 +926,13 @@ class _DialPainter extends CustomPainter { // This checks that the selector's theta is between two labels. A remainder // between 0.1 and 0.45 indicates that the selector is roughly not above any // labels. The values were derived by manually testing the dial. - final double labelThetaIncrement = -_kTwoPi / primaryLabels.length; + final labelThetaIncrement = -_kTwoPi / primaryLabels.length; if (theta % labelThetaIncrement > 0.1 && theta % labelThetaIncrement < 0.45) { canvas.drawCircle(focusedPoint, 2.0, selectorPaint..color = dotColor); } - final Rect focusedRect = Rect.fromCircle( + final focusedRect = Rect.fromCircle( center: focusedPoint, radius: focusedRadius, ); @@ -1011,8 +1025,8 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { } void _animateTo(double targetTheta) { - final double currentTheta = _theta.value; - double beginTheta = + final currentTheta = _theta.value; + var beginTheta = _nearest(targetTheta, currentTheta, currentTheta + _kTwoPi); beginTheta = _nearest(targetTheta, beginTheta, currentTheta - _kTwoPi); _thetaTween @@ -1024,17 +1038,17 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { } double _getThetaForTime(TimeOfDay time) { - final int hoursFactor = widget.use24HourDials + final hoursFactor = widget.use24HourDials ? TimeOfDay.hoursPerDay : TimeOfDay.hoursPerPeriod; - final double fraction = widget.mode == _TimePickerMode.hour + final fraction = widget.mode == _TimePickerMode.hour ? (time.hour / hoursFactor) % hoursFactor : (time.minute / TimeOfDay.minutesPerHour) % TimeOfDay.minutesPerHour; return (math.pi / 2.0 - fraction * _kTwoPi) % _kTwoPi; } TimeOfDay _getTimeForTheta(double theta, {bool roundMinutes = false}) { - final double fraction = (0.25 - (theta % _kTwoPi) / _kTwoPi) % 1.0; + final fraction = (0.25 - (theta % _kTwoPi) / _kTwoPi) % 1.0; if (widget.mode == _TimePickerMode.hour) { int newHour; if (widget.use24HourDials) { @@ -1047,7 +1061,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { } return widget.selectedTime.replacing(hour: newHour); } else { - int minute = (fraction * TimeOfDay.minutesPerHour).round() % + var minute = (fraction * TimeOfDay.minutesPerHour).round() % TimeOfDay.minutesPerHour; if (roundMinutes) { // Round the minutes to nearest 5 minute interval. @@ -1058,8 +1072,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { } TimeOfDay _notifyOnChangedIfNeeded({bool roundMinutes = false}) { - final TimeOfDay current = - _getTimeForTheta(_theta.value, roundMinutes: roundMinutes); + final current = _getTimeForTheta(_theta.value, roundMinutes: roundMinutes); if (widget.onChanged == null) return current; if (current != widget.selectedTime) widget.onChanged!(current); return current; @@ -1067,12 +1080,12 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { void _updateThetaForPan({bool roundMinutes = false}) { setState(() { - final Offset offset = _position! - _center!; - double angle = - (math.atan2(offset.dx, offset.dy) - math.pi / 2.0) % _kTwoPi; + final offset = _position! - _center!; + var angle = (math.atan2(offset.dx, offset.dy) - math.pi / 2.0) % _kTwoPi; if (roundMinutes) { angle = _getThetaForTime( - _getTimeForTheta(angle, roundMinutes: roundMinutes)); + _getTimeForTheta(angle, roundMinutes: roundMinutes), + ); } _thetaTween ..begin = angle @@ -1086,7 +1099,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { void _handlePanStart(DragStartDetails details) { assert(!_dragging); _dragging = true; - final RenderBox box = context.findRenderObject()! as RenderBox; + final box = context.findRenderObject()! as RenderBox; _position = box.globalToLocal(details.globalPosition); _center = box.size.center(Offset.zero); _updateThetaForPan(); @@ -1111,26 +1124,33 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { } void _handleTapUp(TapUpDetails details) { - final RenderBox box = context.findRenderObject()! as RenderBox; + final box = context.findRenderObject()! as RenderBox; _position = box.globalToLocal(details.globalPosition); _center = box.size.center(Offset.zero); _updateThetaForPan(roundMinutes: true); - final TimeOfDay newTime = _notifyOnChangedIfNeeded(roundMinutes: true); + final newTime = _notifyOnChangedIfNeeded(roundMinutes: true); if (widget.mode == _TimePickerMode.hour) { if (widget.use24HourDials) { _announceToAccessibility( - context, localizations.formatDecimal(newTime.hour)); + context, + localizations.formatDecimal(newTime.hour), + ); } else { _announceToAccessibility( - context, localizations.formatDecimal(newTime.hourOfPeriod)); + context, + localizations.formatDecimal(newTime.hourOfPeriod), + ); } widget.onHourSelected?.call(); } else { _announceToAccessibility( - context, localizations.formatDecimal(newTime.minute)); + context, + localizations.formatDecimal(newTime.minute), + ); } _animateTo( - _getThetaForTime(_getTimeForTheta(_theta.value, roundMinutes: true))); + _getThetaForTime(_getTimeForTheta(_theta.value, roundMinutes: true)), + ); _dragging = false; _position = null; _center = null; @@ -1146,11 +1166,12 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { time = TimeOfDay(hour: hour, minute: widget.selectedTime.minute); } else { time = TimeOfDay( - hour: hour + TimeOfDay.hoursPerPeriod, - minute: widget.selectedTime.minute); + hour: hour + TimeOfDay.hoursPerPeriod, + minute: widget.selectedTime.minute, + ); } } - final double angle = _getThetaForTime(time); + final angle = _getThetaForTime(time); _thetaTween ..begin = angle ..end = angle; @@ -1159,11 +1180,11 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { void _selectMinute(int minute) { _announceToAccessibility(context, localizations.formatDecimal(minute)); - final TimeOfDay time = TimeOfDay( + final time = TimeOfDay( hour: widget.selectedTime.hour, minute: minute, ); - final double angle = _getThetaForTime(time); + final angle = _getThetaForTime(time); _thetaTween ..begin = angle ..end = angle; @@ -1200,9 +1221,14 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { TimeOfDay(hour: 22, minute: 0), ]; - _TappableLabel _buildTappableLabel(TextTheme textTheme, Color color, - int value, String label, VoidCallback onTap) { - final TextStyle style = textTheme.bodyText1!.copyWith(color: color); + _TappableLabel _buildTappableLabel( + TextTheme textTheme, + Color color, + int value, + String label, + VoidCallback onTap, + ) { + final style = textTheme.bodyText1!.copyWith(color: color); final double labelScaleFactor = math.min(MediaQuery.of(context).textScaleFactor, 2.0); return _TappableLabel( @@ -1223,8 +1249,10 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { textTheme, color, timeOfDay.hour, - localizations.formatHour(timeOfDay, - alwaysUse24HourFormat: media.alwaysUse24HourFormat), + localizations.formatHour( + timeOfDay, + alwaysUse24HourFormat: media.alwaysUse24HourFormat, + ), () { _selectHour(timeOfDay.hour); }, @@ -1238,8 +1266,10 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { textTheme, color, timeOfDay.hour, - localizations.formatHour(timeOfDay, - alwaysUse24HourFormat: media.alwaysUse24HourFormat), + localizations.formatHour( + timeOfDay, + alwaysUse24HourFormat: media.alwaysUse24HourFormat, + ), () { _selectHour(timeOfDay.hour); }, @@ -1247,7 +1277,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { ]; List<_TappableLabel> _buildMinutes(TextTheme textTheme, Color color) { - const List _minuteMarkerValues = [ + const _minuteMarkerValues = [ TimeOfDay(hour: 0, minute: 0), TimeOfDay(hour: 0, minute: 5), TimeOfDay(hour: 0, minute: 10), @@ -1278,18 +1308,21 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { @override Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final TimePickerThemeData pickerTheme = TimePickerTheme.of(context); - final Color backgroundColor = pickerTheme.dialBackgroundColor ?? + final theme = Theme.of(context); + final pickerTheme = TimePickerTheme.of(context); + final backgroundColor = pickerTheme.dialBackgroundColor ?? themeData.colorScheme.onBackground.withOpacity(0.12); - final Color accentColor = + final accentColor = pickerTheme.dialHandColor ?? themeData.colorScheme.primary; - final Color primaryLabelColor = MaterialStateProperty.resolveAs( - pickerTheme.dialTextColor, {}) ?? + final primaryLabelColor = MaterialStateProperty.resolveAs( + pickerTheme.dialTextColor, + {}, + ) ?? themeData.colorScheme.onSurface; - final Color secondaryLabelColor = MaterialStateProperty.resolveAs( - pickerTheme.dialTextColor, - {MaterialState.selected}) ?? + final secondaryLabelColor = MaterialStateProperty.resolveAs( + pickerTheme.dialTextColor, + {MaterialState.selected}, + ) ?? themeData.colorScheme.onPrimary; List<_TappableLabel> primaryLabels; List<_TappableLabel> secondaryLabels; @@ -1380,7 +1413,7 @@ class _TimePickerInputState extends State<_TimePickerInput> { return null; } - int? newHour = int.tryParse(value); + var newHour = int.tryParse(value); if (newHour == null) { return null; } @@ -1407,7 +1440,7 @@ class _TimePickerInputState extends State<_TimePickerInput> { return null; } - final int? newMinute = int.tryParse(value); + final newMinute = int.tryParse(value); if (newMinute == null) { return null; } @@ -1419,7 +1452,7 @@ class _TimePickerInputState extends State<_TimePickerInput> { } void _handleHourSavedSubmitted(String? value) { - final int? newHour = _parseHour(value); + final newHour = _parseHour(value); if (newHour != null) { _selectedTime = TimeOfDay(hour: newHour, minute: _selectedTime.minute); widget.onChanged(_selectedTime); @@ -1427,7 +1460,7 @@ class _TimePickerInputState extends State<_TimePickerInput> { } void _handleHourChanged(String value) { - final int? newHour = _parseHour(value); + final newHour = _parseHour(value); if (newHour != null && value.length == 2) { // If a valid hour is typed, move focus to the minute TextField. FocusScope.of(context).nextFocus(); @@ -1435,7 +1468,7 @@ class _TimePickerInputState extends State<_TimePickerInput> { } void _handleMinuteSavedSubmitted(String? value) { - final int? newMinute = _parseMinute(value); + final newMinute = _parseMinute(value); if (newMinute != null) { _selectedTime = TimeOfDay(hour: _selectedTime.hour, minute: int.parse(value!)); @@ -1449,7 +1482,7 @@ class _TimePickerInputState extends State<_TimePickerInput> { } String? _validateHour(String? value) { - final int? newHour = _parseHour(value); + final newHour = _parseHour(value); setState(() { hourHasError = newHour == null; }); @@ -1460,7 +1493,7 @@ class _TimePickerInputState extends State<_TimePickerInput> { } String? _validateMinute(String? value) { - final int? newMinute = _parseMinute(value); + final newMinute = _parseMinute(value); setState(() { minuteHasError = newMinute == null; }); @@ -1473,14 +1506,13 @@ class _TimePickerInputState extends State<_TimePickerInput> { @override Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); - final MediaQueryData media = MediaQuery.of(context); - final TimeOfDayFormat timeOfDayFormat = MaterialLocalizations.of(context) + final media = MediaQuery.of(context); + final timeOfDayFormat = MaterialLocalizations.of(context) .timeOfDayFormat(alwaysUse24HourFormat: media.alwaysUse24HourFormat); - final bool use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h; - final ThemeData theme = Theme.of(context); - final TextStyle hourMinuteStyle = - TimePickerTheme.of(context).hourMinuteTextStyle ?? - theme.textTheme.headline2!; + final use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h; + final theme = Theme.of(context); + final hourMinuteStyle = TimePickerTheme.of(context).hourMinuteTextStyle ?? + theme.textTheme.headline2!; return Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0), @@ -1709,10 +1741,8 @@ class _HourMinuteTextFieldState extends State<_HourMinuteTextField> { } String get _formattedValue { - final bool alwaysUse24HourFormat = - MediaQuery.of(context).alwaysUse24HourFormat; - final MaterialLocalizations localizations = - MaterialLocalizations.of(context); + final alwaysUse24HourFormat = MediaQuery.of(context).alwaysUse24HourFormat; + final localizations = MaterialLocalizations.of(context); return !widget.isHour ? localizations.formatMinute(widget.selectedTime) : localizations.formatHour( @@ -1723,12 +1753,11 @@ class _HourMinuteTextFieldState extends State<_HourMinuteTextField> { @override Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final TimePickerThemeData timePickerTheme = TimePickerTheme.of(context); - final ColorScheme colorScheme = theme.colorScheme; + final theme = Theme.of(context); + final timePickerTheme = TimePickerTheme.of(context); + final colorScheme = theme.colorScheme; - final InputDecorationTheme? inputDecorationTheme = - timePickerTheme.inputDecorationTheme; + final inputDecorationTheme = timePickerTheme.inputDecorationTheme; InputDecoration inputDecoration; if (inputDecorationTheme != null) { inputDecoration = @@ -1752,18 +1781,19 @@ class _HourMinuteTextFieldState extends State<_HourMinuteTextField> { hintStyle: widget.style .copyWith(color: colorScheme.onSurface.withOpacity(0.36)), errorStyle: const TextStyle( - fontSize: 0.0, - height: 0.0), // Prevent the error text from appearing. + fontSize: 0.0, + height: 0.0, + ), // Prevent the error text from appearing. ); } - final Color unfocusedFillColor = timePickerTheme.hourMinuteColor ?? + final unfocusedFillColor = timePickerTheme.hourMinuteColor ?? colorScheme.onSurface.withOpacity(0.12); // If screen reader is in use, make the hint text say hours/minutes. // Otherwise, remove the hint text when focused because the centered cursor // appears odd above the hint text. // // resolved, remove the window check for semantics being enabled on web. - final String? hintText = MediaQuery.of(context).accessibleNavigation || + final hintText = MediaQuery.of(context).accessibleNavigation || ui.window.semanticsEnabled ? widget.semanticHintText : (focusNode.hasFocus ? null : _formattedValue); @@ -1789,8 +1819,8 @@ class _HourMinuteTextFieldState extends State<_HourMinuteTextField> { textAlign: TextAlign.center, keyboardType: TextInputType.number, style: widget.style.copyWith( - color: - timePickerTheme.hourMinuteTextColor ?? colorScheme.onSurface), + color: timePickerTheme.hourMinuteTextColor ?? colorScheme.onSurface, + ), controller: controller, decoration: inputDecoration, validator: widget.validator, @@ -1930,11 +1960,15 @@ class _TimePickerWidgetState extends State { switch (_mode) { case _TimePickerMode.hour: _announceToAccessibility( - context, localizations.timePickerHourModeAnnouncement); + context, + localizations.timePickerHourModeAnnouncement, + ); break; case _TimePickerMode.minute: _announceToAccessibility( - context, localizations.timePickerMinuteModeAnnouncement); + context, + localizations.timePickerMinuteModeAnnouncement, + ); break; } _lastModeAnnounced = _mode; @@ -1945,13 +1979,14 @@ class _TimePickerWidgetState extends State { void _announceInitialTimeOnce() { if (_announcedInitialTime) return; - final MediaQueryData media = MediaQuery.of(context); - final MaterialLocalizations localizations = - MaterialLocalizations.of(context); + final media = MediaQuery.of(context); + final localizations = MaterialLocalizations.of(context); _announceToAccessibility( context, - localizations.formatTimeOfDay(widget.initialTime, - alwaysUse24HourFormat: media.alwaysUse24HourFormat), + localizations.formatTimeOfDay( + widget.initialTime, + alwaysUse24HourFormat: media.alwaysUse24HourFormat, + ), ); _announcedInitialTime = true; } @@ -1987,7 +2022,7 @@ class _TimePickerWidgetState extends State { void _handleOk() { if (_entryMode == TimePickerEntryMode.input) { - final FormState form = _formKey.currentState!; + final form = _formKey.currentState!; form.save(); } @@ -1995,8 +2030,8 @@ class _TimePickerWidgetState extends State { } Size _dialogSize(BuildContext context) { - final Orientation orientation = MediaQuery.of(context).orientation; - final ThemeData theme = Theme.of(context); + final orientation = MediaQuery.of(context).orientation; + final theme = Theme.of(context); // Constrain the textScaleFactor to prevent layout issues. Since only some // parts of the time picker scale up with textScaleFactor, we cap the factor // to 1.1 as that provides enough space to reasonably fit all the content. @@ -2035,12 +2070,13 @@ class _TimePickerWidgetState extends State { @override Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); - final MediaQueryData media = MediaQuery.of(context); - final TimeOfDayFormat timeOfDayFormat = localizations.timeOfDayFormat( - alwaysUse24HourFormat: media.alwaysUse24HourFormat); - final bool use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h; - final ThemeData theme = Theme.of(context); - final Orientation orientation = media.orientation; + final media = MediaQuery.of(context); + final timeOfDayFormat = localizations.timeOfDayFormat( + alwaysUse24HourFormat: media.alwaysUse24HourFormat, + ); + final use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h; + final theme = Theme.of(context); + final orientation = media.orientation; final Widget actions = Row( children: [ @@ -2051,9 +2087,11 @@ class _TimePickerWidgetState extends State { theme.colorScheme.brightness == Brightness.dark ? 1.0 : 0.6, ), onPressed: _handleEntryModeToggle, - icon: Icon(_entryMode == TimePickerEntryMode.dial - ? Icons.keyboard - : Icons.access_time), + icon: Icon( + _entryMode == TimePickerEntryMode.dial + ? Icons.keyboard + : Icons.access_time, + ), tooltip: _entryMode == TimePickerEntryMode.dial ? MaterialLocalizations.of(context).inputTimeModeButtonLabel : MaterialLocalizations.of(context).dialModeButtonLabel, @@ -2070,7 +2108,8 @@ class _TimePickerWidgetState extends State { TextButton( onPressed: _handleCancel, child: Text( - widget.cancelText ?? localizations.cancelButtonLabel), + widget.cancelText ?? localizations.cancelButtonLabel, + ), ), TextButton( onPressed: _handleOk, @@ -2176,7 +2215,7 @@ class _TimePickerWidgetState extends State { break; } - final Size dialogSize = _dialogSize(context); + final dialogSize = _dialogSize(context); return AnimatedContainer( width: dialogSize.width, height: dialogSize.height, diff --git a/lib/src/widget/survey_kit_audio_player.dart b/lib/src/widget/survey_kit_audio_player.dart new file mode 100644 index 00000000..118c34a2 --- /dev/null +++ b/lib/src/widget/survey_kit_audio_player.dart @@ -0,0 +1,56 @@ +import 'package:audioplayers/audioplayers.dart'; +import 'package:flutter/material.dart'; + +class SurveyKitAudioPlayer extends StatefulWidget { + const SurveyKitAudioPlayer({ + super.key, + required this.audioUrl, + }); + final String audioUrl; + + @override + State createState() => _SurveyKitAudioPlayerState(); +} + +class _SurveyKitAudioPlayerState extends State { + late final AudioPlayer player; + late final Future audioReady; + + @override + void initState() { + super.initState(); + player = AudioPlayer(); + audioReady = player.setSourceUrl(widget.audioUrl); + } + + @override + Widget build(BuildContext context) { + return Container( + height: 50, + child: FutureBuilder( + future: audioReady, + builder: (_, snapshot) { + if (ConnectionState.done == snapshot.connectionState) { + return IconButton( + onPressed: () { + if (player.state == PlayerState.playing) { + player.pause(); + } else { + player.resume(); + } + setState(() {}); + }, + icon: Icon( + player.state == PlayerState.playing + ? Icons.pause + : Icons.play_arrow, + ), + ); + } else { + return const SizedBox.shrink(); + } + }, + ), + ); + } +} diff --git a/lib/src/widget/survey_kit_markdown.dart b/lib/src/widget/survey_kit_markdown.dart new file mode 100644 index 00000000..aa6c809f --- /dev/null +++ b/lib/src/widget/survey_kit_markdown.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; + +class SurveyKitMarkdown extends StatelessWidget { + const SurveyKitMarkdown({ + super.key, + required this.markdown, + }); + + final String markdown; + + @override + Widget build(BuildContext context) { + return MarkdownBody( + data: markdown, + selectable: true, + ); + } +} diff --git a/lib/src/widget/survey_kit_video_player.dart b/lib/src/widget/survey_kit_video_player.dart new file mode 100644 index 00000000..7bace423 --- /dev/null +++ b/lib/src/widget/survey_kit_video_player.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:video_player/video_player.dart'; + +class SurveyKitVideoPlayer extends StatefulWidget { + const SurveyKitVideoPlayer({ + super.key, + required this.videoUrl, + }); + + final String videoUrl; + + @override + State createState() => _SurveyKitVideoPlayerState(); +} + +class _SurveyKitVideoPlayerState extends State { + late VideoPlayerController _controller; + + @override + void initState() { + super.initState(); + _controller = VideoPlayerController.network( + widget.videoUrl, + )..initialize().then((_) { + // Ensure the first frame is shown after the video is initialized, even before the play button has been pressed. + setState(() {}); + }); + } + + @override + Widget build(BuildContext context) { + return Container( + height: 300, + child: MaterialApp( + title: 'Video Demo', + home: Scaffold( + body: Center( + child: _controller.value.isInitialized + ? AspectRatio( + aspectRatio: _controller.value.aspectRatio, + child: VideoPlayer(_controller), + ) + : Container(), + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + setState(() { + _controller.value.isPlaying + ? _controller.pause() + : _controller.play(); + }); + }, + child: Icon( + _controller.value.isPlaying ? Icons.pause : Icons.play_arrow, + ), + ), + ), + ), + ); + } + + @override + void dispose() { + super.dispose(); + _controller.dispose(); + } +} diff --git a/lib/src/widget/survey_progress.dart b/lib/src/widget/survey_progress.dart index c3829cc9..aea1b29f 100644 --- a/lib/src/widget/survey_progress.dart +++ b/lib/src/widget/survey_progress.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:survey_kit/src/presenter/survey_presenter.dart'; import 'package:survey_kit/src/presenter/survey_state.dart'; -import 'package:survey_kit/src/widget/survey_progress_configuration.dart'; +import 'package:survey_kit/src/survey_configuration.dart'; +import 'package:survey_kit/src/survey_presenter_inherited.dart'; class SurveyProgress extends StatefulWidget { const SurveyProgress({Key? key}) : super(key: key); @@ -15,54 +14,55 @@ class _SurveyProgressState extends State { @override Widget build(BuildContext context) { final progressbarConfiguration = - context.read(); - return BlocBuilder(builder: (context, state) { - if (state is PresentingSurveyState) { - return Padding( - padding: progressbarConfiguration.padding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - progressbarConfiguration.showLabel && - progressbarConfiguration.label != null - ? progressbarConfiguration.label!( - state.currentStepIndex.toString(), - state.stepCount.toString()) - : SizedBox.shrink(), - ClipRRect( - borderRadius: progressbarConfiguration.borderRadius ?? - BorderRadius.circular(14.0), - child: Stack( - children: [ - Container( - width: MediaQuery.of(context).size.width, - height: progressbarConfiguration.height, - color: progressbarConfiguration.progressbarColor, - ), - LayoutBuilder( - builder: (context, constraints) { - return AnimatedContainer( - duration: const Duration(milliseconds: 300), - curve: Curves.linear, - width: (state.currentStepIndex + 1) / - state.stepCount * - constraints.maxWidth, - height: progressbarConfiguration.height, - color: - progressbarConfiguration.valueProgressbarColor ?? - Theme.of(context).primaryColor, - ); - }, - ), - ], - ), + SurveyConfiguration.of(context).surveyProgressConfiguration; + final state = SurveyPresenterInherited.of(context).state; + + if (state is PresentingSurveyState) { + return Padding( + padding: progressbarConfiguration.padding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (progressbarConfiguration.showLabel && + progressbarConfiguration.label != null) + progressbarConfiguration.label!( + state.currentStepIndex.toString(), + state.stepCount.toString(), + ) + else + const SizedBox.shrink(), + ClipRRect( + borderRadius: progressbarConfiguration.borderRadius ?? + BorderRadius.circular(14.0), + child: Stack( + children: [ + Container( + width: MediaQuery.of(context).size.width, + height: progressbarConfiguration.height, + color: progressbarConfiguration.progressbarColor, + ), + LayoutBuilder( + builder: (context, constraints) { + return AnimatedContainer( + duration: const Duration(milliseconds: 300), + curve: Curves.linear, + width: (state.currentStepIndex + 1) / + state.stepCount * + constraints.maxWidth, + height: progressbarConfiguration.height, + color: progressbarConfiguration.valueProgressbarColor ?? + Theme.of(context).primaryColor, + ); + }, + ), + ], ), - ], - ), - ); - } - return SizedBox.shrink(); - }); + ), + ], + ), + ); + } + return const SizedBox.shrink(); } } diff --git a/lib/src/widget/survey_progress_configuration.dart b/lib/src/widget/survey_progress_configuration.dart index 1d9a9e83..2d05ba4a 100644 --- a/lib/src/widget/survey_progress_configuration.dart +++ b/lib/src/widget/survey_progress_configuration.dart @@ -23,7 +23,7 @@ class SurveyProgressConfiguration { /// Label widget which should be shown above the appbar (Also need to /// activate via the 'showLabel flag {from currentProgress, to /// finishOfProgress}) - final Function(String from, String to)? label; + final Widget Function(String from, String to)? label; /// The corner radius of the progress bar - If not defines /// BorderRadius.circular(14.0) diff --git a/lib/survey_kit.dart b/lib/survey_kit.dart index 609524c3..fafbf000 100644 --- a/lib/survey_kit.dart +++ b/lib/survey_kit.dart @@ -24,7 +24,6 @@ export 'src/navigator/rules/navigation_rule.dart'; export 'src/navigator/rules/rule_not_defined_exception.dart'; export 'src/navigator/task_navigator.dart'; export 'src/presenter/survey_event.dart'; -export 'src/presenter/survey_presenter.dart'; export 'src/presenter/survey_state.dart'; export 'src/result/question/boolean_question_result.dart'; export 'src/result/question/date_question_result.dart'; @@ -43,9 +42,14 @@ export 'src/result/step/completion_step_result.dart'; export 'src/result/step/instruction_step_result.dart'; export 'src/result/step_result.dart'; export 'src/result/survey/survey_result.dart'; +export 'src/steps/cms_steps/audio_cms_step.dart'; +export 'src/steps/cms_steps/cms_content_step.dart'; +export 'src/steps/cms_steps/markdown_cms_step.dart'; +export 'src/steps/cms_steps/video_cms_step.dart'; export 'src/steps/identifier/identifier.dart'; export 'src/steps/identifier/step_identifier.dart'; export 'src/steps/predefined_steps/answer_format_not_defined_exception.dart'; +export 'src/steps/predefined_steps/cms_step.dart'; export 'src/steps/predefined_steps/completion_step.dart'; export 'src/steps/predefined_steps/instruction_step.dart'; export 'src/steps/predefined_steps/question_step.dart'; @@ -58,6 +62,7 @@ export 'src/task/ordered_task.dart'; export 'src/task/task.dart'; export 'src/task/task_not_defined_exception.dart'; export 'src/views/boolean_answer_view.dart'; +export 'src/views/cms_step_view.dart'; export 'src/views/completion_view.dart'; export 'src/views/date_answer_view.dart'; export 'src/views/decoration/input_decoration.dart'; diff --git a/pubspec.lock b/pubspec.lock index 750ca4b0..a56fb114 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -36,8 +36,57 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.9.0" - bloc: + audioplayers: dependency: "direct main" + description: + name: audioplayers + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + audioplayers_android: + dependency: transitive + description: + name: audioplayers_android + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + audioplayers_darwin: + dependency: transitive + description: + name: audioplayers_darwin + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + audioplayers_linux: + dependency: transitive + description: + name: audioplayers_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + audioplayers_platform_interface: + dependency: transitive + description: + name: audioplayers_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + audioplayers_web: + dependency: transitive + description: + name: audioplayers_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + audioplayers_windows: + dependency: transitive + description: + name: audioplayers_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + bloc: + dependency: transitive description: name: bloc url: "https://pub.dartlang.org" @@ -232,6 +281,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" file: dependency: transitive description: @@ -258,6 +314,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "8.0.1" + flutter_markdown: + dependency: "direct main" + description: + name: flutter_markdown + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.13" flutter_platform_widgets: dependency: "direct main" description: @@ -296,13 +359,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.2" - go_router: - dependency: "direct main" - description: - name: go_router - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.0" graphs: dependency: transitive description: @@ -422,6 +478,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + markdown: + dependency: transitive + description: + name: markdown + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.1" matcher: dependency: transitive description: @@ -471,6 +534,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.2" + path_provider: + dependency: transitive + description: + name: path_provider + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.22" + path_provider_ios: + dependency: transitive + description: + name: path_provider_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.7" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.6" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" plugin_platform_interface: dependency: transitive description: @@ -485,8 +604,15 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.5.0" + process: + dependency: transitive + description: + name: process + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.4" provider: - dependency: "direct main" + dependency: transitive description: name: provider url: "https://pub.dartlang.org" @@ -672,6 +798,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.0" + win32: + dependency: transitive + description: + name: win32 + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.2" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0+2" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 35bdf908..32f4325b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,7 +10,7 @@ environment: flutter: ">=1.20.0" dependencies: - bloc: ^8.0.3 + audioplayers: ^1.1.1 camera: ^0.10.0+1 collection: ^1.15.0 cupertino_icons: ^1.0.2 @@ -18,13 +18,12 @@ dependencies: flutter: sdk: flutter flutter_bloc: ^8.0.1 + flutter_markdown: ^0.6.13 flutter_platform_widgets: ^2.0.0 - go_router: ^4.0.0 image_picker: ^0.8.5+3 intl: ^0.17.0 json_annotation: ^4.0.1 lottie: ^1.0.1 - provider: ^6.0.2 uuid: ^3.0.4 video_player: ^2.1.6 diff --git a/test/src/result/question/multiple_choice_question_result_test.dart b/test/src/result/question/multiple_choice_question_result_test.dart index c4e7dfd6..ef723069 100644 --- a/test/src/result/question/multiple_choice_question_result_test.dart +++ b/test/src/result/question/multiple_choice_question_result_test.dart @@ -7,7 +7,7 @@ void main() { startDate: DateTime(2022, 8, 12, 16, 4), endDate: DateTime(2022, 8, 12, 16, 14), valueIdentifier: 'multiChoice1', - result: [ + result: const [ TextChoice(text: 'doubleVal1', value: '123.45'), TextChoice(text: 'doubleVal2', value: '234.56'), ], diff --git a/test/src/result/question/single_choice_result_test.dart b/test/src/result/question/single_choice_result_test.dart index 5c6cd9a0..0fb9c958 100644 --- a/test/src/result/question/single_choice_result_test.dart +++ b/test/src/result/question/single_choice_result_test.dart @@ -7,7 +7,7 @@ void main() { startDate: DateTime(2022, 8, 12, 16, 4), endDate: DateTime(2022, 8, 12, 16, 14), valueIdentifier: 'singleChoiceValue1', - result: TextChoice(text: 'choice1', value: 'option2'), + result: const TextChoice(text: 'choice1', value: 'option2'), ); group('serialisation', () { diff --git a/test/src/result/question/time_question_result_test.dart b/test/src/result/question/time_question_result_test.dart index 7a7031b0..c567811a 100644 --- a/test/src/result/question/time_question_result_test.dart +++ b/test/src/result/question/time_question_result_test.dart @@ -8,7 +8,7 @@ void main() { startDate: DateTime(2022, 8, 12, 16, 4), endDate: DateTime(2022, 8, 12, 16, 14), valueIdentifier: 'timeInput1', - result: TimeOfDay(hour: 14, minute: 59), + result: const TimeOfDay(hour: 14, minute: 59), ); group('serialisation', () { diff --git a/test/src/result/step/video_step_result_test.dart b/test/src/result/step/video_step_result_test.dart index e0780dc4..6a8dbb80 100644 --- a/test/src/result/step/video_step_result_test.dart +++ b/test/src/result/step/video_step_result_test.dart @@ -9,7 +9,7 @@ void main() { endDate: DateTime(2022, 8, 12, 16, 14), result: VideoResult( stayedInVideo: DateTime(2022, 8, 12, 16, 12, 30), - leftVideoAt: Duration(minutes: 1, seconds: 13, milliseconds: 123), + leftVideoAt: const Duration(minutes: 1, seconds: 13, milliseconds: 123), ), ); diff --git a/test/src/survey/survey_result_test.dart b/test/src/survey/survey_result_test.dart index 9119994e..15ce77dd 100644 --- a/test/src/survey/survey_result_test.dart +++ b/test/src/survey/survey_result_test.dart @@ -2,7 +2,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:survey_kit/survey_kit.dart'; void main() { - final List tQuestionResults = ([ + final tQuestionResults = [ InstructionStepResult( Identifier(id: 'example1_intro'), DateTime(2022, 8, 12, 16, 4), @@ -20,7 +20,7 @@ void main() { DateTime(2022, 8, 12, 16, 10), DateTime(2022, 8, 12, 16, 14), ), - ]); + ]; final tSurveyResult = SurveyResult( id: Identifier(id: 'example1'), startDate: DateTime(2022, 8, 12, 16, 4), diff --git a/test/steps/identifier/identifier_test.dart b/test/steps/identifier/identifier_test.dart index 5f816fdd..d45315e5 100644 --- a/test/steps/identifier/identifier_test.dart +++ b/test/steps/identifier/identifier_test.dart @@ -5,12 +5,13 @@ import 'package:survey_kit/survey_kit.dart'; void main() { test('identifier created by json is the same as created by code', () { - final jsonStr = ''' + const jsonStr = ''' { "id":"123" } '''; - final jsonIdentifier = Identifier.fromJson(json.decode(jsonStr)); + final jsonIdentifier = + Identifier.fromJson(json.decode(jsonStr) as Map); final identifier = Identifier(id: '123'); expect(identifier, jsonIdentifier); diff --git a/test/steps/step_test.dart b/test/steps/step_test.dart index 2cbc48ae..dab7d8e8 100644 --- a/test/steps/step_test.dart +++ b/test/steps/step_test.dart @@ -7,40 +7,44 @@ import 'package:survey_kit/src/steps/step.dart'; void main() { test('instruction step is the same created by json and code', () { - final jsonStr = ''' + const jsonStr = r''' { "stepIdentifier": { "id": "1" }, "type": "intro", - "title": "Welcome to the\\nQuickBird Studios\\nHealth Survey", + "title": "Welcome to the\nQuickBird Studios\nHealth Survey", "text": "Get ready for a bunch of super random questions!", "buttonText": "Let's go!" } '''; - final jsonStep = Step.fromJson(json.decode(jsonStr)); + final jsonStep = + Step.fromJson(json.decode(jsonStr) as Map); final step = InstructionStep( - stepIdentifier: StepIdentifier(id: "1"), + stepIdentifier: StepIdentifier(id: '1'), title: 'Welcome to the\nQuickBird Studios\nHealth Survey', text: 'Get ready for a bunch of super random questions!', - buttonText: 'Let\'s go!', + buttonText: "Let's go!", ); expect(step, jsonStep); }); test('throw step not defined exception of type is unvalid', () { - final jsonStr = ''' + const jsonStr = r''' { "stepIdentifier": { "id": "1" }, "type": "undefined", - "title": "Welcome to the\\nQuickBird Studios\\nHealth Survey", + "title": "Welcome to the\nQuickBird Studios\nHealth Survey", "text": "Get ready for a bunch of super random questions!", "buttonText": "Let's go!" } '''; - expect(() => Step.fromJson(json.decode(jsonStr)), throwsException); + expect( + () => Step.fromJson(json.decode(jsonStr) as Map), + throwsException, + ); }); } diff --git a/test/surveykit_flutter_test.dart b/test/surveykit_flutter_test.dart index 93bf931d..9dca597b 100644 --- a/test/surveykit_flutter_test.dart +++ b/test/surveykit_flutter_test.dart @@ -9,16 +9,16 @@ void main() { home: Scaffold( body: SurveyKit( task: OrderedTask( - id: TaskIdentifier(id: "1"), + id: TaskIdentifier(id: '1'), steps: [ InstructionStep( title: 'Welcome to the\nQuickBird Studios\nHealth Survey', text: 'Get ready for a bunch of super random questions!', - buttonText: 'Let\'s go!', + buttonText: "Let's go!", ), QuestionStep( title: 'How old are you?', - answerFormat: IntegerAnswerFormat( + answerFormat: const IntegerAnswerFormat( defaultValue: 25, hint: 'Please enter your age', ), @@ -41,7 +41,7 @@ void main() { await tester.pumpWidget(surveyWidget); await tester.pumpAndSettle(); - final introButton = find.text('Let\'s go!'.toUpperCase()); + final introButton = find.text("Let's go!".toUpperCase()); expect(introButton, findsOneWidget); await tester.tap(introButton); diff --git a/test/task/navigable_task_test.dart b/test/task/navigable_task_test.dart index 7240eab2..85b1553e 100644 --- a/test/task/navigable_task_test.dart +++ b/test/task/navigable_task_test.dart @@ -5,7 +5,7 @@ import 'package:survey_kit/survey_kit.dart'; void main() { test('navigable task created by json is the same as created via code', () { - final jsonStr = ''' + const jsonStr = ''' { "id": "123", "type": "navigable", @@ -23,7 +23,7 @@ void main() { ] } '''; - final NavigableTask navigableTask = NavigableTask( + final navigableTask = NavigableTask( id: TaskIdentifier(id: '123'), steps: [], ); @@ -32,9 +32,9 @@ void main() { navigationRule: ConditionalNavigationRule( resultToStepIdentifierMapper: (input) { switch (input) { - case "Yes": + case 'Yes': return StepIdentifier(id: '321'); - case "No": + case 'No': return StepIdentifier(id: '456'); default: return null; @@ -43,7 +43,8 @@ void main() { ), ); - final navigableJsonTask = NavigableTask.fromJson(json.decode(jsonStr)); + final navigableJsonTask = + NavigableTask.fromJson(json.decode(jsonStr) as Map); expect(navigableJsonTask, navigableTask); }); diff --git a/test/task/ordered_task_test.dart b/test/task/ordered_task_test.dart index 09b2aaaf..04b6bc16 100644 --- a/test/task/ordered_task_test.dart +++ b/test/task/ordered_task_test.dart @@ -5,7 +5,7 @@ import 'package:survey_kit/survey_kit.dart'; void main() { test('ordered task created by json is the same as created via code', () { - final jsonStr = ''' + const jsonStr = ''' { "id": "123", "type": "ordered" @@ -14,7 +14,8 @@ void main() { final Task orderedTask = OrderedTask(id: TaskIdentifier(id: '123'), steps: []); - final orderedJsonTask = OrderedTask.fromJson(json.decode(jsonStr)); + final orderedJsonTask = + OrderedTask.fromJson(json.decode(jsonStr) as Map); expect(orderedTask, orderedJsonTask); }); From 2dd597e6f8a2f1709ba6a143b3f9e708c77fe529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Ma=CC=88rz?= Date: Thu, 15 Dec 2022 13:46:25 +0100 Subject: [PATCH 002/108] chore/lint --- CHANGELOG.md | 3 ++ analysis_options.yaml | 2 +- example/lib/main.dart | 2 +- .../answer_format/boolean_answer_format.dart | 4 +-- lib/src/answer_format/multi_double.dart | 4 ++- lib/src/answer_format/text_choice.dart | 5 ++- lib/src/presenter/survey_state.dart | 6 ++-- lib/src/result/step_result.dart | 16 ++++----- lib/src/result/survey/survey_result.dart | 7 ++-- lib/src/steps/identifier/identifier.dart | 4 ++- lib/src/steps/identifier/step_identifier.dart | 2 +- lib/src/steps/predefined_steps/cms_step.dart | 11 +++---- .../predefined_steps/completion_step.dart | 8 +++-- .../predefined_steps/instruction_step.dart | 11 ++++--- lib/src/steps/step.dart | 1 + lib/src/survey_configuration.dart | 6 ++-- lib/src/survey_presenter_inherited.dart | 16 ++++----- lib/src/task/navigable_task.dart | 6 ++-- lib/src/task/task.dart | 3 ++ lib/src/views/boolean_answer_view.dart | 16 ++++----- lib/src/views/cms_step_view.dart | 3 +- .../views/multiple_double_answer_view.dart | 2 +- lib/src/views/widget/selection_list_tile.dart | 2 +- .../boolean_question_result_test.dart | 2 +- .../multiple_double_question_result_test.dart | 2 +- test/src/survey/survey_result_test.dart | 4 +-- test/surveykit_flutter_test.dart | 2 +- test/task/navigable_task_test.dart | 33 +++++++++---------- test/task/ordered_task_test.dart | 2 +- 29 files changed, 101 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9082b9a9..413ea075 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# 0.2.0 +- BREAKING: BooleanResult is now lowercase +- BREAKING: FinishReason is now lowercase # 0.1.1 - INFO: Update dependencies (Flutter 3.0.2) # 0.1.0 diff --git a/analysis_options.yaml b/analysis_options.yaml index d4b479d7..221a3851 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -63,7 +63,7 @@ linter: - cancel_subscriptions - cascade_invocations - cast_nullable_to_non_nullable - - comment_references + # - comment_references - constant_identifier_names - control_flow_in_finally - curly_braces_in_flow_control_structures diff --git a/example/lib/main.dart b/example/lib/main.dart index 1c6998fc..41a29690 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -184,7 +184,7 @@ class _MyAppState extends State { answerFormat: const BooleanAnswerFormat( positiveAnswer: 'Yes', negativeAnswer: 'No', - result: BooleanResult.POSITIVE, + result: BooleanResult.positive, ), ), QuestionStep( diff --git a/lib/src/answer_format/boolean_answer_format.dart b/lib/src/answer_format/boolean_answer_format.dart index 39d01434..3bebd4fa 100644 --- a/lib/src/answer_format/boolean_answer_format.dart +++ b/lib/src/answer_format/boolean_answer_format.dart @@ -12,7 +12,7 @@ class BooleanAnswerFormat implements AnswerFormat { const BooleanAnswerFormat({ required this.positiveAnswer, required this.negativeAnswer, - this.result = BooleanResult.NONE, + this.result = BooleanResult.none, }) : super(); factory BooleanAnswerFormat.fromJson(Map json) => @@ -21,4 +21,4 @@ class BooleanAnswerFormat implements AnswerFormat { Map toJson() => _$BooleanAnswerFormatToJson(this); } -enum BooleanResult { NONE, POSITIVE, NEGATIVE } +enum BooleanResult { none, positive, negative } diff --git a/lib/src/answer_format/multi_double.dart b/lib/src/answer_format/multi_double.dart index e6696334..ad139be2 100644 --- a/lib/src/answer_format/multi_double.dart +++ b/lib/src/answer_format/multi_double.dart @@ -1,13 +1,15 @@ +import 'package:flutter/foundation.dart'; import 'package:json_annotation/json_annotation.dart'; part 'multi_double.g.dart'; @JsonSerializable() +@immutable class MultiDouble { final String text; final double value; - MultiDouble({ + const MultiDouble({ required this.text, required this.value, }) : super(); diff --git a/lib/src/answer_format/text_choice.dart b/lib/src/answer_format/text_choice.dart index e3bc43e8..cb17b354 100644 --- a/lib/src/answer_format/text_choice.dart +++ b/lib/src/answer_format/text_choice.dart @@ -1,8 +1,10 @@ +import 'package:flutter/foundation.dart'; import 'package:json_annotation/json_annotation.dart'; part 'text_choice.g.dart'; @JsonSerializable() +@immutable class TextChoice { final String text; final String value; @@ -17,7 +19,8 @@ class TextChoice { Map toJson() => _$TextChoiceToJson(this); @override - bool operator ==(Object o) => o is TextChoice && text == o.text && value == o.value; + bool operator ==(Object other) => + other is TextChoice && text == other.text && value == other.value; @override int get hashCode => text.hashCode ^ value.hashCode; } diff --git a/lib/src/presenter/survey_state.dart b/lib/src/presenter/survey_state.dart index 4c543237..24e81898 100644 --- a/lib/src/presenter/survey_state.dart +++ b/lib/src/presenter/survey_state.dart @@ -1,8 +1,10 @@ +import 'package:flutter/foundation.dart'; import 'package:survey_kit/src/configuration/app_bar_configuration.dart'; import 'package:survey_kit/src/result/question_result.dart'; import 'package:survey_kit/src/result/survey/survey_result.dart'; import 'package:survey_kit/src/steps/step.dart'; +@immutable abstract class SurveyState { const SurveyState(); } @@ -19,7 +21,7 @@ class PresentingSurveyState extends SurveyState { final int stepCount; final bool isPreviousStep; - PresentingSurveyState({ + const PresentingSurveyState({ required this.stepCount, required this.appBarConfiguration, required this.currentStep, @@ -58,7 +60,7 @@ class SurveyResultState extends SurveyState { final Step? currentStep; final QuestionResult? stepResult; - SurveyResultState({ + const SurveyResultState({ required this.result, this.stepResult, required this.currentStep, diff --git a/lib/src/result/step_result.dart b/lib/src/result/step_result.dart index b31646f0..e98c3539 100644 --- a/lib/src/result/step_result.dart +++ b/lib/src/result/step_result.dart @@ -23,12 +23,12 @@ class StepResult extends Result { @_Converter() final List results; - const StepResult( - {required Identifier? id, - required DateTime startDate, - required DateTime endDate, - required this.results,}) - : super(id: id, startDate: startDate, endDate: endDate); + const StepResult({ + required Identifier? id, + required DateTime startDate, + required DateTime endDate, + required this.results, + }) : super(id: id, startDate: startDate, endDate: endDate); factory StepResult.fromQuestion({required QuestionResult questionResult}) { return StepResult( @@ -113,7 +113,7 @@ class _Converter implements JsonConverter, Object> { qrJson['type'] = (VideoStepResult).toString(); allQuestionResultsEncoded.add(qrJson); } else { - throw 'Unhandled Question Result Type'; + throw Exception('Unhandled Question Result Type'); } } @@ -154,7 +154,7 @@ class _Converter implements JsonConverter, Object> { } else if (qType == (VideoStepResult).toString()) { results.add(VideoStepResult.fromJson(qData)); } else { - throw 'Unhandled Question Result Type'; + throw Exception('Unhandled Question Result Type'); } } diff --git a/lib/src/result/survey/survey_result.dart b/lib/src/result/survey/survey_result.dart index 564cdbca..4bad568d 100644 --- a/lib/src/result/survey/survey_result.dart +++ b/lib/src/result/survey/survey_result.dart @@ -17,8 +17,9 @@ class SurveyResult extends Result { required this.finishReason, required this.results, }) : super(id: id, startDate: startDate, endDate: endDate); - - factory SurveyResult.fromJson(Map json) => _$SurveyResultFromJson(json); + + factory SurveyResult.fromJson(Map json) => + _$SurveyResultFromJson(json); Map toJson() => _$SurveyResultToJson(this); @@ -26,4 +27,4 @@ class SurveyResult extends Result { List get props => [id, startDate, endDate, finishReason]; } -enum FinishReason { SAVED, DISCARDED, COMPLETED, FAILED } +enum FinishReason { saved, discarded, completed, failed } diff --git a/lib/src/steps/identifier/identifier.dart b/lib/src/steps/identifier/identifier.dart index 3ae5bc84..a3b637cf 100644 --- a/lib/src/steps/identifier/identifier.dart +++ b/lib/src/steps/identifier/identifier.dart @@ -1,9 +1,11 @@ +import 'package:flutter/material.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:uuid/uuid.dart'; part 'identifier.g.dart'; @JsonSerializable() +@immutable class Identifier { final String id; @@ -14,7 +16,7 @@ class Identifier { Map toJson() => _$IdentifierToJson(this); @override - bool operator ==(Object o) => o is Identifier && o.id == id; + bool operator ==(Object other) => other is Identifier && other.id == id; @override int get hashCode => id.hashCode; } diff --git a/lib/src/steps/identifier/step_identifier.dart b/lib/src/steps/identifier/step_identifier.dart index 7716bfde..0035706c 100644 --- a/lib/src/steps/identifier/step_identifier.dart +++ b/lib/src/steps/identifier/step_identifier.dart @@ -13,7 +13,7 @@ class StepIdentifier extends Identifier { Map toJson() => _$StepIdentifierToJson(this); @override - bool operator ==(Object o) => o is StepIdentifier && id == o.id; + bool operator ==(Object other) => other is StepIdentifier && id == other.id; @override int get hashCode => id.hashCode; } diff --git a/lib/src/steps/predefined_steps/cms_step.dart b/lib/src/steps/predefined_steps/cms_step.dart index 3d926681..15aa3293 100644 --- a/lib/src/steps/predefined_steps/cms_step.dart +++ b/lib/src/steps/predefined_steps/cms_step.dart @@ -4,9 +4,10 @@ import 'package:survey_kit/src/steps/cms_steps/cms_content_step.dart'; import 'package:survey_kit/src/views/cms_step_view.dart'; @JsonSerializable() +@immutable class CMSStep { final List contextSteps; - CMSStep({ + const CMSStep({ required this.contextSteps, }); @@ -17,12 +18,8 @@ class CMSStep { } @override - bool operator ==(Object o) => super == o && o is CMSStep; + bool operator ==(Object other) => super == other && other is CMSStep; @override - // TODO: implement hashCode - int get hashCode => super.hashCode; - - - + int get hashCode => super.hashCode ^ contextSteps.hashCode; } diff --git a/lib/src/steps/predefined_steps/completion_step.dart b/lib/src/steps/predefined_steps/completion_step.dart index d7a36b88..ea39cf40 100644 --- a/lib/src/steps/predefined_steps/completion_step.dart +++ b/lib/src/steps/predefined_steps/completion_step.dart @@ -8,6 +8,7 @@ import 'package:survey_kit/src/views/completion_view.dart'; part 'completion_step.g.dart'; @JsonSerializable() +@immutable class CompletionStep extends Step { final String title; final String text; @@ -39,8 +40,11 @@ class CompletionStep extends Step { Map toJson() => _$CompletionStepToJson(this); @override - bool operator ==(Object o) => - super == o && o is CompletionStep && o.title == title && o.text == text; + bool operator ==(Object other) => + super == other && + other is CompletionStep && + other.title == title && + other.text == text; @override int get hashCode => super.hashCode ^ title.hashCode ^ text.hashCode; } diff --git a/lib/src/steps/predefined_steps/instruction_step.dart b/lib/src/steps/predefined_steps/instruction_step.dart index 6675050b..a992ebf3 100644 --- a/lib/src/steps/predefined_steps/instruction_step.dart +++ b/lib/src/steps/predefined_steps/instruction_step.dart @@ -8,6 +8,7 @@ import 'package:survey_kit/src/views/instruction_view.dart'; part 'instruction_step.g.dart'; @JsonSerializable(explicitToJson: true) +@immutable class InstructionStep extends Step { final String title; final String text; @@ -43,11 +44,11 @@ class InstructionStep extends Step { Map toJson() => _$InstructionStepToJson(this); @override - bool operator ==(Object o) => - super == o && - o is InstructionStep && - o.title == title && - o.text == text; + bool operator ==(Object other) => + super == other && + other is InstructionStep && + other.title == title && + other.text == text; @override int get hashCode => super.hashCode ^ title.hashCode ^ text.hashCode; } diff --git a/lib/src/steps/step.dart b/lib/src/steps/step.dart index 96189839..dfe5ca05 100644 --- a/lib/src/steps/step.dart +++ b/lib/src/steps/step.dart @@ -7,6 +7,7 @@ import 'package:survey_kit/src/steps/predefined_steps/instruction_step.dart'; import 'package:survey_kit/src/steps/predefined_steps/question_step.dart'; import 'package:survey_kit/src/steps/step_not_defined_exception.dart'; +@immutable abstract class Step { final StepIdentifier stepIdentifier; @JsonKey(defaultValue: false) diff --git a/lib/src/survey_configuration.dart b/lib/src/survey_configuration.dart index aa453403..0b3b2aac 100644 --- a/lib/src/survey_configuration.dart +++ b/lib/src/survey_configuration.dart @@ -28,7 +28,7 @@ class SurveyConfiguration extends InheritedWidget { } @override - bool updateShouldNotify(SurveyConfiguration old) => - surveyProgressConfiguration != old.surveyProgressConfiguration && - showProgress != old.showProgress; + bool updateShouldNotify(SurveyConfiguration oldWidget) => + surveyProgressConfiguration != oldWidget.surveyProgressConfiguration && + showProgress != oldWidget.showProgress; } diff --git a/lib/src/survey_presenter_inherited.dart b/lib/src/survey_presenter_inherited.dart index 38d5dff2..ac1bd838 100644 --- a/lib/src/survey_presenter_inherited.dart +++ b/lib/src/survey_presenter_inherited.dart @@ -12,6 +12,7 @@ import 'package:survey_kit/src/result/survey/survey_result.dart'; import 'package:survey_kit/src/steps/identifier/step_identifier.dart'; import 'package:survey_kit/src/steps/step.dart'; +// ignore: must_be_immutable class SurveyPresenterInherited extends InheritedWidget { SurveyPresenterInherited({ super.key, @@ -20,7 +21,6 @@ class SurveyPresenterInherited extends InheritedWidget { required super.child, }) : _state = LoadingSurveyState(), startDate = DateTime.now() { - //TODO: Do somewhere else onEvent(StartSurvey()); } @@ -93,7 +93,7 @@ class SurveyPresenterInherited extends InheritedWidget { id: taskNavigator.task.id, startDate: startDate, endDate: DateTime.now(), - finishReason: FinishReason.COMPLETED, + finishReason: FinishReason.completed, results: const [], ); return SurveyResultState( @@ -181,7 +181,7 @@ class SurveyPresenterInherited extends InheritedWidget { id: taskNavigator.task.id, startDate: startDate, endDate: DateTime.now(), - finishReason: FinishReason.DISCARDED, + finishReason: FinishReason.discarded, results: stepResults, ); return SurveyResultState( @@ -199,7 +199,7 @@ class SurveyPresenterInherited extends InheritedWidget { id: taskNavigator.task.id, startDate: startDate, endDate: DateTime.now(), - finishReason: FinishReason.COMPLETED, + finishReason: FinishReason.completed, results: stepResults, ); return SurveyResultState( @@ -214,10 +214,10 @@ class SurveyPresenterInherited extends InheritedWidget { return; } results - .removeWhere((QuestionResult result) => result.id == questionResult.id); - results.add( - questionResult, - ); + ..removeWhere((QuestionResult result) => result.id == questionResult.id) + ..add( + questionResult, + ); } int get countSteps => taskNavigator.countSteps; diff --git a/lib/src/task/navigable_task.dart b/lib/src/task/navigable_task.dart index 83c7d074..ce9cf88b 100644 --- a/lib/src/task/navigable_task.dart +++ b/lib/src/task/navigable_task.dart @@ -5,7 +5,6 @@ import 'package:survey_kit/src/task/identifier/task_identifier.dart'; import 'package:survey_kit/src/task/task.dart'; /// Definition of task which can handle routing between [Tasks] -/// /// The [navigationRules] defines on which Step [StepIdentifier] which next Step /// is called. The logic which [Step] is called is defined in the /// [NavigationRule] @@ -48,9 +47,10 @@ class NavigableTask extends Task { for (final rule in rules) { navigationRules.putIfAbsent( StepIdentifier.fromJson( - rule['triggerStepIdentifier'] as Map, + (rule as Map)['triggerStepIdentifier'] + as Map, ), - () => NavigationRule.fromJson(rule as Map), + () => NavigationRule.fromJson(rule), ); } } diff --git a/lib/src/task/task.dart b/lib/src/task/task.dart index 4d494435..fe8ae0e1 100644 --- a/lib/src/task/task.dart +++ b/lib/src/task/task.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:survey_kit/src/steps/step.dart'; import 'package:survey_kit/src/task/identifier/task_identifier.dart'; @@ -10,6 +11,7 @@ import 'package:survey_kit/src/task/task_not_defined_exception.dart'; /// If you want to create a custom task: /// * Inherit from Task /// * If you want to use JSON override [fromJson] and add your type +@immutable abstract class Task { late final TaskIdentifier id; @JsonKey(defaultValue: []) @@ -25,6 +27,7 @@ abstract class Task { id = TaskIdentifier(); return; } + // ignore: prefer_initializing_formals this.id = id; } diff --git a/lib/src/views/boolean_answer_view.dart b/lib/src/views/boolean_answer_view.dart index d2356edc..94cdecc2 100644 --- a/lib/src/views/boolean_answer_view.dart +++ b/lib/src/views/boolean_answer_view.dart @@ -40,9 +40,9 @@ class _BooleanAnswerViewState extends State { id: widget.questionStep.stepIdentifier, startDate: _startDate, endDate: DateTime.now(), - valueIdentifier: _result == BooleanResult.POSITIVE + valueIdentifier: _result == BooleanResult.positive ? _answerFormat.positiveAnswer - : _result == BooleanResult.NEGATIVE + : _result == BooleanResult.negative ? _answerFormat.negativeAnswer : '', result: _result, @@ -73,26 +73,26 @@ class _BooleanAnswerViewState extends State { SelectionListTile( text: _answerFormat.positiveAnswer, onTap: () { - if (_result == BooleanResult.POSITIVE) { + if (_result == BooleanResult.positive) { _result = null; } else { - _result = BooleanResult.POSITIVE; + _result = BooleanResult.positive; } setState(() {}); }, - isSelected: _result == BooleanResult.POSITIVE, + isSelected: _result == BooleanResult.positive, ), SelectionListTile( text: _answerFormat.negativeAnswer, onTap: () { - if (_result == BooleanResult.NEGATIVE) { + if (_result == BooleanResult.negative) { _result = null; } else { - _result = BooleanResult.NEGATIVE; + _result = BooleanResult.negative; } setState(() {}); }, - isSelected: _result == BooleanResult.NEGATIVE, + isSelected: _result == BooleanResult.negative, ), ], ), diff --git a/lib/src/views/cms_step_view.dart b/lib/src/views/cms_step_view.dart index 8748ffad..8b3f10ce 100644 --- a/lib/src/views/cms_step_view.dart +++ b/lib/src/views/cms_step_view.dart @@ -3,9 +3,8 @@ import 'package:survey_kit/src/steps/predefined_steps/cms_step.dart'; class CMSStepView extends StatelessWidget { final CMSStep cmsStep; - final _startDate = DateTime.now(); - CMSStepView({ + const CMSStepView({ super.key, required this.cmsStep, }); diff --git a/lib/src/views/multiple_double_answer_view.dart b/lib/src/views/multiple_double_answer_view.dart index 212f8099..23b379b5 100644 --- a/lib/src/views/multiple_double_answer_view.dart +++ b/lib/src/views/multiple_double_answer_view.dart @@ -45,7 +45,7 @@ class _MultipleDoubleAnswerViewState extends State { _insertedValues = List.generate( _multipleDoubleAnswer.hints.length, - (index) => MultiDouble( + (index) => const MultiDouble( text: '', value: 0.0, ), diff --git a/lib/src/views/widget/selection_list_tile.dart b/lib/src/views/widget/selection_list_tile.dart index 95bf5e06..007fff02 100644 --- a/lib/src/views/widget/selection_list_tile.dart +++ b/lib/src/views/widget/selection_list_tile.dart @@ -39,7 +39,7 @@ class SelectionListTile extends StatelessWidget { width: 32, height: 32, ), - onTap: () => onTap.call(), + onTap: () => onTap, ), ), const Divider( diff --git a/test/src/result/question/boolean_question_result_test.dart b/test/src/result/question/boolean_question_result_test.dart index bd403083..0b66ad12 100644 --- a/test/src/result/question/boolean_question_result_test.dart +++ b/test/src/result/question/boolean_question_result_test.dart @@ -7,7 +7,7 @@ void main() { startDate: DateTime(2022, 8, 12, 16, 4), endDate: DateTime(2022, 8, 12, 16, 14), valueIdentifier: 'bool1', - result: BooleanResult.NEGATIVE, + result: BooleanResult.negative, ); group('serialisation', () { diff --git a/test/src/result/question/multiple_double_question_result_test.dart b/test/src/result/question/multiple_double_question_result_test.dart index 772c4d79..420e570e 100644 --- a/test/src/result/question/multiple_double_question_result_test.dart +++ b/test/src/result/question/multiple_double_question_result_test.dart @@ -7,7 +7,7 @@ void main() { startDate: DateTime(2022, 8, 12, 16, 4), endDate: DateTime(2022, 8, 12, 16, 14), valueIdentifier: 'multiDouble1', - result: [ + result: const [ MultiDouble(text: 'doubleVal1', value: 123.45), MultiDouble(text: 'doubleVal2', value: 234.56), ], diff --git a/test/src/survey/survey_result_test.dart b/test/src/survey/survey_result_test.dart index 15ce77dd..5e46e6af 100644 --- a/test/src/survey/survey_result_test.dart +++ b/test/src/survey/survey_result_test.dart @@ -13,7 +13,7 @@ void main() { startDate: DateTime(2022, 8, 12, 16, 5), endDate: DateTime(2022, 8, 12, 16, 10), valueIdentifier: 'bool1', - result: BooleanResult.NEGATIVE, + result: BooleanResult.negative, ), CompletionStepResult( Identifier(id: 'example1_completion'), @@ -25,7 +25,7 @@ void main() { id: Identifier(id: 'example1'), startDate: DateTime(2022, 8, 12, 16, 4), endDate: DateTime(2022, 8, 12, 16, 14), - finishReason: FinishReason.COMPLETED, + finishReason: FinishReason.completed, results: [ StepResult( id: Identifier(id: 'example1_stepResult'), diff --git a/test/surveykit_flutter_test.dart b/test/surveykit_flutter_test.dart index 9dca597b..c7050c18 100644 --- a/test/surveykit_flutter_test.dart +++ b/test/surveykit_flutter_test.dart @@ -32,7 +32,7 @@ void main() { ], ), onResult: (result) { - expect(result.finishReason, FinishReason.COMPLETED); + expect(result.finishReason, FinishReason.completed); }, ), ), diff --git a/test/task/navigable_task_test.dart b/test/task/navigable_task_test.dart index 85b1553e..3c99cea2 100644 --- a/test/task/navigable_task_test.dart +++ b/test/task/navigable_task_test.dart @@ -25,23 +25,22 @@ void main() { '''; final navigableTask = NavigableTask( id: TaskIdentifier(id: '123'), - steps: [], - ); - navigableTask.addNavigationRule( - forTriggerStepIdentifier: StepIdentifier(id: '123'), - navigationRule: ConditionalNavigationRule( - resultToStepIdentifierMapper: (input) { - switch (input) { - case 'Yes': - return StepIdentifier(id: '321'); - case 'No': - return StepIdentifier(id: '456'); - default: - return null; - } - }, - ), - ); + steps: const [], + )..addNavigationRule( + forTriggerStepIdentifier: StepIdentifier(id: '123'), + navigationRule: ConditionalNavigationRule( + resultToStepIdentifierMapper: (input) { + switch (input) { + case 'Yes': + return StepIdentifier(id: '321'); + case 'No': + return StepIdentifier(id: '456'); + default: + return null; + } + }, + ), + ); final navigableJsonTask = NavigableTask.fromJson(json.decode(jsonStr) as Map); diff --git a/test/task/ordered_task_test.dart b/test/task/ordered_task_test.dart index 04b6bc16..b94973d6 100644 --- a/test/task/ordered_task_test.dart +++ b/test/task/ordered_task_test.dart @@ -12,7 +12,7 @@ void main() { } '''; final Task orderedTask = - OrderedTask(id: TaskIdentifier(id: '123'), steps: []); + OrderedTask(id: TaskIdentifier(id: '123'), steps: const []); final orderedJsonTask = OrderedTask.fromJson(json.decode(jsonStr) as Map); From 81af76e3a88dd8d4e9f2ec33eb2b1fcca5f98216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Ma=CC=88rz?= Date: Thu, 15 Dec 2022 13:47:00 +0100 Subject: [PATCH 003/108] chore/lint --- .../multiple_auto_complete_answer_view.dart | 84 ++++++++++--------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/lib/src/views/multiple_auto_complete_answer_view.dart b/lib/src/views/multiple_auto_complete_answer_view.dart index 9fd552d8..61e26139 100644 --- a/lib/src/views/multiple_auto_complete_answer_view.dart +++ b/lib/src/views/multiple_auto_complete_answer_view.dart @@ -35,7 +35,7 @@ class _MultipleChoiceAutoCompleteAnswerViewState _startDateTime = DateTime.now(); } - // TODO refactor the widgets and organize, DRY also + // TODO(marvin): refactor the widgets and organize, DRY also @override Widget build(BuildContext context) { return StepView( @@ -91,8 +91,10 @@ class _MultipleChoiceAutoCompleteAnswerViewState ) .toList(), ..._selectedChoices - .where((element) => - !_multipleChoiceAnswer.textChoices.contains(element),) + .where( + (element) => + !_multipleChoiceAnswer.textChoices.contains(element), + ) .map( (TextChoice tc) => SelectionListTile( text: tc.text, @@ -189,16 +191,17 @@ class _AutoComplete extends StatelessWidget { controller: textEditingController, focusNode: focusNode, decoration: InputDecoration( - contentPadding: const EdgeInsets.symmetric(horizontal: 32), - labelText: 'Search', - hintText: 'Type here to search', - suffixIcon: IconButton( - padding: EdgeInsets.zero, - icon: const Icon(Icons.clear), - onPressed: () { - textEditingController.clear(); - }, - ),), + contentPadding: const EdgeInsets.symmetric(horizontal: 32), + labelText: 'Search', + hintText: 'Type here to search', + suffixIcon: IconButton( + padding: EdgeInsets.zero, + icon: const Icon(Icons.clear), + onPressed: () { + textEditingController.clear(); + }, + ), + ), onSubmitted: (v) { onFieldSubmitted(); }, @@ -214,9 +217,11 @@ class _AutoComplete extends StatelessWidget { return const Iterable.empty(); } - return suggestions.where((element) => element.text - .toLowerCase() - .contains(textEditingValue.text.toLowerCase()),); + return suggestions.where( + (element) => element.text + .toLowerCase() + .contains(textEditingValue.text.toLowerCase()), + ); }, onSelected: onSelected, ); @@ -252,28 +257,31 @@ class _OptionsViewBuilder extends StatelessWidget { onTap: () { onSelected(option); }, - child: Builder(builder: (BuildContext context) { - final highlight = - AutocompleteHighlightedOption.of(context) == index; - if (highlight) { - SchedulerBinding.instance - .addPostFrameCallback((Duration timeStamp) { - Scrollable.ensureVisible(context, alignment: 0.5); - }); - } - return Container( - color: highlight ? Theme.of(context).focusColor : null, - padding: const EdgeInsets.all(16.0), - margin: const EdgeInsets.only(right: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(option.text), - if (selectedChoices.contains(option)) const Icon(Icons.done) - ], - ), - ); - },), + child: Builder( + builder: (BuildContext context) { + final highlight = + AutocompleteHighlightedOption.of(context) == index; + if (highlight) { + SchedulerBinding.instance + .addPostFrameCallback((Duration timeStamp) { + Scrollable.ensureVisible(context, alignment: 0.5); + }); + } + return Container( + color: highlight ? Theme.of(context).focusColor : null, + padding: const EdgeInsets.all(16.0), + margin: const EdgeInsets.only(right: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(option.text), + if (selectedChoices.contains(option)) + const Icon(Icons.done) + ], + ), + ); + }, + ), ); }, ), From f269c6c364f9f030522d2420e13de2228e497da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Ma=CC=88rz?= Date: Thu, 15 Dec 2022 13:53:56 +0100 Subject: [PATCH 004/108] chore/generate fles --- lib/src/answer_format/boolean_answer_format.g.dart | 8 ++++---- lib/src/result/question/boolean_question_result.g.dart | 6 +++--- lib/src/result/survey/survey_result.g.dart | 8 ++++---- lib/src/steps/predefined_steps/completion_step.g.dart | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/src/answer_format/boolean_answer_format.g.dart b/lib/src/answer_format/boolean_answer_format.g.dart index 5cd7bd8f..b9854738 100644 --- a/lib/src/answer_format/boolean_answer_format.g.dart +++ b/lib/src/answer_format/boolean_answer_format.g.dart @@ -11,7 +11,7 @@ BooleanAnswerFormat _$BooleanAnswerFormatFromJson(Map json) => positiveAnswer: json['positiveAnswer'] as String, negativeAnswer: json['negativeAnswer'] as String, result: $enumDecodeNullable(_$BooleanResultEnumMap, json['result']) ?? - BooleanResult.NONE, + BooleanResult.none, ); Map _$BooleanAnswerFormatToJson( @@ -23,7 +23,7 @@ Map _$BooleanAnswerFormatToJson( }; const _$BooleanResultEnumMap = { - BooleanResult.NONE: 'NONE', - BooleanResult.POSITIVE: 'POSITIVE', - BooleanResult.NEGATIVE: 'NEGATIVE', + BooleanResult.none: 'none', + BooleanResult.positive: 'positive', + BooleanResult.negative: 'negative', }; diff --git a/lib/src/result/question/boolean_question_result.g.dart b/lib/src/result/question/boolean_question_result.g.dart index dc5154da..fdb11936 100644 --- a/lib/src/result/question/boolean_question_result.g.dart +++ b/lib/src/result/question/boolean_question_result.g.dart @@ -27,7 +27,7 @@ Map _$BooleanQuestionResultToJson( }; const _$BooleanResultEnumMap = { - BooleanResult.NONE: 'NONE', - BooleanResult.POSITIVE: 'POSITIVE', - BooleanResult.NEGATIVE: 'NEGATIVE', + BooleanResult.none: 'none', + BooleanResult.positive: 'positive', + BooleanResult.negative: 'negative', }; diff --git a/lib/src/result/survey/survey_result.g.dart b/lib/src/result/survey/survey_result.g.dart index 5d4e456d..245feb52 100644 --- a/lib/src/result/survey/survey_result.g.dart +++ b/lib/src/result/survey/survey_result.g.dart @@ -28,8 +28,8 @@ Map _$SurveyResultToJson(SurveyResult instance) => }; const _$FinishReasonEnumMap = { - FinishReason.SAVED: 'SAVED', - FinishReason.DISCARDED: 'DISCARDED', - FinishReason.COMPLETED: 'COMPLETED', - FinishReason.FAILED: 'FAILED', + FinishReason.saved: 'saved', + FinishReason.discarded: 'discarded', + FinishReason.completed: 'completed', + FinishReason.failed: 'failed', }; diff --git a/lib/src/steps/predefined_steps/completion_step.g.dart b/lib/src/steps/predefined_steps/completion_step.g.dart index 37b697a4..fea09baa 100644 --- a/lib/src/steps/predefined_steps/completion_step.g.dart +++ b/lib/src/steps/predefined_steps/completion_step.g.dart @@ -15,7 +15,7 @@ CompletionStep _$CompletionStepFromJson(Map json) => showAppBar: json['showAppBar'] as bool? ?? true, title: json['title'] as String, text: json['text'] as String, - assetPath: json['assetPath'] as String? ?? "", + assetPath: json['assetPath'] as String? ?? '', ); Map _$CompletionStepToJson(CompletionStep instance) => From 1f354eb0c45e25b6f0a533d20301c26fcb4c5ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Ma=CC=88rz?= Date: Thu, 15 Dec 2022 13:56:23 +0100 Subject: [PATCH 005/108] fix/adapted json --- example/assets/example_json.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/assets/example_json.json b/example/assets/example_json.json index 0452cfd6..0b3da2eb 100644 --- a/example/assets/example_json.json +++ b/example/assets/example_json.json @@ -84,7 +84,7 @@ "type": "bool", "positiveAnswer": "Yes", "negativeAnswer": "No", - "result": "POSITIVE" + "result": "positive" } }, { From bb0478cb1fa66501d0fdc8d8b8d066a1f8fad37d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Ma=CC=88rz?= Date: Tue, 27 Dec 2022 14:30:14 +0100 Subject: [PATCH 006/108] feature/surveykit new version --- example/assets/example_new.json | 154 ++++++++++ example/lib/main.dart | 264 ++++++++++-------- example/pubspec.lock | 86 +++--- lib/src/_new/model/answer/answer.dart | 23 ++ .../model/answer}/boolean_answer_format.dart | 7 +- .../answer}/boolean_answer_format.g.dart | 2 +- .../model/answer}/date_answer_format.dart | 7 +- .../model/answer}/date_answer_format.g.dart | 0 .../model/answer}/double_answer_format.dart | 7 +- .../model/answer}/double_answer_format.g.dart | 0 .../model/answer}/image_answer_format.dart | 7 +- .../model/answer}/image_answer_format.g.dart | 0 .../model/answer}/integer_answer_format.dart | 7 +- .../answer}/integer_answer_format.g.dart | 0 .../model/answer}/multi_double.dart | 0 .../model/answer}/multi_double.g.dart | 0 .../model/answer/multi_select_answer.dart | 26 ++ .../model/answer/multi_select_answer.g.dart | 25 ++ ...le_choice_auto_complete_answer_format.dart | 19 +- ..._choice_auto_complete_answer_format.g.dart | 6 +- .../multiple_double_answer_format.dart | 10 +- .../multiple_double_answer_format.g.dart | 0 lib/src/_new/model/answer/option.dart | 18 ++ .../model/answer/option.g.dart} | 11 +- .../model/answer}/scale_answer_format.dart | 7 +- .../model/answer}/scale_answer_format.g.dart | 0 .../model/answer/single_select_answer.dart | 23 ++ .../model/answer/single_select_answer.g.dart | 23 ++ .../model/answer}/text_answer_format.dart | 7 +- .../model/answer}/text_answer_format.g.dart | 0 .../model/answer}/time_answer_formart.dart | 7 +- .../model/answer}/time_answer_formart.g.dart | 10 +- lib/src/_new/model/content/audio_content.dart | 19 ++ .../model/content/audio_content.g.dart} | 11 +- lib/src/_new/model/content/content.dart | 30 ++ .../_new/model/content/markdown_content.dart | 19 ++ .../model/content/markdown_content.g.dart | 19 ++ lib/src/_new/model/content/text_content.dart | 19 ++ .../model/content/text_content.g.dart} | 10 +- lib/src/_new/model/content/video_content.dart | 19 ++ .../model/content/video_content.g.dart} | 11 +- lib/src/_new/model/glossary.dart | 19 ++ lib/src/_new/model/glossary.g.dart | 25 ++ lib/src/_new/model/module.dart | 36 +++ lib/src/_new/model/module_group.dart | 25 ++ lib/src/_new/model/module_group.g.dart | 26 ++ .../model/result/step_result.dart} | 78 ++++-- lib/src/_new/model/result/step_result.g.dart | 39 +++ lib/src/_new/model/result/video_result.dart | 19 ++ lib/src/_new/model/result/video_result.g.dart | 18 ++ lib/src/_new/model/step.dart | 24 ++ lib/src/_new/model/step.g.dart | 31 ++ lib/src/_new/view/answer_view.dart | 51 ++++ .../view}/boolean_answer_view.dart | 47 ++-- lib/src/_new/view/content/audio_widget.dart | 19 ++ lib/src/_new/view/content/content_widget.dart | 42 +++ .../_new/view/content/markdown_widget.dart | 19 ++ lib/src/_new/view/content/text_widget.dart | 18 ++ lib/src/_new/view/content/video_widget.dart | 19 ++ .../view}/decoration/input_decoration.dart | 0 .../view}/multiple_choice_answer_view.dart | 69 ++--- .../view}/selection_list_tile.dart | 4 +- lib/src/_new/view/step_view.dart | 67 +++++ lib/src/answer_format/answer_format.dart | 51 ---- .../multiple_choice_answer_format.dart | 25 -- .../multiple_choice_answer_format.g.dart | 28 -- .../single_choice_answer_format.dart | 21 -- .../single_choice_answer_format.g.dart | 26 -- lib/src/answer_format/text_choice.dart | 26 -- lib/src/controller/survey_controller.dart | 14 +- .../navigator/navigable_task_navigator.dart | 19 +- lib/src/navigator/ordered_task_navigator.dart | 10 +- .../rules/conditional_navigation_rule.dart | 5 +- .../rules/direct_navigation_rule.dart | 3 +- .../rules/direct_navigation_rule.g.dart | 3 +- lib/src/navigator/task_navigator.dart | 9 +- lib/src/presenter/survey_event.dart | 8 +- lib/src/presenter/survey_state.dart | 15 +- .../question/boolean_question_result.dart | 30 -- .../question/boolean_question_result.g.dart | 33 --- .../result/question/date_question_result.dart | 29 -- .../question/date_question_result.g.dart | 27 -- .../question/double_question_result.dart | 29 -- .../question/double_question_result.g.dart | 27 -- .../question/image_question_result.dart | 30 -- .../question/image_question_result.g.dart | 26 -- .../question/integer_question_result.dart | 29 -- .../question/integer_question_result.g.dart | 27 -- .../multiple_choice_question_result.dart | 31 -- .../multiple_choice_question_result.g.dart | 29 -- .../multiple_double_question_result.dart | 30 -- .../multiple_double_question_result.g.dart | 29 -- .../question/scale_question_result.dart | 29 -- .../question/scale_question_result.g.dart | 26 -- .../single_choice_question_result.dart | 30 -- .../single_choice_question_result.g.dart | 29 -- .../result/question/text_question_result.dart | 29 -- .../question/text_question_result.g.dart | 25 -- .../question/time_question_result.g.dart | 25 -- lib/src/result/question_result.dart | 14 - lib/src/result/result.dart | 14 - .../result/step/completion_step_result.dart | 27 -- .../result/step/completion_step_result.g.dart | 23 -- .../result/step/instruction_step_result.dart | 27 -- .../step/instruction_step_result.g.dart | 23 -- lib/src/result/step/video_step_result.dart | 45 --- lib/src/result/step/video_step_result.g.dart | 34 --- lib/src/result/step_result.dart | 163 ----------- lib/src/result/step_result.g.dart | 24 -- lib/src/result/survey/survey_result.dart | 20 +- lib/src/result/survey/survey_result.g.dart | 18 +- lib/src/steps/cms_steps/audio_cms_step.dart | 26 -- lib/src/steps/cms_steps/audio_cms_step.g.dart | 16 -- lib/src/steps/cms_steps/cms_content_step.dart | 7 - .../steps/cms_steps/markdown_cms_step.dart | 26 -- .../steps/cms_steps/markdown_cms_step.g.dart | 17 -- lib/src/steps/cms_steps/video_cms_step.dart | 26 -- lib/src/steps/cms_steps/video_cms_step.g.dart | 16 -- lib/src/steps/identifier/identifier.dart | 22 -- lib/src/steps/identifier/step_identifier.dart | 19 -- .../answer_format_not_defined_exception.dart | 3 - lib/src/steps/predefined_steps/cms_step.dart | 25 -- .../predefined_steps/completion_step.dart | 50 ---- .../predefined_steps/completion_step.g.dart | 30 -- .../predefined_steps/instruction_step.dart | 54 ---- .../predefined_steps/instruction_step.g.dart | 34 --- .../steps/predefined_steps/question_step.dart | 158 ----------- .../predefined_steps/question_step.g.dart | 32 --- lib/src/steps/step.dart | 55 ---- lib/src/steps/step_not_defined_exception.dart | 3 - lib/src/survey_kit.dart | 37 ++- lib/src/survey_presenter_inherited.dart | 54 ++-- lib/src/survey_presenter_notifier.dart | 198 +++++++++++++ lib/src/task/identifier/task_identifier.dart | 15 - lib/src/task/navigable_task.dart | 26 +- lib/src/task/ordered_task.dart | 7 +- lib/src/task/task.dart | 10 +- lib/src/views/cms_step_view.dart | 28 -- lib/src/views/completion_view.dart | 30 +- lib/src/views/date_answer_view.dart | 68 ++--- lib/src/views/double_answer_view.dart | 38 ++- lib/src/views/image_answer_view.dart | 61 ++-- lib/src/views/instruction_view.dart | 31 +- lib/src/views/integer_answer_view.dart | 38 ++- .../multiple_auto_complete_answer_view.dart | 88 +++--- .../views/multiple_double_answer_view.dart | 42 ++- lib/src/views/scale_answer_view.dart | 43 ++- lib/src/views/single_choice_answer_view.dart | 58 ++-- lib/src/views/text_answer_view.dart | 47 ++-- lib/src/views/time_answer_view.dart | 56 ++-- lib/src/views/widget/step_view.dart | 77 ----- lib/src/views/widget/survey_app_bar.dart | 41 +-- lib/src/views/widget/time_picker_widget.dart | 20 +- lib/survey_kit.dart | 60 +--- pubspec.lock | 135 +++++---- pubspec.yaml | 2 - 156 files changed, 1954 insertions(+), 2877 deletions(-) create mode 100644 example/assets/example_new.json create mode 100644 lib/src/_new/model/answer/answer.dart rename lib/src/{answer_format => _new/model/answer}/boolean_answer_format.dart (80%) rename lib/src/{answer_format => _new/model/answer}/boolean_answer_format.g.dart (94%) rename lib/src/{answer_format => _new/model/answer}/date_answer_format.dart (89%) rename lib/src/{answer_format => _new/model/answer}/date_answer_format.g.dart (100%) rename lib/src/{answer_format => _new/model/answer}/double_answer_format.dart (77%) rename lib/src/{answer_format => _new/model/answer}/double_answer_format.g.dart (100%) rename lib/src/{answer_format => _new/model/answer}/image_answer_format.dart (75%) rename lib/src/{answer_format => _new/model/answer}/image_answer_format.g.dart (100%) rename lib/src/{answer_format => _new/model/answer}/integer_answer_format.dart (74%) rename lib/src/{answer_format => _new/model/answer}/integer_answer_format.g.dart (100%) rename lib/src/{answer_format => _new/model/answer}/multi_double.dart (100%) rename lib/src/{answer_format => _new/model/answer}/multi_double.g.dart (100%) create mode 100644 lib/src/_new/model/answer/multi_select_answer.dart create mode 100644 lib/src/_new/model/answer/multi_select_answer.g.dart rename lib/src/{answer_format => _new/model/answer}/multiple_choice_auto_complete_answer_format.dart (60%) rename lib/src/{answer_format => _new/model/answer}/multiple_choice_auto_complete_answer_format.g.dart (83%) rename lib/src/{answer_format => _new/model/answer}/multiple_double_answer_format.dart (69%) rename lib/src/{answer_format => _new/model/answer}/multiple_double_answer_format.g.dart (100%) create mode 100644 lib/src/_new/model/answer/option.dart rename lib/src/{steps/identifier/identifier.g.dart => _new/model/answer/option.g.dart} (50%) rename lib/src/{answer_format => _new/model/answer}/scale_answer_format.dart (83%) rename lib/src/{answer_format => _new/model/answer}/scale_answer_format.g.dart (100%) create mode 100644 lib/src/_new/model/answer/single_select_answer.dart create mode 100644 lib/src/_new/model/answer/single_select_answer.g.dart rename lib/src/{answer_format => _new/model/answer}/text_answer_format.dart (84%) rename lib/src/{answer_format => _new/model/answer}/text_answer_format.g.dart (100%) rename lib/src/{answer_format => _new/model/answer}/time_answer_formart.dart (87%) rename lib/src/{answer_format => _new/model/answer}/time_answer_formart.g.dart (64%) create mode 100644 lib/src/_new/model/content/audio_content.dart rename lib/src/{steps/identifier/step_identifier.g.dart => _new/model/content/audio_content.g.dart} (51%) create mode 100644 lib/src/_new/model/content/content.dart create mode 100644 lib/src/_new/model/content/markdown_content.dart create mode 100644 lib/src/_new/model/content/markdown_content.g.dart create mode 100644 lib/src/_new/model/content/text_content.dart rename lib/src/{answer_format/text_choice.g.dart => _new/model/content/text_content.g.dart} (58%) create mode 100644 lib/src/_new/model/content/video_content.dart rename lib/src/{task/identifier/task_identifier.g.dart => _new/model/content/video_content.g.dart} (51%) create mode 100644 lib/src/_new/model/glossary.dart create mode 100644 lib/src/_new/model/glossary.g.dart create mode 100644 lib/src/_new/model/module.dart create mode 100644 lib/src/_new/model/module_group.dart create mode 100644 lib/src/_new/model/module_group.g.dart rename lib/src/{result/question/time_question_result.dart => _new/model/result/step_result.dart} (51%) create mode 100644 lib/src/_new/model/result/step_result.g.dart create mode 100644 lib/src/_new/model/result/video_result.dart create mode 100644 lib/src/_new/model/result/video_result.g.dart create mode 100644 lib/src/_new/model/step.dart create mode 100644 lib/src/_new/model/step.g.dart create mode 100644 lib/src/_new/view/answer_view.dart rename lib/src/{views => _new/view}/boolean_answer_view.dart (61%) create mode 100644 lib/src/_new/view/content/audio_widget.dart create mode 100644 lib/src/_new/view/content/content_widget.dart create mode 100644 lib/src/_new/view/content/markdown_widget.dart create mode 100644 lib/src/_new/view/content/text_widget.dart create mode 100644 lib/src/_new/view/content/video_widget.dart rename lib/src/{views => _new/view}/decoration/input_decoration.dart (100%) rename lib/src/{views => _new/view}/multiple_choice_answer_view.dart (65%) rename lib/src/{views/widget => _new/view}/selection_list_tile.dart (88%) create mode 100644 lib/src/_new/view/step_view.dart delete mode 100644 lib/src/answer_format/answer_format.dart delete mode 100644 lib/src/answer_format/multiple_choice_answer_format.dart delete mode 100644 lib/src/answer_format/multiple_choice_answer_format.g.dart delete mode 100644 lib/src/answer_format/single_choice_answer_format.dart delete mode 100644 lib/src/answer_format/single_choice_answer_format.g.dart delete mode 100644 lib/src/answer_format/text_choice.dart delete mode 100644 lib/src/result/question/boolean_question_result.dart delete mode 100644 lib/src/result/question/boolean_question_result.g.dart delete mode 100644 lib/src/result/question/date_question_result.dart delete mode 100644 lib/src/result/question/date_question_result.g.dart delete mode 100644 lib/src/result/question/double_question_result.dart delete mode 100644 lib/src/result/question/double_question_result.g.dart delete mode 100644 lib/src/result/question/image_question_result.dart delete mode 100644 lib/src/result/question/image_question_result.g.dart delete mode 100644 lib/src/result/question/integer_question_result.dart delete mode 100644 lib/src/result/question/integer_question_result.g.dart delete mode 100644 lib/src/result/question/multiple_choice_question_result.dart delete mode 100644 lib/src/result/question/multiple_choice_question_result.g.dart delete mode 100644 lib/src/result/question/multiple_double_question_result.dart delete mode 100644 lib/src/result/question/multiple_double_question_result.g.dart delete mode 100644 lib/src/result/question/scale_question_result.dart delete mode 100644 lib/src/result/question/scale_question_result.g.dart delete mode 100644 lib/src/result/question/single_choice_question_result.dart delete mode 100644 lib/src/result/question/single_choice_question_result.g.dart delete mode 100644 lib/src/result/question/text_question_result.dart delete mode 100644 lib/src/result/question/text_question_result.g.dart delete mode 100644 lib/src/result/question/time_question_result.g.dart delete mode 100644 lib/src/result/question_result.dart delete mode 100644 lib/src/result/result.dart delete mode 100644 lib/src/result/step/completion_step_result.dart delete mode 100644 lib/src/result/step/completion_step_result.g.dart delete mode 100644 lib/src/result/step/instruction_step_result.dart delete mode 100644 lib/src/result/step/instruction_step_result.g.dart delete mode 100644 lib/src/result/step/video_step_result.dart delete mode 100644 lib/src/result/step/video_step_result.g.dart delete mode 100644 lib/src/result/step_result.dart delete mode 100644 lib/src/result/step_result.g.dart delete mode 100644 lib/src/steps/cms_steps/audio_cms_step.dart delete mode 100644 lib/src/steps/cms_steps/audio_cms_step.g.dart delete mode 100644 lib/src/steps/cms_steps/cms_content_step.dart delete mode 100644 lib/src/steps/cms_steps/markdown_cms_step.dart delete mode 100644 lib/src/steps/cms_steps/markdown_cms_step.g.dart delete mode 100644 lib/src/steps/cms_steps/video_cms_step.dart delete mode 100644 lib/src/steps/cms_steps/video_cms_step.g.dart delete mode 100644 lib/src/steps/identifier/identifier.dart delete mode 100644 lib/src/steps/identifier/step_identifier.dart delete mode 100644 lib/src/steps/predefined_steps/answer_format_not_defined_exception.dart delete mode 100644 lib/src/steps/predefined_steps/cms_step.dart delete mode 100644 lib/src/steps/predefined_steps/completion_step.dart delete mode 100644 lib/src/steps/predefined_steps/completion_step.g.dart delete mode 100644 lib/src/steps/predefined_steps/instruction_step.dart delete mode 100644 lib/src/steps/predefined_steps/instruction_step.g.dart delete mode 100644 lib/src/steps/predefined_steps/question_step.dart delete mode 100644 lib/src/steps/predefined_steps/question_step.g.dart delete mode 100644 lib/src/steps/step.dart delete mode 100644 lib/src/steps/step_not_defined_exception.dart create mode 100644 lib/src/survey_presenter_notifier.dart delete mode 100644 lib/src/task/identifier/task_identifier.dart delete mode 100644 lib/src/views/cms_step_view.dart delete mode 100644 lib/src/views/widget/step_view.dart diff --git a/example/assets/example_new.json b/example/assets/example_new.json new file mode 100644 index 00000000..a9243736 --- /dev/null +++ b/example/assets/example_new.json @@ -0,0 +1,154 @@ +{ + "text": "Module group1", + "description": "Description module group", + "image_url": "https://imageurl.com", + "locking_configuration": {}, + "modules": [ + { + "id": "1", + "type": "survey", + "title": "Title Module 1", + "description": "Description module 1", + "image_url": "Image Url", + "navigation_rules": [ + { + "step_id": "1", + "next_step_id": "3", + "condition": { + "value": "United States" + } + } + ], + "steps": [ + { + "id": "1", + "isMandatory": true, + "content": [ + { + "id": "content_1", + "type": "markdown", + "text": "This is a markdown text" + }, + { + "id": "content_2", + "type": "video", + "url": "https://www.youtube.com/" + }, + { + "id": "content_3", + "type": "audio", + "url": "https://www.youtube.com/" + }, + { + "id": "content_4", + "type": "image", + "url": "https://www.quickbird.com/" + }, + { + "id": "content_5", + "type": "text", + "text": "Text 123", + "fontSize": 14 + } + ], + "answer" : { + "type": "multi", + "options": [ + { + "id": "1", + "value": "United States" + }, + { + "id": "2", + "value": "Canada" + }, + { + "id": "3", + "value": "Germany" + } + ] + } + }, + { + "id": "2", + "type": "text", + "isMandatory": true, + "answer" : { + "type": "single", + "options": [ + { + "id": "1", + "value": "United States" + }, + { + "id": "2", + "value": "Canada" + }, + { + "id": "3", + "value": "Germany" + } + ] + } + }, + { + "id": "2", + "type": "text", + "isMandatory": true, + "answer" : { + "type": "single", + "options": [ + { + "id": "1", + "value": "United States" + }, + { + "id": "2", + "value": "Canada" + }, + { + "id": "3", + "value": "Germany" + } + ] + } + } + ] + }, + { + "id": "2", + "type": "glossary", + "title": "Title mdule 2", + "description": "Description module 2", + "image_url": "https://www.google.com", + "content": [ + { + "id": "content_1", + "type": "markdown", + "text": "This is a markdown text" + }, + { + "id": "content_2", + "type": "video", + "url": "https://www.youtube.com/" + }, + { + "id": "content_3", + "type": "audio", + "url": "https://www.youtube.com/" + }, + { + "id": "content_4", + "type": "image", + "url": "https://www.quickbird.com/" + }, + { + "id": "content_5", + "type": "text", + "text": "Text 123", + "fontSize": 14 + } + ] + } + ] +} \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index 41a29690..1e7e7f68 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'dart:developer'; import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' hide Step; import 'package:flutter/services.dart'; import 'package:survey_kit/survey_kit.dart'; @@ -45,13 +45,7 @@ class _MyAppState extends State { 'next': 'Next', }, themeData: Theme.of(context).copyWith( - colorScheme: ColorScheme.fromSwatch( - primarySwatch: Colors.cyan, - ).copyWith( - onPrimary: Colors.white, - ), primaryColor: Colors.cyan, - backgroundColor: Colors.white, appBarTheme: const AppBarTheme( color: Colors.white, iconTheme: IconThemeData( @@ -99,14 +93,14 @@ class _MyAppState extends State { if (state.contains(MaterialState.disabled)) { return Theme.of(context) .textTheme - .button + .labelLarge ?.copyWith( color: Colors.grey, ); } return Theme.of(context) .textTheme - .button + .labelLarge ?.copyWith( color: Colors.cyan, ); @@ -117,26 +111,26 @@ class _MyAppState extends State { textButtonTheme: TextButtonThemeData( style: ButtonStyle( textStyle: MaterialStateProperty.all( - Theme.of(context).textTheme.button?.copyWith( + Theme.of(context).textTheme.labelLarge?.copyWith( color: Colors.cyan, ), ), ), ), textTheme: const TextTheme( - headline2: TextStyle( + displayMedium: TextStyle( fontSize: 28.0, color: Colors.black, ), - headline5: TextStyle( + headlineSmall: TextStyle( fontSize: 24.0, color: Colors.black, ), - bodyText2: TextStyle( + bodyMedium: TextStyle( fontSize: 18.0, color: Colors.black, ), - subtitle1: TextStyle( + titleMedium: TextStyle( fontSize: 18.0, color: Colors.black, ), @@ -146,6 +140,13 @@ class _MyAppState extends State { color: Colors.black, ), ), + colorScheme: ColorScheme.fromSwatch( + primarySwatch: Colors.cyan, + ) + .copyWith( + onPrimary: Colors.white, + ) + .copyWith(background: Colors.white), ), surveyProgressbarConfiguration: SurveyProgressConfiguration( backgroundColor: Colors.white, @@ -161,120 +162,143 @@ class _MyAppState extends State { ); } - Future getSampleTask() { + Future newSampleTask() { final task = NavigableTask( - id: TaskIdentifier(), - steps: [ - InstructionStep( - title: 'Welcome to the\nQuickBird Studios\nHealth Survey', - text: 'Get ready for a bunch of super random questions!', - buttonText: "Let's go!", - ), - QuestionStep( - title: 'How old are you?', - answerFormat: const IntegerAnswerFormat( - defaultValue: 25, - hint: 'Please enter your age', - ), - isOptional: true, - ), - QuestionStep( - title: 'Medication?', - text: 'Are you using any medication', - answerFormat: const BooleanAnswerFormat( - positiveAnswer: 'Yes', - negativeAnswer: 'No', - result: BooleanResult.positive, - ), - ), - QuestionStep( - title: 'Tell us about you', - text: - 'Tell us about yourself and why you want to improve your health.', - answerFormat: const TextAnswerFormat( - maxLines: 5, - validationRegEx: r'^(?!s*$).+', - ), - ), - QuestionStep( - title: 'Select your body type', - answerFormat: const ScaleAnswerFormat( - step: 1, - minimumValue: 1, - maximumValue: 5, - defaultValue: 3, - minimumValueDescription: '1', - maximumValueDescription: '5', - ), - ), - QuestionStep( - title: 'Known allergies', - text: 'Do you have any allergies that we should be aware of?', - isOptional: false, - answerFormat: const MultipleChoiceAnswerFormat( - textChoices: [ - TextChoice(text: 'Penicillin', value: 'Penicillin'), - TextChoice(text: 'Latex', value: 'Latex'), - TextChoice(text: 'Pet', value: 'Pet'), - TextChoice(text: 'Pollen', value: 'Pollen'), - ], - ), - ), - QuestionStep( - title: 'Done?', - text: 'We are done, do you mind to tell us more about yourself?', - isOptional: true, - answerFormat: const SingleChoiceAnswerFormat( - textChoices: [ - TextChoice(text: 'Yes', value: 'Yes'), - TextChoice(text: 'No', value: 'No'), - ], - defaultSelection: TextChoice(text: 'No', value: 'No'), - ), - ), - QuestionStep( - title: 'When did you wake up?', - answerFormat: const TimeAnswerFormat( - defaultValue: TimeOfDay( - hour: 12, - minute: 0, + id: 't', + steps: const [ + Step( + id: '1', + title: 'First Step', + content: [ + TextContent(id: '1', text: 'Text'), + MarkdownContent(id: '1', text: 'Text'), + VideoContent( + id: '1', + url: + 'https://admin.mamly.de:1337/uploads/was_ist_coaching_c85aa48fc0.m4v', ), - ), - ), - QuestionStep( - title: 'When was your last holiday?', - answerFormat: DateAnswerFormat( - minDate: DateTime.utc(1970), - defaultDate: DateTime.now(), - maxDate: DateTime.now(), - ), - ), - CompletionStep( - stepIdentifier: StepIdentifier(id: '321'), - text: 'Thanks for taking the survey, we will contact you soon!', - title: 'Done!', - buttonText: 'Submit survey', + ], ), ], ); - task.addNavigationRule( - forTriggerStepIdentifier: task.steps[6].stepIdentifier, - navigationRule: ConditionalNavigationRule( - resultToStepIdentifierMapper: (input) { - switch (input) { - case 'Yes': - return task.steps[0].stepIdentifier; - case 'No': - return task.steps[7].stepIdentifier; - default: - return null; - } - }, - ), - ); + return Future.value(task); } + // Future getSampleTask() { + // final task = NavigableTask( + // id: TaskIdentifier(), + // steps: [ + // InstructionStep( + // title: 'Welcome to the\nQuickBird Studios\nHealth Survey', + // text: 'Get ready for a bunch of super random questions!', + // buttonText: "Let's go!", + // ), + // QuestionStep( + // title: 'How old are you?', + // answerFormat: const IntegerAnswerFormat( + // defaultValue: 25, + // hint: 'Please enter your age', + // ), + // isOptional: true, + // ), + // QuestionStep( + // title: 'Medication?', + // text: 'Are you using any medication', + // answerFormat: const BooleanAnswerFormat( + // positiveAnswer: 'Yes', + // negativeAnswer: 'No', + // result: BooleanResult.positive, + // ), + // ), + // QuestionStep( + // title: 'Tell us about you', + // text: + // 'Tell us about yourself and why you want to improve your health.', + // answerFormat: const TextAnswerFormat( + // maxLines: 5, + // validationRegEx: r'^(?!s*$).+', + // ), + // ), + // QuestionStep( + // title: 'Select your body type', + // answerFormat: const ScaleAnswerFormat( + // step: 1, + // minimumValue: 1, + // maximumValue: 5, + // defaultValue: 3, + // minimumValueDescription: '1', + // maximumValueDescription: '5', + // ), + // ), + // QuestionStep( + // title: 'Known allergies', + // text: 'Do you have any allergies that we should be aware of?', + // isOptional: false, + // answerFormat: const MultipleChoiceAnswerFormat( + // textChoices: [ + // TextChoice(text: 'Penicillin', value: 'Penicillin'), + // TextChoice(text: 'Latex', value: 'Latex'), + // TextChoice(text: 'Pet', value: 'Pet'), + // TextChoice(text: 'Pollen', value: 'Pollen'), + // ], + // ), + // ), + // QuestionStep( + // title: 'Done?', + // text: 'We are done, do you mind to tell us more about yourself?', + // isOptional: true, + // answerFormat: const SingleChoiceAnswerFormat( + // textChoices: [ + // TextChoice(text: 'Yes', value: 'Yes'), + // TextChoice(text: 'No', value: 'No'), + // ], + // defaultSelection: TextChoice(text: 'No', value: 'No'), + // ), + // ), + // QuestionStep( + // title: 'When did you wake up?', + // answerFormat: const TimeAnswerFormat( + // defaultValue: TimeOfDay( + // hour: 12, + // minute: 0, + // ), + // ), + // ), + // QuestionStep( + // title: 'When was your last holiday?', + // answerFormat: DateAnswerFormat( + // minDate: DateTime.utc(1970), + // defaultDate: DateTime.now(), + // maxDate: DateTime.now(), + // ), + // ), + // CompletionStep( + // stepIdentifier: StepIdentifier(id: '321'), + // text: 'Thanks for taking the survey, we will contact you soon!', + // title: 'Done!', + // buttonText: 'Submit survey', + // ), + // ], + // ); + // task.addNavigationRule( + // forTriggerStepIdentifier: task.steps[6].stepIdentifier, + // navigationRule: ConditionalNavigationRule( + // resultToStepIdentifierMapper: (input) { + // switch (input) { + // case 'Yes': + // return task.steps[0].stepIdentifier; + // case 'No': + // return task.steps[7].stepIdentifier; + // default: + // return null; + // } + // }, + // ), + // ); + // return Future.value(task); + // } + Future getJsonTask() async { final taskJson = await rootBundle.loadString('assets/example_json.json'); final taskMap = json.decode(taskJson) as Map; diff --git a/example/pubspec.lock b/example/pubspec.lock index 2119a098..e1b29070 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.3.0" + version: "3.3.5" args: dependency: transitive description: @@ -77,7 +77,7 @@ packages: name: bloc url: "https://pub.dartlang.org" source: hosted - version: "8.0.3" + version: "8.1.0" boolean_selector: dependency: transitive description: @@ -91,35 +91,35 @@ packages: name: camera url: "https://pub.dartlang.org" source: hosted - version: "0.10.0+1" + version: "0.10.0+5" camera_android: dependency: transitive description: name: camera_android url: "https://pub.dartlang.org" source: hosted - version: "0.10.0+2" + version: "0.10.1" camera_avfoundation: dependency: transitive description: name: camera_avfoundation url: "https://pub.dartlang.org" source: hosted - version: "0.9.8+5" + version: "0.9.9" camera_platform_interface: dependency: transitive description: name: camera_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.2" camera_web: dependency: transitive description: name: camera_web url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.3.1" characters: dependency: transitive description: @@ -141,13 +141,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.16.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" cross_file: dependency: transitive description: name: cross_file url: "https://pub.dartlang.org" source: hosted - version: "0.3.3+1" + version: "0.3.3+2" crypto: dependency: transitive description: @@ -169,13 +176,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.5" - equatable: - dependency: transitive - description: - name: equatable - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" fake_async: dependency: transitive description: @@ -208,7 +208,7 @@ packages: name: flutter_bloc url: "https://pub.dartlang.org" source: hosted - version: "8.0.1" + version: "8.1.1" flutter_markdown: dependency: transitive description: @@ -216,13 +216,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.13" - flutter_platform_widgets: - dependency: transitive - description: - name: flutter_platform_widgets - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -246,7 +239,7 @@ packages: name: html url: "https://pub.dartlang.org" source: hosted - version: "0.15.0" + version: "0.15.1" http: dependency: transitive description: @@ -260,42 +253,42 @@ packages: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.1" + version: "4.0.2" image_picker: dependency: transitive description: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.8.5+3" + version: "0.8.6" image_picker_android: dependency: transitive description: name: image_picker_android url: "https://pub.dartlang.org" source: hosted - version: "0.8.5+3" + version: "0.8.5+4" image_picker_for_web: dependency: transitive description: name: image_picker_for_web url: "https://pub.dartlang.org" source: hosted - version: "2.1.8" + version: "2.1.10" image_picker_ios: dependency: transitive description: name: image_picker_ios url: "https://pub.dartlang.org" source: hosted - version: "0.8.6" + version: "0.8.6+2" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.6.1" + version: "2.6.2" intl: dependency: transitive description: @@ -316,14 +309,14 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.5.0" + version: "4.7.0" lottie: dependency: transitive description: name: lottie url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.4.3" markdown: dependency: transitive description: @@ -428,7 +421,14 @@ packages: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.2" process: dependency: transitive description: @@ -442,7 +442,7 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "6.0.3" + version: "6.0.5" quiver: dependency: transitive description: @@ -482,7 +482,7 @@ packages: name: stream_transform url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" string_scanner: dependency: transitive description: @@ -524,7 +524,7 @@ packages: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "3.0.6" + version: "3.0.7" vector_math: dependency: transitive description: @@ -538,42 +538,42 @@ packages: name: video_player url: "https://pub.dartlang.org" source: hosted - version: "2.4.5" + version: "2.4.10" video_player_android: dependency: transitive description: name: video_player_android url: "https://pub.dartlang.org" source: hosted - version: "2.3.6" + version: "2.3.10" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation url: "https://pub.dartlang.org" source: hosted - version: "2.3.5" + version: "2.3.8" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "5.1.3" + version: "6.0.1" video_player_web: dependency: transitive description: name: video_player_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.10" + version: "2.0.13" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "3.1.2" + version: "3.1.3" xdg_directories: dependency: transitive description: @@ -583,4 +583,4 @@ packages: version: "0.2.0+2" sdks: dart: ">=2.18.0 <3.0.0" - flutter: ">=3.0.0" + flutter: ">=3.3.0" diff --git a/lib/src/_new/model/answer/answer.dart b/lib/src/_new/model/answer/answer.dart new file mode 100644 index 00000000..1767beba --- /dev/null +++ b/lib/src/_new/model/answer/answer.dart @@ -0,0 +1,23 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/_new/model/answer/multi_select_answer.dart'; +import 'package:survey_kit/src/_new/model/answer/single_select_answer.dart'; + +@JsonSerializable() +abstract class Answer { + const Answer(); + + factory Answer.fromJson(Map json) { + final type = json['type'] as String?; + assert(type != null, 'type is required'); + + switch (type) { + case MultiSelectAnswer.type: + return MultiSelectAnswer.fromJson(json); + case SingleSelectAnswer.type: + return SingleSelectAnswer.fromJson(json); + + default: + throw Exception('Unknown type: $type'); + } + } +} diff --git a/lib/src/answer_format/boolean_answer_format.dart b/lib/src/_new/model/answer/boolean_answer_format.dart similarity index 80% rename from lib/src/answer_format/boolean_answer_format.dart rename to lib/src/_new/model/answer/boolean_answer_format.dart index 3bebd4fa..e98ff6e4 100644 --- a/lib/src/answer_format/boolean_answer_format.dart +++ b/lib/src/_new/model/answer/boolean_answer_format.dart @@ -1,10 +1,12 @@ import 'package:json_annotation/json_annotation.dart'; -import 'package:survey_kit/src/answer_format/answer_format.dart'; +import 'package:survey_kit/src/_new/model/answer/answer.dart'; part 'boolean_answer_format.g.dart'; @JsonSerializable() -class BooleanAnswerFormat implements AnswerFormat { +class BooleanAnswerFormat implements Answer { + static const String type = 'bool'; + final String positiveAnswer; final String negativeAnswer; final BooleanResult result; @@ -17,7 +19,6 @@ class BooleanAnswerFormat implements AnswerFormat { factory BooleanAnswerFormat.fromJson(Map json) => _$BooleanAnswerFormatFromJson(json); - @override Map toJson() => _$BooleanAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/boolean_answer_format.g.dart b/lib/src/_new/model/answer/boolean_answer_format.g.dart similarity index 94% rename from lib/src/answer_format/boolean_answer_format.g.dart rename to lib/src/_new/model/answer/boolean_answer_format.g.dart index b9854738..9dca857f 100644 --- a/lib/src/answer_format/boolean_answer_format.g.dart +++ b/lib/src/_new/model/answer/boolean_answer_format.g.dart @@ -19,7 +19,7 @@ Map _$BooleanAnswerFormatToJson( { 'positiveAnswer': instance.positiveAnswer, 'negativeAnswer': instance.negativeAnswer, - 'result': _$BooleanResultEnumMap[instance.result], + 'result': _$BooleanResultEnumMap[instance.result]!, }; const _$BooleanResultEnumMap = { diff --git a/lib/src/answer_format/date_answer_format.dart b/lib/src/_new/model/answer/date_answer_format.dart similarity index 89% rename from lib/src/answer_format/date_answer_format.dart rename to lib/src/_new/model/answer/date_answer_format.dart index ddced727..ca1d61b2 100644 --- a/lib/src/answer_format/date_answer_format.dart +++ b/lib/src/_new/model/answer/date_answer_format.dart @@ -1,10 +1,12 @@ import 'package:json_annotation/json_annotation.dart'; -import 'package:survey_kit/src/answer_format/answer_format.dart'; +import 'package:survey_kit/src/_new/model/answer/answer.dart'; part 'date_answer_format.g.dart'; @JsonSerializable() -class DateAnswerFormat implements AnswerFormat { +class DateAnswerFormat implements Answer { + static const String type = 'date'; + /// Default date which will be preselected on datepicker opening final DateTime? defaultDate; @@ -40,6 +42,5 @@ class DateAnswerFormat implements AnswerFormat { factory DateAnswerFormat.fromJson(Map json) => _$DateAnswerFormatFromJson(json); - @override Map toJson() => _$DateAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/date_answer_format.g.dart b/lib/src/_new/model/answer/date_answer_format.g.dart similarity index 100% rename from lib/src/answer_format/date_answer_format.g.dart rename to lib/src/_new/model/answer/date_answer_format.g.dart diff --git a/lib/src/answer_format/double_answer_format.dart b/lib/src/_new/model/answer/double_answer_format.dart similarity index 77% rename from lib/src/answer_format/double_answer_format.dart rename to lib/src/_new/model/answer/double_answer_format.dart index ac55edf6..f6b96f0f 100644 --- a/lib/src/answer_format/double_answer_format.dart +++ b/lib/src/_new/model/answer/double_answer_format.dart @@ -1,12 +1,14 @@ // by Antonio Bruno, Giacomo Ignesti and Massimo Martinelli import 'package:json_annotation/json_annotation.dart'; -import 'package:survey_kit/src/answer_format/answer_format.dart'; +import 'package:survey_kit/src/_new/model/answer/answer.dart'; part 'double_answer_format.g.dart'; @JsonSerializable() -class DoubleAnswerFormat implements AnswerFormat { +class DoubleAnswerFormat implements Answer { + static const String type = 'double'; + final double? defaultValue; final String hint; @@ -17,6 +19,5 @@ class DoubleAnswerFormat implements AnswerFormat { factory DoubleAnswerFormat.fromJson(Map json) => _$DoubleAnswerFormatFromJson(json); - @override Map toJson() => _$DoubleAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/double_answer_format.g.dart b/lib/src/_new/model/answer/double_answer_format.g.dart similarity index 100% rename from lib/src/answer_format/double_answer_format.g.dart rename to lib/src/_new/model/answer/double_answer_format.g.dart diff --git a/lib/src/answer_format/image_answer_format.dart b/lib/src/_new/model/answer/image_answer_format.dart similarity index 75% rename from lib/src/answer_format/image_answer_format.dart rename to lib/src/_new/model/answer/image_answer_format.dart index db89b22d..a4b0d2fa 100644 --- a/lib/src/answer_format/image_answer_format.dart +++ b/lib/src/_new/model/answer/image_answer_format.dart @@ -1,10 +1,12 @@ import 'package:json_annotation/json_annotation.dart'; -import 'package:survey_kit/src/answer_format/answer_format.dart'; +import 'package:survey_kit/src/_new/model/answer/answer.dart'; part 'image_answer_format.g.dart'; @JsonSerializable() -class ImageAnswerFormat implements AnswerFormat { +class ImageAnswerFormat implements Answer { + static const String type = 'image'; + final String? defaultValue; final String buttonText; @@ -16,6 +18,5 @@ class ImageAnswerFormat implements AnswerFormat { factory ImageAnswerFormat.fromJson(Map json) => _$ImageAnswerFormatFromJson(json); - @override Map toJson() => _$ImageAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/image_answer_format.g.dart b/lib/src/_new/model/answer/image_answer_format.g.dart similarity index 100% rename from lib/src/answer_format/image_answer_format.g.dart rename to lib/src/_new/model/answer/image_answer_format.g.dart diff --git a/lib/src/answer_format/integer_answer_format.dart b/lib/src/_new/model/answer/integer_answer_format.dart similarity index 74% rename from lib/src/answer_format/integer_answer_format.dart rename to lib/src/_new/model/answer/integer_answer_format.dart index 7969c122..77672fa3 100644 --- a/lib/src/answer_format/integer_answer_format.dart +++ b/lib/src/_new/model/answer/integer_answer_format.dart @@ -1,10 +1,12 @@ import 'package:json_annotation/json_annotation.dart'; -import 'package:survey_kit/src/answer_format/answer_format.dart'; +import 'package:survey_kit/src/_new/model/answer/answer.dart'; part 'integer_answer_format.g.dart'; @JsonSerializable() -class IntegerAnswerFormat implements AnswerFormat { +class IntegerAnswerFormat implements Answer { + static const String type = 'integer'; + final int? defaultValue; final String hint; @@ -15,6 +17,5 @@ class IntegerAnswerFormat implements AnswerFormat { factory IntegerAnswerFormat.fromJson(Map json) => _$IntegerAnswerFormatFromJson(json); - @override Map toJson() => _$IntegerAnswerFormatToJson(this); } diff --git a/lib/src/answer_format/integer_answer_format.g.dart b/lib/src/_new/model/answer/integer_answer_format.g.dart similarity index 100% rename from lib/src/answer_format/integer_answer_format.g.dart rename to lib/src/_new/model/answer/integer_answer_format.g.dart diff --git a/lib/src/answer_format/multi_double.dart b/lib/src/_new/model/answer/multi_double.dart similarity index 100% rename from lib/src/answer_format/multi_double.dart rename to lib/src/_new/model/answer/multi_double.dart diff --git a/lib/src/answer_format/multi_double.g.dart b/lib/src/_new/model/answer/multi_double.g.dart similarity index 100% rename from lib/src/answer_format/multi_double.g.dart rename to lib/src/_new/model/answer/multi_double.g.dart diff --git a/lib/src/_new/model/answer/multi_select_answer.dart b/lib/src/_new/model/answer/multi_select_answer.dart new file mode 100644 index 00000000..f7ffbaec --- /dev/null +++ b/lib/src/_new/model/answer/multi_select_answer.dart @@ -0,0 +1,26 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:survey_kit/src/_new/model/answer/answer.dart'; +import 'package:survey_kit/src/_new/model/answer/option.dart'; + +part 'multi_select_answer.g.dart'; + +@JsonSerializable() +class MultiSelectAnswer implements Answer { + static const String type = 'multi'; + + final List