From ca96abf8c085326cf97f83cde2767eb95e8c3c90 Mon Sep 17 00:00:00 2001 From: "Tibor Bossanyi (Freelancer)" Date: Sat, 28 Jan 2023 12:53:16 +0100 Subject: [PATCH] v1.0.0 outsourced from aitrainer_app --- .flutter-plugins | 37 + .flutter-plugins-dependencies | 1 + .gitignore | 30 + .metadata | 10 + CHANGELOG.md | 3 + LICENSE | 1 + README.md | 39 + analysis_options.yaml | 4 + lib/model/cache.dart | 801 ++++++++++++++++++ lib/model/customer.dart | 128 +++ lib/model/customer_activity.dart | 30 + lib/model/customer_exercise_device.dart | 42 + lib/model/customer_property.dart | 69 ++ lib/model/customer_training_plan.dart | 97 +++ lib/model/customer_training_plan_details.dart | 162 ++++ .../customer_training_plan_exercise.dart | 30 + lib/model/description.dart | 40 + lib/model/evaluation.dart | 28 + lib/model/evaluation_attribute.dart | 41 + lib/model/exercise.dart | 68 ++ lib/model/exercise_ability.dart | 25 + lib/model/exercise_device.dart | 21 + lib/model/exercise_plan.dart | 70 ++ lib/model/exercise_plan_detail.dart | 91 ++ lib/model/exercise_plan_template.dart | 50 ++ lib/model/exercise_result.dart | 46 + lib/model/exercise_tree.dart | 76 ++ lib/model/exercise_tree_parents.dart | 13 + lib/model/exercise_type.dart | 134 +++ lib/model/exercise_type_device.dart | 11 + lib/model/faq.dart | 37 + lib/model/fitness_state.dart | 67 ++ lib/model/mautic.dart | 46 + lib/model/model_change.dart | 7 + lib/model/product.dart | 53 ++ lib/model/property.dart | 28 + lib/model/purchase.dart | 31 + lib/model/result.dart | 101 +++ lib/model/split_test.dart | 36 + lib/model/sport.dart | 30 + lib/model/tracking.dart | 24 + lib/model/training_evaluation_exercise.dart | 33 + lib/model/training_plan.dart | 74 ++ lib/model/training_plan_day.dart | 29 + lib/model/training_plan_detail.dart | 44 + lib/model/training_result.dart | 29 + lib/model/tutorial.dart | 37 + lib/model/tutorial_step.dart | 98 +++ lib/model/user.dart | 14 + lib/model/workout_menu_tree.dart | 86 ++ .../customer_exercise_device_repository.dart | 74 ++ lib/repository/customer_repository.dart | 573 +++++++++++++ .../exercise_device_repository.dart | 52 ++ lib/repository/exercise_repository.dart | 538 ++++++++++++ lib/repository/exercise_type_repository.dart | 26 + lib/repository/mautic_repository.dart | 93 ++ lib/repository/property_repository.dart | 31 + .../training_plan_day_repository.dart | 35 + lib/repository/training_plan_repository.dart | 448 ++++++++++ lib/repository/user_repository.dart | 224 +++++ lib/service/api.dart | 141 +++ .../customer_exercise_device_service.dart | 47 + lib/service/customer_service.dart | 240 ++++++ lib/service/exercise_device_service.dart | 17 + lib/service/exercise_service.dart | 44 + lib/service/exercise_tree_service.dart | 82 ++ lib/service/exercise_type_service.dart | 40 + lib/service/firebase_api.dart | 403 +++++++++ lib/service/mautic.dart | 29 + lib/service/package_service.dart | 210 +++++ lib/service/product_service.dart | 17 + lib/service/property_service.dart | 18 + lib/service/purchase_service.dart | 29 + lib/service/tracking_service.dart | 18 + lib/service/training_plan_service.dart | 34 + lib/util/app_language.dart | 68 ++ lib/util/app_localization.dart | 78 ++ lib/util/common.dart | 176 ++++ lib/util/enums.dart | 129 +++ lib/util/env.dart | 3 + lib/util/logging.dart | 16 + lib/util/not_found_exception.dart | 13 + lib/util/string_extension.dart | 5 + lib/util/track.dart | 53 ++ lib/workouttest_util.dart | 1 + pubspec.yaml | 73 ++ test/workouttest_util_test.dart | 9 + 87 files changed, 7189 insertions(+) create mode 100644 .flutter-plugins create mode 100644 .flutter-plugins-dependencies create mode 100644 .gitignore create mode 100644 .metadata create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 analysis_options.yaml create mode 100644 lib/model/cache.dart create mode 100644 lib/model/customer.dart create mode 100644 lib/model/customer_activity.dart create mode 100644 lib/model/customer_exercise_device.dart create mode 100644 lib/model/customer_property.dart create mode 100644 lib/model/customer_training_plan.dart create mode 100644 lib/model/customer_training_plan_details.dart create mode 100644 lib/model/customer_training_plan_exercise.dart create mode 100644 lib/model/description.dart create mode 100644 lib/model/evaluation.dart create mode 100644 lib/model/evaluation_attribute.dart create mode 100644 lib/model/exercise.dart create mode 100644 lib/model/exercise_ability.dart create mode 100644 lib/model/exercise_device.dart create mode 100644 lib/model/exercise_plan.dart create mode 100644 lib/model/exercise_plan_detail.dart create mode 100644 lib/model/exercise_plan_template.dart create mode 100644 lib/model/exercise_result.dart create mode 100644 lib/model/exercise_tree.dart create mode 100644 lib/model/exercise_tree_parents.dart create mode 100644 lib/model/exercise_type.dart create mode 100644 lib/model/exercise_type_device.dart create mode 100644 lib/model/faq.dart create mode 100644 lib/model/fitness_state.dart create mode 100644 lib/model/mautic.dart create mode 100644 lib/model/model_change.dart create mode 100644 lib/model/product.dart create mode 100644 lib/model/property.dart create mode 100644 lib/model/purchase.dart create mode 100644 lib/model/result.dart create mode 100644 lib/model/split_test.dart create mode 100644 lib/model/sport.dart create mode 100644 lib/model/tracking.dart create mode 100644 lib/model/training_evaluation_exercise.dart create mode 100644 lib/model/training_plan.dart create mode 100644 lib/model/training_plan_day.dart create mode 100644 lib/model/training_plan_detail.dart create mode 100644 lib/model/training_result.dart create mode 100644 lib/model/tutorial.dart create mode 100644 lib/model/tutorial_step.dart create mode 100644 lib/model/user.dart create mode 100644 lib/model/workout_menu_tree.dart create mode 100644 lib/repository/customer_exercise_device_repository.dart create mode 100644 lib/repository/customer_repository.dart create mode 100644 lib/repository/exercise_device_repository.dart create mode 100644 lib/repository/exercise_repository.dart create mode 100644 lib/repository/exercise_type_repository.dart create mode 100644 lib/repository/mautic_repository.dart create mode 100644 lib/repository/property_repository.dart create mode 100644 lib/repository/training_plan_day_repository.dart create mode 100644 lib/repository/training_plan_repository.dart create mode 100644 lib/repository/user_repository.dart create mode 100644 lib/service/api.dart create mode 100644 lib/service/customer_exercise_device_service.dart create mode 100644 lib/service/customer_service.dart create mode 100644 lib/service/exercise_device_service.dart create mode 100644 lib/service/exercise_service.dart create mode 100644 lib/service/exercise_tree_service.dart create mode 100644 lib/service/exercise_type_service.dart create mode 100644 lib/service/firebase_api.dart create mode 100644 lib/service/mautic.dart create mode 100644 lib/service/package_service.dart create mode 100644 lib/service/product_service.dart create mode 100644 lib/service/property_service.dart create mode 100644 lib/service/purchase_service.dart create mode 100644 lib/service/tracking_service.dart create mode 100644 lib/service/training_plan_service.dart create mode 100644 lib/util/app_language.dart create mode 100644 lib/util/app_localization.dart create mode 100644 lib/util/common.dart create mode 100644 lib/util/enums.dart create mode 100644 lib/util/env.dart create mode 100644 lib/util/logging.dart create mode 100644 lib/util/not_found_exception.dart create mode 100644 lib/util/string_extension.dart create mode 100644 lib/util/track.dart create mode 100644 lib/workouttest_util.dart create mode 100644 pubspec.yaml create mode 100644 test/workouttest_util_test.dart diff --git a/.flutter-plugins b/.flutter-plugins new file mode 100644 index 0000000..3af0410 --- /dev/null +++ b/.flutter-plugins @@ -0,0 +1,37 @@ +# This is a generated file; do not edit or check into version control. +device_info_plus=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\device_info_plus-8.0.0\\ +facebook_auth_desktop=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\facebook_auth_desktop-0.0.8\\ +firebase_analytics=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\firebase_analytics-10.1.0\\ +firebase_analytics_web=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\firebase_analytics_web-0.5.1+8\\ +firebase_auth=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\firebase_auth-4.2.5\\ +firebase_auth_web=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\firebase_auth_web-5.2.4\\ +firebase_core=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\firebase_core-2.4.1\\ +firebase_core_web=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\firebase_core_web-2.1.0\\ +firebase_messaging=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\firebase_messaging-14.2.1\\ +firebase_messaging_web=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\firebase_messaging_web-3.2.11\\ +firebase_remote_config=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\firebase_remote_config-3.0.9\\ +firebase_remote_config_web=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\firebase_remote_config_web-1.1.18\\ +flutter_facebook_auth=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\flutter_facebook_auth-5.0.7\\ +flutter_facebook_auth_web=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\flutter_facebook_auth_web-4.1.1\\ +flutter_secure_storage=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\flutter_secure_storage-7.0.1\\ +flutter_secure_storage_linux=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\flutter_secure_storage_linux-1.1.2\\ +flutter_secure_storage_macos=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\flutter_secure_storage_macos-2.0.1\\ +flutter_secure_storage_web=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\flutter_secure_storage_web-1.1.1\\ +flutter_secure_storage_windows=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\flutter_secure_storage_windows-1.1.3\\ +google_sign_in=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\google_sign_in-5.4.3\\ +google_sign_in_android=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\google_sign_in_android-6.1.5\\ +google_sign_in_ios=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\google_sign_in_ios-5.5.1\\ +google_sign_in_web=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\google_sign_in_web-0.10.2+1\\ +package_info_plus=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\package_info_plus-3.0.2\\ +path_provider_linux=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\path_provider_linux-2.1.7\\ +path_provider_windows=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\path_provider_windows-2.1.3\\ +posthog_session=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\git\\posthog_session-0db36d398cc23a7bfab09e0ddb6773525a92107b\\ +sentry_flutter=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\sentry_flutter-6.19.0\\ +shared_preferences=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\shared_preferences-2.0.17\\ +shared_preferences_android=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\shared_preferences_android-2.0.15\\ +shared_preferences_foundation=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\shared_preferences_foundation-2.1.2\\ +shared_preferences_linux=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\shared_preferences_linux-2.1.3\\ +shared_preferences_web=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\shared_preferences_web-2.0.4\\ +shared_preferences_windows=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\shared_preferences_windows-2.1.3\\ +sign_in_with_apple=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\sign_in_with_apple-4.3.0\\ +sign_in_with_apple_web=C:\\Users\\bossa\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\sign_in_with_apple_web-1.0.1\\ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies new file mode 100644 index 0000000..b459952 --- /dev/null +++ b/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\device_info_plus-8.0.0\\\\","native_build":true,"dependencies":[]},{"name":"firebase_analytics","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_analytics-10.1.0\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_auth","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_auth-4.2.5\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_core-2.4.1\\\\","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_messaging-14.2.1\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_remote_config","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_remote_config-3.0.9\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_facebook_auth","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_facebook_auth-5.0.7\\\\","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_secure_storage-7.0.1\\\\","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\google_sign_in_ios-5.5.1\\\\","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\package_info_plus-3.0.2\\\\","native_build":true,"dependencies":[]},{"name":"posthog_session","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\git\\\\posthog_session-0db36d398cc23a7bfab09e0ddb6773525a92107b\\\\","native_build":true,"dependencies":[]},{"name":"sentry_flutter","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sentry_flutter-6.19.0\\\\","native_build":true,"dependencies":["package_info_plus"]},{"name":"shared_preferences_foundation","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_foundation-2.1.2\\\\","native_build":true,"dependencies":[]},{"name":"sign_in_with_apple","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sign_in_with_apple-4.3.0\\\\","native_build":true,"dependencies":[]}],"android":[{"name":"device_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\device_info_plus-8.0.0\\\\","native_build":true,"dependencies":[]},{"name":"firebase_analytics","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_analytics-10.1.0\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_auth","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_auth-4.2.5\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_core-2.4.1\\\\","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_messaging-14.2.1\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_remote_config","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_remote_config-3.0.9\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_facebook_auth","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_facebook_auth-5.0.7\\\\","native_build":true,"dependencies":[]},{"name":"flutter_secure_storage","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_secure_storage-7.0.1\\\\","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\google_sign_in_android-6.1.5\\\\","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\package_info_plus-3.0.2\\\\","native_build":true,"dependencies":[]},{"name":"posthog_session","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\git\\\\posthog_session-0db36d398cc23a7bfab09e0ddb6773525a92107b\\\\","native_build":true,"dependencies":[]},{"name":"sentry_flutter","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sentry_flutter-6.19.0\\\\","native_build":true,"dependencies":["package_info_plus"]},{"name":"shared_preferences_android","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_android-2.0.15\\\\","native_build":true,"dependencies":[]},{"name":"sign_in_with_apple","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sign_in_with_apple-4.3.0\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"device_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\device_info_plus-8.0.0\\\\","native_build":true,"dependencies":[]},{"name":"facebook_auth_desktop","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\facebook_auth_desktop-0.0.8\\\\","native_build":true,"dependencies":[]},{"name":"firebase_analytics","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_analytics-10.1.0\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_auth","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_auth-4.2.5\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_core","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_core-2.4.1\\\\","native_build":true,"dependencies":[]},{"name":"firebase_messaging","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_messaging-14.2.1\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"firebase_remote_config","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_remote_config-3.0.9\\\\","native_build":true,"dependencies":["firebase_core"]},{"name":"flutter_secure_storage_macos","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_secure_storage_macos-2.0.1\\\\","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\package_info_plus-3.0.2\\\\","native_build":true,"dependencies":[]},{"name":"sentry_flutter","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sentry_flutter-6.19.0\\\\","native_build":true,"dependencies":["package_info_plus"]},{"name":"shared_preferences_foundation","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_foundation-2.1.2\\\\","native_build":true,"dependencies":[]},{"name":"sign_in_with_apple","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sign_in_with_apple-4.3.0\\\\","native_build":true,"dependencies":[]}],"linux":[{"name":"device_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\device_info_plus-8.0.0\\\\","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_linux","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_secure_storage_linux-1.1.2\\\\","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\package_info_plus-3.0.2\\\\","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_linux-2.1.7\\\\","native_build":false,"dependencies":[]},{"name":"sentry_flutter","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sentry_flutter-6.19.0\\\\","native_build":true,"dependencies":["package_info_plus"]},{"name":"shared_preferences_linux","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_linux-2.1.3\\\\","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"device_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\device_info_plus-8.0.0\\\\","native_build":false,"dependencies":[]},{"name":"flutter_secure_storage_windows","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_secure_storage_windows-1.1.3\\\\","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\package_info_plus-3.0.2\\\\","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider_windows-2.1.3\\\\","native_build":false,"dependencies":[]},{"name":"sentry_flutter","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sentry_flutter-6.19.0\\\\","native_build":true,"dependencies":["package_info_plus"]},{"name":"shared_preferences_windows","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_windows-2.1.3\\\\","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"device_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\device_info_plus-8.0.0\\\\","dependencies":[]},{"name":"firebase_analytics_web","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_analytics_web-0.5.1+8\\\\","dependencies":["firebase_core_web"]},{"name":"firebase_auth_web","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_auth_web-5.2.4\\\\","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_core_web-2.1.0\\\\","dependencies":[]},{"name":"firebase_messaging_web","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_messaging_web-3.2.11\\\\","dependencies":["firebase_core_web"]},{"name":"firebase_remote_config_web","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\firebase_remote_config_web-1.1.18\\\\","dependencies":["firebase_core_web"]},{"name":"flutter_facebook_auth_web","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_facebook_auth_web-4.1.1\\\\","dependencies":[]},{"name":"flutter_secure_storage_web","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_secure_storage_web-1.1.1\\\\","dependencies":[]},{"name":"google_sign_in_web","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\google_sign_in_web-0.10.2+1\\\\","dependencies":[]},{"name":"package_info_plus","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\package_info_plus-3.0.2\\\\","dependencies":[]},{"name":"posthog_session","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\git\\\\posthog_session-0db36d398cc23a7bfab09e0ddb6773525a92107b\\\\","dependencies":[]},{"name":"sentry_flutter","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sentry_flutter-6.19.0\\\\","dependencies":["package_info_plus"]},{"name":"shared_preferences_web","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences_web-2.0.4\\\\","dependencies":[]},{"name":"sign_in_with_apple_web","path":"C:\\\\Users\\\\bossa\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sign_in_with_apple_web-1.0.1\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"device_info_plus","dependencies":[]},{"name":"facebook_auth_desktop","dependencies":["flutter_secure_storage"]},{"name":"firebase_analytics","dependencies":["firebase_analytics_web","firebase_core"]},{"name":"firebase_analytics_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_remote_config","dependencies":["firebase_core","firebase_remote_config_web"]},{"name":"firebase_remote_config_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_facebook_auth","dependencies":["flutter_facebook_auth_web","facebook_auth_desktop"]},{"name":"flutter_facebook_auth_web","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"posthog_session","dependencies":[]},{"name":"sentry_flutter","dependencies":["package_info_plus"]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"sign_in_with_apple","dependencies":["sign_in_with_apple_web"]},{"name":"sign_in_with_apple_web","dependencies":[]}],"date_created":"2023-01-28 12:44:03.284349","version":"3.3.10"} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96486fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..541c2f6 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 135454af32477f815a7525073027a3ff9eff1bfd + channel: stable + +project_type: package diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..41cc7d8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ba75c69 --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/README.md b/README.md new file mode 100644 index 0000000..02fe8ec --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..a5744c1 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/lib/model/cache.dart b/lib/model/cache.dart new file mode 100644 index 0000000..80888ae --- /dev/null +++ b/lib/model/cache.dart @@ -0,0 +1,801 @@ +import 'dart:collection'; +import 'dart:convert'; +import 'package:flutter/foundation.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:workouttest_util/model/customer.dart'; +import 'package:workouttest_util/model/customer_activity.dart'; +import 'package:workouttest_util/model/customer_property.dart'; +import 'package:workouttest_util/model/customer_training_plan.dart'; +import 'package:workouttest_util/model/description.dart'; +import 'package:workouttest_util/model/evaluation.dart'; +import 'package:workouttest_util/model/exercise_plan.dart'; +import 'package:workouttest_util/model/exercise_plan_detail.dart'; +import 'package:workouttest_util/model/exercise_plan_template.dart'; +import 'package:workouttest_util/model/exercise_tree.dart'; +import 'package:workouttest_util/model/exercise.dart'; +import 'package:workouttest_util/model/faq.dart'; +import 'package:workouttest_util/model/model_change.dart'; +import 'package:workouttest_util/model/product.dart' as wt_product; +import 'package:workouttest_util/model/product.dart'; +import 'package:workouttest_util/model/property.dart'; +import 'package:workouttest_util/model/purchase.dart'; +import 'package:workouttest_util/model/split_test.dart'; +import 'package:workouttest_util/model/sport.dart'; +import 'package:workouttest_util/model/training_plan.dart'; +import 'package:workouttest_util/model/training_plan_day.dart'; +import 'package:workouttest_util/model/tutorial.dart'; +import 'package:workouttest_util/model/workout_menu_tree.dart'; +import 'package:workouttest_util/repository/customer_repository.dart'; +import 'package:workouttest_util/service/firebase_api.dart'; +import 'package:workouttest_util/service/package_service.dart'; +import 'package:workouttest_util/util/enums.dart'; +import 'package:workouttest_util/util/env.dart'; +import 'package:workouttest_util/util/track.dart'; +import 'package:firebase_remote_config/firebase_remote_config.dart'; +import 'package:flutter_facebook_auth/flutter_facebook_auth.dart'; +import 'package:matomo_tracker/matomo_tracker.dart'; +import 'package:posthog_session/posthog_session.dart'; +// ignore: depend_on_referenced_packages +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:workouttest_util/model/exercise_type.dart'; +// ignore: depend_on_referenced_packages +import 'package:intl/intl.dart'; + +import '../util/logging.dart'; +import 'customer_exercise_device.dart'; +import 'exercise_device.dart'; + +enum SharePrefsChange { + login, + registration, + logout, +} +/* + Auth flow of the app + 1. During the login screen the authentication will be executed + - if not successful: message: Network error, try again later + - if successful + - get the stored shared preferences and customer id + - if customer_id not present -> registration page + - if present, check if the expiration_date > 10 days -> login page + - else get the API customer by the stored customer_id + - After registration / login store the preferences: + - AuthToken + - customer_id + - last_store_date + - is_registered + - is_logged_in + */ + +enum ActivityDone { + tutorialExecuteFirstTest, + tutorialBasic, + tutorialBasicChestPress, + tutorialBasicLegPress, + tutorialDevelopment, + isExerciseLogSeen, + isMuscleDevelopmentSeen, + isBodyTypeSeen, + exerciseSaveTestTip, + exerciseSaveTrainingTip, + exerciseSaveTestsetTip +} + +extension ActivityDoneExt on ActivityDone { + String toStr() => toString().split(".").last; + bool equalsTo(ActivityDone value) => toString() == value.toString(); + bool equalsStringTo(String value) => toStr() == value; + + ActivityDone? searchByString(String activityString) { + ActivityDone? activity; + for (var element in ActivityDone.values) { + if (element.equalsStringTo(activityString)) { + activity = element; + } + } + return activity; + } +} + +class Cache with Logging { + static final Cache _singleton = Cache._internal(); + + // Keys to store and fetch data from SharedPreferences + static const String authTokenKey = "auth_token"; + static const String customerIdKey = "customer_id"; + static const String firebaseUidKey = "firebase_uid"; + static const String lastStoreDateKey = "last_date"; + static const String isRegisteredKey = "is_registered"; + static const String isLoggedInKey = "is_logged_in"; + static const String langKey = "lang"; + static const String serverKey = "live"; + static const String hardwareKey = "hardware"; + static const String loginTypeKey = "login_type"; + static const String timerDisplayKey = "timer_display"; + static const String activeExercisePlanKey = "active_exercise_plan"; + static const String activeExercisePlanDateKey = "active_exercise_plan_date"; + static const String activeExercisePlanDetailsKey = "active_exercise_details_plan"; + static const String myTrainingPlanKey = "myTrainingPlan"; + + static String baseUrlLive = 'https://api.workouttest.org/api/'; + static String baseUrlTest = 'https://apitest.workouttest.org/api/'; + late String baseUrl; + static const String mediaUrl = 'https://admin.workouttest.org/media/'; + static const String username = 'bosi'; + static const String password = 'andio2009'; + + String authToken = ""; + AccessToken? accessTokenFacebook; + Customer? userLoggedIn; + String? firebaseUid; + String? firebaseMessageToken; + LoginType? loginType; + PackageInfo? packageInfo; + + bool hasPurchased = false; + + bool firstLoad = true; + + List? _exerciseTypes; + List? _exerciseTree; + List? _evaluations; + + List? _exercises; + ExercisePlan? _myExercisePlan; + List? _properties; + List? _sports; + List? _products; + List _purchases = []; + List _splitTests = []; + List _trainingPlanDays = []; + + List _exercisePlanTemplates = []; + + ExercisePlan? activeExercisePlan; + CustomerTrainingPlan? myTrainingPlan; + List? activeExercisePlanDetails; + + List? _devices; + + List? _customerDevices; + List? _customerActivities; + List? _customerTrainingPlans; + List? _customerPropertyAll; + + List? _tutorials; + List? _descriptions; + List? _faqs; + List? _trainingPlans; + + LinkedHashMap _myExercisesPlanDetails = LinkedHashMap(); + + LinkedHashMap _tree = LinkedHashMap(); + double _percentExercises = -1; + + Customer? _trainee; + List? _exercisesTrainee; + ExercisePlan? _traineeExercisePlan; + + FirebaseRemoteConfig? remoteConfig; + + LinkedHashMap _badges = LinkedHashMap(); + + List? deviceLanguages; + String startPage = "home"; + late String testEnvironment; + bool liveServer = true; + bool? hasHardware = false; + + HashMap activitiesDone = HashMap(); + + factory Cache() { + return _singleton; + } + + Cache._internal() { + String testEnv = EnvironmentConfig.test_env; + testEnvironment = testEnv; + print("testEnv $testEnv"); + if (testEnv == "1") { + baseUrl = baseUrlTest; + liveServer = false; + } + + for (var element in ActivityDone.values) { + activitiesDone[element.toStr()] = false; + } + } + + void setTestBaseUrl() { + baseUrl = baseUrlTest; + } + + String getAuthToken() { + return authToken; + } + + Future deleteCustomerId(int customerId) async { + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences = await prefs; + sharedPreferences.remove(Cache.customerIdKey); + } + + Future saveActiveExercisePlan(ExercisePlan exercisePlan, List exercisePlanDetails) async { + activeExercisePlan = exercisePlan; + activeExercisePlanDetails = exercisePlanDetails; + String exercisePlanJson = const JsonEncoder().convert(exercisePlan.toJson()); + String detailsJson = jsonEncode(exercisePlanDetails.map((i) => i.toJsonWithExerciseList()).toList()).toString(); + + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences; + sharedPreferences = await prefs; + + final DateTime now = DateTime.now(); + sharedPreferences.setString(Cache.activeExercisePlanKey, exercisePlanJson); + sharedPreferences.setString(Cache.activeExercisePlanDetailsKey, detailsJson); + String savingDay = DateFormat("yyyy-MM-dd HH:mm:ss").format(now); + sharedPreferences.setString(Cache.activeExercisePlanDateKey, savingDay); + } + + Future saveMyTrainingPlan() async { + if (myTrainingPlan == null) { + return; + } + String myTrainingPlanJson = const JsonEncoder().convert(myTrainingPlan!.toJsonWithDetails()); + + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences; + sharedPreferences = await prefs; + sharedPreferences.setString(Cache.myTrainingPlanKey, myTrainingPlanJson); + } + + Future deleteMyTrainingPlan() async { + if (myTrainingPlan == null) { + return; + } + + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences; + sharedPreferences = await prefs; + sharedPreferences.remove(Cache.myTrainingPlanKey); + } + + Future getMyTrainingPlan() async { + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences; + sharedPreferences = await prefs; + + final String? savedTrainingPlanJson = sharedPreferences.getString(Cache.myTrainingPlanKey); + if (savedTrainingPlanJson == null) { + return; + } + //String jsonPlan = savedTrainingPlanJson.replaceAllMapped(RegExp(r'[a-zA-Z]+\:'), (Match m) => "\"${m[0]}\""); + Map map; + try { + map = JsonDecoder().convert(savedTrainingPlanJson); + //print("Training plan: $savedTrainingPlanJson"); + this.myTrainingPlan = CustomerTrainingPlan.fromJsonWithDetails(map); + } on Exception catch (e) { + print(e.toString()); + } + } + + Future deleteActiveExercisePlan() async { + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences; + sharedPreferences = await prefs; + + sharedPreferences.remove(Cache.activeExercisePlanDateKey); + this.activeExercisePlan = null; + this.activeExercisePlanDetails = null; + } + + Future getActiveExercisePlan() async { + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences; + sharedPreferences = await prefs; + + final savedPlanDateString = sharedPreferences.getString(Cache.activeExercisePlanDateKey); + if (savedPlanDateString == null) { + return; + } + + DateFormat format = DateFormat("yyyy-MM-dd HH:mm:ss"); + DateTime savedPlanDate; + + savedPlanDate = format.parse(savedPlanDateString); + print("Saved plan: $savedPlanDate"); + + final DateTime now = DateTime.now(); + final DateTime added = savedPlanDate.add(Duration(days: 1)); + if (added.isBefore(now)) { + return; + } + + String? exercisePlanJson = sharedPreferences.getString(Cache.activeExercisePlanKey); + if (exercisePlanJson != null) { + final Map map = JsonDecoder().convert(exercisePlanJson); + this.activeExercisePlan = ExercisePlan.fromJson(map); + } + + String? detailsJson = sharedPreferences.getString(Cache.activeExercisePlanDetailsKey); + if (detailsJson != null) { + Iterable json = jsonDecode(detailsJson); + this.activeExercisePlanDetails = json.map((details) => ExercisePlanDetail.fromJsonWithExerciseList(details)).toList(); + } + } + + Future setServer(bool live) async { + if (this.testEnvironment == "1") { + liveServer = false; + live = false; + } + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences; + sharedPreferences = await prefs; + liveServer = live; + sharedPreferences.setBool(Cache.serverKey, live); + } + + void getHardware(SharedPreferences prefs) { + final bool? hasHardware = prefs.getBool(Cache.hardwareKey); + this.hasHardware = hasHardware; + if (hasHardware == null) { + this.hasHardware = false; + } + } + + Future selectedHardwareBefore() async { + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences = await prefs; + + final bool? selectedHardware = sharedPreferences.getBool(Cache.hardwareKey); + return selectedHardware == null; + } + + Future setHardware(bool hasHardware) async { + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences; + sharedPreferences = await prefs; + sharedPreferences.setBool(Cache.hardwareKey, hasHardware); + this.hasHardware = hasHardware; + } + + void setServerAddress(SharedPreferences prefs) { + if (this.testEnvironment == "1") { + baseUrl = baseUrlTest; + print("TestEnv $baseUrl"); + return; + } + final bool? live = prefs.getBool(Cache.serverKey); + if (live == null) { + baseUrl = baseUrlLive; + print("Live Env $baseUrl"); + liveServer = true; + return; + } + liveServer = live; + if (live) { + baseUrl = baseUrlLive; + } else { + baseUrl = baseUrlTest; + } + + print("Env $baseUrl"); + } + + Future setLoginTypeFromPrefs() async { + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences = await prefs; + final String? loginType = sharedPreferences.getString(Cache.loginTypeKey); + LoginType type = LoginType.email; + if (loginType == LoginType.apple.toString()) { + type = LoginType.apple; + } else if (loginType == LoginType.google.toString()) { + type = LoginType.google; + } else if (loginType == LoginType.fb.toString()) { + type = LoginType.fb; + } else if (loginType == LoginType.email.toString()) { + type = LoginType.email; + } + //print("LoginType: " + loginType == null ? "NULL" : loginType); + Cache().setLoginType(type); + } + + static String? getToken(SharedPreferences prefs) { + return prefs.getString(authTokenKey); + } + + String getBaseUrl() { + return baseUrl; + } + + static String getMediaUrl() { + return mediaUrl; + } + + afterRegistration(Customer customer) async { + Future prefs = SharedPreferences.getInstance(); + + userLoggedIn = customer; + final String uid = Cache().firebaseUid!; + SharedPreferences sharedPreferences = await prefs; + sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString()); + await setPreferences(prefs, SharePrefsChange.registration, customer.customerId!, uid); + } + + afterLogin(Customer customer) async { + Future prefs = SharedPreferences.getInstance(); + + userLoggedIn = customer; + SharedPreferences sharedPreferences = await prefs; + sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString()); + await setPreferences(prefs, SharePrefsChange.login, customer.customerId!, Cache().firebaseUid!); + } + + afterFirebaseLogin() async { + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences = await prefs; + sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString()); + await setPreferences(prefs, SharePrefsChange.login, userLoggedIn!.customerId!, Cache().firebaseUid!); + } + + afterFacebookLogin() async { + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences = await prefs; + sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString()); + await setPreferences(prefs, SharePrefsChange.login, userLoggedIn!.customerId!, Cache().firebaseUid!); + } + + logout() async { + if (this.accessTokenFacebook != null) { + await FirebaseApi().logOutFacebook(); + } + userLoggedIn = null; + firebaseUid = null; + authToken = ""; + _trainee = null; + _percentExercises = -1; + _exercisesTrainee = null; + _traineeExercisePlan = null; + _exercises = []; + _myExercisesPlanDetails = LinkedHashMap(); + log("Trainees is null? " + (_trainee == null).toString()); + Future prefs = SharedPreferences.getInstance(); + await setPreferences(prefs, SharePrefsChange.logout, 0, ""); + } + + Future setPreferences(Future prefs, SharePrefsChange type, int customerId, String firebaseUid) async { + SharedPreferences sharedPreferences; + sharedPreferences = await prefs; + + DateTime now = DateTime.now(); + sharedPreferences.setString(Cache.lastStoreDateKey, now.toString()); + if (type == SharePrefsChange.registration) { + sharedPreferences.setInt(Cache.customerIdKey, customerId); + sharedPreferences.setBool(Cache.isRegisteredKey, true); + sharedPreferences.setBool(Cache.isLoggedInKey, true); + sharedPreferences.setString(Cache.firebaseUidKey, firebaseUid); + await initCustomer(customerId); + } else if (type == SharePrefsChange.login) { + sharedPreferences.setInt(Cache.customerIdKey, customerId); + sharedPreferences.setString(Cache.firebaseUidKey, firebaseUid); + sharedPreferences.setBool(Cache.isLoggedInKey, true); + await initCustomer(customerId); + } else if (type == SharePrefsChange.logout) { + sharedPreferences.setBool(Cache.isLoggedInKey, false); + sharedPreferences.setInt(Cache.customerIdKey, 0); + sharedPreferences.setString(Cache.firebaseUidKey, ""); + sharedPreferences.setString(authTokenKey, ""); + } + initBadges(); + } + + void setExerciseTypes(List exerciseTypes) { + this._exerciseTypes = exerciseTypes; + } + + void setExerciseTree(List exerciseTree) { + this._exerciseTree = exerciseTree; + } + + void setExercises(List exercises) => this._exercises = exercises; + + void setExercisesTrainee(List exercises) { + this._exercisesTrainee = exercises; + } + + void setWorkoutMenuTree(LinkedHashMap tree) { + this._tree = tree; + } + + List? getExerciseTypes() => this._exerciseTypes; + + ExerciseType? getExerciseTypeById(int exerciseTypeId) { + ExerciseType? exerciseType; + if (_exerciseTypes != null) { + this._exerciseTypes!.forEach((element) { + if (element.exerciseTypeId == exerciseTypeId) { + exerciseType = element; + } + }); + } + return exerciseType; + } + + List? getExerciseTree() => this._exerciseTree; + + List? getExercises() => this._exercises; + + List? getExercisesTrainee() => this._exercisesTrainee; + + LinkedHashMap getWorkoutMenuTree() => this._tree; + + void setPercentExercises(double percent) => this._percentExercises = percent; + + double getPercentExercises() => this._percentExercises; + + void addExercise(Exercise exercise) => _exercises!.add(exercise); + + void addExerciseTrainee(Exercise exercise) => _exercisesTrainee!.add(exercise); + + Customer? getTrainee() => this._trainee; + + void setTrainee(Customer trainee) => _trainee = trainee; + + void setTraineeExercisePlan(ExercisePlan exercisePlan) => this._traineeExercisePlan = exercisePlan; + + ExercisePlan? getTraineesExercisePlan() => this._traineeExercisePlan; + + void setMyExercisePlan(ExercisePlan exercisePlan) => _myExercisePlan = exercisePlan; + + ExercisePlan? getMyExercisePlan() => _myExercisePlan; + + void setMyExercisePlanDetails(LinkedHashMap listExercisePlanDetail) => + _myExercisesPlanDetails = listExercisePlanDetail; + + void addToMyExercisePlanDetails(ExercisePlanDetail detail) => _myExercisesPlanDetails[detail.exerciseTypeId] = detail; + + LinkedHashMap getMyExercisePlanDetails() => _myExercisesPlanDetails; + + void resetMyExercisePlanDetails() => _myExercisesPlanDetails = LinkedHashMap(); + + void updateMyExercisePlanDetail(ExercisePlanDetail detail) { + this.addToMyExercisePlanDetails(detail); + } + + void deleteMyExercisePlanDetail(ExercisePlanDetail detail) => this.deleteMyExercisePlanDetailByExerciseTypeId(detail.exerciseTypeId); + + void deletedMyExercisePlanDetail(ExercisePlanDetail detail) => + this._myExercisesPlanDetails[detail.exerciseTypeId]!.change = ModelChange.deleted; + + void deleteMyExercisePlanDetailByExerciseTypeId(int exerciseTypeId) { + this._myExercisesPlanDetails[exerciseTypeId]!.change = ModelChange.delete; + } + + void setProperties(List properties) => this._properties = properties; + List? getProperties() => _properties; + + List? getSports() => _sports; + void setSports(List sports) => this._sports = sports; + + void setDevices(List devices) => this._devices = devices; + + List? getDevices() => this._devices; + + void setCustomerDevices(List devices) => this._customerDevices = devices; + + List? getCustomerDevices() => this._customerDevices; + + LinkedHashMap getBadges() => _badges; + + void setBadge(String key, bool inc) { + if (inc) { + if (_badges[key] != null) { + _badges[key] = _badges[key]! + 1; + } else { + _badges[key] = 1; + } + } else { + if (_badges[key] != null) { + if (_badges[key] == 1) { + _badges.remove(key); + } else { + _badges[key] = _badges[key]! - 1; + } + } + } + } + + void setBadgeNr(String key, int counter) { + if (_badges[key] != null) { + _badges[key] = _badges[key]! + counter; + } else { + _badges[key] = counter; + } + } + + void initBadges() { + CustomerRepository customerRepository = CustomerRepository(); + _badges = LinkedHashMap(); + if (userLoggedIn == null) { + return; + } + customerRepository.setCustomer(userLoggedIn!); + int _ecto = customerRepository.getCustomerPropertyValue(PropertyEnum.Ectomorph.toStr()).toInt(); + int _mezo = customerRepository.getCustomerPropertyValue(PropertyEnum.Mesomorph.toStr()).toInt(); + int _endo = customerRepository.getCustomerPropertyValue(PropertyEnum.Endomorph.toStr()).toInt(); + + //print("endo " + _endo.toString() + " mezo " + _mezo.toString()); + if (this.userLoggedIn != null) { + if (this.userLoggedIn!.birthYear == null || this.userLoggedIn!.birthYear == 0) { + setBadge("personalData", true); + setBadge("account", true); + } + if (this._customerDevices == null || this._customerDevices!.isEmpty) { + setBadge("customerDevice", true); + setBadge("account", true); + } + if (userLoggedIn!.properties.isEmpty) { + setBadge("personalData", true); + setBadge("bodyType", true); + setBadge("Sizes", true); + setBadge("BMI", true); + setBadge("BMR", true); + setBadgeNr("My Body", 3); + setBadgeNr("home", 3); + } else if (customerRepository.getWeight() == 0) { + setBadge("BMI", true); + setBadge("BMR", true); + setBadge("My Body", true); + setBadgeNr("home", 1); + } + if (_ecto == 0 && _mezo == 0 && _endo == 0) { + setBadge("account", true); + setBadge("bodyType", true); + } + if (this._exercises == null || this._exercises!.isEmpty) { + setBadge("home", true); + setBadge("Custom Tests", true); + setBadge("Start Training", true); + } + if (customerRepository.getHeight() == 0) { + setBadge("BMI", true); + setBadge("BMR", true); + setBadge("My Body", true); + setBadgeNr("home", 1); + } + if (userLoggedIn!.goal == null) { + setBadge("Goal", true); + setBadge("account", true); + } + if (userLoggedIn!.fitnessLevel == null) { + setBadge("FitnessLevel", true); + setBadge("account", true); + } + if (this._exercises != null && this._exercises!.isNotEmpty) { + if (!activitiesDone[ActivityDone.isExerciseLogSeen.toStr()]!) { + setBadge("exerciseLog", true); + setBadge("development", true); + } + if (!activitiesDone[ActivityDone.isMuscleDevelopmentSeen.toStr()]!) { + setBadge("muscleDevelopment", true); + setBadge("development", true); + } + } + } + log("Badges: " + _badges.toString()); + } + + List? get products => _products; + void setProducts(List value) => _products = value; + + List get purchases => _purchases; + setPurchases(List value) => _purchases = value; + + Future initCustomer(int customerId) async { + log(" *** initCustomer"); + try { + await PackageApi().getCustomerPackage(customerId); + } on Exception catch (_) { + return; + } + + if (kReleaseMode) { + //FlurryData.setUserId(customerId.toString()); + //FlutterUxcam.setUserProperty("username", customerId.toString()); + //FlutterUxcam.setUserIdentity(customerId.toString()); + //Smartlook.setUserIdentifier(customerId.toString()); + //Smartlook.instance. + Track().track(TrackingEvent.enter); + MatomoTracker.instance.setVisitorUserId(customerId.toString()); + MatomoTracker.instance.trackEvent(eventCategory: "wt", action: TrackingEvent.enter.enumToString()); + Posthog().identify(userId: customerId.toString()); + Posthog().capture(eventName: TrackingEvent.enter.enumToString()); + } + + await Future.forEach(ActivityDone.values, (element) async { + ActivityDone activity = element as ActivityDone; + await isActivityDonePrefs(activity); + }); + + print("Firebase token save: $firebaseMessageToken"); + if (firebaseMessageToken != null) { + userLoggedIn!.firebaseRegToken = firebaseMessageToken; + CustomerRepository customerRepository = CustomerRepository(); + customerRepository.customer = userLoggedIn; + customerRepository.saveCustomer(); + } + + await getMyTrainingPlan(); + + Cache().startPage = "home"; + } + + AccessToken? get getAccessTokenFacebook => accessTokenFacebook; + set setAccessTokenFacebook(AccessToken accessTokenFacebook) => this.accessTokenFacebook = accessTokenFacebook; + + LoginType? getLoginType() => loginType; + void setLoginType(LoginType type) => this.loginType = type; + + List get exercisePlanTemplates => this._exercisePlanTemplates; + setExercisePlanTemplates(value) => this._exercisePlanTemplates = value; + + isActivityDonePrefs(ActivityDone activity) async { + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences = await prefs; + if (sharedPreferences.getBool(activity.toStr()) != null) { + activitiesDone[activity.toStr()] = sharedPreferences.getBool(activity.toStr())!; + } + + return activitiesDone[activity.toStr()]!; + } + + setActivityDonePrefs(ActivityDone activity) async { + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences = await prefs; + activitiesDone[activity.toStr()] = true; + sharedPreferences.setBool(activity.toStr(), true); + } + + bool isActivityDone(ActivityDone activity) => activitiesDone[activity.toStr()] == true; + + List? get evaluations => this._evaluations; + set evaluations(List? value) => this._evaluations = value; + + List? get customerActivities => this._customerActivities; + setCustomerActivities(List? value) => this._customerActivities = value; + + List? get tutorials => this._tutorials; + setTutorials(List? value) => this._tutorials = value; + + FirebaseRemoteConfig? getRemoteConfig() => this.remoteConfig; + setRemoteConfig(FirebaseRemoteConfig? remoteConfig) => this.remoteConfig = remoteConfig; + + List? getDescriptions() => this._descriptions; + setDescriptions(List? value) => this._descriptions = value; + + List? getFaqs() => this._faqs; + setFaqs(List? value) => this._faqs = value; + + List? getTrainingPlans() => this._trainingPlans; + setTrainingPlans(List? value) => this._trainingPlans = value; + + List? getCustomerTrainingPlans() => this._customerTrainingPlans; + setCustomerTrainingPlans(value) => this._customerTrainingPlans = value; + + List getSplitTests() => this._splitTests; + setSplitTests(value) => this._splitTests = value; + + List getTrainingPlanDays() => this._trainingPlanDays; + setTrainingPlanDays(value) => this._trainingPlanDays = value; + + List? getCustomerPropertyAll() => this._customerPropertyAll; + setCustomerPropertyAll(value) => this._customerPropertyAll = value; + addCustomerProperty(CustomerProperty property) { + if (this._customerPropertyAll == null) { + this._customerPropertyAll = []; + } + this._customerPropertyAll!.add(property); + } +} diff --git a/lib/model/customer.dart b/lib/model/customer.dart new file mode 100644 index 0000000..2166df7 --- /dev/null +++ b/lib/model/customer.dart @@ -0,0 +1,128 @@ +import 'dart:collection'; +import 'package:intl/intl.dart'; + +import 'customer_property.dart'; + +class Customer { + String? name; + String? email; + String? firstname; + String? sex; + int? age; + String? active; + int? customerId; + String? password; + int? birthYear; + String? goal; + String? fitnessLevel; + String? bodyType; + int? admin; + int? trainer; + int? dataPolicyAllowed; + String? firebaseUid; + DateTime? dateAdd; + DateTime? dateChange; + int? emailSubscription; + int? sportId; + DateTime? syncedDate; + DateTime? trialDate; + String? firebaseRegToken; + String? lang; + int? lifeLong; + + LinkedHashMap properties = LinkedHashMap(); + + Customer( + {this.customerId, + this.name, + this.firstname, + this.email, + this.sex, + this.age, + this.active, + this.password, + this.birthYear, + this.bodyType, + this.fitnessLevel, + this.goal, + this.admin, + this.trainer, + this.dataPolicyAllowed, + this.firebaseUid, + this.dateAdd, + this.dateChange}) { + dateAdd = DateTime.now(); + dateChange = DateTime.now(); + } + + Customer.fromJson(Map json) { + this.customerId = json['customerId']; + this.name = json['name']; + this.firstname = json['firstname']; + this.email = json['email']; + this.sex = json['sex']; + this.age = json['age']; + this.active = json['active']; + this.birthYear = json['birthYear']; + this.bodyType = json['bodyType']; + this.fitnessLevel = json['fitnessLevel']; + this.goal = json['goal']; + this.admin = json['admin']; + this.lifeLong = json['lifeLong']; + + this.trainer = json['trainer']; + this.firebaseUid = json['firebaseUid']; + this.firebaseRegToken = json['firebaseRegToken']; + this.lang = json['lang']; + + this.dataPolicyAllowed = json['dataPolicyAllowed']; + this.emailSubscription = json['emailSubscription']; + this.sportId = json['sportId']; + this.syncedDate = json['syncedDate'] == null ? null : DateTime.parse(json['syncedDate']); + this.trialDate = json['trialDate'] == null ? null : DateTime.parse(json['trialDate']); + + this.dateAdd = json['dateAdd'] == null ? DateTime.parse("0000-00-00") : DateTime.parse(json['dateAdd']); + this.dateChange = json['dateChange'] == null ? DateTime.parse("0000-00-00") : DateTime.parse(json['dateChange']); + } + + Map toJson() => { + "name": name, + "firstname": firstname, + "email": email, + "age": age, + "sex": sex, + "active": 'Y', + "password": password, + "birthYear": birthYear, + "bodyType": bodyType, + "fitnessLevel": fitnessLevel, + "goal": goal, + "admin": admin, + "trainer": trainer, + "dataPolicyAllowed": dataPolicyAllowed, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!), + "dateChange": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateChange!), + "emailSubscription": this.emailSubscription, + "sportId": this.sportId, + "syncedDate": this.syncedDate == null ? null : DateFormat('yyyy-MM-dd HH:mm:ss').format(this.syncedDate!), + "trialDate": this.trialDate == null ? null : DateFormat('yyyy-MM-dd HH:mm:ss').format(this.trialDate!), + "firebaseRegToken": this.firebaseRegToken, + "lang": this.lang, + "lifeLong": this.lifeLong, + }; + + @override + String toString() => this.toJson().toString(); + + double getProperty(String propertyName) { + if (this.properties[propertyName] == null) { + return 0; + } else { + return this.properties[propertyName]!.propertyValue; + } + } + + setProperty(String propertyName, double value) { + this.properties[propertyName]!.propertyValue = value; + } +} diff --git a/lib/model/customer_activity.dart b/lib/model/customer_activity.dart new file mode 100644 index 0000000..5960f80 --- /dev/null +++ b/lib/model/customer_activity.dart @@ -0,0 +1,30 @@ +import 'package:intl/intl.dart'; + +class CustomerActivity { + late int activityId; + late int customerId; + late String type; + late DateTime? dateAdd; + bool? skipped; + + CustomerActivity.fromJson(Map json) { + activityId = json['activityId']; + customerId = json['custoemrId']; + type = json['type']; + skipped = json['skipped']; + this.dateAdd = DateTime.parse(json['dateAdd']); + } + + Map toJson() => { + 'activityId': this.activityId, + 'customerId': this.customerId, + 'type': this.type, + 'skipped': this.skipped, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!), + }; + + @override + String toString() { + return this.toJson().toString(); + } +} diff --git a/lib/model/customer_exercise_device.dart b/lib/model/customer_exercise_device.dart new file mode 100644 index 0000000..0477b47 --- /dev/null +++ b/lib/model/customer_exercise_device.dart @@ -0,0 +1,42 @@ +import 'package:intl/intl.dart'; + +class CustomerExerciseDevice { + int? customerExerciseDeviceId; + late int exerciseDeviceId; + late int customerId; + late bool favourite; + late DateTime dateAdd; + + late String change; + + CustomerExerciseDevice({required this.exerciseDeviceId, required this.customerId, required this.favourite}) { + dateAdd = DateTime.now(); + } + + CustomerExerciseDevice.fromJson(Map json) { + this.customerExerciseDeviceId = json['customerExerciseDeviceId']; + this.exerciseDeviceId = json['exerciseDeviceId']; + this.customerId = json['customerId']; + this.favourite = json['favourite'] == 1 ? true : false; + this.dateAdd = DateTime.parse(json['dateAdd']); + } + + Map toJson() { + if (customerExerciseDeviceId == null) { + return { + "exerciseDeviceId": exerciseDeviceId, + "customerId": customerId, + "favourite": favourite == true ? 1 : 0, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd), + }; + } else { + return { + "customerExerciseDeviceId": customerExerciseDeviceId, + "exerciseDeviceId": exerciseDeviceId, + "customerId": customerId, + "favourite": favourite == true ? 1 : 0, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd), + }; + } + } +} diff --git a/lib/model/customer_property.dart b/lib/model/customer_property.dart new file mode 100644 index 0000000..2d3d4fa --- /dev/null +++ b/lib/model/customer_property.dart @@ -0,0 +1,69 @@ +import 'package:intl/intl.dart'; + +class CustomerProperty { + int? customerPropertyId; + late int propertyId; + late int customerId; + DateTime? dateAdd; + String? dateYmd; + String? dateYm; + String? dateY; + late double propertyValue; + bool newData = false; + + CustomerProperty( + {required this.propertyId, + required this.customerId, + required this.dateAdd, + required this.propertyValue}); + + CustomerProperty.fromJson(Map json) { + this.customerPropertyId = json['customerPropertyId']; + this.propertyId = json['propertyId']; + this.customerId = json['customerId']; + this.dateAdd = DateTime.parse(json['dateAdd']); + + if (this.dateAdd != null) { + dateYmd = DateFormat('yyyy-MM-dd').format(this.dateAdd!); + dateYm = DateFormat('yyyy-MM').format(this.dateAdd!); + dateY = DateFormat('yyyy').format(this.dateAdd!); + } + + this.propertyValue = json['propertyValue']; + + print("Json $json, ${this.toString()}"); + } + + Map toJson() { + if (customerPropertyId != null) { + return { + "customerPropertyId": this.customerPropertyId, + "propertyId": this.propertyId, + "customerId": this.customerId, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!), + "propertyValue": this.propertyValue + }; + } else { + return { + "propertyId": this.propertyId, + "customerId": this.customerId, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!), + "propertyValue": this.propertyValue + }; + } + } + + String toString() { + Map json = { + "customerPropertyId": this.customerPropertyId, + "propertyId": this.propertyId, + "customerId": this.customerId, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!), + "propertyValue": this.propertyValue, + "dateYmd": this.dateYmd, + "dateYm": this.dateYm, + "dateY": this.dateY, + }; + return json.toString(); + } +} diff --git a/lib/model/customer_training_plan.dart b/lib/model/customer_training_plan.dart new file mode 100644 index 0000000..c8cb00a --- /dev/null +++ b/lib/model/customer_training_plan.dart @@ -0,0 +1,97 @@ +import 'dart:collection'; +import 'dart:convert'; +// ignore: depend_on_referenced_packages +import 'package:intl/intl.dart'; +import 'package:workouttest_util/repository/exercise_type_repository.dart'; + +import 'package:workouttest_util/model/customer_training_plan_details.dart'; + +enum CustomerTrainingPlanType { custom, template, none } + +extension CustomerTrainingPlanTypeExt on CustomerTrainingPlanType { + String toStr() => toString().split(".").last; + bool equalsTo(CustomerTrainingPlanType type) => toString() == type.toString(); + bool equalsStringTo(String type) => toStr() == type; +} + +class CustomerTrainingPlan { + int? customerTrainingPlanId; + int? customerId; + int? trainingPlanId; + DateTime? dateAdd; + bool? active; + String? status; + + String? name; + + CustomerTrainingPlanType type = CustomerTrainingPlanType.none; + + CustomerTrainingPlan(); + + List details = []; + + HashMap> days = HashMap(); + + CustomerTrainingPlan.fromJson(Map json) { + customerTrainingPlanId = json['customerTrainingPlanId']; + customerId = json['customerId']; + trainingPlanId = json['trainingPlanId']; + dateAdd = DateTime.parse(json['dateAdd']); + active = json['active']; + status = json['status']; + name = json['name']; + } + + CustomerTrainingPlan.fromJsonWithDetails(Map json) { + customerTrainingPlanId = json['customerTrainingPlanId']; + customerId = json['customerId']; + trainingPlanId = json['trainingPlanId']; + dateAdd = json['dateAdd'] != null ? DateTime.parse(json['dateAdd']) : DateTime.now(); + active = json['active']; + status = json['status']; + name = json['name']; + + try { + final String details = json['details']; + String jsonDetails = details.replaceAllMapped(RegExp(r'([a-zA-Z]+)\:'), (Match m) => "\"${m[1]}\":"); + jsonDetails = jsonDetails.replaceAllMapped(RegExp(r'\: ([a-zA-Z /]+)'), (Match m) => ":\"${m[1]}\""); + + jsonDetails = + jsonDetails.replaceAllMapped(RegExp(r'([0-9]{4}\-[0-9]{2}\-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})'), (Match m) => "\"${m[0]}\""); + + print("detail: $jsonDetails"); + + Iterable iterable = jsonDecode(jsonDetails); + this.details = iterable.map((detail) => CustomerTrainingPlanDetails.fromJsonWithExerciseList(detail)).toList(); + this.details.forEach((detail) { + detail.alternatives = ExerciseTypeRepository.getExerciseTypeAlternatives(detail.exerciseTypeId); + }); + } on Exception catch (e) { + print("JsonDecode error " + e.toString()); + } + } + + Map toJson() => { + "customerTrainingPlanId": customerTrainingPlanId, + "customerId": customerId, + "trainingPlanId": trainingPlanId, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(dateAdd!), + "name": name, + "active": active, + "status": status + }; + + Map toJsonWithDetails() => { + "customerTrainingPlanId": customerTrainingPlanId, + "customerId": customerId, + "trainingPlanId": trainingPlanId, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(dateAdd!).toString(), + "name": name, + "active": active, + "status": status, + 'details': details.isEmpty ? [].toString() : details.map((detail) => detail.toJsonWithExercises()).toList().toString(), + }; + + @override + String toString() => toJson().toString(); +} diff --git a/lib/model/customer_training_plan_details.dart b/lib/model/customer_training_plan_details.dart new file mode 100644 index 0000000..2d462ad --- /dev/null +++ b/lib/model/customer_training_plan_details.dart @@ -0,0 +1,162 @@ +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/exercise.dart'; +import 'package:workouttest_util/model/exercise_plan_detail.dart'; +import 'package:workouttest_util/model/exercise_type.dart'; +import 'package:workouttest_util/repository/training_plan_day_repository.dart'; + +class CustomerTrainingPlanDetails { + /// customerTrainingPlanDetails + int? customerTrainingPlanDetailsId; + + /// trainingPlanDetailsId + int? trainingPlanDetailsId; + + /// exerciseTypeId + int? exerciseTypeId; + + /// set + int? set; + + /// repeats + int? repeats; + + /// weight + double? weight; + + int? restingTime; + bool? parallel; + String? day; + + int? dayId; + + /// exerciseType + ExerciseType? exerciseType; + + ExercisePlanDetailState state = ExercisePlanDetailState.start; + + List exercises = []; + + bool isTest = false; + + double baseOneRepMax = -1; + + List alternatives = []; + + CustomerTrainingPlanDetails(); + + CustomerTrainingPlanDetails.fromJson(Map json) { + this.customerTrainingPlanDetailsId = json['customerTrainingPlanDetailsId']; + this.exerciseTypeId = json['exerciseTypeId']; + this.set = json['set']; + this.repeats = json['repeats']; + this.weight = json['weight']; + this.restingTime = json['restingTime']; + this.parallel = json['parallel']; + this.day = json['day']; + } + + CustomerTrainingPlanDetails.fromJsonWithExerciseList(Map json) { + this.customerTrainingPlanDetailsId = json['customerTrainingPlanDetailsId'] == "null" || json['customerTrainingPlanDetailsId'] == null + ? 0 + : json['customerTrainingPlanDetailsId']; + this.trainingPlanDetailsId = json['trainingPlanDetailsId'] == "null" ? 0 : json['trainingPlanDetailsId']; + this.exerciseTypeId = json['exerciseTypeId']; + this.set = json['set']; + this.repeats = json['repeats'] == "null" ? -1 : json['repeats']; + this.weight = json['weight'] == "null" ? 0 : json['weight']; + this.restingTime = json['restingTime']; + this.parallel = json['parallel'] == "false" + ? false + : json['parallel'] == "true" + ? true + : null; + this.dayId = json['dayId'] == "null" ? null : json['dayId']; + TrainingPlanDayRepository trainingPlanDayRepository = TrainingPlanDayRepository(); + this.day = trainingPlanDayRepository.getNameById(this.dayId); + + try { + Iterable iterable = json['exercises']; + this.exercises = iterable.map((exercise) => Exercise.fromJson(exercise)).toList(); + } on Exception catch (e) { + print("JsonDecode error " + e.toString()); + } + + if (json['state'] == ExercisePlanDetailState.finished.toStr()) { + this.state = ExercisePlanDetailState.finished; + } else if (json['state'] == ExercisePlanDetailState.inProgress.toStr()) { + this.state = ExercisePlanDetailState.inProgress; + } else if (json['state'] == ExercisePlanDetailState.skipped.toStr()) { + this.state = ExercisePlanDetailState.skipped; + } else { + this.state = ExercisePlanDetailState.start; + } + this.isTest = json['isTest'] == "true" ? true : false; + + this.exerciseType = Cache().getExerciseTypeById(exerciseTypeId!); + + this.baseOneRepMax = json['baseOneRepMax'] == null ? 0 : json['baseOneRepMax']; + } + + ExerciseType? getExerciseType() => exerciseType; + + Map toJson() => { + "customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId, + "exerciseTypeId": this.exerciseTypeId, + "set": this.set, + "repeats": this.repeats, + "weight": this.weight, + "restingTime": this.restingTime, + "parallel": this.parallel, + "day": this.day == null ? '1.' : this.day, + }; + + Map toJsonWithExercises() { + final Map jsonMap = { + "customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId, + "trainingPlanDetailsId": this.trainingPlanDetailsId, + "exerciseTypeId": this.exerciseTypeId, + "set": this.set, + "repeats": this.repeats, + "weight": this.weight, + "restingTime": this.restingTime, + "parallel": this.parallel, + 'exercises': exercises.isEmpty ? [].toString() : exercises.map((exercise) => exercise.toJson()).toList().toString(), + 'state': this.state.toStr(), + "isTest": this.isTest, + "dayId": this.dayId, + "baseOneRepMax": this.baseOneRepMax, + }; + + //print("Detail toJson $jsonMap"); + return jsonMap; + } + + @override + String toString() => this.toJsonWithExercises().toString(); + + void copy(CustomerTrainingPlanDetails from) { + this.customerTrainingPlanDetailsId = from.customerTrainingPlanDetailsId; + this.trainingPlanDetailsId = from.trainingPlanDetailsId; + this.exerciseTypeId = from.exerciseTypeId; + this.exerciseType = from.exerciseType; + this.set = from.set; + this.repeats = from.repeats; + this.weight = from.weight; + this.restingTime = from.restingTime; + this.parallel = from.parallel; + this.exercises = from.exercises; + this.state = from.state; + this.isTest = from.isTest; + this.day = from.day; + this.dayId = from.dayId; + this.baseOneRepMax = from.baseOneRepMax; + if (from.exercises.length == 0) { + this.exercises = []; + } + if (from.alternatives.length > 0) { + from.alternatives.forEach((alternative) { + this.alternatives.add(alternative); + }); + } + } +} diff --git a/lib/model/customer_training_plan_exercise.dart b/lib/model/customer_training_plan_exercise.dart new file mode 100644 index 0000000..5c05fb6 --- /dev/null +++ b/lib/model/customer_training_plan_exercise.dart @@ -0,0 +1,30 @@ +class CustomerTrainingPlanExercise { + int? customerTrainingPlanExerciseId; + int? customerTrainingPlanDetailsId; + int? customerId; + int? exerciseId; + double? weight; + int? repeats; + + CustomerTrainingPlanExercise(); + + CustomerTrainingPlanExercise.fromJson(Map json) { + this.customerTrainingPlanExerciseId = json['customerTrainingPlanExerciseId']; + this.customerTrainingPlanDetailsId = json['customerTrainingPlanDetailsId']; + this.customerId = json['customerId']; + this.exerciseId = json['exerciseId']; + this.repeats = json['repeats']; + this.weight = json['weight']; + } + + Map toJson() => { + "customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId, + "customerId": this.customerId, + "exerciseId": this.exerciseId, + "weight": this.weight, + "repeats": this.repeats + }; + + @override + String toString() => this.toJson().toString(); +} diff --git a/lib/model/description.dart b/lib/model/description.dart new file mode 100644 index 0000000..9ec6d36 --- /dev/null +++ b/lib/model/description.dart @@ -0,0 +1,40 @@ +import 'package:workouttest_util/util/app_language.dart'; +import 'dart:ui'; + +class Description { + late int descriptionId; + late String name; + late String description; + int? version; + DateTime? validFrom; + DateTime? validTo; + + String? descriptionTranslation; + + Description.fromJson(Map json) { + this.descriptionId = json['descriptionId']; + this.name = json['name']; + this.description = json['description']; + this.version = json['version']; + this.validFrom = json['validFrom']; + this.validTo = json['validTo']; + + if (json['translations'] != null && json['translations'].length > 0) { + this.descriptionTranslation = + AppLanguage().appLocal == Locale('hu') ? json['translations'][0]['descriptionTranslation'] : json['description']; + } + } + + Map toJson() => { + "descriptionId": this.descriptionId, + "name": this.name, + "description": this.description, + "version": this.version, + "validFrom": this.validFrom, + "validTo": this.validTo, + "descriptionTranslation": this.descriptionTranslation + }; + + @override + String toString() => this.toJson().toString(); +} diff --git a/lib/model/evaluation.dart b/lib/model/evaluation.dart new file mode 100644 index 0000000..ce654be --- /dev/null +++ b/lib/model/evaluation.dart @@ -0,0 +1,28 @@ +import 'package:workouttest_util/model/evaluation_attribute.dart'; + +class Evaluation { + int? evaluationId; + late String name; + int? exerciseTypeId; + String? unit; + late List attributes; + + Evaluation.fromJson(Map json) { + evaluationId = json['evaluationId']; + name = json['name']; + exerciseTypeId = json['exerciseTypeId']; + unit = json['unit']; + this.attributes = json['attributes'].map((attr) => EvaluationAttribute.fromJson(attr)).toList(); + } + + @override + String toString() { + Map json = { + 'evaluationId': this.evaluationId, + 'name': this.name, + 'exerciseTypeId': this.exerciseTypeId, + 'unit': this.unit + }; + return json.toString(); + } +} diff --git a/lib/model/evaluation_attribute.dart b/lib/model/evaluation_attribute.dart new file mode 100644 index 0000000..3d4caff --- /dev/null +++ b/lib/model/evaluation_attribute.dart @@ -0,0 +1,41 @@ +class EvaluationAttribute { + late int evaluationAttrId; + int? evaluationId; + late String name; + late String sex; + late int ageMin; + late int ageMax; + late double valueMin; + late double valueMax; + late String evaluationText; + String? suggestion; + + EvaluationAttribute.fromJson(Map json) { + evaluationAttrId = json['evaluationAttrId']; + evaluationId = json['evaluationId']; + name = json['name']; + sex = json['sex']; + ageMin = json['ageMin']; + ageMax = json['ageMax']; + valueMin = json['valueMin']; + valueMax = json['valueMax']; + evaluationText = json['evaluation_text']; + suggestion = json['suggestion']; + } + + @override + String toString() { + Map json = { + 'evaluationAttrId': this.evaluationAttrId, + 'evaluationId': this.evaluationId, + 'name': this.name, + 'sex': this.sex, + 'ageMin': this.ageMin, + 'ageMax': this.ageMax, + 'valueMin': this.valueMin, + 'valueMax': this.valueMax, + 'evaluation_text': this.evaluationText, + }; + return json.toString(); + } +} diff --git a/lib/model/exercise.dart b/lib/model/exercise.dart new file mode 100644 index 0000000..79ee76e --- /dev/null +++ b/lib/model/exercise.dart @@ -0,0 +1,68 @@ +import 'package:intl/intl.dart'; + +class Exercise { + int? exerciseId; + int? exerciseTypeId; + int? customerId; + double? quantity; + String? unit; + double? unitQuantity; + DateTime? dateAdd; + int? exercisePlanDetailId; + int? trainingPlanDetailsId; + + String? datePart; + double? calculated; + String? summary; + + Exercise({this.exerciseTypeId, this.customerId, this.quantity, this.dateAdd}); + + Exercise.fromJson(Map json) { + this.exerciseId = json['exerciseId']; + this.exerciseTypeId = json['exerciseTypeId']; + this.customerId = json['customerId']; + this.quantity = json['quantity']; + this.unit = json['unit']; + this.unitQuantity = json['unitQuantity']; + this.dateAdd = DateTime.parse(json['dateAdd']); + this.datePart = DateFormat('yyyy-MM-dd').format(this.dateAdd!); + this.calculated = quantity; + this.exercisePlanDetailId = json['exercisePlanDetailId'] == "null" ? null : json['exercisePlanDetailId']; + this.trainingPlanDetailsId = json['trainingPlanDetailsId'] == "null" ? null : json['trainingPlanDetailsId']; + } + + Map toJson() => { + "exerciseTypeId": exerciseTypeId, + "customerId": customerId, + "quantity": quantity, + "unit": unit, + "unitQuantity": unitQuantity, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!), + "exercisePlanDetailId": exercisePlanDetailId, + "trainingPlanDetailsId": trainingPlanDetailsId, + }; + + Map toJsonDatePart() => { + "exerciseTypeId": exerciseTypeId, + "customerId": customerId, + "quantity": quantity, + 'calculated': calculated, + "unit": unit, + "unitQuantity": unitQuantity, + "datePart": this.datePart, + }; + + Exercise copy() { + Exercise newExercise = + Exercise(exerciseTypeId: this.exerciseTypeId, customerId: this.customerId, quantity: this.quantity, dateAdd: this.dateAdd); + newExercise.unit = this.unit; + newExercise.unitQuantity = this.unitQuantity; + newExercise.exercisePlanDetailId = this.exercisePlanDetailId; + return newExercise; + } + + @override + String toString() { + return this.toJson().toString(); + } +} diff --git a/lib/model/exercise_ability.dart b/lib/model/exercise_ability.dart new file mode 100644 index 0000000..a73d32b --- /dev/null +++ b/lib/model/exercise_ability.dart @@ -0,0 +1,25 @@ +enum ExerciseAbility { oneRepMax, endurance, running, mini_test_set, paralell_test, training, training_execute, none } + +extension ExerciseAbilityExt on ExerciseAbility { + String enumToString() => this.toString().split(".").last; + bool equalsTo(ExerciseAbility ability) => this.toString() == ability.toString(); + bool equalsStringTo(String ability) => this.enumToString() == ability; + String get description { + switch (this) { + case ExerciseAbility.endurance: + return "Endurance"; + case ExerciseAbility.oneRepMax: + return "One Rep Max"; + case ExerciseAbility.running: + return "Running"; + case ExerciseAbility.mini_test_set: + return "Compact Test"; + case ExerciseAbility.paralell_test: + return "Custom Test"; + case ExerciseAbility.training: + return "Training"; + default: + return "Compact Test"; + } + } +} diff --git a/lib/model/exercise_device.dart b/lib/model/exercise_device.dart new file mode 100644 index 0000000..68cc5e2 --- /dev/null +++ b/lib/model/exercise_device.dart @@ -0,0 +1,21 @@ +class ExerciseDevice { + late int exerciseDeviceId; + late String name; + late String description; + late String imageUrl; + late String nameTranslation; + late int sort; + late bool place; + + bool? isGym; + + ExerciseDevice.fromJson(Map json) { + this.exerciseDeviceId = json['exerciseDeviceId']; + this.name = json['name']; + this.description = json['description']; + this.imageUrl = json['imageUrl']; + this.nameTranslation = json['translations'][0]['name']; + this.sort = json['sort']; + this.place = json['place'] == 1 ? true : false; + } +} diff --git a/lib/model/exercise_plan.dart b/lib/model/exercise_plan.dart new file mode 100644 index 0000000..1763c18 --- /dev/null +++ b/lib/model/exercise_plan.dart @@ -0,0 +1,70 @@ +import 'package:intl/intl.dart'; + +class ExercisePlan { + int? exercisePlanId; + late int customerId; + late String name; + String? description; + late bool private; + late DateTime? dateAdd; + late DateTime dateUpd; + String? type; + int? exercisePlanTemplateId; + + ExercisePlan(String name, int customerId) { + this.customerId = customerId; + this.name = name; + this.dateUpd = DateTime.now(); + } + + ExercisePlan.fromJson(Map json) { + this.exercisePlanId = json['exercisePlanId']; + this.customerId = json['customerId']; + this.name = json['name']; + this.private = json['private']; + this.description = json['description']; + this.dateAdd = (json['dateAdd'] == null ? null : DateTime.parse(json['dateAdd']))!; + this.dateUpd = (json['dateUpd'] == null ? null : DateTime.parse(json['dateUpd']))!; + this.type = json['type']; + this.exercisePlanTemplateId = json['exercisePlanTemplateId']; + } + + Map toJson() { + String? formattedDateAdd; + if (dateAdd != null) { + formattedDateAdd = DateFormat('yyyy-MM-dd HH:mm').format(dateAdd!); + } + String formattedDateUpd = DateFormat('yyyy-MM-dd HH:mm').format(dateUpd); + + if (exercisePlanId == null) { + return { + "customerId": customerId, + "name": name, + "description": description, + "private": private, + "dateAdd": formattedDateAdd, + "dateUpd": formattedDateUpd, + "type": type, + "exercisePlanTemplateId": exercisePlanTemplateId + }; + } else { + return { + "exercisePlanId": exercisePlanId, + "customerId": customerId, + "name": name, + "description": description, + "private": private, + "dateAdd": formattedDateAdd, + "dateUpd": formattedDateUpd, + "type": type, + "exercisePlanTemplateId": exercisePlanTemplateId + }; + } + } + + @override + String toString() { + Map json = toJson(); + return json.toString(); + } +} diff --git a/lib/model/exercise_plan_detail.dart b/lib/model/exercise_plan_detail.dart new file mode 100644 index 0000000..e4275a4 --- /dev/null +++ b/lib/model/exercise_plan_detail.dart @@ -0,0 +1,91 @@ +import 'dart:convert'; + +import 'package:workouttest_util/model/exercise.dart'; +import 'package:workouttest_util/model/exercise_type.dart'; + +enum ExercisePlanDetailState { start, inProgress, skipped, finished, extra } + +extension ExericisePlanDetailStateExt on ExercisePlanDetailState { + bool equalsTo(ExercisePlanDetailState state) => this.toString() == state.toString(); + bool equalsStringTo(String state) => this.toString() == state; + String toStr() => this.toString().split(".").last; +} + +class ExercisePlanDetail { + int? exercisePlanDetailId; + int? exercisePlanId; + late int exerciseTypeId; + int? serie; + int? repeats; + String? weightEquation; + + /// List + List? exercises; + + /// bool finished + bool? finished; + ExercisePlanDetailState state = ExercisePlanDetailState.start; + + ExerciseType? exerciseType; + + String? change; // 1: update -1:delete 0: new + + ExercisePlanDetail(int exerciseTypeId) { + this.exerciseTypeId = exerciseTypeId; + } + + ExercisePlanDetail.fromJson(Map json) { + this.exercisePlanDetailId = json['exercisePlanDetailId']; + this.exercisePlanId = json['exercisePlanId']; + this.exerciseTypeId = json['exerciseTypeId']; + this.serie = json['serie']; + this.repeats = json['repeats']; + this.weightEquation = json['weightEquation']; + } + + ExercisePlanDetail.fromJsonWithExerciseList(Map json) { + this.exercisePlanDetailId = json['exercisePlanDetailId']; + this.exercisePlanId = json['exercisePlanId']; + this.exerciseTypeId = json['exerciseTypeId']; + this.serie = json['serie']; + this.repeats = json['repeats']; + this.weightEquation = json['weightEquation']; + try { + final String exercises = json['exercises']; + String jsonExercises = exercises.replaceAllMapped( + RegExp(r'([a-zA-Z]+|[0-9]{4}\-[0-9]{2}\-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})'), (Match m) => "\"${m[0]}\""); + + jsonExercises = jsonExercises.replaceAll(r'\"null\"', 'null'); + + //print("Exercises $jsonExercises"); + Iterable iterable = jsonDecode(jsonExercises); + this.exercises = iterable.map((exercise) => Exercise.fromJson(exercise)).toList(); + } on Exception catch (e) { + print("JsonDecode error " + e.toString()); + } + } + + Map toJson() => { + "exercisePlanId": exercisePlanId == null ? 0 : exercisePlanId, + "exerciseTypeId": exerciseTypeId, + "serie": serie, + "repeats": repeats, + "weightEquation": weightEquation + }; + + Map toJsonWithExerciseList() => { + "exercisePlanDetailId": exercisePlanDetailId, + "exercisePlanId": exercisePlanId, + "exerciseTypeId": exerciseTypeId, + "serie": serie, + "repeats": repeats, + "weightEquation": weightEquation, + 'exercises': exercises == null ? [].toString() : exercises!.map((exercise) => exercise.toJson()).toList().toString(), + }; + + @override + String toString() { + Map json = toJsonWithExerciseList(); + return json.toString(); + } +} diff --git a/lib/model/exercise_plan_template.dart b/lib/model/exercise_plan_template.dart new file mode 100644 index 0000000..dc1d710 --- /dev/null +++ b/lib/model/exercise_plan_template.dart @@ -0,0 +1,50 @@ +import 'dart:ui'; + +import 'package:workouttest_util/util/app_language.dart'; + +class ExercisePlanTemplate { + late int? exercisePlanTemplateId; + late String name; + late String description; + late String templateType; + late String nameTranslation; + late String descriptionTranslation; + List exerciseTypes = []; + + ExercisePlanTemplate.fromJson(Map json) { + this.exercisePlanTemplateId = json['exercisePlanId']; + this.name = json['name']; + this.description = json['description']; + this.templateType = json['templateType']; + if (json['translations'].length > 0) { + this.nameTranslation = AppLanguage().appLocal == Locale('hu') ? json['translations'][0]['name'] : json['name']; + this.descriptionTranslation = AppLanguage().appLocal == Locale('hu') ? json['translations'][0]['description'] : json['description']; + } + + if (json['details'] != null && (json['details']).length > 0) { + final List details = json['details']; + details.sort((a, b) { + if (a['sort'] == null || b['sort'] == null) { + return a['exercisePlanTemplateDetailId'] < b['exercisePlanTemplateDetailId'] ? -1 : 1; + } else { + return a['sort'] < b['sort'] ? -1 : 1; + } + }); + details.forEach((element) { + exerciseTypes.add(element['exerciseTypeId']); + }); + } + } + + Map toJson() { + return { + "exercisePlanTemplateId": exercisePlanTemplateId, + "name": name, + "description": "description", + "templateType": templateType, + "nameTranslation": nameTranslation, + "descriptionTranslation": descriptionTranslation, + "exerciseTypes": exerciseTypes.toString() + }; + } +} diff --git a/lib/model/exercise_result.dart b/lib/model/exercise_result.dart new file mode 100644 index 0000000..3924103 --- /dev/null +++ b/lib/model/exercise_result.dart @@ -0,0 +1,46 @@ +import 'package:workouttest_util/model/result.dart'; +import 'package:intl/intl.dart'; + +class ExerciseResult { + late int? exerciseResultId; + late int customerId; + late int exerciseId; + late int exercisePlanId; + late String resultType; + late double value; + late DateTime dateFrom; + late DateTime? dateTo; + + ResultExt? resultExtension; + + ExerciseResult(); + + Map toJson() { + String? formattedDateTo; + if (dateTo != null) { + formattedDateTo = DateFormat('yyyy-MM-dd HH:mm').format(dateTo!); + } + + return { + "customerId": customerId, + "exerciseId": exerciseId, + "exercisePlanId": exercisePlanId, + "resultType": resultType, + "value": value, + "dateFrom": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateFrom), + "dateTo": formattedDateTo, + }; + } + + ExerciseResult.fromJson(Map json) { + this.exerciseResultId = json['exerciseResultId']; + this.exerciseId = json['exerciseId']; + this.exercisePlanId = json['exercisePlanId']; + this.customerId = json['customerId']; + this.resultType = json['resultType']; + this.value = json["value"]; + this.dateFrom = DateTime.parse(json['dateFrom']); + this.dateTo = DateTime.parse(json['dateTo']); + this.resultExtension = ResultExt(itemString: this.resultType); + } +} diff --git a/lib/model/exercise_tree.dart b/lib/model/exercise_tree.dart new file mode 100644 index 0000000..b2ad6b0 --- /dev/null +++ b/lib/model/exercise_tree.dart @@ -0,0 +1,76 @@ +class ExerciseTree { + /// treeId + late int treeId; + + /// parentId + late int parentId; + + /// name + late String name; + + /// imageUrl + late String imageUrl; + + /// active + late bool active; + + /// nameTranslation + late String nameTranslation; + + /// sort + int? sort; + + String? internalName; + + String? description; + String? descriptionTranslation; + + ExerciseTree(); + + ExerciseTree.fromJson(Map json) { + this.treeId = json['treeId']; + this.name = json['name']; + this.parentId = 0; + this.imageUrl = json['imageUrl']; + this.active = json['active']; + this.nameTranslation = json['translations'] != null && (json['translations']).length > 0 ? json['translations'][0]['name'] : this.name; + this.descriptionTranslation = + json['translations'] != null && (json['translations']).length > 0 && json['translations'][0]['description'] != null + ? json['translations'][0]['description'] + : this.description; + this.sort = 99; + this.internalName = json['internalName']; + } + + Map toJson() { + return { + "treeId": treeId, + "parentId": parentId, + "name": name, + "description": description, + "imageUrl": imageUrl, + "active": active.toString(), + "nameTranslation": nameTranslation, + "descriptionTranslation": descriptionTranslation, + "sort": sort, + }; + } + + @override + String toString() => this.toJson().toString(); + + ExerciseTree copy(int parentId) { + ExerciseTree newTree = ExerciseTree(); + newTree.treeId = this.treeId; + newTree.name = this.name; + newTree.imageUrl = this.imageUrl; + newTree.nameTranslation = this.nameTranslation; + if (parentId != -1) { + newTree.parentId = parentId; + } + newTree.active = this.active; + newTree.sort = this.sort == null ? 99 : this.sort; + + return newTree; + } +} diff --git a/lib/model/exercise_tree_parents.dart b/lib/model/exercise_tree_parents.dart new file mode 100644 index 0000000..829e894 --- /dev/null +++ b/lib/model/exercise_tree_parents.dart @@ -0,0 +1,13 @@ +class ExerciseTreeParents { + late int exerciseTreeParentsId; + late int exerciseTreeParentId; + late int exerciseTreeChildId; + late int sort; + + ExerciseTreeParents.fromJson(Map json) { + this.exerciseTreeParentsId = json['exerciseTreeParentsId']; + this.exerciseTreeParentId = json['exerciseTreeParentId']; + this.exerciseTreeChildId = json['exerciseTreeChildId']; + this.sort = json['sort']; + } +} diff --git a/lib/model/exercise_type.dart b/lib/model/exercise_type.dart new file mode 100644 index 0000000..0a6062c --- /dev/null +++ b/lib/model/exercise_type.dart @@ -0,0 +1,134 @@ +import 'package:workouttest_util/model/exercise_ability.dart'; +import 'package:workouttest_util/util/app_language.dart'; +import 'package:workouttest_util/util/enums.dart'; +import 'package:flutter/material.dart'; + +class ExerciseType { + ///exerciseTypeId + late int exerciseTypeId; + + /// name + late String name; + + /// description + late String description; + + /// unit + late String unit; + + /// unitQuantity + String? unitQuantity; + + /// unitQuantityUnit + String? unitQuantityUnit; + + ///active + late bool active; + + /// base + late bool base; + + late bool buddyWarning; + + /// imageUrl + String imageUrl = ""; + + /// nameTranslation + String nameTranslation = ""; + + /// descriptionTranslation + String descriptionTranslation = ""; + + /// devices[] + List devices = []; + + /// parents[] + List parents = []; + + /// alternatives [] + List alternatives = []; + + /// ability + ExerciseAbility? ability; + + /// TrainingPlanState - whether the exercise_type exists in the + /// custom training plan + ExerciseTypeTrainingPlanState trainingPlanState = ExerciseTypeTrainingPlanState.none; + + ExerciseType({required this.name, required this.description}); + + ExerciseType.fromJson(Map json) { + this.exerciseTypeId = json['exerciseTypeId']; + //this.treeId = json['treeId']; + this.name = json['name']; + this.description = json['description']; + this.unit = json['unit']; + this.unitQuantity = json['unitQuantity']; + this.unitQuantityUnit = json['unitQuantityUnit']; + this.active = json['active']; + this.base = json['base']; + this.buddyWarning = json['buddyWarning']; + if (json['images'].length > 0) { + this.imageUrl = json['images'][0]['url']; + } + if (json['translations'].length > 0) { + this.nameTranslation = AppLanguage().appLocal == Locale('hu') ? json['translations'][0]['name'] : json['name']; + this.descriptionTranslation = AppLanguage().appLocal == Locale('hu') ? json['translations'][0]['description'] : json['description']; + } + + if (json['devices'].length > 0) { + final List jsonDevices = json['devices']; + + jsonDevices.forEach((device) { + this.devices.add(device['exerciseDeviceId']); + }); + } + + if (json['parents'].length > 0) { + final List jsonParents = json['parents']; + + jsonParents.forEach((parent) { + this.parents.add(parent['exerciseTreeId']); + }); + } + + if (json['alternatives'].length > 0) { + final List jsonAlternatives = json['alternatives']; + + jsonAlternatives.forEach((alternative) { + this.alternatives.add(alternative['exerciseTypeChildId']); + }); + } + } + + Map toJson() => { + "name": name, + "description": description, + "unit": unit, + "unitQuantity": unitQuantity, + "unitQuantityUnit": unitQuantityUnit, + "active": active, + "base": base, + "buddyWarning": buddyWarning, + "devices": this.devices.toString(), + "nameTranslation": this.nameTranslation, + "parents": this.parents.toString() + }; + + void setAbility(ExerciseAbility ability) { + this.ability = ability; + } + + ExerciseAbility getAbility() { + return this.ability!; + } + + bool is1RM() { + return this.ability!.equalsTo(ExerciseAbility.oneRepMax); + } + + @override + String toString() { + return this.toJson().toString(); + } +} diff --git a/lib/model/exercise_type_device.dart b/lib/model/exercise_type_device.dart new file mode 100644 index 0000000..c0e8c3b --- /dev/null +++ b/lib/model/exercise_type_device.dart @@ -0,0 +1,11 @@ +class ExerciseTypeDevice { + late int exerciseTypeDeviceId; + late int exerciseDeviceId; + + ExerciseTypeDevice(); + + ExerciseTypeDevice.fromJson(Map json) { + this.exerciseTypeDeviceId = json['exerciseTypeDeviceId']; + this.exerciseDeviceId = json['exerciseDeviceId']; + } +} diff --git a/lib/model/faq.dart b/lib/model/faq.dart new file mode 100644 index 0000000..2f4dd2c --- /dev/null +++ b/lib/model/faq.dart @@ -0,0 +1,37 @@ +import 'dart:collection'; + +class Faq { + late int faqId; + late String name; + late String description; + int? sort; + + HashMap nameTranslations = HashMap(); + HashMap descriptionTranslations = HashMap(); + + Faq.fromJson(Map json) { + this.faqId = json['faqId']; + this.name = json['name']; + this.description = json['description']; + this.sort = json['sort']; + + nameTranslations['en'] = name; + descriptionTranslations['en'] = description; + if (json['translations'] != null && json['translations'].length > 0) { + json['translations'].forEach((translation) { + nameTranslations[translation['languageCode']] = translation['nameTranslation']; + descriptionTranslations[translation['languageCode']] = translation['descriptionTranslation']; + }); + } + } + + Map toJson() => { + "faqId": this.faqId, + "name": this.name, + "description": this.description, + "nameTranslation": this.nameTranslations.toString(), + }; + + @override + String toString() => this.toJson().toString(); +} diff --git a/lib/model/fitness_state.dart b/lib/model/fitness_state.dart new file mode 100644 index 0000000..e24c109 --- /dev/null +++ b/lib/model/fitness_state.dart @@ -0,0 +1,67 @@ +class FitnessState { + late final String value; + late final String stateText; + late final String explanation; + + static String beginner = "beginner"; + static String intermediate = "intermediate"; + static String advanced = "advanced"; + static String professional = "professional"; + + FitnessState({required this.value, required this.stateText, required this.explanation}); + + bool isEqual(FitnessState? state) { + if (state == null) { + return false; + } + return state.value == this.value; + } + + @override + String toString() { + return stateText; + } +} + +class FitnessItem { + static final FitnessItem _singleton = FitnessItem._internal(); + List elements = []; + + factory FitnessItem() { + return _singleton; + } + + FitnessItem._internal() { + elements.add(FitnessState( + value: FitnessState.beginner, stateText: _capitalize(FitnessState.beginner), explanation: "I am " + FitnessState.beginner)); + elements.add(FitnessState( + value: FitnessState.intermediate, + stateText: _capitalize(FitnessState.intermediate), + explanation: "I am " + FitnessState.intermediate)); + elements.add(FitnessState( + value: FitnessState.advanced, stateText: _capitalize(FitnessState.advanced), explanation: "I am " + FitnessState.advanced)); + elements.add(FitnessState( + value: FitnessState.professional, + stateText: _capitalize(FitnessState.professional), + explanation: "I am " + FitnessState.professional)); + } + + String _capitalize(String value) { + return "${value[0].toUpperCase()}${value.substring(1)}"; + } + + List toList() => elements; + + FitnessState? getItem(String? value) { + if (value == null || value.length == 0) { + return elements[0]; + } + FitnessState? selected; + elements.forEach((element) { + if (element.value == value) { + selected = element; + } + }); + return selected; + } +} diff --git a/lib/model/mautic.dart b/lib/model/mautic.dart new file mode 100644 index 0000000..056ed26 --- /dev/null +++ b/lib/model/mautic.dart @@ -0,0 +1,46 @@ +class Mautic { + late int formId; + String? firstname; + String? lastname; + String? email; + String? fitnessLevel; + String? goal; + int? databaseId; + String? subscriptionDate; + String? language; + String? purchaseDate; + String? exerciseDate; + String? trialDate; + + Map toJson() => { + "formId": formId, + "firstname": firstname, + "lastname": lastname, + "email": email, + "fitnessLevel": fitnessLevel, + "goal": goal, + "databaseId": databaseId, + "subscriptionDate": subscriptionDate, + "lang": language + }; + + String toForm() { + String form = "mauticform[formId]=$formId"; + form += email == null ? "" : "&mauticform[email]=$email"; + form += lastname == null ? "" : "&mauticform[f_name]=$lastname"; + form += firstname == null ? "" : "&mauticform[firstname]=$firstname"; + form += fitnessLevel == null ? "" : "&mauticform[fitness_level]=$fitnessLevel"; + form += goal == null ? "" : "&mauticform[goal]=$goal"; + form += subscriptionDate == null ? "" : "&mauticform[subscribed]=$subscriptionDate"; + form += databaseId == null ? "" : "&mauticform[databaseid]=$databaseId"; + form += language == null ? "" : "&mauticform[lang]=$language"; + form += purchaseDate == null ? "" : "&mauticform[purchase_date]=$purchaseDate"; + form += exerciseDate == null ? "" : "&mauticform[last_exercise]=$exerciseDate"; + form += trialDate == null ? "" : "&mauticform[trialdate]=$trialDate"; + + return form; + } + + @override + String toString() => this.toJson().toString(); +} diff --git a/lib/model/model_change.dart b/lib/model/model_change.dart new file mode 100644 index 0000000..deae972 --- /dev/null +++ b/lib/model/model_change.dart @@ -0,0 +1,7 @@ +class ModelChange { + static const String add = "add"; + static const String delete = "delete"; + static const String update = "update"; + static const String deleted = "deleted"; + static const String saved = "saved"; +} diff --git a/lib/model/product.dart b/lib/model/product.dart new file mode 100644 index 0000000..0d3744e --- /dev/null +++ b/lib/model/product.dart @@ -0,0 +1,53 @@ +class Product { + late int productId; + late String name; + late String description; + late String type; + late String appVersion; + late int sort; + late int productSet; + late DateTime validFrom; + late DateTime? validTo; + late String? productIdIos; + late String? productIdAndroid; + late double? priceIos; + late double? priceAndroid; + String? localizedPrice; + + Product.fromJson(Map json) { + this.productId = json['productId']; + this.name = json['name']; + this.description = json['description']; + this.type = json['type']; + this.appVersion = json['appVersion']; + this.sort = json['sort']; + this.productSet = json['productSet']; + this.validFrom = (json['validFrom'] == null ? null : DateTime.parse(json['validFrom']))!; + this.validTo = json['validTo'] == null ? null : DateTime.parse(json['validTo']); + this.productIdIos = json['productIdIos']; + this.productIdAndroid = json['productIdAndroid']; + this.priceIos = json['priceIos']; + this.priceAndroid = json['priceAndroid']; + } + + @override + String toString() { + Map json = { + 'productId': this.productId, + 'name': this.name, + 'description': this.description, + 'type': this.type, + 'appVersion': this.appVersion, + 'sort': this.sort, + 'productSet': this.productSet, + 'validFrom': this.validFrom, + 'validTo': validTo, + 'productIdIos': this.productIdIos, + 'productIdAndroid': this.productIdAndroid, + 'priceIos': this.priceIos, + 'priceAndroid': this.priceAndroid, + 'localizedPrice': this.localizedPrice + }; + return json.toString(); + } +} diff --git a/lib/model/property.dart b/lib/model/property.dart new file mode 100644 index 0000000..cb137bc --- /dev/null +++ b/lib/model/property.dart @@ -0,0 +1,28 @@ +class Property { + late int propertyId; + late String propertyName; + late String propertyUnit; + late String propertyNameTranslation; + int? top; + int? left; + double? value; + + Property.fromJson(Map json) { + this.propertyId = json['propertyId']; + this.propertyName = json['propertyName']; + this.propertyUnit = json['propertyUnit']; + this.propertyNameTranslation = + json['translations'] != null && (json['translations']).length > 0 + ? json['translations'][0]['propertyName'] + : this.propertyName; + } + + String toString() { + Map json = { + "propertyId": propertyId, + "propertyName": propertyName, + "propertyUnit": propertyUnit + }; + return json.toString(); + } +} diff --git a/lib/model/purchase.dart b/lib/model/purchase.dart new file mode 100644 index 0000000..2e436ff --- /dev/null +++ b/lib/model/purchase.dart @@ -0,0 +1,31 @@ +import 'package:intl/intl.dart'; + +class Purchase { + int? purchaseId; + late int customerId; + late int productId; + + late DateTime dateAdd; + late double purchaseSum; + late String currency; + + Purchase({required this.customerId, required this.productId}); + + Purchase.fromJson(Map json) { + this.purchaseId = json['purchaseId']; + this.customerId = json['customerId']; + this.productId = json['productId']; + this.dateAdd = DateTime.parse(json['dateAdd']); + this.purchaseSum = json['purchaseSum']; + this.currency = json['currency']; + } + + Map toJson() => { + "purchaseId": purchaseId, + "customerId": customerId, + "productId": productId, + "purchaseSum": purchaseSum, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd), + "currency": currency, + }; +} diff --git a/lib/model/result.dart b/lib/model/result.dart new file mode 100644 index 0000000..9fabf3c --- /dev/null +++ b/lib/model/result.dart @@ -0,0 +1,101 @@ +enum ResultItem { + calorie, + development_percent_bodypart, + distance, + fatburn_percent, + bpm_avg, + bpm_min, + bpm_max, + speed_max, + reps_volume, + steps, + //time, + weight_volume +} + +extension ResultItemExt on ResultItem { + static const ResultItemDesc = { + ResultItem.calorie: "Calorie", + ResultItem.development_percent_bodypart: "Development in %", + ResultItem.distance: "Distance", + ResultItem.bpm_avg: "Average BPM", + ResultItem.bpm_min: "Min BPM", + ResultItem.bpm_max: "Max BPM", + ResultItem.speed_max: "Max speed", + ResultItem.reps_volume: "Repeats volume", + ResultItem.steps: "Steps", + //ResultItem.time: "Time", + ResultItem.weight_volume: "Weight volume", + ResultItem.fatburn_percent: "Fatburn %", + }; + + static const ResultItemImg = { + ResultItem.calorie: "pict_calorie.png", + ResultItem.development_percent_bodypart: "pic_development_by_bodypart_percent.png", + ResultItem.distance: "pict_distance_m.png", + ResultItem.bpm_avg: "pict_hravg_bpm.png", + ResultItem.bpm_min: "pict_hrmin_bpm.png", + ResultItem.bpm_max: "pict_hrmax_bpm.png", + ResultItem.speed_max: "pict_maxspeed_kmh.png", + ResultItem.reps_volume: "pict_reps_volumen_db.png", + ResultItem.steps: "pict_steps.png", + //ResultItem.time: "pict_time_h.png", + ResultItem.weight_volume: "pict_weight_volumen_tonna.png", + ResultItem.fatburn_percent: "pict_fatburn_percent.png", + }; + + static const HardwareData = { + ResultItem.calorie: true, + ResultItem.development_percent_bodypart: false, + ResultItem.distance: true, + ResultItem.bpm_avg: true, + ResultItem.bpm_min: true, + ResultItem.bpm_max: true, + ResultItem.speed_max: true, + ResultItem.reps_volume: false, + ResultItem.steps: true, + //ResultItem.time: false, + ResultItem.weight_volume: false, + ResultItem.fatburn_percent: true, + }; + + bool equals(ResultItem item) => this.toString() == item.toString(); + bool equalsString(String item) => this.description == item; + + String? get description => ResultItemDesc[this]; + String? get image => ResultItemImg[this]; + bool? get isHardware => HardwareData[this]; + + String? displayString() => description; +} + +class ResultExt { + late final String itemString; + late ResultItem item; + double data = 0; + int? exerciseId; + DateTime? dateFrom; + + DateTime? dateTo; + + ResultExt({required this.itemString}) { + ResultItem.values.forEach((element) { + if (element.equalsString(itemString)) { + item = element; + } + }); + } + + String? getDescription() => item.description; + String getImage() => "asset/image/" + item.image!; + bool? isHardware() => item.isHardware; + int? get getExerciseId => exerciseId; + set setExerciseId(int exerciseId) => this.exerciseId = exerciseId; + set setDateFrom(DateTime dateFrom) => this.dateFrom = dateFrom; + DateTime? get getDateFrom => dateFrom; + set setDateTo(DateTime dateTo) => this.dateTo = dateTo; + DateTime? get getDateTo => dateTo; + + bool equals(ResultItem item) => this.item.equals(item); + bool equalsString(String item) => this.item.equalsString(item); +} diff --git a/lib/model/split_test.dart b/lib/model/split_test.dart new file mode 100644 index 0000000..a2917c1 --- /dev/null +++ b/lib/model/split_test.dart @@ -0,0 +1,36 @@ +class SplitTest { + late int testId; + late String name; + late String remoteConfigKey; + late String remoteConfigValue; + late String testValue; + String? source; + late bool active; + DateTime? validTo; + + SplitTest.fromJson(Map json) { + this.testId = json['testId']; + this.name = json['name']; + this.remoteConfigKey = json['remoteConfigKey']; + this.remoteConfigValue = json['remoteConfigValue']; + this.testValue = json['testValue']; + this.source = json['source']; + this.active = json['active']; + this.validTo = json['validTo'] == null ? null : DateTime.parse(json['validTo']); + } + + @override + String toString() { + Map json = { + 'productId': this.testId, + 'name': this.name, + 'remoteConfigKey': this.remoteConfigKey, + 'remoteConfigValue': this.remoteConfigValue, + 'testValue': this.testValue, + 'source': this.source, + 'active': this.active, + 'validTo': validTo, + }; + return json.toString(); + } +} diff --git a/lib/model/sport.dart b/lib/model/sport.dart new file mode 100644 index 0000000..31a94c7 --- /dev/null +++ b/lib/model/sport.dart @@ -0,0 +1,30 @@ +import 'dart:collection'; + +class Sport { + late int sportId; + late String name; + + HashMap nameTranslations = HashMap(); + + Sport.fromJson(Map json) { + this.sportId = json['sportId']; + this.name = json['name']; + + nameTranslations['en'] = name; + if (json['translations'] != null && json['translations'].length > 0) { + json['translations'].forEach((translation) { + nameTranslations[translation['languageCode']] = translation['sportName']; + }); + } + } + + Map toJson() => { + "sportId": sportId, + "name": name, + }; + + @override + String toString() { + return this.toJson().toString(); + } +} diff --git a/lib/model/tracking.dart b/lib/model/tracking.dart new file mode 100644 index 0000000..e0d2c36 --- /dev/null +++ b/lib/model/tracking.dart @@ -0,0 +1,24 @@ +import 'dart:io'; + +import 'package:workouttest_util/model/cache.dart'; +import 'package:intl/intl.dart'; + +class Tracking { + late int customerId; + late DateTime dateAdd; + late String event; + String? eventValue; + late String area; + late String platform; + late String version; + + Map toJson() => { + "customerId": customerId, + "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd), + "event": event, + "eventValue": eventValue, + "area": Platform.localeName, + "platform": Platform.isAndroid ? "Android" : "iOS", + "version": Cache().packageInfo != null ? Cache().packageInfo!.version + "+" + Cache().packageInfo!.buildNumber : "" + }; +} diff --git a/lib/model/training_evaluation_exercise.dart b/lib/model/training_evaluation_exercise.dart new file mode 100644 index 0000000..72fe743 --- /dev/null +++ b/lib/model/training_evaluation_exercise.dart @@ -0,0 +1,33 @@ +import 'package:workouttest_util/model/exercise_plan_detail.dart'; +import 'package:workouttest_util/model/exercise_type.dart'; +import 'package:flutter/material.dart'; + +enum TrainingEvaluationExerciseType { weightBased, repeatBased, secondBased } + +extension TrainingEvaluationExerciseTypeExt on TrainingEvaluationExerciseType { + String toStr() => this.toString().split(".").last; + bool equalsTo(TrainingEvaluationExerciseType value) => this.toString() == value.toString(); + bool equalsStringTo(String value) => this.toString() == value; +} + +class TrainingEvaluationExercise { + late int exerciseTypeId; + late String name; + late TrainingEvaluationExerciseType type; + late ExerciseType exerciseType; + + int? repeats; + int? maxRepeats; + + double? totalLift; + double? maxTotalLift; + + double? oneRepMax; + double? max1RM; + + late double? trend; + late String trendText; + late Color trendColor; + + late ExercisePlanDetailState state; +} diff --git a/lib/model/training_plan.dart b/lib/model/training_plan.dart new file mode 100644 index 0000000..a0789aa --- /dev/null +++ b/lib/model/training_plan.dart @@ -0,0 +1,74 @@ +import 'dart:collection'; + +import 'package:workouttest_util/model/training_plan_detail.dart'; + +class TrainingPlan { + late int trainingPlanId; + String? type; + late String name; + String? internalName; + String? description; + late bool free; + late bool active; + int? treeId; + + HashMap nameTranslations = HashMap(); + HashMap descriptionTranslations = HashMap(); + + List? details; + + TrainingPlan.fromJson(Map json) { + this.trainingPlanId = json['trainingPlanId']; + this.name = json['name']; + this.type = json['type']; + this.internalName = json['internalName']; + this.description = json['description']; + this.free = json['free']; + this.active = json['active']; + this.treeId = json['treeId']; + + nameTranslations['en'] = name; + descriptionTranslations['en'] = description ?? ""; + if (json['translations'] != null && json['translations'].length > 0) { + json['translations'].forEach((translation) { + nameTranslations[translation['languageCode']] = translation['nameTranslation']; + descriptionTranslations[translation['languageCode']] = translation['descriptionTranslation']; + }); + } + + if (json['details'] != null && json['details'].length > 0) { + details = json['details'].map((detail) => TrainingPlanDetail.fromJson(detail)).toList(); + if (details != null && details!.isNotEmpty) { + details!.sort((a, b) { + if (a.sort == 0 || b.sort == 0) { + if (a.trainingPlanDetailId <= b.trainingPlanDetailId) { + return -1; + } else { + return 1; + } + } + if (a.sort <= b.sort) { + return -1; + } else { + return 1; + } + }); + } + } + } + + Map toJson() => { + "trainingPlanId": this.trainingPlanId, + "treeId": this.treeId, + "name": this.name, + "type": this.type, + "internalName": this.internalName, + "free": this.free, + "active": this.active, + "description": this.description, + "nameTranslation": this.nameTranslations.toString(), + }; + + @override + String toString() => this.toJson().toString(); +} diff --git a/lib/model/training_plan_day.dart b/lib/model/training_plan_day.dart new file mode 100644 index 0000000..8286eb7 --- /dev/null +++ b/lib/model/training_plan_day.dart @@ -0,0 +1,29 @@ +import 'dart:collection'; + +class TrainingPlanDay { + late int dayId; + late String name; + + HashMap nameTranslations = HashMap(); + + TrainingPlanDay.fromJson(Map json) { + this.dayId = json['dayId']; + this.name = json['name']; + + nameTranslations['en'] = name; + if (json['translations'] != null && json['translations'].length > 0) { + json['translations'].forEach((translation) { + nameTranslations[translation['languageCode']] = translation['nameTranslation']; + }); + } + } + + Map toJson() => { + "dayId": this.dayId, + "name": this.name, + "nameTranslation": this.nameTranslations.toString(), + }; + + @override + String toString() => this.toJson().toString(); +} diff --git a/lib/model/training_plan_detail.dart b/lib/model/training_plan_detail.dart new file mode 100644 index 0000000..ccac359 --- /dev/null +++ b/lib/model/training_plan_detail.dart @@ -0,0 +1,44 @@ +class TrainingPlanDetail { + late int trainingPlanDetailId; + int? trainingPlanId; + late int exerciseTypeId; + late int sort; + late int set; + int? repeats; + double? weight; + int? restingTime; + bool? parallel; + int? dayId; + String? day; + String? summary; + + TrainingPlanDetail.fromJson(Map json) { + this.trainingPlanDetailId = json['trainingPlanDetailId']; + this.trainingPlanId = json['trainingPlanId']; + this.exerciseTypeId = json['exerciseTypeId']; + this.sort = json['sort']; + this.set = json['set']; + this.repeats = json['repeats']; + this.weight = json['weight']; + this.restingTime = json['restingTime']; + this.parallel = json['parallel']; + this.dayId = json['dayId']; + } + + Map toJson() => { + "trainingPlanDetailId": this.trainingPlanDetailId, + "trainingPlanId": this.trainingPlanId, + "exerciseType": this.exerciseTypeId, + "sort": this.sort, + "repeats": this.repeats, + "weight": this.weight, + "restingTime": this.restingTime, + "parallel": this.parallel, + "dayId": this.dayId, + "day": this.day, + "summary": this.summary, + }; + + @override + String toString() => this.toJson().toString(); +} diff --git a/lib/model/training_result.dart b/lib/model/training_result.dart new file mode 100644 index 0000000..db72392 --- /dev/null +++ b/lib/model/training_result.dart @@ -0,0 +1,29 @@ +import 'package:workouttest_util/model/exercise.dart'; +import 'package:flutter/material.dart'; + +class TrainingResult { + final Exercise? exercise; + final String eventName; + final DateTime from; + final DateTime to; + Color background; + Color color; + final bool isAllDay; + final bool isTest; + final bool isExercise; + String? summary; + bool search = false; + + TrainingResult({ + required this.eventName, + required this.from, + required this.to, + required this.background, + required this.color, + required this.isAllDay, + required this.exercise, + required this.isTest, + required this.isExercise, + this.summary, + }); +} diff --git a/lib/model/tutorial.dart b/lib/model/tutorial.dart new file mode 100644 index 0000000..15cd9aa --- /dev/null +++ b/lib/model/tutorial.dart @@ -0,0 +1,37 @@ +import 'package:workouttest_util/model/tutorial_step.dart'; + +enum TutorialEnum { basic, development, training } + +class Tutorial { + late int tutorialId; + late String name; + + List? steps; + + Tutorial.fromJson(Map json) { + this.tutorialId = json['tutorialId']; + this.name = json['name']; + + if (json['steps'] != null && json['steps'].length > 0) { + steps = json['steps'].map((step) => TutorialStep.fromJson(step)).toList(); + if (steps != null) { + steps!.sort((a, b) { + if (a.step == null || b.step == null) { + return -1; + } else { + if (a.step! <= b.step!) { + return -1; + } else { + return 1; + } + } + }); + } + } + } + + Map toJson() => {'tutorialId': this.tutorialId, 'name': this.name, 'steps': steps.toString()}; + + @override + String toString() => this.toJson().toString(); +} diff --git a/lib/model/tutorial_step.dart b/lib/model/tutorial_step.dart new file mode 100644 index 0000000..d999b44 --- /dev/null +++ b/lib/model/tutorial_step.dart @@ -0,0 +1,98 @@ +import 'dart:ui'; +import 'dart:convert'; + +import 'package:workouttest_util/util/app_language.dart'; + +enum TutorialEnum { basic, development, training } + +class TutorialStepAction { + late String direction; + late int top; + late int left; + late bool showBubble; + late int bubbleX; + late int bubbleY; + late int bubbleWidth; + late int bubbleHeight; + late bool showCheckText; + late int parent; + + TutorialStepAction.fromJson(Map json) { + this.direction = json['direction']; + this.top = json['top']; + this.left = json['left']; + this.showBubble = json['show_bubble']; + this.bubbleX = json['bubble_x']; + this.bubbleY = json['bubble_y']; + this.bubbleWidth = json['bubble_width']; + this.bubbleHeight = json['bubble_height']; + this.showCheckText = json['show_check_text']; + this.parent = json['parent']; + } + + Map toJson() => { + "direction": this.direction, + "top": this.top, + "left": this.left, + "showBubble": this.showBubble, + "bubbleX": this.bubbleX, + "bubbleY": this.bubbleY, + "bubbleWidth": this.bubbleWidth, + "bubbleHeight": this.bubbleHeight, + "showCheckText": this.showCheckText, + "parent": this.parent, + }; + + @override + String toString() => this.toJson().toString(); +} + +class TutorialStep { + int? tutorialStepId; + int? tutorialId; + int? step; + String? tutorialText; + String? direction; + String? checkText; + String? condition; + String? branch; + int? parentId; + TutorialStepAction? action; + + String? tutorialTextTranslation; + String? errorTextTranslation; + + TutorialStep.fromJson(Map json) { + this.tutorialStepId = json['tutorialStepId']; + this.tutorialId = json['tutorialId']; + this.step = json['step']; + this.tutorialText = json['tutorialText']; + this.checkText = json['checkText']; + this.condition = json['condition']; + if (this.condition != null) { + this.condition = condition!.replaceAll(r'\\', "replace"); + this.action = TutorialStepAction.fromJson(jsonDecode(condition!)); + } + + if (json['translations'] != null && json['translations'].length > 0) { + this.tutorialTextTranslation = + AppLanguage().appLocal == Locale('hu') ? json['translations'][0]['tutorialText'] : json['tutorialText']; + this.errorTextTranslation = AppLanguage().appLocal == Locale('hu') ? json['translations'][0]['errorText'] : json['errorText']; + } + } + + Map toJson() => { + "tutorialStepId": this.tutorialStepId, + "tutorialId": this.tutorialId, + "step": this.step, + "tutorialText": this.tutorialText, + "checkText": this.checkText, + "tutorialTextTranslation": this.tutorialTextTranslation, + "errorTextTranslation": this.errorTextTranslation, + "condition": this.condition, + "action": this.action != null ? this.action!.toJson() : "" + }; + + @override + String toString() => this.toJson().toString(); +} diff --git a/lib/model/user.dart b/lib/model/user.dart new file mode 100644 index 0000000..2b4dedd --- /dev/null +++ b/lib/model/user.dart @@ -0,0 +1,14 @@ +class User { + String? email; + String? password; + int? customerId; + String? firebaseUid; + + User(); + + Map toJson() => { + "username": email, + "password": password, + "firebaseUid": firebaseUid, + }; +} diff --git a/lib/model/workout_menu_tree.dart b/lib/model/workout_menu_tree.dart new file mode 100644 index 0000000..cd1943c --- /dev/null +++ b/lib/model/workout_menu_tree.dart @@ -0,0 +1,86 @@ +import 'dart:ui'; + +import 'exercise_type.dart'; + +enum WorkoutType { endurance, oneRepMax, cardio, staticExercise } + +extension WorkoutTypeExt on WorkoutType { + static const WorkoutTypeMenu = { + WorkoutType.endurance: "Endurance", + WorkoutType.cardio: "Cardio", + WorkoutType.oneRepMax: "One Rep Max", + WorkoutType.staticExercise: "Static" + }; + + bool equals(WorkoutType type) => this.toString() == type.toString(); + bool equalsString(String type) => this.toString() == type; + + String? get menu => WorkoutTypeMenu[this]; +} + +class WorkoutMenuTree { + late int id; + late int parent; + late String name; + late String imageName; + late Color color; + late double fontSize; + late bool child; + late int exerciseTypeId; + ExerciseType? exerciseType; + late bool base; + + late bool is1RM; + late bool isRunning; + List workoutTypes = []; + bool selected = false; + bool executed = false; + late String exerciseDetail; + late String nameEnglish; + late String parentName; + late String parentNameEnglish; + late int sort; + late String internalName; + + WorkoutMenuTree( + this.id, + this.parent, + this.name, + this.imageName, + this.color, + this.fontSize, + this.child, + this.exerciseTypeId, + this.exerciseType, + this.base, + this.is1RM, + this.isRunning, + this.nameEnglish, + this.parentName, + this.parentNameEnglish, + this.sort, + this.internalName); + + Map toJson() { + return { + "id": id, + "parent": parent, + "name": name, + "imageName": imageName, + "color": color.toString(), + "fontSize": fontSize.toString(), + "child": child.toString(), + "exerciseTypeId": exerciseTypeId.toString(), + "base": base.toString(), + "is1RM": is1RM.toString(), + "isRunning": isRunning.toString(), + "sort": sort, + "internalName": internalName, + }; + } + + @override + String toString() { + return this.toJson().toString(); + } +} diff --git a/lib/repository/customer_exercise_device_repository.dart b/lib/repository/customer_exercise_device_repository.dart new file mode 100644 index 0000000..2f43554 --- /dev/null +++ b/lib/repository/customer_exercise_device_repository.dart @@ -0,0 +1,74 @@ +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/customer_exercise_device.dart'; +import 'package:workouttest_util/model/exercise_device.dart'; +import 'package:workouttest_util/model/model_change.dart'; +import 'package:workouttest_util/service/customer_exercise_device_service.dart'; + +class CustomerExerciseDeviceRepository { + List _devices = []; + + List getDevices() => this._devices; + + void setDevices(List devices) => this._devices = devices; + + Future?> getDBDevices() async { + if (Cache().userLoggedIn != null) { + final int customerId = Cache().userLoggedIn!.customerId!; + this._devices = await CustomerExerciseDeviceApi().getDevices(customerId); + } + return this._devices; + } + + Future addDevice(ExerciseDevice device) async { + CustomerExerciseDevice? found; + + this._devices.forEach((element) { + if (element.exerciseDeviceId == device.exerciseDeviceId) { + found = element; + } + }); + + if (found == null) { + int? customerId; + if (Cache().userLoggedIn != null) { + customerId = Cache().userLoggedIn!.customerId!; + } + CustomerExerciseDevice newDevice = + CustomerExerciseDevice(customerId: customerId!, exerciseDeviceId: device.exerciseDeviceId, favourite: false); + newDevice.change = ModelChange.add; + CustomerExerciseDevice saved = await CustomerExerciseDeviceApi().addDevice(newDevice); + this._devices.add(saved); + Cache().setCustomerDevices(_devices); + } + } + + Future removeDevice(ExerciseDevice device) async { + CustomerExerciseDevice? found; + + this._devices.forEach((element) { + if (element.exerciseDeviceId == device.exerciseDeviceId) { + found = element; + } + }); + + if (found != null) { + this._devices.remove(found); + //if (found.change != ModelChange.add) { + await CustomerExerciseDeviceApi().removeDevice(found!.customerExerciseDeviceId!); + //} + Cache().setCustomerDevices(_devices); + } + } + + bool hasDevice(int exerciseDeviceId) { + bool found = false; + + this._devices.forEach((element) { + if (element.exerciseDeviceId == exerciseDeviceId) { + found = true; + } + }); + + return found; + } +} diff --git a/lib/repository/customer_repository.dart b/lib/repository/customer_repository.dart new file mode 100644 index 0000000..cf8a0be --- /dev/null +++ b/lib/repository/customer_repository.dart @@ -0,0 +1,573 @@ +import 'dart:collection'; + +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/customer.dart'; +import 'package:workouttest_util/model/customer_property.dart'; +import 'package:workouttest_util/model/property.dart'; +import 'package:workouttest_util/model/purchase.dart'; +import 'package:workouttest_util/model/sport.dart'; +import 'package:workouttest_util/repository/property_repository.dart'; +import 'package:workouttest_util/service/customer_service.dart'; +import 'package:workouttest_util/util/logging.dart'; +import 'package:workouttest_util/service/purchase_service.dart'; +import 'package:workouttest_util/util/enums.dart'; + +class GenderItem { + GenderItem(this.dbValue, this.name); + final String dbValue; + String name; +} + +class CustomerRepository with Logging { + Customer? customer; + Customer? _trainee; + List? _trainees; + List? _properties; + //List? _allCustomerProperties; + final PropertyRepository propertyRepository = PropertyRepository(); + final List womanSizes = []; + final List manSizes = []; + + final double baseWidth = 312; + final double baseHeight = 675.2; + double mediaWidth = 0; + double mediaHeight = 0; + bool isMan = true; + + //List customerList = List(); + bool visibleDetails = false; + late List genders; + + CustomerRepository() { + customer = Customer(); + + if (Cache().userLoggedIn != null) { + isMan = (Cache().userLoggedIn!.sex == "m"); + } + + //_allCustomerProperties = Cache().getCustomerPropertyAll(); + } + + String? getGenderByName(String name) { + String? dbValue; + genders.forEach((element) { + if (element.name == name) { + dbValue = element.dbValue; + } + }); + return dbValue; + } + + String? getGenderByDBValue(String dbValue) { + String? name; + genders.forEach((element) { + if (element.dbValue == dbValue) { + name = element.name; + } + }); + return name; + } + + String? get name { + return this.customer != null && this.customer!.name != null ? this.customer!.name : ""; + } + + String? get firstName { + return this.customer != null && this.customer!.firstname != null ? this.customer!.firstname : ""; + } + + String get sex { + if (this.customer == null) throw Exception("Initialize the customer object"); + return this.customer!.sex == "m" ? "Man" : "Woman"; + } + + int? get birthYear { + if (this.customer == null) throw Exception("Initialize the customer object"); + return this.customer!.birthYear; + } + + String? get goal { + if (this.customer == null) throw Exception("Initialize the customer object"); + return this.customer!.goal; + } + + String? getSportString() { + if (this.customer == null) throw Exception("Initialize the customer object"); + String? sport; + List? sports = Cache().getSports(); + if (sports != null) { + for (Sport sportObject in sports) { + if (sportObject.sportId == this.customer!.sportId) { + sport = sportObject.name; + break; + } + } + } + return sport; + } + + Sport? getSport() { + if (this.customer == null) throw Exception("Initialize the customer object"); + Sport? sport; + List? sports = Cache().getSports(); + if (sports != null) { + for (Sport sportObject in sports) { + if (sportObject.sportId == this.customer!.sportId) { + sport = sportObject; + break; + } + } + } + return sport; + } + + String? get fitnessLevel { + if (this.customer == null) throw Exception("Initialize the customer object"); + return this.customer!.fitnessLevel; + } + + String? get bodyType { + if (this.customer == null) throw Exception("Initialize the customer object"); + return this.customer!.bodyType; + } + + setName(String name) { + if (this.customer == null) throw Exception("Initialize the customer object"); + this.customer!.name = name; + } + + setFirstName(String firstName) { + if (this.customer == null) throw Exception("Initialize the customer object"); + this.customer!.firstname = firstName; + } + + setPassword(String password) { + if (this.customer == null) throw Exception("Initialize the customer object"); + this.customer!.password = password; + } + + setEmail(String email) { + if (this.customer == null) throw Exception("Initialize the customer object"); + this.customer!.email = email; + } + + setSex(String sex) { + if (this.customer == null) throw Exception("Initialize the customer object"); + this.customer!.sex = sex; + } + + setWeight(double weight) { + final propertyName = "Weight"; + this.setCustomerProperty(propertyName, weight); + } + + setHeight(int height) { + final propertyName = "Height"; + this.setCustomerProperty(propertyName, height.toDouble()); + } + + setCustomerProperty(String propertyName, double value, {id = 0}) { + if (this.customer == null) { + throw Exception("Initialize the customer object"); + } + if (this.customer!.properties[propertyName] == null) { + this.customer!.properties[propertyName] = CustomerProperty( + propertyId: propertyRepository.getPropertyByName("Height")!.propertyId, + customerId: this.customer!.customerId == null ? 0 : this.customer!.customerId!, + propertyValue: value, + dateAdd: DateTime.now()); + } else { + this.customer!.properties[propertyName]!.propertyValue = value; + } + this.customer!.properties[propertyName]!.dateAdd = DateTime.now(); + this.customer!.properties[propertyName]!.newData = true; + if (id > 0) { + this.customer!.properties[propertyName]!.customerPropertyId = id; + } + Cache().addCustomerProperty(this.customer!.properties[propertyName]!); + } + + double getWeight() { + return getCustomerPropertyValue("Weight"); + } + + double getHeight() { + return getCustomerPropertyValue("Height"); + } + + double getCustomerPropertyValue(String propertyName) { + if (this.customer == null || this.customer!.properties[propertyName] == null) { + return 0.0; + } else { + return this.customer!.properties[propertyName]!.propertyValue; + } + } + + CustomerProperty? getCustomerProperty(String propertyName) { + if (this.customer == null) throw Exception("Initialize the customer object"); + return this.customer!.properties[propertyName]; + } + + setBirthYear(int birthYear) { + if (this.customer == null) throw Exception("Initialize the customer object"); + this.customer!.birthYear = birthYear; + } + + setFitnessLevel(String level) { + if (this.customer == null) throw Exception("Initialize the customer object"); + this.customer!.fitnessLevel = level; + } + + setGoal(String goal) { + if (this.customer == null) throw Exception("Initialize the customer object"); + this.customer!.goal = goal; + } + + setSportString(String selectedSport) { + if (this.customer == null) throw Exception("Initialize the customer object"); + List? sports = Cache().getSports(); + if (sports != null) { + for (Sport sportObject in sports) { + if (sportObject.name == selectedSport) { + this.customer!.sportId = sportObject.sportId; + break; + } + } + } + } + + setBodyType(String bodyType) { + if (this.customer == null) throw Exception("Initialize the customer object"); + this.customer!.bodyType = bodyType; + } + + createNew() { + this.customer = Customer(); + } + + Customer getCustomer() { + if (this.customer == null) throw Exception("Initialize the customer object"); + return this.customer!; + } + + void setCustomer(Customer customer) { + this.customer = customer; + } + + Future addCustomer() async { + if (this.customer == null) throw Exception("Initialize the customer object"); + final Customer modelCustomer = customer!; + await CustomerApi().addCustomer(modelCustomer); + } + + Future saveCustomer() async { + if (this.customer == null) throw Exception("Initialize the customer object"); + final Customer modelCustomer = customer!; + if (modelCustomer.sex == null) { + modelCustomer.sex = "m"; + } + if (modelCustomer.fitnessLevel == null) { + modelCustomer.fitnessLevel = "beginner"; + } + await CustomerApi().saveCustomer(modelCustomer); + await this.saveProperties(modelCustomer.properties); + } + + Future saveProperties(LinkedHashMap properties) async { + properties.forEach((propertyName, property) async { + if (property.newData == true) { + await CustomerApi().addProperty(property); + property.newData = false; + } + }); + } + + Future savePropertyByName(String name) async { + await Future.forEach(this._properties!, (element) async { + final CustomerProperty customerProperty = element as CustomerProperty; + final Property? property = propertyRepository.getPropertyByName(name); + if (property != null) { + if (property.propertyId == customerProperty.propertyId) { + await CustomerApi().updateProperty(customerProperty); + } + } + }); + } + + Future getTraineeAsCustomer() async { + this._trainee = await CustomerApi().getTrainee(Cache().userLoggedIn!.customerId!); + return _trainee; + } + + Future?> getTrainees() async { + int trainerId = Cache().userLoggedIn!.customerId!; + final results = await CustomerApi().getTrainees(trainerId); + this._trainees = results; + return results; + } + + Future> getAllCustomerProperties() async { + int customerId = Cache().userLoggedIn!.customerId!; + final results = await CustomerApi().getAllProperties(customerId); + this._properties = results; + return results; + } + + List? getAllProperties() { + return this._properties; + } + + List? getTraineesList() { + return _trainees; + } + + void setTrainee(int traineeId) { + if (_trainees == null) { + return; + } + _trainees!.forEach((element) { + if (traineeId == element.customerId) { + this._trainee = element; + } + }); + } + + void emptyTrainees() { + _trainees = null; + _trainee = null; + } + + Customer? getTrainee() { + return this._trainee; + } + + Customer? getTraineeById(int customerId) { + if (_trainees == null) { + return null; + } + _trainees!.forEach((element) { + if (customerId == element.customerId) { + this._trainee = element; + } + }); + return _trainee; + } + + Future> getPurchase() async { + int customerId = Cache().userLoggedIn!.customerId!; + List purchases = await PurchaseApi().getPurchasesByCustomer(customerId); + return purchases; + } + + Future addPurchase(Purchase purchase) async { + await PurchaseApi().savePurchase(purchase); + } + + void setMediaDimensions(double width, double height) { + this.mediaHeight = height; + this.mediaWidth = width; + this.addSizes(this.sex); + } + + void addSizes(String sex) { + if (this.customer == null) throw Exception("Initialize the customer object"); + List? properties = Cache().getProperties(); + if (properties == null) { + return; + } + final double distortionWidth = mediaWidth / baseWidth; + final double distortionHeight = mediaHeight / baseHeight; + if (isMan) { + properties.forEach((element) { + if (element.propertyName == "Shoulder") { + element.top = (122 * distortionHeight).toInt(); + element.left = (130 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Shoulder"); + manSizes.add(element); + } else if (element.propertyName == "Neck") { + element.top = (68 * distortionHeight).toInt(); + element.left = (130 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Neck"); + manSizes.add(element); + } else if (element.propertyName == "Biceps") { + element.top = (178 * distortionHeight).toInt(); + element.left = (208 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Biceps"); + manSizes.add(element); + } else if (element.propertyName == "Chest") { + element.top = (154 * distortionHeight).toInt(); + element.left = (130 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Chest"); + manSizes.add(element); + } else if (element.propertyName == "Belly") { + element.top = (244 * distortionHeight).toInt(); + element.left = (130 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Belly"); + manSizes.add(element); + } else if (element.propertyName == "Hip") { + element.top = (308 * distortionHeight).toInt(); + element.left = (130 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Hip"); + manSizes.add(element); + } else if (element.propertyName == "Thigh Top") { + element.top = (332 * distortionHeight).toInt(); + element.left = (165 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Thigh Top"); + manSizes.add(element); + } else if (element.propertyName == "Thigh Middle") { + element.top = (382 * distortionHeight).toInt(); + element.left = (100 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Thigh Middle"); + manSizes.add(element); + } else if (element.propertyName == "Knee") { + element.top = (464 * distortionHeight).toInt(); + element.left = (97 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Knee"); + manSizes.add(element); + } else if (element.propertyName == "Calf") { + element.top = (520 * distortionHeight).toInt(); + element.left = (97 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Calf"); + manSizes.add(element); + } else if (element.propertyName == "Ankle") { + element.top = (620 * distortionHeight).toInt(); + element.left = (150 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Ankle"); + manSizes.add(element); + } else if (element.propertyName == "Weight") { + element.top = (402 * distortionHeight).toInt(); + element.left = (240 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Weight"); + manSizes.add(element); + } + }); + } else { + properties.forEach((element) { + if (element.propertyName == "Shoulder") { + element.top = (122 * distortionHeight).toInt(); + element.left = (151 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Shoulder"); + manSizes.add(element); + } else if (element.propertyName == "Neck") { + element.top = (78 * distortionHeight).toInt(); + element.left = (151 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Neck"); + manSizes.add(element); + } else if (element.propertyName == "Biceps") { + element.top = (178 * distortionHeight).toInt(); + element.left = (212 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Biceps"); + manSizes.add(element); + } else if (element.propertyName == "Chest") { + element.top = (154 * distortionHeight).toInt(); + element.left = (151 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Chest"); + manSizes.add(element); + } else if (element.propertyName == "Belly") { + element.top = (230 * distortionHeight).toInt(); + element.left = (151 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Belly"); + manSizes.add(element); + } else if (element.propertyName == "Hip") { + element.top = (294 * distortionHeight).toInt(); + element.left = (151 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Hip"); + manSizes.add(element); + } else if (element.propertyName == "Thigh Top") { + element.top = (335 * distortionHeight).toInt(); + element.left = (185 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Thigh Top"); + manSizes.add(element); + } else if (element.propertyName == "Thigh Middle") { + element.top = (377 * distortionHeight).toInt(); + element.left = (125 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Thigh Middle"); + manSizes.add(element); + } else if (element.propertyName == "Knee") { + element.top = (468 * distortionHeight).toInt(); + element.left = (129 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Knee"); + manSizes.add(element); + } else if (element.propertyName == "Calf") { + element.top = (525 * distortionHeight).toInt(); + element.left = (129 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Calf"); + manSizes.add(element); + } else if (element.propertyName == "Ankle") { + element.top = (620 * distortionHeight).toInt(); + element.left = (162 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Ankle"); + manSizes.add(element); + } else if (element.propertyName == "Weight") { + element.top = (402 * distortionHeight).toInt(); + element.left = (240 * distortionWidth).toInt(); + element.value = this.customer!.getProperty("Weight"); + manSizes.add(element); + } + }); + } + } + + int? getWeightCoordinate(isMan, {isTop = false, isLeft = false}) { + int? value = 0; + this.manSizes.forEach((element) { + if (element.propertyName == SizesEnum.Weight.toStr()) { + if (isTop == true) { + value = element.top; + } else if (isLeft == true) { + value = element.left; + } + } + }); + return value; + } + + Property? getPropertyByName(String propertyName) { + Property? property; + List sizes; + if (this.sex == "m") { + sizes = this.manSizes; + } else { + sizes = this.womanSizes; + } + + sizes.forEach((element) { + if (element.propertyName == propertyName) { + property = element; + } + }); + return property; + } + + void updateSizes(String propertyName, double value) { + List sizes; + if (this.sex == "m") { + sizes = this.manSizes; + } else { + sizes = this.womanSizes; + } + + sizes.forEach((element) { + if (element.propertyName == propertyName) { + element.value = value; + } + }); + } + + List getAllCustomerPropertyByName(String propertyName) { + List allProperties = []; + + Property? property = propertyRepository.getPropertyByName(propertyName); + print(property); + if (property == null || Cache().getCustomerPropertyAll() == null) { + return allProperties; + } + + Cache().getCustomerPropertyAll()!.forEach((element) { + if (element.propertyId == property.propertyId) { + allProperties.add(element); + } + }); + return allProperties; + } +} diff --git a/lib/repository/exercise_device_repository.dart b/lib/repository/exercise_device_repository.dart new file mode 100644 index 0000000..2cf49e7 --- /dev/null +++ b/lib/repository/exercise_device_repository.dart @@ -0,0 +1,52 @@ +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/exercise_device.dart'; +import 'package:workouttest_util/service/exercise_device_service.dart'; + +class ExerciseDeviceRepository { + List _devices = []; + + List getDevices() { + return this._devices; + } + + void setDevices(List list) { + _devices = list; + } + + Future> getDBDevices() async { + this._devices = await ExerciseDeviceApi().getDevices(); + return this._devices; + } + + bool isGym(int deviceId) { + bool isGym = false; + _devices.forEach((element) { + isGym = isGymElement(element.name); + }); + return isGym; + } + + bool isGymElement(String name) { + return name == "Cable" || + name == "Baar" || + name == "Gym Machine" || + name == "Dumbbells" || + name == "Barbell" || + name == "HOME" || + name == "STREET"; + } + + List getGymDevices() { + if (Cache().getDevices() == null) return []; + final List gymDevices = []; + if (_devices.isEmpty) { + _devices = Cache().getDevices()!; + } + _devices.forEach((element) { + if (isGymElement(element.name)) { + gymDevices.add(element); + } + }); + return gymDevices; + } +} diff --git a/lib/repository/exercise_repository.dart b/lib/repository/exercise_repository.dart new file mode 100644 index 0000000..b195ebf --- /dev/null +++ b/lib/repository/exercise_repository.dart @@ -0,0 +1,538 @@ +import 'dart:collection'; + +import 'package:workouttest_util/util/app_language.dart'; +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/customer.dart'; +import 'package:workouttest_util/model/exercise.dart'; +import 'package:workouttest_util/model/exercise_type.dart'; +import 'package:workouttest_util/model/workout_menu_tree.dart'; +import 'package:workouttest_util/service/exercise_service.dart'; +// ignore: depend_on_referenced_packages +import 'package:intl/intl.dart'; + +class ExerciseRepository { + Exercise? exercise; + Customer? customer; + ExerciseType? exerciseType; + List? exerciseList; + List? exerciseLogList = []; + List? actualExerciseList = []; + bool noRegistration = false; + + double rmWendler = 0; + double rmMcglothlin = 0; + double rmLombardi = 0; + double rmMayhew = 0; + double rmOconner = 0; + double rmWathen = 0; + + DateTime? start; + DateTime? end; + + ExerciseRepository() { + this.createNew(); + } + + createNew() { + this.exercise = Exercise(); + exercise!.dateAdd = DateTime.now(); + } + + setQuantity(double quantity) { + if (this.exercise == null) { + this.createNew(); + } + this.exercise!.quantity = quantity; + } + + setUnitQuantity(double unitQuantity) { + if (this.exercise == null) { + this.createNew(); + } + + this.exercise!.unitQuantity = unitQuantity; + } + + setUnit(String unit) { + if (this.exercise == null) { + this.createNew(); + } + + this.exercise!.unit = unit; + } + + setDatetimeExercise(DateTime datetimeExercise) { + if (this.exercise == null) { + this.createNew(); + } + + this.exercise!.dateAdd = datetimeExercise; + } + + double? get unitQuantity => this.exercise!.unitQuantity; + + double? get quantity => this.exercise!.quantity; + + Exercise? getExercise() => this.exercise; + + Future addExercise() async { + if (this.customer == null) { + throw Exception("Please log in"); + } + final Exercise modelExercise = this.exercise!; + modelExercise.customerId = this.customer!.customerId; + modelExercise.exerciseTypeId = this.exerciseType!.exerciseTypeId; + if (exerciseType!.unitQuantity != "1") { + modelExercise.unitQuantity = null; + } + + Exercise copy = modelExercise.copy(); + this.actualExerciseList!.add(copy); + //final int index = this.actualExerciseList.length - 1; + //print("$index. actual exercise " + this.actualExerciseList[index].toJson().toString()); + Exercise savedExercise = await ExerciseApi().addExercise(modelExercise); + + //this.actualExerciseList[index].exerciseId = savedExercise.exerciseId; + if (customer!.customerId == Cache().userLoggedIn!.customerId) { + Cache().addExercise(savedExercise); + } else if (Cache().getTrainee() != null && customer!.customerId == Cache().getTrainee()!.customerId) { + Cache().addExerciseTrainee(savedExercise); + } + + return savedExercise; + } + + void addExerciseNoRegistration() { + final Exercise modelExercise = this.exercise!; + modelExercise.exerciseTypeId = this.exerciseType!.exerciseTypeId; + if (exerciseType!.unitQuantity != "1") { + modelExercise.unitQuantity = null; + } + Exercise copy = modelExercise.copy(); + this.actualExerciseList!.add(copy); + this.exerciseList = []; + this.exerciseList!.add(copy); + this.noRegistration = true; + } + + void initExercise() { + this.createNew(); + this.exerciseType = exerciseType; + this.setUnit(exerciseType!.unit); + exercise!.exerciseTypeId = this.exerciseType!.exerciseTypeId; + this.setQuantity(12); + this.setUnitQuantity(30); + this.exercise!.exercisePlanDetailId = 0; + exercise!.exerciseId = 0; + this.start = DateTime.now(); + } + + Future deleteExercise(Exercise exercise) async { + await ExerciseApi().deleteExercise(exercise); + } + + setCustomer(Customer customer) => this.customer = customer; + + setExerciseType(ExerciseType exerciseType) => this.exerciseType = exerciseType; + + Future> getExercisesByCustomer(int customerId) async { + final results = await ExerciseApi().getExercisesByCustomer(customerId); + this.exerciseList = results; + if (Cache().userLoggedIn != null) { + if (customerId == Cache().userLoggedIn!.customerId) { + Cache().setExercises(exerciseList!); + } else if (Cache().getTrainee() != null && customerId == Cache().getTrainee()!.customerId) { + Cache().setExercisesTrainee(exerciseList!); + } + } + return this.exerciseList!; + } + + List? getExerciseList() { + this.exerciseList = Cache().getExercises(); + return this.exerciseList; + } + + List? getExerciseListTrainee() { + this.exerciseList = Cache().getExercisesTrainee(); + return this.exerciseList; + } + + String? nextMissingBaseExercise(SplayTreeMap sortedTree) { + if (exerciseList == null) { + exerciseList = Cache().getExercises(); + } + + if (exerciseList == null) { + return null; + } + String? missingTreeName; + String? foundTreeName; + bool isBreak = false; + + sortedTree.forEach((key, list) { + List listByMuscle = list as List; + String treeName = key as String; + treeName = treeName.substring(3); + foundTreeName = null; + listByMuscle.forEach((exercise) { + if (missingTreeName == null) { + missingTreeName = treeName; + } + if (exercise.base) { + if (exerciseList != null) { + exerciseList!.forEach((element) { + if (element.exerciseTypeId == exercise.exerciseTypeId) { + foundTreeName = treeName; + //print("Found " + foundTreeName + " Missing actual: " + missingTreeName); + isBreak = true; + } + }); + } + } + }); + if (foundTreeName == null && !isBreak) { + missingTreeName = treeName; + isBreak = true; + } + }); + + return missingTreeName; + } + + void getBaseExerciseFinishedPercent() { + List checkedExerciseTypeId = []; + List baseTreeItem = []; + List checkedBaseTreeItem = []; + int count1RMExercises = 0; + LinkedHashMap tree = Cache().getWorkoutMenuTree(); + + if (tree.isEmpty) { + return; + } + + tree.forEach((key, value) { + WorkoutMenuTree treeItem = value; + if (treeItem.exerciseType != null && treeItem.exerciseType!.base == true && !baseTreeItem.contains(treeItem.parent)) { + baseTreeItem.add(treeItem.parent); + } + }); + + if (exerciseList == null) { + exerciseList = Cache().getExercises(); + } + + if (exerciseList == null) { + return; + } + + exerciseList!.forEach((element) { + Exercise exercise = element; + if (!checkedExerciseTypeId.contains(exercise.exerciseTypeId)) { + checkedExerciseTypeId.add(exercise.exerciseTypeId!); + tree.forEach((key, value) { + WorkoutMenuTree treeItem = value; + if (treeItem.exerciseType != null && + treeItem.exerciseType!.base == true && + exercise.exerciseTypeId == treeItem.exerciseType!.exerciseTypeId && + !checkedBaseTreeItem.contains(treeItem.parent)) { + //print ("id: " + exercise.exerciseTypeId.toString()); + checkedBaseTreeItem.add(treeItem.parent); + count1RMExercises++; + } + }); + } + }); + + //print ("checkedExerciseTypeid: " + checkedExerciseTypeId.toString()); + //print ("baseTreeItem: " + baseTreeItem.toString()); + //print ("count1RMExercises: " + count1RMExercises.toString()); + final double percent = count1RMExercises / baseTreeItem.length; + Cache().setPercentExercises(percent); + } + + void getLastExercise() { + List? exercises = this.getExerciseList(); + Exercise? lastExercise = exercises == null ? null : exercises[0]; + if (exercises != null) { + exercises.forEach((element) { + Exercise actualExercise = element; + if (actualExercise.dateAdd!.compareTo(lastExercise!.dateAdd!) > 0) { + lastExercise = actualExercise; + } + }); + } + this.exercise = lastExercise; + this.customer = Cache().userLoggedIn!; + this.exerciseType = getExerciseTypeById(exercise!.exerciseTypeId!); + return; + } + + ExerciseType? getExerciseTypeById(int exerciseTypeId) { + ExerciseType? actualExerciseType; + List? exercises = Cache().getExerciseTypes(); + if (exercises != null) { + exercises.forEach((element) { + ExerciseType exerciseType = element; + if (exerciseType.exerciseTypeId == exerciseTypeId) { + actualExerciseType = exerciseType; + } + }); + } + if (actualExerciseType == null) { + throw Exception("Data error, no ExerciseType for exerciseTypeId $exerciseTypeId"); + } + return actualExerciseType; + } + + void getSameExercise(int exerciseTypeId, String day) { + if (!this.noRegistration) { + this.actualExerciseList = []; + } + if (exerciseList != null) { + int index = 0; + for (int i = 0; i < this.exerciseList!.length; i++) { + Exercise exercise = exerciseList![i]; + final String exerciseDate = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd!); + if (exerciseTypeId == exercise.exerciseTypeId && exerciseDate == day && index < 4) { + this.actualExerciseList!.add(exercise); + index++; + } + } + } + } + + double calculate1RM(Exercise exercise) { + double weight = exercise.unitQuantity!; + double repeat = exercise.quantity!; + if (weight == 0 || repeat == 0) { + return 0; + } + + double rmWendler = weight * repeat * 0.0333 + weight; + double rmOconner = weight * (1 + repeat / 40); + double average = (rmWendler + rmOconner) / 2; + + return average; + } + + double getBest1RM(Exercise exercise) { + double result = 0; + if (this.exerciseList == null || this.exerciseList!.isEmpty) { + this.exerciseList = Cache().getExercises(); + } + + final int exerciseTypeId = exercise.exerciseTypeId!; + double toCompare = this.calculate1RM(exercise); + result = toCompare; + + final String today = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(DateTime.now()); + List oldExercises = []; + if (exerciseList == null) { + return toCompare; + } + this.exerciseList!.forEach((exercise) { + final String exerciseDate = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd!); + if (exercise.exerciseTypeId == exerciseTypeId && exerciseDate.compareTo(today) < 0) { + oldExercises.add(exercise); + } + }); + + if (oldExercises.isNotEmpty) { + oldExercises.sort((a, b) { + double sumA = 0; + double sumB = 0; + if (a.unitQuantity != null && b.unitQuantity != null) { + sumA = a.quantity! * a.unitQuantity!; + sumB = b.quantity! * b.unitQuantity!; + } else { + sumA = a.quantity!; + sumB = b.quantity!; + } + return sumA >= sumB ? 1 : -1; + }); + + double withCompare = this.calculate1RM(oldExercises.last); + + //result = toCompare >= withCompare ? (1 - toCompare / withCompare) * 100 : (1 - toCompare / withCompare) * -100; + result = toCompare >= withCompare ? toCompare : withCompare; + } + return result; + } + + double getLast1RMPercent(Exercise exercise) { + double result = 0; + if (this.exerciseList == null || this.exerciseList!.isEmpty) { + this.exerciseList = Cache().getExercises(); + } + + final int exerciseTypeId = exercise.exerciseTypeId!; + double toCompare = this.calculate1RM(exercise); + + final String today = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd!); + List oldExercises = []; + + if (exerciseList == null) { + return result; + } + this.exerciseList!.forEach((exercise) { + final String exerciseDate = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd!); + if (exercise.exerciseTypeId == exerciseTypeId && exerciseDate.compareTo(today) < 0) { + oldExercises.add(exercise); + } + }); + + if (oldExercises.isNotEmpty) { + double withCompare = this.calculate1RM(oldExercises.first); + result = toCompare >= withCompare ? (toCompare / withCompare) * 100 : (1 - toCompare / withCompare) * -100; + } + return result; + } + + double getBestVolume(Exercise exercise) { + double result = 0; + if (this.exerciseList == null || this.exerciseList!.isEmpty) { + this.exerciseList = Cache().getExercises(); + } + + final int exerciseTypeId = exercise.exerciseTypeId!; + double toCompare = exercise.unitQuantity != null ? exercise.quantity! * exercise.unitQuantity! : exercise.quantity!; + result = toCompare; + + final String today = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(DateTime.now()); + List oldExercises = []; + if (exerciseList == null) { + return toCompare; + } + this.exerciseList!.forEach((exercise) { + final String exerciseDate = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd!); + if (exercise.exerciseTypeId == exerciseTypeId && exerciseDate.compareTo(today) < 0) { + oldExercises.add(exercise); + } + }); + + if (oldExercises.isNotEmpty) { + oldExercises.sort((a, b) { + double sumA = 0; + double sumB = 0; + if (a.unitQuantity != null && b.unitQuantity != null) { + sumA = a.quantity! * a.unitQuantity!; + sumB = b.quantity! * b.unitQuantity!; + } else { + sumA = a.quantity!; + sumB = b.quantity!; + } + return sumA >= sumB ? 1 : -1; + }); + + double withCompare = + oldExercises.last.unitQuantity != null ? oldExercises.last.quantity! * oldExercises.last.unitQuantity! : oldExercises.last.quantity!; + + //result = toCompare >= withCompare ? (1 - toCompare / withCompare) * 100 : (1 - toCompare / withCompare) * -100; + //print("Last Best: ${oldExercises.last} - result: $result"); + result = toCompare >= withCompare ? toCompare : withCompare; + } + return result; + } + + double getLastExercisePercent(Exercise exercise) { + double result = 0; + if (this.exerciseList == null || this.exerciseList!.isEmpty) { + this.exerciseList = Cache().getExercises(); + } + + final int exerciseTypeId = exercise.exerciseTypeId!; + double toCompare = exercise.unitQuantity != null ? exercise.quantity! * exercise.unitQuantity! : exercise.quantity!; + + final String today = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd!); + List oldExercises = []; + if (exerciseList == null) { + return result; + } + this.exerciseList!.forEach((exercise) { + final String exerciseDate = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd!); + if (exercise.exerciseTypeId == exerciseTypeId && exerciseDate.compareTo(today) < 0) { + oldExercises.add(exercise); + } + }); + + if (oldExercises.isNotEmpty) { + double withCompare = + oldExercises.first.unitQuantity != null ? oldExercises.first.quantity! * oldExercises.first.unitQuantity! : oldExercises.first.quantity!; + + result = toCompare >= withCompare ? (toCompare / withCompare) * 100 : (1 - toCompare / withCompare) * -100; + print("Last Last: ${oldExercises.first} vs. $exercise - - result: $result"); + } + return result; + } + + void sortByDate() { + if (exerciseList == null || exerciseList!.isEmpty) { + return; + } + + exerciseList!.sort((a, b) { + final String datePartA = DateFormat('yyyyMMdd', AppLanguage().appLocal.toString()).format(a.dateAdd!); + String aId = datePartA + "_" + a.exerciseTypeId.toString(); + final String datePartB = DateFormat('yyyyMMdd', AppLanguage().appLocal.toString()).format(b.dateAdd!); + String bId = datePartB + "_" + b.exerciseTypeId.toString(); + return bId.compareTo(aId); + }); + + this.exerciseLogList = []; + String summary = ""; + + String prevDate = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exerciseList![0].dateAdd!); + int prevExerciseTypeId = exerciseList![0].exerciseTypeId!; + Exercise prevExercise = exerciseList![0]; + int prevCount = 0; + for (int i = 0; i < this.exerciseList!.length; i++) { + Exercise exercise = exerciseList![i]; + int exerciseTypeId = exercise.exerciseTypeId!; + String exerciseDate = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd!); + //print(" -- $prevExerciseTypeId - '$prevDate' against $exerciseTypeId - '$exerciseDate'"); + if (exerciseTypeId != prevExerciseTypeId || prevDate != exerciseDate) { + ExerciseType? exerciseType = Cache().getExerciseTypeById(prevExercise.exerciseTypeId!); + String unit = exerciseType != null && exerciseType.unitQuantityUnit != null ? exerciseType.unitQuantityUnit! : prevExercise.unit!; + prevExercise.summary = summary + " " + unit; + exerciseLogList!.add(prevExercise); + //print("Log add " + exercise.toJson().toString()); + summary = ""; + prevCount = 0; + } + String delimiter = ""; + if (prevCount > 0) delimiter = ", "; + double quantity = exercise.quantity == null ? 0 : exercise.quantity!; + summary += delimiter + quantity.toStringAsFixed(0); + ExerciseType? exerciseType = Cache().getExerciseTypeById(exercise.exerciseTypeId!); + //print("exerciseType " + (exerciseType == null ? "NULL" : exerciseType.name) + " ID " + exercise.exerciseTypeId.toString()); + if (exerciseType != null) { + if (exerciseType.unitQuantity == "1") { + summary += "x" + exercise.unitQuantity!.toStringAsFixed(0); + } + //print(" --- sum " + exerciseType.name + " $summary"); + } + + prevExerciseTypeId = exerciseTypeId; + prevDate = exerciseDate; + prevExercise = exercise; + prevCount++; + } + prevExercise.summary = summary; + exerciseLogList!.add(prevExercise); + } + + List getExercisesByExerciseTypeId(int exerciseTypeId) { + List list = []; + List? allExercise = Cache().getExercises(); + if (allExercise == null) { + return list; + } + allExercise.forEach((element) { + if (element.exerciseTypeId == exerciseTypeId) { + list.add(element); + } + }); + return list; + } +} diff --git a/lib/repository/exercise_type_repository.dart b/lib/repository/exercise_type_repository.dart new file mode 100644 index 0000000..750af76 --- /dev/null +++ b/lib/repository/exercise_type_repository.dart @@ -0,0 +1,26 @@ +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/exercise_type.dart'; +import 'package:workouttest_util/util/logging.dart'; + +class ExerciseTypeRepository with Logging { + + static List getExerciseTypeAlternatives(int? exerciseTypeId) { + if (exerciseTypeId == null || exerciseTypeId <= 0) { + return []; + } + List list = []; + List? exerciseTypes = Cache().getExerciseTypes(); + if (exerciseTypes != null) { + exerciseTypes.forEach((exerciseType) { + if (exerciseType.alternatives.isNotEmpty) { + exerciseType.alternatives.forEach((childId) { + if (childId == exerciseTypeId) { + list.add(exerciseType); + } + }); + } + }); + } + return list; + } +} \ No newline at end of file diff --git a/lib/repository/mautic_repository.dart b/lib/repository/mautic_repository.dart new file mode 100644 index 0000000..822dacd --- /dev/null +++ b/lib/repository/mautic_repository.dart @@ -0,0 +1,93 @@ +// ignore: depend_on_referenced_packages +import 'package:intl/intl.dart'; +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/mautic.dart'; +import 'package:workouttest_util/repository/customer_repository.dart'; +import 'package:workouttest_util/service/mautic.dart'; +import 'package:workouttest_util/util/app_language.dart'; + +class MauticRepository { + final CustomerRepository customerRepository; + + const MauticRepository({required this.customerRepository}); + + Future sendMauticSubscription() async { + Mautic mautic = Mautic(); + mautic.formId = 2; + mautic.databaseId = Cache().userLoggedIn!.customerId!; + mautic.firstname = customerRepository.customer!.firstname == null ? "" : customerRepository.customer!.firstname!; + mautic.lastname = customerRepository.customer!.name == null ? "" : customerRepository.customer!.name!; + mautic.email = customerRepository.customer!.email == null ? "" : customerRepository.customer!.email!; + if (mautic.email == null || mautic.email!.contains("privaterelay.appleid.com")) { + return; + } + mautic.fitnessLevel = customerRepository.customer!.fitnessLevel == null ? "" : customerRepository.customer!.fitnessLevel!; + mautic.goal = customerRepository.customer!.goal == null ? "" : customerRepository.customer!.goal!; + mautic.subscriptionDate = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); + mautic.language = AppLanguage().appLocal.languageCode; + + await MauticApi().sendMauticForm(mautic); + + customerRepository.customer!.syncedDate = DateTime.now(); + await customerRepository.saveCustomer(); + } + + Future sendMauticDataChange() async { + Mautic mautic = Mautic(); + mautic.formId = 3; + mautic.databaseId = Cache().userLoggedIn!.customerId!; + mautic.firstname = customerRepository.customer!.firstname == null ? "" : customerRepository.customer!.firstname!; + mautic.lastname = customerRepository.customer!.name == null ? "" : customerRepository.customer!.name!; + mautic.email = customerRepository.customer!.email == null ? "" : customerRepository.customer!.email!; + if (mautic.email == null || mautic.email!.contains("privaterelay.appleid.com")) { + return; + } + mautic.fitnessLevel = customerRepository.customer!.fitnessLevel == null ? "" : customerRepository.customer!.fitnessLevel!; + mautic.goal = customerRepository.customer!.goal == null ? "" : customerRepository.customer!.goal!; + mautic.language = AppLanguage().appLocal.languageCode; + + await MauticApi().sendMauticForm(mautic); + } + + Future sendMauticPurchase() async { + Mautic mautic = Mautic(); + mautic.formId = 4; + mautic.firstname = customerRepository.customer!.firstname == null ? "" : customerRepository.customer!.firstname!; + mautic.lastname = customerRepository.customer!.name == null ? "" : customerRepository.customer!.name!; + mautic.email = customerRepository.customer!.email == null ? "" : customerRepository.customer!.email!; + if (mautic.email == null || mautic.email!.contains("privaterelay.appleid.com")) { + return; + } + mautic.purchaseDate = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); + + await MauticApi().sendMauticForm(mautic); + } + + Future sendMauticExercise() async { + Mautic mautic = Mautic(); + mautic.formId = 5; + mautic.firstname = customerRepository.customer!.firstname == null ? "" : customerRepository.customer!.firstname!; + mautic.lastname = customerRepository.customer!.name == null ? "" : customerRepository.customer!.name!; + mautic.email = customerRepository.customer!.email == null ? "" : customerRepository.customer!.email!; + if (mautic.email == null || mautic.email!.contains("privaterelay.appleid.com")) { + return; + } + mautic.exerciseDate = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); + mautic.databaseId = Cache().userLoggedIn!.customerId!; + + await MauticApi().sendMauticForm(mautic); + } + + Future sendMauticTrial() async { + Mautic mautic = Mautic(); + mautic.formId = 6; + mautic.email = customerRepository.customer!.email == null ? "" : customerRepository.customer!.email!; + if (mautic.email == null || mautic.email!.contains("privaterelay.appleid.com")) { + return; + } + mautic.trialDate = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); + mautic.databaseId = Cache().userLoggedIn!.customerId!; + + await MauticApi().sendMauticForm(mautic); + } +} diff --git a/lib/repository/property_repository.dart b/lib/repository/property_repository.dart new file mode 100644 index 0000000..18cf343 --- /dev/null +++ b/lib/repository/property_repository.dart @@ -0,0 +1,31 @@ +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/property.dart'; +import 'package:workouttest_util/service/property_service.dart'; + +class PropertyRepository { + List? _properties; + + Future?> getDBProperties() async { + this._properties = await PropertyApi().getProperties(); + return this._properties; + } + + List? getProperties() { + return this._properties; + } + + Property? getPropertyByName(String name) { + Property? property; + if (_properties == null) { + _properties = Cache().getProperties(); + } + if (_properties != null) { + this._properties!.forEach((element) { + if (name == element.propertyName) { + property = element; + } + }); + } + return property; + } +} diff --git a/lib/repository/training_plan_day_repository.dart b/lib/repository/training_plan_day_repository.dart new file mode 100644 index 0000000..6767681 --- /dev/null +++ b/lib/repository/training_plan_day_repository.dart @@ -0,0 +1,35 @@ +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/training_plan.dart'; +import 'package:workouttest_util/util/app_language.dart'; + +class TrainingPlanDayRepository { + const TrainingPlanDayRepository(); + + void assignTrainingPlanDays() { + List? plans = Cache().getTrainingPlans(); + if (plans == null) { + return; + } + plans.forEach((plan) { + if (plan.details != null) { + plan.details!.forEach((element) { + element.day = this.getNameById(element.dayId); + }); + } + }); + } + + String? getNameById(int? dayId) { + if (dayId == null) { + return ""; + } + String? name; + for (var day in Cache().getTrainingPlanDays()) { + if (day.dayId == dayId) { + name = day.nameTranslations[AppLanguage().appLocal.languageCode]; + break; + } + } + return name; + } +} diff --git a/lib/repository/training_plan_repository.dart b/lib/repository/training_plan_repository.dart new file mode 100644 index 0000000..c080079 --- /dev/null +++ b/lib/repository/training_plan_repository.dart @@ -0,0 +1,448 @@ +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/customer_training_plan.dart'; +import 'package:workouttest_util/model/customer_training_plan_details.dart'; +import 'package:workouttest_util/model/exercise.dart'; +import 'package:workouttest_util/model/exercise_plan_detail.dart'; +import 'package:workouttest_util/model/exercise_tree.dart'; +import 'package:workouttest_util/model/fitness_state.dart'; +import 'package:workouttest_util/model/training_plan.dart'; +import 'package:workouttest_util/model/training_plan_detail.dart'; +import 'package:workouttest_util/repository/exercise_type_repository.dart'; +import 'package:workouttest_util/repository/training_plan_day_repository.dart'; +import 'package:workouttest_util/util/app_language.dart'; +import 'package:workouttest_util/util/common.dart'; + +class TrainingPlanRepository with Common { + ExerciseTree? parentTree; + List getPlansByParent(String parent) { + final List resultList = []; + final List? exerciseTree = Cache().getExerciseTree(); + int? parentId; + if (exerciseTree != null) { + exerciseTree.forEach((element) { + if (element.internalName == parent) { + parentId = element.treeId; + parentTree = element; + } + }); + } + + final List? plans = Cache().getTrainingPlans(); + if (plans != null && parentId != null) { + plans.forEach((element) { + if (element.treeId == parentId) { + resultList.add(element); + } + }); + } + return resultList; + } + + /// 1. deactivate old training plans - update all + + /// 2. calculate customer_training_plan_details weights / repleats + /// 3. create new customer_training_plan + + CustomerTrainingPlan? activateTrainingPlan(int trainingPlanId) { + print(" **** Activate Plan: $trainingPlanId"); + // 1. deactivate + if (Cache().getCustomerTrainingPlans() != null) { + Cache().getCustomerTrainingPlans()!.forEach((plan) { + plan.active = false; + if (plan.customerTrainingPlanId != null) { + //TrainingPlanApi().updateCustomerTrainingPlan(plan, plan.customerTrainingPlanId!); + } + }); + } + + CustomerTrainingPlan plan = CustomerTrainingPlan(); + plan.customerId = Cache().userLoggedIn!.customerId; + plan.trainingPlanId = trainingPlanId; + plan.active = true; + plan.status = "open"; + plan.dateAdd = DateTime.now(); + TrainingPlan? trainingPlan = this.getTrainingPlanById(trainingPlanId); + if (trainingPlan == null || trainingPlan.details == null) { + print("trainingPlan null"); + return null; + } + plan.name = trainingPlan.nameTranslations[AppLanguage().appLocal.toString()]; + + // 3 calculate weights + int index = 0; + int exerciseTypeIdOrig = 0; + trainingPlan.details!.forEach((elem) { + List list = createDetail(plan, elem, exerciseTypeIdOrig, index); + exerciseTypeIdOrig = elem.exerciseTypeId; + list.forEach((element) { + plan.details.add(element); + index++; + }); + }); + + Cache().myTrainingPlan = plan; + + return plan; + } + + CustomerTrainingPlanDetails? getDetailById(CustomerTrainingPlan? plan, int customerTrainingPlanDetailsId) { + CustomerTrainingPlanDetails? foundDetail; + + if (plan == null || plan.details.length == 0 || customerTrainingPlanDetailsId == 0) { + return foundDetail; + } + + for (var detail in plan.details) { + if (detail.customerTrainingPlanDetailsId == customerTrainingPlanDetailsId) { + foundDetail = detail; + break; + } + } + + return foundDetail; + } + + CustomerTrainingPlanDetails createAlternativeDetail( + CustomerTrainingPlan plan, CustomerTrainingPlanDetails detail, TrainingPlanDetail elem, int exerciseTypeId) { + CustomerTrainingPlanDetails alternativeDetail = CustomerTrainingPlanDetails(); + alternativeDetail.copy(detail); + alternativeDetail.exerciseTypeId = exerciseTypeId; + alternativeDetail.exerciseType = Cache().getExerciseTypeById(exerciseTypeId); + + if (elem.weight == -1) { + if (alternativeDetail.exerciseType!.unitQuantityUnit != null) { + alternativeDetail = getCalculatedWeightRepeats(elem.exerciseTypeId, alternativeDetail); + } else { + alternativeDetail.weight = 0; + } + } else if (elem.weight == -2) { + final CustomerTrainingPlanDetails calculated = this.isWeightCalculatedByExerciseType(elem.exerciseTypeId, alternativeDetail, plan); + if (calculated.weight != -1) { + alternativeDetail.weight = calculated.weight; + } else { + alternativeDetail.weight = -2; + } + } else { + alternativeDetail.weight = elem.weight; + } + //print("Detail $alternativeDetail exerciseType: ${alternativeDetail.exerciseType!.exerciseTypeId}"); + + return alternativeDetail; + } + + List createDetail(CustomerTrainingPlan plan, TrainingPlanDetail elem, int exerciseTypeIdOrig, int index, + {bool changeExerciseType = false}) { + List list = []; + CustomerTrainingPlanDetails detail = CustomerTrainingPlanDetails(); + detail.customerTrainingPlanDetailsId = ++index; + detail.trainingPlanDetailsId = elem.trainingPlanDetailId; + detail.exerciseTypeId = changeExerciseType ? exerciseTypeIdOrig : elem.exerciseTypeId; + detail.repeats = elem.repeats; + detail.set = elem.set; + detail.dayId = elem.dayId; + TrainingPlanDayRepository trainingPlanDayRepository = TrainingPlanDayRepository(); + detail.day = trainingPlanDayRepository.getNameById(elem.dayId); + detail.parallel = elem.parallel; + detail.restingTime = elem.restingTime; + detail.exerciseType = Cache().getExerciseTypeById(detail.exerciseTypeId!); + detail.alternatives = ExerciseTypeRepository.getExerciseTypeAlternatives(detail.exerciseTypeId); + if (elem.weight == -1) { + if (detail.exerciseType!.unitQuantityUnit != null) { + detail = getCalculatedWeightRepeats(elem.exerciseTypeId, detail); + } else { + detail.weight = 0; + } + } else if (elem.weight == -2) { + final CustomerTrainingPlanDetails calculated = this.isWeightCalculatedByExerciseType(elem.exerciseTypeId, detail, plan); + if (calculated.weight != -1) { + detail.weight = calculated.weight; + } else { + detail.weight = -2; + } + } else { + detail.weight = elem.weight; + } + print("Detail $detail exerciseType: ${detail.exerciseType!.exerciseTypeId}"); + + detail.state = ExercisePlanDetailState.start; + if (detail.weight != null && detail.weight! > 0) { + detail.baseOneRepMax = calculate1RM(detail.weight!, detail.repeats!.toDouble()); + } + + // first repeat: 50% more + if (detail.weight != null && detail.weight! > 0 && exerciseTypeIdOrig != detail.exerciseTypeId && detail.repeats! > 0) { + CustomerTrainingPlanDetails firstDetail = CustomerTrainingPlanDetails(); + firstDetail.copy(detail); + firstDetail.repeats = (detail.repeats! * 1.5).round(); + firstDetail.baseOneRepMax = calculate1RM(firstDetail.weight!, firstDetail.repeats!.toDouble()); + firstDetail.set = 1; + detail.set = detail.set! - 1; + if (detail.set! > 0) { + index++; + } + detail.customerTrainingPlanDetailsId = index; + list.add(firstDetail); + } + + if (detail.set! > 0) { + list.add(detail); + } + return list; + } + + CustomerTrainingPlanDetails isWeightCalculatedByExerciseType(int exerciseTypeId, CustomerTrainingPlanDetails detail, CustomerTrainingPlan plan) { + CustomerTrainingPlanDetails calculated = detail; + for (var element in plan.details) { + if (element.exerciseTypeId == exerciseTypeId) { + calculated = element; + break; + } + } + + return calculated; + } + + TrainingPlan? getTrainingPlanById(int trainingPlanId) { + TrainingPlan? plan; + if (Cache().getTrainingPlans() == null) { + return plan; + } + + for (var trainingPlan in Cache().getTrainingPlans()!) { + if (trainingPlan.trainingPlanId == trainingPlanId) { + plan = trainingPlan; + break; + } + } + + return plan; + } + + int? getTrainingPlanByInternalName(String internalName) { + int? id; + if (Cache().getTrainingPlans() == null) { + return id; + } + + for (var trainingPlan in Cache().getTrainingPlans()!) { + //print("internal ${trainingPlan.internalName}"); + if (trainingPlan.internalName == internalName) { + id = trainingPlan.trainingPlanId; + break; + } + } + + return id; + } + + CustomerTrainingPlanDetails getCalculatedWeightRepeats(int exerciseTypeId, CustomerTrainingPlanDetails detail) { + double weight = -1; + if (Cache().getExercises() == null) { + detail.weight = weight; + detail.isTest = true; + return detail; + } + + Exercise? lastExercise1RM; + DateTime dt = DateTime.now().subtract(Duration(days: 30)); + List exercises = Cache().getExercises()!; + exercises.sort((a, b) { + // reverse + return a.dateAdd!.compareTo(b.dateAdd!); + }); + exercises.forEach((exercise) { + if (exercise.exerciseTypeId == exerciseTypeId && exercise.dateAdd!.compareTo(dt) >= 0) { + detail.weight = weight; + lastExercise1RM = exercise; + //print("last exercise: $exercise"); + } + }); + + if (lastExercise1RM == null || lastExercise1RM!.unitQuantity == null) { + detail.weight = weight; + detail.isTest = true; + return detail; + } + + double oneRepMax = calculateMax1RMSameDay(lastExercise1RM!); + // Common.calculate1RM(lastExercise1RM!.unitQuantity!, lastExercise1RM!.quantity!); + //print("Exercise $exerciseTypeId - 1RM : $oneRepMax"); + weight = oneRepMax * Common.get1RMPercent(detail.repeats!); + //print("Exercise $exerciseTypeId - weight : $weight"); + //weight = Common.roundWeight(weight); + //detail.weight = Common.calculateWeigthByChangedQuantity(detail.weight!, detail.repeats!.toDouble(), lastExercise1RM!.quantity!); + //weight = lastExercise1RM!.unitQuantity! * detail.repeats! / lastExercise1RM!.quantity!; + weight = Common.roundWeight(weight); + //print("Recaluclated weight ${detail.weight} - repeat: ${detail.repeats}"); + + //detail.repeats = Common.calculateQuantityByChangedWeight(oneRepMax, weight, detail.repeats!.toDouble()); + + detail.weight = weight; + return detail; + } + + double calculateMax1RMSameDay(Exercise actual) { + List exercises = Cache().getExercises()!; + double max1RM = 0.0; + + exercises.forEach((exercise) { + if (actual.exerciseTypeId == exercise.exerciseTypeId && + actual.dateAdd!.year == exercise.dateAdd!.year && + actual.dateAdd!.month == exercise.dateAdd!.month && + actual.dateAdd!.day == exercise.dateAdd!.day) { + double oneRepMax = calculate1RM(exercise.unitQuantity!, exercise.quantity!); + if (max1RM < oneRepMax) { + max1RM = oneRepMax; + } + } + }); + + return max1RM; + } + + int getOriginalRepeats(int trainingPlanId, CustomerTrainingPlanDetails detail) { + TrainingPlan? plan = getTrainingPlanById(trainingPlanId); + if (plan == null) { + return 0; + } + int originalRepeats = 0; + plan.details!.forEach((element) { + if (element.trainingPlanDetailId == detail.trainingPlanDetailsId) { + originalRepeats = element.repeats ?? 0; + } + }); + return originalRepeats; + } + + double getOriginalWeight(int trainingPlanId, CustomerTrainingPlanDetails detail) { + TrainingPlan? plan = getTrainingPlanById(trainingPlanId); + if (plan == null) { + return 0; + } + double originalWeight = 0; + plan.details!.forEach((element) { + if (element.trainingPlanDetailId == detail.trainingPlanDetailsId) { + originalWeight = element.weight ?? 0; + } + }); + return originalWeight; + } + + CustomerTrainingPlanDetails recalculateDetailFixRepeats(int trainingPlanId, CustomerTrainingPlanDetails detail) { + TrainingPlan? plan = getTrainingPlanById(trainingPlanId); + if (plan == null) { + return detail; + } + int originalRepeats = getOriginalRepeats(trainingPlanId, detail); + + detail.weight = Common.calculateWeigthByChangedQuantity(detail.weight!, detail.repeats!.toDouble(), originalRepeats.toDouble()); + detail.weight = Common.roundWeight(detail.weight!); + print("Recalculated weight: ${detail.weight}"); + detail.repeats = originalRepeats; + return detail; + } + + CustomerTrainingPlanDetails recalculateDetailFixRepeatsSet1( + int trainingPlanId, CustomerTrainingPlanDetails detail, CustomerTrainingPlanDetails detailWithData) { + TrainingPlan? plan = getTrainingPlanById(trainingPlanId); + if (plan == null) { + return detail; + } + int originalRepeats = getOriginalRepeats(trainingPlanId, detail); + + detail.weight = Common.calculateWeigthByChangedQuantity(detailWithData.weight!, detailWithData.repeats!.toDouble(), originalRepeats.toDouble()); + detail.weight = Common.roundWeight(detail.weight!); + print("Recalculated weight: ${detail.weight}"); + detail.repeats = originalRepeats; + return detail; + } + + CustomerTrainingPlanDetails recalculateDetail(int trainingPlanId, CustomerTrainingPlanDetails detail, CustomerTrainingPlanDetails nextDetail) { + CustomerTrainingPlanDetails recalculatedDetail = nextDetail; + + // 1. get original repeats + + // 1a get original plan + TrainingPlan? plan = getTrainingPlanById(trainingPlanId); + if (plan == null) { + return recalculatedDetail; + } + + // 1.b get the original detail's repeat + int originalRepeats = detail.repeats!; + plan.details!.forEach((element) { + if (element.trainingPlanDetailId == detail.trainingPlanDetailsId) { + originalRepeats = element.repeats ?? 0; + } + }); + + // 2 get recalculated repeats + recalculatedDetail.weight = Common.calculateWeigthByChangedQuantity(detail.weight!, detail.repeats!.toDouble(), originalRepeats.toDouble()); + recalculatedDetail.weight = Common.roundWeight(recalculatedDetail.weight!); + print("recalculated repeats for $originalRepeats: ${recalculatedDetail.weight}"); + //recalculatedDetail.repeats = originalRepeats; + + return recalculatedDetail; + } + + void generateTrainingPlan() { + int? trainingPlanId; + if (Cache().userLoggedIn == null) { + return; + } + + bool isWoman = Cache().userLoggedIn!.sex == "w"; + + if (Cache().userLoggedIn!.goal == "shape_forming") { + if (Cache().userLoggedIn!.fitnessLevel == FitnessState.beginner) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("women_shape_L1") : getTrainingPlanByInternalName("man_routine1"); + } else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.intermediate) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("women_shape_L2") : getTrainingPlanByInternalName("man_routine3"); + } else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.advanced) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("women_shape_L3") : getTrainingPlanByInternalName("man_routine4"); + } else { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("women_shape_L4") : getTrainingPlanByInternalName("man_routine2"); + } + } else if (Cache().userLoggedIn!.goal == "muscle_endurance") { + if (Cache().userLoggedIn!.fitnessLevel == FitnessState.beginner) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("man_se_l1") : getTrainingPlanByInternalName("man_se_l1"); + } else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.intermediate) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("man_se_l2") : getTrainingPlanByInternalName("man_se_l2"); + } else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.advanced) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("man_se_l3") : getTrainingPlanByInternalName("man_se_l3"); + } else { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("man_se_l4") : getTrainingPlanByInternalName("man_se_l4"); + } + } else if (Cache().userLoggedIn!.goal == "gain_strength") { + if (Cache().userLoggedIn!.fitnessLevel == FitnessState.beginner) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("man_power_l1") : getTrainingPlanByInternalName("man_power_l1"); + } else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.intermediate) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("man_power_l2") : getTrainingPlanByInternalName("man_power_l2"); + } else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.advanced) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("man_power_l3") : getTrainingPlanByInternalName("man_power_l3"); + } else { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("man_power_l4") : getTrainingPlanByInternalName("man_power_l4"); + } + } else if (Cache().userLoggedIn!.goal == "gain_muscle") { + if (Cache().userLoggedIn!.fitnessLevel == FitnessState.beginner) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_beginner") : getTrainingPlanByInternalName("beginner_man"); + } else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.intermediate) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_beginner_split") : getTrainingPlanByInternalName("man_foundation"); + } else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.advanced) { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_advanced") : getTrainingPlanByInternalName("basic_mass_building"); + } else { + trainingPlanId = isWoman ? getTrainingPlanByInternalName("man_routine2") : getTrainingPlanByInternalName("mass_building"); + } + } + + print("Generated plan $trainingPlanId fitness ${Cache().userLoggedIn!.fitnessLevel} - ${FitnessState.beginner}"); + + if (trainingPlanId != null) { + CustomerTrainingPlan? customerTrainingPlan = activateTrainingPlan(trainingPlanId); + if (customerTrainingPlan != null) { + Cache().myTrainingPlan = customerTrainingPlan; + Cache().saveMyTrainingPlan(); + } + } + } +} diff --git a/lib/repository/user_repository.dart b/lib/repository/user_repository.dart new file mode 100644 index 0000000..51732fc --- /dev/null +++ b/lib/repository/user_repository.dart @@ -0,0 +1,224 @@ +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/user.dart'; +import 'package:workouttest_util/service/customer_service.dart'; +import 'package:workouttest_util/service/firebase_api.dart'; +import 'package:workouttest_util/util/logging.dart'; +import 'package:workouttest_util/util/not_found_exception.dart'; +import 'package:firebase_auth/firebase_auth.dart' as auth; + +class UserRepository with Logging { + late User user; + + UserRepository() { + this.createNewUser(); + } + + setEmail(String email) { + this.user.email = email; + } + + setPassword(String password) { + this.user.password = password; + } + + createNewUser() { + this.user = User(); + } + + Future addUser() async { + final User modelUser = this.user; + try { + String rc = await FirebaseApi().registerEmail(modelUser.email!, modelUser.password!); + if (rc == FirebaseApi.SIGN_IN_OK) { + modelUser.firebaseUid = Cache().firebaseUid; + await CustomerApi().addUser(modelUser); + } + } catch (e) { + final String message = e.toString(); + log(message); + if (message.contains("CERT_ALREADY_IN_HASH_TABLE")) { + } else { + throw new Exception(e); + } + } + } + + Future addUserFB() async { + final User modelUser = this.user; + try { + Map userData = await FirebaseApi().registerWithFacebook(); + + modelUser.email = userData['email']; + if (modelUser.email == null) { + throw new Exception("Facebook signup was not successful. Please try another method"); + } + modelUser.password = Cache().firebaseUid; + modelUser.firebaseUid = Cache().firebaseUid; + await CustomerApi().addUser(modelUser); + } on auth.FirebaseAuthException catch (e) { + if (e.code == 'email-already-in-use') { + log('The account already exists for that email.'); + throw Exception("The email address has been registered already"); + } else if (e.code == 'weak-password') { + log('The password provided is too weak.'); + throw Exception("Password too short"); + } else if (e.code == 'account-exists-with-different-credential') { + log(e.code); + throw Exception("The account exists with different credential"); + } else { + print(e.code); + throw Exception(e); + } + } on WorkoutTestException catch (ex) { + if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) { + log('The account already exists for that email.'); + throw Exception("The email address has been registered already"); + } + } on Exception catch (ex) { + log("FB exception: " + ex.toString()); + throw Exception("Facebook Sign In failed"); + } + } + + Future addUserGoogle() async { + final User modelUser = this.user; + try { + Map userData = await FirebaseApi().registerWithGoogle(); + + modelUser.email = userData['email']; + if (modelUser.email == null) { + throw new Exception("Google signup was not successful. Please try another method"); + } + modelUser.password = Cache().firebaseUid; + modelUser.firebaseUid = Cache().firebaseUid; + await CustomerApi().addUser(modelUser); + } on auth.FirebaseAuthException catch (e) { + if (e.code == 'email-already-in-use') { + log('The account already exists for that email.'); + throw Exception("The email address has been registered already"); + } else { + throw Exception(e); + } + } on WorkoutTestException catch (ex) { + if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) { + log('The account already exists for that email.'); + throw Exception("The email address has been registered already"); + } + } on Exception catch (ex) { + log("Google exception: " + ex.toString()); + throw Exception("Google Sign In failed"); + } + } + + Future addUserApple() async { + final User modelUser = this.user; + try { + Map userData = await FirebaseApi().registerWithApple(); + + modelUser.email = userData['email']; + if (modelUser.email == null) { + throw new Exception("Apple signup was not successful. Please try another method"); + } + modelUser.password = Cache().firebaseUid; + modelUser.firebaseUid = Cache().firebaseUid; + await CustomerApi().addUser(modelUser); + } on auth.FirebaseAuthException catch (e) { + if (e.code == 'email-already-in-use') { + log('The account already exists for that email.'); + throw Exception("The email address has been registered already"); + } + } on WorkoutTestException catch (ex) { + if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) { + log('The account already exists for that email.'); + throw Exception("The email address has been registered already"); + } + } on Exception catch (ex) { + log("Apple exception: " + ex.toString()); + throw Exception(ex); + } + } + + Future getUserByFB() async { + final User modelUser = this.user; + try { + Map userData = await FirebaseApi().signInWithFacebook(); + modelUser.email = userData['email']; + + await CustomerApi().getUserByEmail(modelUser.email!); + await Cache().afterFirebaseLogin(); + } /* on FacebookAuthException catch (e) { + switch (e.errorCode) { + case FacebookAuthErrorCode.OPERATION_IN_PROGRESS: + throw Exception("You have a previous Facebook login operation in progress"); + break; + case FacebookAuthErrorCode.CANCELLED: + throw Exception("Facebook login cancelled"); + break; + case FacebookAuthErrorCode.FAILED: + throw Exception("Facebook login failed"); + break; + } + } */ + on NotFoundException catch (ex) { + log("FB exception: " + ex.toString()); + throw Exception("Customer does not exist or the password is wrong"); + } on Exception catch (e) { + log(e.toString()); + throw new Exception(e); + } + } + + Future getUserByGoogle() async { + final User modelUser = this.user; + try { + Map userData = await FirebaseApi().signInWithGoogle(); + if (userData['email'] == null) { + throw new Exception("Google login was not successful"); + } + modelUser.email = userData['email']; + + await CustomerApi().getUserByEmail(modelUser.email!); + await Cache().afterFirebaseLogin(); + } on Exception catch (ex) { + log("Google exception: " + ex.toString()); + throw Exception(ex); + } + } + + Future getUserByApple() async { + final User modelUser = this.user; + Map userData = await FirebaseApi().signInWithApple(); + if (userData['email'] == null) { + throw new Exception("Apple login was not successful"); + } + modelUser.email = userData['email']; + try { + await CustomerApi().getUserByEmail(modelUser.email!); + await Cache().afterFirebaseLogin(); + } on Exception catch (ex) { + log("Apple exception: " + ex.toString()); + throw Exception("Customer does not exist or the password is wrong"); + } + } + + Future getUser() async { + final User modelUser = this.user; + String rc = await FirebaseApi().signInEmail(modelUser.email, modelUser.password); + try { + if (rc == FirebaseApi.SIGN_IN_OK) { + await CustomerApi().getUserByEmail(modelUser.email!); + await Cache().afterFirebaseLogin(); + } else { + log("Exception: user not found or password is wrong"); + throw Exception("Customer does not exist or the password is wrong"); + } + } on NotFoundException catch (_) { + throw Exception("Customer does not exist or the password is wrong"); + } + } + + Future resetPassword() async { + final User modelUser = this.user; + await FirebaseApi().resetPassword(modelUser.email!); + } +} diff --git a/lib/service/api.dart b/lib/service/api.dart new file mode 100644 index 0000000..4626267 --- /dev/null +++ b/lib/service/api.dart @@ -0,0 +1,141 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:workouttest_util/util/logging.dart'; +import 'package:workouttest_util/util/common.dart'; +import 'package:workouttest_util/util/not_found_exception.dart'; +import 'package:flutter/services.dart'; +import 'package:workouttest_util/model/cache.dart'; + +class APIClient with Common, Logging { + static final APIClient _singleton = APIClient._internal(); + late bool cert; + + factory APIClient() { + return _singleton; + } + + APIClient._internal() { + cert = false; + } + + dynamic authenticateUser(String email, String password) async { + var url = Cache().getBaseUrl() + "authenticate"; + + try { + ByteData data = await rootBundle.load('asset/data/aitrainer_server.crt.pem'); + SecurityContext context = SecurityContext.defaultContext; + if (cert == false) { + print("Set CERT $cert"); + context.setTrustedCertificatesBytes(data.buffer.asUint8List(), password: "[xxxx]"); + cert = true; + } + + HttpClient client = new HttpClient(); //context: context Todo provide the right certificate + client.badCertificateCallback = ((X509Certificate cert, String host, int port) { + print("Host: $host Port: $port"); + return true; + }); + var uri = Uri.parse(url); + final HttpClientRequest request = await client.postUrl(uri); + request.headers.set('Content-Type', 'application/json'); + request.headers.set('Authorization', '1'); + + final body = '{"username":"$email", "password":"$password"}'; + request.write(body); + HttpClientResponse result = await request.close(); + client.close(); + if (result.statusCode != 200) { + trace("authentication response: ${result.statusCode} with URL: $url"); + throw Exception("Authentication error: ${result.statusCode}"); + } + return jsonDecode(await result.transform(utf8.decoder).join()); + } catch (exception) { + print(exception.toString()); + try { + await Sentry.captureException(exception); + } on Exception catch (e) { + print(e); + } + + throw Exception("Network error, try again later!"); + } + } + + Future post(String endPoint, String body) async { + final url = Cache().getBaseUrl() + endPoint; + trace(" ------------ http/post body $body - url: $url "); + try { + String authToken = Cache().getAuthToken(); + if (authToken.length == 0) { + var responseJson = await this.authenticateUser(Cache.username, Cache.password); + authToken = responseJson['token']; + Cache().authToken = authToken; + } + var uri = Uri.parse(url); + HttpClient client = new HttpClient(); + + client.badCertificateCallback = ((X509Certificate cert, String host, int port) => true); + + final HttpClientRequest request = await client.postUrl(uri); + request.headers.contentType = new ContentType("application", "json", charset: "utf-8"); + request.headers.set('Authorization', 'Bearer $authToken'); + //request.contentLength = body.length; + request.write(body); + HttpClientResponse result = await request.close(); + client.close(); + trace(" ------------post response code: " + result.statusCode.toString()); + if (result.statusCode == 200) { + return await result.transform(utf8.decoder).join(); + } else if (result.statusCode == 404) { + throw NotFoundException(message: "Not Found"); + } else { + throw Exception("Network Error, please try again later"); + } + } on NotFoundException catch(e) { + throw NotFoundException(message: "Not Found"); + } on Exception catch (e) { + print("Post Exception: $e"); + await Sentry.captureException(e); + throw Exception("Network Error, please try again later"); + } + } + + Future get(String endPoint, String param) async { + final url = Cache().getBaseUrl() + endPoint + param; + try { + trace("-------- API get " + url); + String authToken = Cache().getAuthToken(); + if (authToken.length == 0) { + var responseJson = await this.authenticateUser(Cache.username, Cache.password); + authToken = responseJson['token']; + Cache().authToken = authToken; + } + var uri = Uri.parse(url); + + HttpClient client = new HttpClient(); + + client.badCertificateCallback = ((X509Certificate cert, String host, int port) => true); + + final HttpClientRequest request = await client.getUrl(uri); + request.headers.set('Content-Type', 'application/json'); + request.headers.set('Authorization', 'Bearer $authToken'); + HttpClientResponse result = await request.close(); + client.close(); + trace(" ------------get response code: " + result.statusCode.toString()); + if (result.statusCode == 200) { + return await result.transform(utf8.decoder).join(); + } else if (result.statusCode == 404) { + throw NotFoundException(message: "Not Found"); + } else { + throw Exception("Network Error, please try again later"); + } + } on NotFoundException catch(e) { + throw NotFoundException(message: "Not Found"); + } on Exception catch (e) { + print("Post Exception: $e"); + await Sentry.captureException(e); + throw Exception("Network Error, please try again later"); + } + } +} diff --git a/lib/service/customer_exercise_device_service.dart b/lib/service/customer_exercise_device_service.dart new file mode 100644 index 0000000..58f390a --- /dev/null +++ b/lib/service/customer_exercise_device_service.dart @@ -0,0 +1,47 @@ +import 'package:workouttest_util/model/customer_exercise_device.dart'; +import 'package:workouttest_util/util/logging.dart'; +import 'package:workouttest_util/util/not_found_exception.dart'; +import 'dart:convert'; + +import 'api.dart'; + +class CustomerExerciseDeviceApi with Logging { + final APIClient _client = APIClient(); + + Future> getDevices(int customerId) async { + List devices = []; + try { + log(" --- get customer_exercise_devices: "); + final body = await _client.get("customer_exercise_device/customer/" + customerId.toString(), ""); + final Iterable json = jsonDecode(body); + devices = json.map((device) => CustomerExerciseDevice.fromJson(device)).toList(); + } on NotFoundException catch (_) { + log("No devices found"); + devices = []; + } + return devices; + } + + Future addDevice(CustomerExerciseDevice device) async { + CustomerExerciseDevice savedDevice; + try { + final String body = JsonEncoder().convert(device.toJson()); + log(" --- add customer_exercise_device: " + body); + final String responseBody = await _client.post("customer_exercise_device", body); + savedDevice = CustomerExerciseDevice.fromJson(jsonDecode(responseBody)); + } on Exception catch (e) { + throw new Exception(e.toString()); + } + return savedDevice; + } + + Future removeDevice(int id) async { + try { + log(" --- delete customer_exercise_device: " + id.toString()); + await _client.post("customer_exercise_device/delete/" + id.toString(), ""); + } on Exception catch (e) { + throw new Exception(e.toString()); + } + return; + } +} diff --git a/lib/service/customer_service.dart b/lib/service/customer_service.dart new file mode 100644 index 0000000..68d72a6 --- /dev/null +++ b/lib/service/customer_service.dart @@ -0,0 +1,240 @@ +import 'dart:collection'; +import 'dart:convert'; +import 'package:workouttest_util/model/customer.dart'; +import 'package:workouttest_util/model/customer_property.dart'; +import 'package:workouttest_util/model/property.dart'; +import 'package:workouttest_util/model/user.dart'; +import 'package:workouttest_util/service/api.dart'; +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/util/logging.dart'; +import 'package:workouttest_util/util/not_found_exception.dart'; + +class CustomerApi with Logging { + final APIClient _client = APIClient(); + + Future> getRealCustomers(String param) async { + final body = await _client.get("customers/", param); + final Iterable json = jsonDecode(body); + final List customers = json.map((customer) => Customer.fromJson(customer)).toList(); + + return customers; + } + + Future saveCustomer(Customer customer) async { + customer.dateChange = DateTime.now(); + String body = JsonEncoder().convert(customer.toJson()); + log(" ===== saving customer id: " + customer.customerId.toString() + ":" + body); + await _client.post("customers/" + customer.customerId.toString(), body); + } + + Future updateFirebaseUid(int customerId, String uid) async { + log(" ===== update Firebase uid : " + customerId.toString() + ": " + uid); + await _client.post("customers/update_firebase_uid/" + customerId.toString(), uid); + } + + Future deactivateCustomer(int customerId) async { + log(" ===== deactivate : $customerId"); + await _client.post("customers/deactivate/$customerId", ""); + } + + Future addCustomer(Customer customer) async { + customer.dateAdd = DateTime.now(); + customer.dateChange = DateTime.now(); + String body = JsonEncoder().convert(customer.toJson()); + log(" ===== add new customer: " + body); + await _client.post("customers", body); + } + + Future addUser(User user) async { + String body = JsonEncoder().convert(user.toJson()); + log(" ===== add new user: " + body); + final String responseBody = await _client.post("registration", body); + Customer customer; + try { + int? status = jsonDecode(responseBody)['status']; + if (status != null) { + String error = jsonDecode(responseBody)['error']; + throw new Exception(error); + } else { + customer = Customer.fromJson(jsonDecode(responseBody)); + await Cache().afterRegistration(customer); + } + } on FormatException { + if (responseBody == "Customer exists") { + throw WorkoutTestException(code: WorkoutTestException.CUSTOMER_EXISTS, message: responseBody); + } + throw new Exception(responseBody); + } + } + + Future getUser(User user) async { + String body = JsonEncoder().convert(user.toJson()); + log(" ===== login the user: " + body); + final String responseBody = await _client.post("login", body); + Customer customer; + try { + customer = Customer.fromJson(jsonDecode(responseBody)); + await Cache().afterLogin(customer); + } on FormatException { + throw new Exception(responseBody); + } + } + + Future getUserByEmail(String email) async { + log(" ===== User getByEmail : " + email); + final String responseBody = await _client.get("customers/find_by_email/" + email, ""); + Customer customer; + try { + customer = Customer.fromJson(jsonDecode(responseBody)); + if (customer.firebaseUid == null) { + await this.updateFirebaseUid(customer.customerId!, Cache().firebaseUid!); + } + Cache().userLoggedIn = customer; + final List? properties = await this.getActualProperties(customer.customerId!); + if (properties != null) { + this.initProperties(properties); + } + } on FormatException { + throw new Exception(responseBody); + } + } + + Future getCustomer(int customerId) async { + String body = ""; + log(" ===== get the customer by id: " + customerId.toString()); + try { + final String responseBody = await _client.get("customers/" + customerId.toString(), body); + Customer customer = Customer.fromJson(jsonDecode(responseBody)); + log(" --- Customer: " + customer.toJson().toString()); + Cache().userLoggedIn = customer; + final List? properties = await this.getActualProperties(customerId); + //log(" ---- Props: " + properties.toJson().toString()); + //await Cache().initCustomer(customerId); + if (properties != null) { + this.initProperties(properties); + } + } on Exception catch (exception) { + log("Exception: " + exception.toString()); + log(" === go to registration "); + Cache().logout(); + Cache().startPage = "registration"; + } + } + + void initProperties(final List? customerProperties) { + List? properties = Cache().getProperties(); + Customer customer = Cache().userLoggedIn!; + customer.properties = LinkedHashMap(); + + if (properties != null) { + // reset Properties + properties.forEach((property) { + CustomerProperty customerProperty = + CustomerProperty(propertyId: property.propertyId, customerId: customer.customerId!, dateAdd: DateTime.now(), propertyValue: 0); + customer.properties[property.propertyName] = customerProperty; + }); + + customerProperties!.forEach((customerProperty) { + properties.forEach((property) { + if (customerProperty.propertyId == property.propertyId) { + customer.properties[property.propertyName] = customerProperty; + } + }); + }); + } + } + + Future getTrainee(int customerId) async { + String body = ""; + Customer customer; + log(" ===== get Trainee customer by id: " + customerId.toString()); + try { + final String responseBody = await _client.get("customers/" + customerId.toString(), body); + customer = Customer.fromJson(jsonDecode(responseBody)); + log(" --- Trainee: " + customer.toJson().toString()); + } catch (exception) { + log("Exception: " + exception.toString()); + throw Exception(exception); + } + return customer; + } + + Future> getTrainees(int trainerId) async { + List trainees = []; + log("Get trainees list"); + try { + String body = ""; + final String responseBody = await _client.get("customers/trainees/" + trainerId.toString(), body); + final Iterable json = jsonDecode(responseBody); + trainees = json.map((customer) => Customer.fromJson(customer)).toList(); + } catch (exception) { + log("Exception: " + exception.toString()); + throw Exception(exception); + } + return trainees; + } + + Future> getAllProperties(int customerId) async { + final body = await _client.get("customer_property/", customerId.toString()); + final Iterable json = jsonDecode(body); + final List properties = json.map((property) => CustomerProperty.fromJson(property)).toList(); + + return properties; + } + + Future?> getActualProperties(int customerId) async { + List? properties; + try { + final body = await _client.get("customer_property/last/", customerId.toString()); + final Iterable json = jsonDecode(body); + properties = json.map((property) => CustomerProperty.fromJson(property)).toList(); + } on Exception catch (ex) { + log(ex.toString()); + } + return properties; + } + + Future addProperty(CustomerProperty property) async { + String body = JsonEncoder().convert(property.toJson()); + log(" ===== add new customer property: " + body); + CustomerProperty customerProperty; + String? responseBody; + try { + responseBody = await _client.post("customer_property", body); + log(" responseBody: " + responseBody); + int? status = jsonDecode(responseBody)['status']; + if (status != null) { + throw new Exception(jsonDecode(responseBody)['error']); + } else { + customerProperty = CustomerProperty.fromJson(jsonDecode(responseBody)); + } + } on FormatException { + throw new Exception(responseBody); + } on Exception catch (e) { + throw new Exception(e); + } + return customerProperty; + } + + Future updateProperty(CustomerProperty property) async { + String body = JsonEncoder().convert(property.toJson()); + CustomerProperty? customerProperty; + log(" ===== update customer property: " + body); + String? responseBody; + try { + responseBody = await _client.post("customer_property/update/" + property.customerPropertyId.toString(), body); + log(" responseBody: " + responseBody); + int? status = jsonDecode(responseBody)['status']; + if (status != null) { + throw new Exception(jsonDecode(responseBody)['error']); + } else { + customerProperty = CustomerProperty.fromJson(jsonDecode(responseBody)); + } + } on FormatException { + throw new Exception(responseBody); + } on Exception catch (e) { + throw new Exception(e); + } + return customerProperty; + } +} diff --git a/lib/service/exercise_device_service.dart b/lib/service/exercise_device_service.dart new file mode 100644 index 0000000..bab29b9 --- /dev/null +++ b/lib/service/exercise_device_service.dart @@ -0,0 +1,17 @@ +import 'package:workouttest_util/model/cache.dart'; +import 'dart:convert'; +import 'package:workouttest_util/model/exercise_device.dart'; + +import 'api.dart'; + +class ExerciseDeviceApi { + final APIClient _client = APIClient(); + + Future> getDevices() async { + final body = await _client.get("exercise_device/", ""); + final Iterable json = jsonDecode(body); + final List devices = json.map((device) => ExerciseDevice.fromJson(device)).toList(); + Cache().setDevices(devices); + return devices; + } +} diff --git a/lib/service/exercise_service.dart b/lib/service/exercise_service.dart new file mode 100644 index 0000000..2e8c8f3 --- /dev/null +++ b/lib/service/exercise_service.dart @@ -0,0 +1,44 @@ +import 'dart:convert'; +import 'package:workouttest_util/model/exercise.dart'; +import 'package:workouttest_util/service/api.dart'; +import 'package:workouttest_util/util/logging.dart'; + +class ExerciseApi with Logging { + final APIClient _client = APIClient(); + + Future saveExercise(Exercise exercise) async { + String body = JsonEncoder().convert(exercise.toJson()); + log(" ===== saving exercise id: " + exercise.exerciseId.toString() + ":" + body); + await _client.post("exercises/" + exercise.exerciseId.toString(), body); + } + + Future> getExercisesByCustomer(int customerId) async { + final body = await _client.get("exercises/customer/", customerId.toString()); + final Iterable json = jsonDecode(body); + final List exercises = json.map((exercise) { + Exercise item = Exercise.fromJson(exercise); + return item; + }).toList(); + //exercises.sort( (a, b) => b.dateAdd.compareTo(a.dateAdd) ); + + return exercises; + } + + Future addExercise(Exercise exercise) async { + String body = JsonEncoder().convert(exercise.toJson()); + log(" ===== add new exercise: " + body); + final String response = await _client.post("exercises", body); + final Exercise savedExercise = Exercise.fromJson(jsonDecode(response)); + return savedExercise; + } + + Future deleteExercise(Exercise exercise) async { + if (exercise.exerciseId == null) { + return; + } + int exerciseId = exercise.exerciseId!; + log(" ===== delete exercise: " + exerciseId.toString()); + await _client.post("exercises/" + exerciseId.toString(), ""); + return; + } +} diff --git a/lib/service/exercise_tree_service.dart b/lib/service/exercise_tree_service.dart new file mode 100644 index 0000000..d554eac --- /dev/null +++ b/lib/service/exercise_tree_service.dart @@ -0,0 +1,82 @@ +import 'dart:convert'; + +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/exercise_tree.dart'; +import 'package:workouttest_util/model/exercise_tree_parents.dart'; +import 'package:workouttest_util/util/logging.dart'; +import 'package:flutter/services.dart'; +import 'api.dart'; + +class ExerciseTreeApi with Logging { + final APIClient _client = APIClient(); + + Future> getExerciseTree() async { + final String body = await _client.get("exercise_tree", ""); + Iterable json = jsonDecode(body); + List? exerciseTrees = json.map((exerciseTree) => ExerciseTree.fromJson(exerciseTree)).toList(); + + exerciseTrees = await getExerciseTreeParents(exerciseTrees); + + await Future.forEach(exerciseTrees, (element) async { + ExerciseTree exerciseTree = element as ExerciseTree; + exerciseTree.imageUrl = await buildImage(exerciseTree.imageUrl, exerciseTree.treeId); + }); + exerciseTrees = await getExerciseTreeParents(exerciseTrees); + log("ExerciseTree downloaded $exerciseTrees"); + Cache().setExerciseTree(exerciseTrees); + + return exerciseTrees; + } + + Future buildImage(String imageUrl, int treeId) async { + String assetImage = 'asset/menu/' + imageUrl.substring(7); + print("asset image $assetImage"); + return await rootBundle.load(assetImage).then((value) { + return assetImage; + }).catchError((_) { + String imagePath = assetImage.substring(10); + String url = Cache.mediaUrl + 'images' + imagePath; + return url; + }); + } + + Future> getExerciseTreeParents(List exerciseTree) async { + List copyList = this.copyList(exerciseTree); + + final String body = await _client.get("exercise_tree_parents", ""); + Iterable json = jsonDecode(body); + final List exerciseTreeParents = + json.map((exerciseTreeParent) => ExerciseTreeParents.fromJson(exerciseTreeParent)).toList(); + + int treeIndex = 0; + copyList.forEach((element) async { + int index = 0; + exerciseTreeParents.forEach((parent) { + if (parent.exerciseTreeChildId == element.treeId) { + if (index > 0) { + ExerciseTree newElement = element.copy(parent.exerciseTreeParentId); + newElement.sort = parent.sort; + exerciseTree.add(newElement); + } else { + element.parentId = parent.exerciseTreeParentId; + element.sort = parent.sort; + exerciseTree[treeIndex].parentId = parent.exerciseTreeParentId; + } + index++; + } + }); + treeIndex++; + }); + return exerciseTree; + } + + List copyList(List tree) { + final List copyList = []; + tree.forEach((element) { + final ExerciseTree copy = element.copy(-1); + copyList.add(copy); + }); + + return copyList; + } +} diff --git a/lib/service/exercise_type_service.dart b/lib/service/exercise_type_service.dart new file mode 100644 index 0000000..3348692 --- /dev/null +++ b/lib/service/exercise_type_service.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/exercise_type.dart'; +import 'package:workouttest_util/service/api.dart'; +import 'package:workouttest_util/util/logging.dart'; +import 'package:flutter/services.dart'; + +class ExerciseTypeApi with Logging { + final APIClient _client = APIClient(); + + Future> getExerciseTypes() async { + final body = await _client.get("exercise_type", ""); + final Iterable json = jsonDecode(body); + final List exerciseTypes = json.map((exerciseType) => ExerciseType.fromJson(exerciseType)).toList(); + + await Future.forEach(exerciseTypes, (element) async { + ExerciseType exerciseType = element as ExerciseType; + exerciseType.imageUrl = await buildImage(exerciseType.imageUrl, exerciseType.exerciseTypeId); + }); + log("ExerciseTypes downloaded"); + Cache().setExerciseTypes(exerciseTypes); + + return exerciseTypes; + } + + Future buildImage(String imageUrl, int exerciseTypeId) async { + if (imageUrl.length > 8) { + String assetImage = 'asset/menu/' + imageUrl.substring(7); + return rootBundle.load(assetImage).then((value) { + return assetImage; + }).catchError((_) { + String imagePath = assetImage.substring(10); + String url = Cache.mediaUrl + 'images' + imagePath; + return url; + }); + } else { + return imageUrl; + } + } +} diff --git a/lib/service/firebase_api.dart b/lib/service/firebase_api.dart new file mode 100644 index 0000000..144997f --- /dev/null +++ b/lib/service/firebase_api.dart @@ -0,0 +1,403 @@ +import 'dart:math' as math; +import 'dart:convert'; +// ignore: depend_on_referenced_packages +import 'package:crypto/crypto.dart'; +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/util/logging.dart' as logger; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sign_in_with_apple/sign_in_with_apple.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +// ignore: depend_on_referenced_packages +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:firebase_remote_config/firebase_remote_config.dart'; +import 'package:flutter_facebook_auth/flutter_facebook_auth.dart'; +import 'package:google_sign_in/google_sign_in.dart'; + +class FirebaseApi with logger.Logging { + bool appleSignInAvailable = false; + + static final FirebaseAuth auth = FirebaseAuth.instance; + + static const String SIGN_IN_OK = "OK"; + static const String SIGN_IN_NOT_FOUND = "user-not-found"; + static const String SIGN_IN_WRONG_PWD = "wrong-password"; + static const String REGISTER_WEAK_PWD = "weak-password"; + static const String REGISTER_EMAIL_IN_USE = "email-already-in-use"; + + late UserCredential userCredential; + String? firebaseRegToken; + + factory FirebaseApi() => FirebaseApi._internal(); + + FirebaseApi._internal(); + + // Define an async function to initialize FlutterFire + Future initializeFlutterFire() async { + try { + // Wait for Firebase to initialize and set `_initialized` state to true + await Firebase.initializeApp(); + + this.appleSignInAvailable = await SignInWithApple.isAvailable(); + + + await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( + alert: true, // Required to display a heads up notification + badge: true, + sound: true, + ); + this.firebaseRegToken = await FirebaseMessaging.instance.getToken(); + Cache().firebaseMessageToken = firebaseRegToken; + log("FirebaseMessaging token $firebaseRegToken"); + + FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); + FirebaseMessaging.onMessage.listen((RemoteMessage message) { + print('Got a message whilst in the foreground!'); + print('Message data: ${message.data}'); + + if (message.notification != null) { + print('Message also contained a notification: ${message.notification}'); + } + }); + } catch (e) { + // Set `_error` state to true if Firebase initialization fails + Sentry.captureException(e); + log("Error initializing Firebase"); + } + } + + Future signInEmail(String? email, String? password) async { + if (email == null) { + throw Exception("Please type an email address"); + } + if (password == null) { + throw Exception("Password too short"); + } + String rc = SIGN_IN_OK; + try { + userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(email: email, password: password); + Cache().firebaseUid = userCredential.user!.uid; + } on FirebaseAuthException catch (e) { + Sentry.captureException(e); + if (e.code == 'user-not-found') { + log('No user found for that email.'); + rc = SIGN_IN_NOT_FOUND; + } else if (e.code == 'wrong-password') { + log('Wrong password provided for that user.'); + rc = SIGN_IN_WRONG_PWD; + throw Exception("Customer does not exist or the password is wrong"); + } + return e.code; + } + return rc; + } + + Future registerEmail(String email, String password) async { + String rc = SIGN_IN_OK; + try { + userCredential = await FirebaseAuth.instance.createUserWithEmailAndPassword(email: email, password: password); + Cache().firebaseUid = userCredential.user!.uid; + } on FirebaseAuthException catch (e) { + Sentry.captureException(e); + if (e.code == 'weak-password') { + log('The password provided is too weak.'); + rc = REGISTER_WEAK_PWD; + throw Exception("Password too short"); + } else if (e.code == 'email-already-in-use') { + log('The account already exists for that email.'); + rc = REGISTER_EMAIL_IN_USE; + throw Exception("The email address has been registered already"); + } + } catch (e) { + log(e.toString()); + Sentry.captureException(e); + throw Exception(e.toString()); + } + return rc; + } + + String generateNonce([int length = 32]) { + final charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._'; + final random = math.Random.secure(); + return List.generate(length, (_) => charset[random.nextInt(charset.length)]).join(); + } + + /// Returns the sha256 hash of [input] in hex notation. + String sha256ofString(String input) { + final bytes = utf8.encode(input); + final digest = sha256.convert(bytes); + return digest.toString(); + } + + Future> signInWithApple() async { + Map userData = Map(); + + // To prevent replay attacks with the credential returned from Apple, we + // include a nonce in the credential request. When signing in with + // Firebase, the nonce in the id token returned by Apple, is expected to + // match the sha256 hash of `rawNonce`. + final rawNonce = generateNonce(); + final nonce = sha256ofString(rawNonce); + + // Request credential for the currently signed in Apple account. + final appleCredential = await SignInWithApple.getAppleIDCredential( + scopes: [ + AppleIDAuthorizationScopes.email, + AppleIDAuthorizationScopes.fullName, + ], + nonce: nonce, + ); + + // Create an `OAuthCredential` from the credential returned by Apple. + final oauthCredential = OAuthProvider("apple.com").credential( + idToken: appleCredential.identityToken, + rawNonce: rawNonce, + ); + UserCredential? userCredential; + try { + // Sign in the user with Firebase. If the nonce we generated earlier does + // not match the nonce in `appleCredential.identityToken`, sign in will fail. + userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential); + } on FirebaseAuthException catch(e) { + Sentry.captureException(e); + throw Exception(e); + } + Cache().firebaseUid = userCredential.user!.uid; + log("userCredential: " + userCredential.toString()); + + log("Apple Credentials: ${appleCredential.userIdentifier} state ${appleCredential.state} email ${userCredential.user!.email!}"); + userData['email'] = userCredential.user!.email; + + return userData; + } + + Future> registerWithApple() async { + Map userData = Map(); + + final rawNonce = generateNonce(); + final nonce = sha256ofString(rawNonce); + + // Request credential for the currently signed in Apple account. + final appleCredential = await SignInWithApple.getAppleIDCredential( + scopes: [ + AppleIDAuthorizationScopes.email, + AppleIDAuthorizationScopes.fullName, + ], + nonce: nonce, + ); + + final oauthCredential = OAuthProvider("apple.com").credential( + idToken: appleCredential.identityToken, + rawNonce: rawNonce, + ); + + UserCredential? userCredential; + try { + // Sign in the user with Firebase. If the nonce we generated earlier does + // not match the nonce in `appleCredential.identityToken`, sign in will fail. + userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential); + } on FirebaseAuthException catch(e) { + Sentry.captureException(e); + throw Exception(e); + } + + Cache().firebaseUid = userCredential.user!.uid; + + userData['email'] = userCredential.user!.email; + + return userData; + } + + Future> signInWithGoogle() async { + Map userData = Map(); + + // Trigger the authentication flow + GoogleSignIn _googleSignIn = GoogleSignIn( + scopes: [ + 'email', + 'https://www.googleapis.com/auth/contacts.readonly', + ], + ); + final GoogleSignInAccount? googleUser = await _googleSignIn.signIn(); + + if (googleUser == null) { + Sentry.captureException(new Exception("Google Sign In failed")); + throw Exception("Google Sign In failed"); + } + + // Obtain the auth details from the request + final GoogleSignInAuthentication googleAuth = await googleUser.authentication; + + // Create a new credential + final OAuthCredential credential = GoogleAuthProvider.credential( + accessToken: googleAuth.accessToken, + idToken: googleAuth.idToken, + ); + + UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(credential); + Cache().firebaseUid = userCredential.user!.uid; + + log("GoogleUser: " + googleUser.toString()); + userData['email'] = googleUser.email; + userData['id'] = googleUser.id; + userData['name'] = googleUser.displayName; + + return userData; + } + + Future> registerWithGoogle() async { + Map userData = Map(); + + // Trigger the authentication flow + GoogleSignIn _googleSignIn = GoogleSignIn( + scopes: [ + 'email', + 'https://www.googleapis.com/auth/contacts.readonly', + ], + ); + final GoogleSignInAccount? googleUser = await _googleSignIn.signIn(); + + if (googleUser == null) { + Sentry.captureException(new Exception("Google Sign In failed")); + throw Exception("Google Sign In failed"); + } + + // Obtain the auth details from the request + final GoogleSignInAuthentication googleAuth = await googleUser.authentication; + + // Create a new credential + final OAuthCredential credential = GoogleAuthProvider.credential( + accessToken: googleAuth.accessToken, + idToken: googleAuth.idToken, + ); + + final userCredential = await FirebaseAuth.instance.signInWithCredential(credential); + + log("Google credentials: " + credential.toString() + " GoogleUser: " + googleUser.toString()); + Cache().firebaseUid = userCredential.user!.uid; + + userData['email'] = googleUser.email; + + return userData; + } + + Future> signInWithFacebook() async { + Map userData; + + // by default the login method has the next permissions ['email','public_profile'] + final LoginResult result = await FacebookAuth.instance.login(); + if (result.status == LoginStatus.success) { + final AccessToken accessToken = result.accessToken!; + log(accessToken.toJson().toString()); + Cache().accessTokenFacebook = accessToken; + // get the user data + userData = await FacebookAuth.instance.getUserData(); + Cache().firebaseUid = userData['id']; + log(userData.toString()); + } else { + Sentry.captureException(new Exception(result.message)); + throw Exception("Facebook login was not successful"); + } + + return userData; + } + + Future> registerWithFacebook() async { + Map userData; + + // by default the login method has the next permissions ['email','public_profile'] + final LoginResult result = await FacebookAuth.instance.login(); + if (result.status == LoginStatus.success) { + final AccessToken accessToken = result.accessToken!; + Cache().accessTokenFacebook = accessToken; + // get the user data + userData = await FacebookAuth.instance.getUserData(); + log("FB user data: " + userData.toString()); + + // Create a credential from the access token + final OAuthCredential facebookAuthCredential = FacebookAuthProvider.credential(accessToken.token); + + // Once signed in, return the UserCredential + final userCredential = await FirebaseAuth.instance.signInWithCredential(facebookAuthCredential); + log("Email by FB: " + userData['email'] + " FB credential: " + userCredential.toString()); + + Cache().firebaseUid = userCredential.user!.uid; + } else { + Sentry.captureException(new Exception(result.message)); + throw Exception("Facebook login was not successful"); + } + + return userData; + } + + Future logOutFacebook() async { + await FacebookAuth.instance.logOut(); + Cache().accessTokenFacebook = null; + } + + Future signOut() async { + await FirebaseAuth.instance.signOut(); + } + + Future resetPassword(String email) async { + await FirebaseAuth.instance.sendPasswordResetEmail(email: email); + } + + Future setupRemoteConfig() async { + //initializeFlutterFire(); + FirebaseRemoteConfig? remoteConfig; + try { + remoteConfig = FirebaseRemoteConfig.instance; + await remoteConfig.setConfigSettings(RemoteConfigSettings( + fetchTimeout: const Duration(seconds: 10), + minimumFetchInterval: const Duration(seconds: 1), + )); + + //RemoteConfigValue(null, ValueSource.valueStatic); + //Cache().setRemoteConfig(remoteConfig); + } on Exception catch (e) { + print('Unable to fetch remote config. Cached or default values will be used: $e'); + if (remoteConfig != null) { + await remoteConfig.setDefaults({ + 'sales_page_text_a': '', + 'product_set_2': '', + 'registration_skip_color': '', + 'email_checkbox': '', + }); + Cache().setRemoteConfig(remoteConfig); + } + } + } +} + +Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { + // If you're going to use other Firebase services in the background, such as Firestore, + // make sure you call `initializeApp` before using other Firebase services. + print('Handling a background message ${message.messageId}'); +} + +/* Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { + print('Handling a background message: ${message.messageId}'); + + if (!StringUtils.isNullOrEmpty(message.notification?.title, considerWhiteSpaceAsEmpty: true) || + !StringUtils.isNullOrEmpty(message.notification?.body, considerWhiteSpaceAsEmpty: true)) { + print('message also contained a notification: ${message.notification}'); + + String? imageUrl; + imageUrl ??= message.notification!.android?.imageUrl; + imageUrl ??= message.notification!.apple?.imageUrl; + + Map notificationAdapter = { + NOTIFICATION_CHANNEL_KEY: 'basic_channel', + NOTIFICATION_ID: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_ID] ?? message.messageId ?? math.Random().nextInt(2147483647), + NOTIFICATION_TITLE: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_TITLE] ?? message.notification?.title, + NOTIFICATION_BODY: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_BODY] ?? message.notification?.body, + NOTIFICATION_LAYOUT: StringUtils.isNullOrEmpty(imageUrl) ? 'Default' : 'BigPicture', + NOTIFICATION_BIG_PICTURE: imageUrl + }; + + AwesomeNotifications().createNotificationFromJsonData(notificationAdapter); + } else { + AwesomeNotifications().createNotificationFromJsonData(message.data); + } +} */ diff --git a/lib/service/mautic.dart b/lib/service/mautic.dart new file mode 100644 index 0000000..f887c64 --- /dev/null +++ b/lib/service/mautic.dart @@ -0,0 +1,29 @@ +import 'dart:io'; + +import 'package:workouttest_util/model/mautic.dart'; +import 'package:workouttest_util/util/logging.dart'; + +class MauticApi with Logging { + final String mauticUrl = "https://mautic.workouttest.org/form/submit?formId="; + + Future sendMauticForm(Mautic model) async { + final String body = model.toForm(); + log(" ===== mautic subscription: $body"); + HttpClient client = HttpClient(); + + String url = mauticUrl + model.formId.toString(); + + var uri = Uri.parse(url); + final HttpClientRequest request = await client.postUrl(uri); + request.headers.set('Content-Type', 'application/x-www-form-urlencoded'); + request.headers.set('cache-control', 'no-cache'); + + request.write(body); + HttpClientResponse result = await request.close(); + client.close(); + if (!(result.statusCode == 200 || result.statusCode == 302)) { + trace("mautic response: ${result.statusCode}"); + //throw Exception("Network error, try again later!"); + } + } +} diff --git a/lib/service/package_service.dart b/lib/service/package_service.dart new file mode 100644 index 0000000..1e09641 --- /dev/null +++ b/lib/service/package_service.dart @@ -0,0 +1,210 @@ +import 'dart:convert'; + +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/customer.dart'; +import 'package:workouttest_util/model/customer_activity.dart'; +import 'package:workouttest_util/model/customer_exercise_device.dart'; +import 'package:workouttest_util/model/customer_property.dart'; +import 'package:workouttest_util/model/description.dart'; +import 'package:workouttest_util/model/evaluation.dart'; +import 'package:workouttest_util/model/exercise.dart'; +import 'package:workouttest_util/model/exercise_device.dart'; +import 'package:workouttest_util/model/exercise_plan_template.dart'; +import 'package:workouttest_util/model/exercise_tree.dart'; +import 'package:workouttest_util/model/exercise_tree_parents.dart'; +import 'package:workouttest_util/model/exercise_type.dart'; +import 'package:workouttest_util/model/faq.dart'; +import 'package:workouttest_util/model/product.dart'; +import 'package:workouttest_util/model/property.dart'; +import 'package:workouttest_util/model/purchase.dart'; +import 'package:workouttest_util/model/split_test.dart'; +import 'package:workouttest_util/model/training_plan.dart'; +import 'package:workouttest_util/model/training_plan_day.dart'; +import 'package:workouttest_util/model/tutorial.dart'; +import 'package:workouttest_util/repository/training_plan_day_repository.dart'; +import 'package:workouttest_util/service/api.dart'; +import 'package:workouttest_util/service/exercise_type_service.dart'; +import 'package:workouttest_util/util/not_found_exception.dart'; + +import '../model/sport.dart'; +import 'customer_service.dart'; +import 'exercise_tree_service.dart'; + +class PackageApi { + final APIClient _client = APIClient(); + + Future getPackage() async { + late List exerciseTree; + late List exerciseTreeParents; + final body = await _client.get("app_package/", ""); + + final List models = body.split("|||"); + await Future.forEach(models, (elem) async { + final String element = elem as String; + final List headRecord = element.split("***"); + final Iterable json = jsonDecode(headRecord[1]); + if (headRecord[0] == "ExerciseDevice") { + final List devices = json.map((device) => ExerciseDevice.fromJson(device)).toList(); + Cache().setDevices(devices); + } else if (headRecord[0] == "Product") { + final List products = json.map((product) => Product.fromJson(product)).toList(); + Cache().setProducts(products); + } else if (headRecord[0] == "Property") { + final List properties = json.map((property) => Property.fromJson(property)).toList(); + Cache().setProperties(properties); + } else if (headRecord[0] == "ExerciseTree") { + exerciseTree = json.map((exerciseTree) => ExerciseTree.fromJson(exerciseTree)).toList(); + } else if (headRecord[0] == "ExerciseType") { + final List exerciseTypes = json.map((exerciseType) => ExerciseType.fromJson(exerciseType)).toList(); + await Future.forEach(exerciseTypes, (elem) async { + final ExerciseType exerciseType = elem as ExerciseType; + exerciseType.imageUrl = await ExerciseTypeApi().buildImage(exerciseType.imageUrl, exerciseType.exerciseTypeId); + }); + Cache().setExerciseTypes(exerciseTypes); + } else if (headRecord[0] == "ExerciseAbility") { + } else if (headRecord[0] == "ExercisePlanTemplate") { + final List exercisePlanTemplates = + json.map((exercisePlanTemplate) => ExercisePlanTemplate.fromJson(exercisePlanTemplate)).toList(); + Cache().setExercisePlanTemplates(exercisePlanTemplates); + } else if (headRecord[0] == "ExerciseTreeParents") { + exerciseTreeParents = json.map((exerciseTreeParent) => ExerciseTreeParents.fromJson(exerciseTreeParent)).toList(); + } else if (headRecord[0] == "Evaluation") { + final List evaluations = json.map((evaluation) => Evaluation.fromJson(evaluation)).toList(); + Cache().evaluations = evaluations; + } else if (headRecord[0] == "Sport") { + final List sports = json.map((sport) => Sport.fromJson(sport)).toList(); + Cache().setSports(sports); + } else if (headRecord[0] == "Tutorial") { + final Iterable json = jsonDecode(headRecord[1]); + final List tutorials = json.map((tutorial) => Tutorial.fromJson(tutorial)).toList(); + + Cache().setTutorials(tutorials); + } else if (headRecord[0] == "Description") { + final Iterable json = jsonDecode(headRecord[1]); + final List? descriptions = json.map((description) => Description.fromJson(description)).toList(); + //print("Description: $descriptions"); + Cache().setDescriptions(descriptions); + } else if (headRecord[0] == "Faq") { + final Iterable json = jsonDecode(headRecord[1]); + final List? faqs = json.map((faq) => Faq.fromJson(faq)).toList(); + //print("Faq: $faqs"); + Cache().setFaqs(faqs); + } else if (headRecord[0] == "TrainingPlan") { + final Iterable json = jsonDecode(headRecord[1]); + final List? plans = json.map((plan) => TrainingPlan.fromJson(plan)).toList(); + + List activePlans = []; + if (plans != null) { + plans.forEach((element) { + if (element.active) { + activePlans.add(element); + } + }); + } + Cache().setTrainingPlans(activePlans); + } else if (headRecord[0] == "SplitTests") { + final Iterable json = jsonDecode(headRecord[1]); + final List? tests = json.map((test) => SplitTest.fromJson(test)).toList(); + //print("A/B tests: $tests"); + Cache().setSplitTests(tests); + } else if (headRecord[0] == "TrainingPlanDay") { + final Iterable json = jsonDecode(headRecord[1]); + final List? days = json.map((day) => TrainingPlanDay.fromJson(day)).toList(); + Cache().setTrainingPlanDays(days); + } + }); + + exerciseTree = this.getExerciseTreeParents(exerciseTree, exerciseTreeParents); + + await Future.forEach(exerciseTree, (element) async { + ExerciseTree tree = element as ExerciseTree; + tree.imageUrl = await ExerciseTreeApi().buildImage(tree.imageUrl, tree.treeId); + }); + Cache().setExerciseTree(exerciseTree); + + TrainingPlanDayRepository trainingPlanDayRepository = TrainingPlanDayRepository(); + trainingPlanDayRepository.assignTrainingPlanDays(); + + return; + } + + List getExerciseTreeParents(final List exerciseTree, final List exerciseTreeParents) { + List copyList = ExerciseTreeApi().copyList(exerciseTree); + + int treeIndex = 0; + copyList.forEach((element) async { + int index = 0; + exerciseTreeParents.forEach((parent) { + if (parent.exerciseTreeChildId == element.treeId) { + if (index > 0) { + ExerciseTree newElement = element.copy(parent.exerciseTreeParentId); + newElement.sort = parent.sort; + exerciseTree.add(newElement); + } else { + element.parentId = parent.exerciseTreeParentId; + element.sort = parent.sort; + exerciseTree[treeIndex].parentId = parent.exerciseTreeParentId; + exerciseTree[treeIndex].sort = parent.sort; + } + index++; + } + }); + + treeIndex++; + }); + + return exerciseTree; + } + + Future getCustomerPackage(int customerId) async { + try { + final body = await _client.get("app_customer_package/" + customerId.toString(), ""); + + final List models = body.split("|||"); + await Future.forEach(models, (elem) async { + final String element = elem as String; + final List headRecord = element.split("***"); + //print("Class " + headRecord[0]); + if (headRecord[0] == "Customer") { + Customer customer = Customer.fromJson(jsonDecode(headRecord[1])); + Cache().userLoggedIn = customer; + } else if (headRecord[0] == "CustomerExerciseDevice") { + final Iterable json = jsonDecode(headRecord[1]); + final List devices = json.map((device) => CustomerExerciseDevice.fromJson(device)).toList(); + Cache().setCustomerDevices(devices); + // ToDo + } else if (headRecord[0] == "Exercises") { + final Iterable json = jsonDecode(headRecord[1]); + final List exercises = json.map((exerciseType) => Exercise.fromJson(exerciseType)).toList(); + Cache().setExercises(exercises); + } else if (headRecord[0] == "Purchase") { + final Iterable json = jsonDecode(headRecord[1]); + final List purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList(); + Cache().setPurchases(purchases); + } else if (headRecord[0] == "CustomerProperty") { + final Iterable json = jsonDecode(headRecord[1]); + final List customerProperties = json.map((property) => CustomerProperty.fromJson(property)).toList(); + CustomerApi().initProperties(customerProperties); + } else if (headRecord[0] == "CustomerPropertyAll") { + final Iterable json = jsonDecode(headRecord[1]); + final List allCustomerProperties = json.map((property) => CustomerProperty.fromJson(property)).toList(); + print(" All Properties ---- $allCustomerProperties"); + Cache().setCustomerPropertyAll(allCustomerProperties); + } else if (headRecord[0] == "ExerciseResult") { + /*final Iterable json = jsonDecode(headRecord[1]); + final List exerciseResults = json.map((exerciseResult) { + ExerciseResult item = ExerciseResult.fromJson(exerciseResult); + return item; + }).toList(); + // ToDo */ + } else if (headRecord[0] == "CustomerActivity") { + final Iterable json = jsonDecode(headRecord[1]); + final List customerActivities = json.map((activity) => CustomerActivity.fromJson(activity)).toList(); + Cache().setCustomerActivities(customerActivities); + } + }); + } on NotFoundException catch (e) { + throw Exception("Please log in $e"); + } + } +} diff --git a/lib/service/product_service.dart b/lib/service/product_service.dart new file mode 100644 index 0000000..1ebb44e --- /dev/null +++ b/lib/service/product_service.dart @@ -0,0 +1,17 @@ +import 'dart:convert'; + +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/product.dart'; +import 'package:workouttest_util/service/api.dart'; + +class ProductApi { + final APIClient _client = APIClient(); + + Future> getProducts() async { + final body = await _client.get("product/", ""); + final Iterable json = jsonDecode(body); + final List products = json.map((product) => Product.fromJson(product)).toList(); + Cache().setProducts(products); + return products; + } +} diff --git a/lib/service/property_service.dart b/lib/service/property_service.dart new file mode 100644 index 0000000..4950982 --- /dev/null +++ b/lib/service/property_service.dart @@ -0,0 +1,18 @@ +import 'dart:convert'; + +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/service/api.dart'; + +import 'package:workouttest_util/model/property.dart'; + +class PropertyApi { + final APIClient _client = APIClient(); + + Future> getProperties() async { + final body = await _client.get("property/", ""); + final Iterable json = jsonDecode(body); + final List properties = json.map((property) => Property.fromJson(property)).toList(); + Cache().setProperties(properties); + return properties; + } +} diff --git a/lib/service/purchase_service.dart b/lib/service/purchase_service.dart new file mode 100644 index 0000000..d52ede5 --- /dev/null +++ b/lib/service/purchase_service.dart @@ -0,0 +1,29 @@ +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/model/purchase.dart'; +import 'package:workouttest_util/util/logging.dart'; +import 'package:workouttest_util/util/not_found_exception.dart'; +import 'dart:convert'; +import 'api.dart'; + +class PurchaseApi with Logging { + final APIClient _client = APIClient(); + + Future> getPurchasesByCustomer(int customerId) async { + List purchases = []; + try { + final body = await _client.get("purchase/customer/" + customerId.toString(), ""); + final Iterable json = jsonDecode(body); + final List purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList(); + Cache().setPurchases(purchases); + } on NotFoundException catch (_) { + log("No purchases found"); + } + return purchases; + } + + Future savePurchase(Purchase purchase) async { + String body = JsonEncoder().convert(purchase.toJson()); + log(" ===== saving purchase:" + body); + await _client.post("purchase/", body); + } +} diff --git a/lib/service/tracking_service.dart b/lib/service/tracking_service.dart new file mode 100644 index 0000000..aa00564 --- /dev/null +++ b/lib/service/tracking_service.dart @@ -0,0 +1,18 @@ +import 'package:workouttest_util/model/tracking.dart'; +import 'package:workouttest_util/util/logging.dart'; +import 'dart:convert'; +import 'api.dart'; + +class TrackingApi with Logging { + final APIClient _client = APIClient(); + + Future saveTracking(Tracking tracking) async { + try { + String body = const JsonEncoder().convert(tracking.toJson()); + log(" ===== saving tracking: $body"); + await _client.post("tracking/", body); + } catch (exception) { + log("exception in tracking: ${exception.toString()}"); + } + } +} diff --git a/lib/service/training_plan_service.dart b/lib/service/training_plan_service.dart new file mode 100644 index 0000000..e2823f2 --- /dev/null +++ b/lib/service/training_plan_service.dart @@ -0,0 +1,34 @@ +import 'dart:convert'; + +import 'package:workouttest_util/model/customer_training_plan.dart'; +import 'package:workouttest_util/model/customer_training_plan_exercise.dart'; +import 'package:workouttest_util/service/api.dart'; +import 'package:workouttest_util/util/logging.dart'; + +class TrainingPlanApi with Logging { + final APIClient _client = APIClient(); + + Future saveCustomerTrainingPlan(CustomerTrainingPlan plan) async { + String body = JsonEncoder().convert(plan.toJson()); + log(" ===== saving customer training plan:" + body); + final String response = await _client.post("customer_training_plan/", body); + final CustomerTrainingPlan saved = CustomerTrainingPlan.fromJson(jsonDecode(response)); + return saved; + } + + Future saveCustomerTrainingPlanExercise(CustomerTrainingPlanExercise planExercise) async { + String body = JsonEncoder().convert(planExercise.toJson()); + log(" ===== saving customer training plan exercise:" + body); + final String response = await _client.post("customer_training_plan_exercise/", body); + final CustomerTrainingPlanExercise saved = CustomerTrainingPlanExercise.fromJson(jsonDecode(response)); + return saved; + } + + Future updateCustomerTrainingPlan(CustomerTrainingPlan plan, int customerTrainingPlanId) async { + String body = JsonEncoder().convert(plan.toJson()); + log(" ===== update customer training plan:" + body); + final String response = await _client.post("customer_training_plan/update/$customerTrainingPlanId", body); + final CustomerTrainingPlan saved = CustomerTrainingPlan.fromJson(jsonDecode(response)); + return saved; + } +} diff --git a/lib/util/app_language.dart b/lib/util/app_language.dart new file mode 100644 index 0000000..3ad0242 --- /dev/null +++ b/lib/util/app_language.dart @@ -0,0 +1,68 @@ +import 'dart:io'; + +import 'package:workouttest_util/util/logging.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class AppLanguage with Logging { + static final AppLanguage _singleton = AppLanguage._internal(); + + Locale? _appLocale = Locale('en'); + + factory AppLanguage() { + return _singleton; + } + + AppLanguage._internal(); + + static Future getInstance() async { + return _singleton; + } + + Locale get appLocal => _appLocale ?? Locale("en"); + + Future fetchLocale() async { + var prefs = await SharedPreferences.getInstance(); + String? langCode = prefs.getString('language_code'); + log(" ---- lang code $langCode"); + if (langCode == null) { + _appLocale = Locale('en'); + } else { + _appLocale = Locale(langCode); + } + log(" ---- Fetched lang: " + _appLocale.toString()); + } + + getLocale(SharedPreferences prefs) { + String? langCode = prefs.getString('language_code'); + if (langCode == null) { + final String localName = Platform.localeName; + if (localName.endsWith("HU")) { + _appLocale = Locale('hu'); + langCode = "hu"; + } else { + _appLocale = Locale('en'); + langCode = "en"; + } + } + _appLocale = Locale(langCode); + log(" ---- Get lang: " + _appLocale.toString() + " lang code $langCode"); + } + + void changeLanguage(Locale type) async { + var prefs = await SharedPreferences.getInstance(); + if (_appLocale == type) { + return; + } + if (type == Locale("hu")) { + _appLocale = Locale("hu"); + await prefs.setString('language_code', 'hu'); + await prefs.setString('countryCode', 'HU'); + } else { + _appLocale = Locale("en"); + await prefs.setString('language_code', 'en'); + await prefs.setString('countryCode', 'US'); + } + log(" ---- Stored lang: " + _appLocale.toString()); + } +} diff --git a/lib/util/app_localization.dart b/lib/util/app_localization.dart new file mode 100644 index 0000000..c699e15 --- /dev/null +++ b/lib/util/app_localization.dart @@ -0,0 +1,78 @@ +import 'dart:convert'; + +import 'package:workouttest_util/util/logging.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; + +class AppLocalizations with Logging { + late Locale locale; + bool isTest; + late Map _localizedStrings; + + AppLocalizations(this.locale, {this.isTest = false}); + + // Helper method to keep the code in the widgets concise + // Localizations are accessed using an InheritedWidget "of" syntax + static AppLocalizations? of(BuildContext context) { + return Localizations.of(context, AppLocalizations); + } + + // Static member to have a simple access to the delegate from the MaterialApp + static const LocalizationsDelegate delegate = AppLocalizationsDelegate(); + + setLocale(Locale locale) { + this.locale = locale; + } + + Future load() async { + // Load the language JSON file from the "lang" folder + log(" -- load language pieces " + locale.languageCode); + String jsonString = await rootBundle.loadString('i18n/${locale.languageCode}.json'); + Map jsonMap = json.decode(jsonString); + + _localizedStrings = jsonMap.map((key, value) { + return MapEntry(key, value.toString()); + }); + + return true; + } + + Future loadTest(Locale locale) async { + return AppLocalizations(locale); + } + + // This method will be called from every widget which needs a localized text + String translate(String key) { + if (isTest) return key; + String? translated = _localizedStrings[key]; + return translated != null ? translated : key; + } +} + +class AppLocalizationsDelegate extends LocalizationsDelegate { + final bool isTest; + // This delegate instance will never change (it doesn't even have fields!) + // It can provide a constant constructor. + const AppLocalizationsDelegate({this.isTest = false}); + + @override + bool isSupported(Locale locale) { + // Include all of your supported language codes here + return ['en', 'hu'].contains(locale.languageCode); + } + + @override + Future load(Locale locale) async { + // AppLocalizations class is where the JSON loading actually runs + AppLocalizations localizations = new AppLocalizations(locale, isTest: this.isTest); + if (isTest) { + await localizations.loadTest(locale); + } else { + await localizations.load(); + } + return localizations; + } + + @override + bool shouldReload(AppLocalizationsDelegate old) => false; +} diff --git a/lib/util/common.dart b/lib/util/common.dart new file mode 100644 index 0000000..8fc3dfd --- /dev/null +++ b/lib/util/common.dart @@ -0,0 +1,176 @@ +import 'dart:convert'; +import 'package:workouttest_util/util/app_language.dart'; + +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class DateRate { + static String daily = "daily"; + static String weekly = "weekly"; + static String monthly = "monthly"; + static String yearly = "yearly"; +} + +mixin Common { + final emailError = "Please type a right email address here."; + final passwordError = "The password must have at least 8 characters."; + + String toJson(Map map) { + String rc = "{"; + map.forEach((key, value) { + rc += "'$key':'$value'"; + }); + rc += "}"; + return rc; + } + + String getDateLocale(DateTime datetime, bool timeDisplay) { + var date = datetime; + + String dateName = DateFormat(DateFormat.YEAR_NUM_MONTH_DAY, AppLanguage().appLocal.toString()).format(date.toUtc()); + if (timeDisplay) { + dateName += " " + DateFormat(DateFormat.HOUR_MINUTE, AppLanguage().appLocal.toString()).format(date.toUtc()); + } + + return dateName; + } + + String utf8convert(String text) { + List bytes = text.toString().codeUnits; + return utf8.decode(bytes); + } + + double mediaSizeWidth(BuildContext context) { + return MediaQuery.of(context).size.width; + } + + /// Calculates week number from a date as per https://en.wikipedia.org/wiki/ISO_week_date#Calculation + int weekNumber(DateTime date) { + int dayOfYear = int.parse(DateFormat("D").format(date)); + return ((dayOfYear - date.weekday + 10) / 7).floor(); + } + + static String? emailValidation(String? email) { + final String error = "Please type an email address"; + if (email == null) { + return error; + } + bool emailValid = RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(email); + return emailValid ? null : error; + } + + static String? passwordValidation(String? value) { + final String error = "Password too short"; + if (value == null || value.length == 0) { + return error; + } + bool valid = 8 < value.length; + return valid ? null : error; + } + + static normalizeDecimal(String value) { + if (value.isEmpty) { + return 0; + } + value = value.replaceFirst(",", "."); + value = value.replaceAll(RegExp(r'[^0-9.]'), ""); + return value; + } + + double calculate1RM(double weight, double repeat) { + if (weight == 0 || repeat == 0) { + return 0; + } + + double rmWendler = weight * repeat * 0.0333 + weight; + double rmOconner = weight * (1 + repeat / 40); + //print("Weight: $weight repeat: $repeat, $rmWendler, Oconner: $rmOconner"); + double average = (rmWendler + rmOconner) / 2; + + return average; + } + + double getRepeatByOneRepMax(double oneRepMax, double weight) { + double repeats = ( 80 * oneRepMax - 80 * weight ) / ( weight * ( 40 * 0.0333 + 1) ); + //print("getRepeatsByOneRepMax: $repeats"); + return repeats; + } + + int calculateRepeatBy1RMPercent(double oneRepMax, double weight, double percent) { + return getRepeatByOneRepMax(oneRepMax , weight * percent).round(); + } + + double calculate1RMPercentByRepeat(double oneRepMax, double weight, double repeat) { + double percent = 80 * oneRepMax / (weight * ( repeat * ( 40 * 0.0333 + 1 ) + 80)); + return percent; + } + + static double get1RMPercent(int repeats) { + double percent = 1; + + if (repeats >= 35) { + percent = 0.50; + } else if (repeats > 12) { + percent = (100 - 2 * repeats) / 100; + } else { + percent = (100.0 - 2 * repeats) / 100; + } + //print("1RM Percent: $percent repeats: $repeats"); + return percent; + } + + static double roundWeight(double weight) { + double rounded = weight.round().toDouble(); + + if (weight > 35) { + final double remainder = weight % 5; + if (remainder < 1) { + rounded = ((weight / 5).floor() * 5).toDouble(); + } else if (remainder > 1 && remainder <= 2.5) { + rounded = (weight / 5).floor() * 5 + 2.5; + } else if (remainder > 2.5 && remainder < 3.25) { + rounded = (weight / 5).floor() * 5 + 2.5; + } else { + rounded = (((weight / 5).ceil() * 5)).toDouble(); + } + } + + return rounded; + } + + static int calculateQuantityByChangedWeight(double initialRM, double weight, double repeat) { + final double repeatWendler = (initialRM - weight) / 0.0333 / weight; + final double repeatOconner = (initialRM / weight - 1) * 40; + final newRepeat = ((repeatOconner + repeatWendler) / 2).ceil(); + print("Initial 1RM: $initialRM Weight: $weight repeatWendler: $repeatWendler repeat Oconner: $repeatOconner. NEW REPEAT: $newRepeat"); + return newRepeat; + } + + static int reCalculateRepeatsByChangedWeight(double weight, double repeat, double changedWeight) { + final double rmWendler = weight * repeat * 0.0333 + weight; + final double rmOconner = weight * (1 + repeat / 40); + + final double repeatWendler = (rmWendler - changedWeight) / 0.0333 / changedWeight; + final double repeatOconner = (rmOconner / changedWeight - 1) * 40; + final newRepeat = ((repeatOconner + repeatWendler) / 2).ceil(); + print("Weight: $weight changedWeight: $changedWeight repeatWendler: $repeatWendler repeat Oconner: $repeatOconner. NEW REPEAT: $newRepeat"); + return newRepeat; + } + + static double calculateWeigthByChangedQuantity(double weight, double repeat, double changedRepeats) { + final double rmWendler = weight * repeat * 0.0333 + weight; + final double rmOconner = weight * (1 + repeat / 40); + final double initialRM = (rmWendler + rmOconner) / 2; + + final double weightWendler = rmWendler / (changedRepeats * 0.0333 + 1); + final double weightOconner = rmOconner / (1 + changedRepeats / 40); + final double newWeight = ((weightWendler + weightOconner) / 2); + print( + "Initial 1RM: $initialRM repeat: $repeat changedRepeat: $changedRepeats Weight: $weight weightWendler: $weightWendler weight Oconner: $weightOconner. NEW WEIGHT: $newWeight"); + return newWeight; + } + + +} + +class CommonHoldingClass with Common {} \ No newline at end of file diff --git a/lib/util/enums.dart b/lib/util/enums.dart new file mode 100644 index 0000000..8f64fc8 --- /dev/null +++ b/lib/util/enums.dart @@ -0,0 +1,129 @@ +import 'package:workouttest_util/util/string_extension.dart'; + +enum LoginType { email, fb, google, apple } + +extension LoginTypeExt on LoginType { + bool equalsTo(LoginType type) => this.toString() == type.toString(); + bool equalsStringTo(String type) => this.toString() == type; +} + +enum TrackingEvent { + enter, + login, + logout, + registration, + login_skip, + home, + sizes, + sizes_save, + my_development, + my_exerciseplan, + account, + settings, + sales_page, + purchase_request, + purchase_successful, + exercise_new, + exercise_new_no_registration, + exercise_new_paralell, + result, + exercise_log, + exercise_log_open, + exercise_log_delete, + exercise_log_result, + my_body_development, + my_muscle_development, + my_size_development, + my_custom_exercise_plan, + my_custom_exercise_plan_save, + my_exercise_plan_execute_open, + my_exercise_plan_execute_save, + my_special_plan, + my_suggested_plan, + prediction, + search, + exercise_device, + customer_change, + settings_lang, + settings_server, + test_set_edit, + test_set_new, + tutorial_step, + tutorial_finished, + tutorial_activate, + terms_of_use, + data_privacy, + delete_account, + faq, + training_plan_open, + training_plan_start, + training_plan_execute, + training_plan_finished, + training_plan_custom, + trial, + feedback_email, +} + +T enumFromString(Iterable values, String value) { + return values.firstWhere((type) => type.toString().split(".").last == value); +} + +extension TrackingEventExt on TrackingEvent { + String enumToString() => this.toString().split(".").last; + + bool equalsTo(TrackingEvent event) => this.toString() == event.toString(); + bool equalsStringTo(String event) => this.toString() == event; +} + +enum PropertyEnum { Ectomorph, Mesomorph, Endomorph } + +extension PropertyExt on PropertyEnum { + String toStr() => this.toString().split(".").last; + + bool equalsTo(PropertyEnum event) => this.toString() == event.toString(); + bool equalsStringTo(String event) => this.toString() == event; +} + +enum SizesEnum { Weight, Height, Shoulder, Neck, Biceps, Chest, Belly, Hip, ThighTop, ThighMiddle, Knee, Calf, Ankle, Underarm, Lowerarm } + +extension SizesExt on SizesEnum { + String toStr() => this.toString().split(".").last; + bool equalsTo(SizesEnum event) => this.toString() == event.toString(); + bool equalsStringTo(String event) => this.toString() == event; +} + +enum EvaluationText { very_poor, poor, fair, below_average, average, above_average, good, excellent, elite } + +extension EvaluationTextExt on EvaluationText { + String toStr() => this.toString().split(".").last; + bool equalsTo(EvaluationText eval) => this.toString() == eval.toString(); + bool equalsStringTo(String eval) => this.toStr() == eval; +} + +enum ExerciseTypeTrainingPlanState { none, added, executed } + +extension ExerciseTypeTrainingPlanStateExt on ExerciseTypeTrainingPlanState { + String toStr() => this.toString().split(".").last; + bool equalsTo(ExerciseTypeTrainingPlanState state) => this.toString() == state.toString(); + bool equalsStringTo(String state) => this.toStr() == state; +} + +enum ExerciseSaveType { test, training, test_set } + +extension ExerciseSaveTypeExt on ExerciseSaveType { + String toStr() => this.toString().split(".").last; + bool equalsTo(ExerciseSaveType type) => this.toString() == type.toString(); + bool equalsStringTo(String type) => this.toStr() == type; +} + +enum MuscleGroup { chest, biceps, triceps, back, shoulders, core, thigh, calf } + +extension MuscleGroupExt on MuscleGroup { + String toStr() => this.toString().split(".").last; + String toText() => this.toString().split(".").last.capitalize(); + bool equalsTo(MuscleGroup type) => this.toString() == type.toString(); + bool equalsStringTo(String type) => this.toStr() == type; + String getStrByIndex(int index) => MuscleGroup.values.elementAt(index).toStr(); + MuscleGroup getByIndex(int index) => MuscleGroup.values.elementAt(index); + String getTextByIndex(int index) => MuscleGroup.values.elementAt(index).toText(); +} diff --git a/lib/util/env.dart b/lib/util/env.dart new file mode 100644 index 0000000..894f096 --- /dev/null +++ b/lib/util/env.dart @@ -0,0 +1,3 @@ +class EnvironmentConfig { + static const test_env = String.fromEnvironment('test_env'); +} \ No newline at end of file diff --git a/lib/util/logging.dart b/lib/util/logging.dart new file mode 100644 index 0000000..5ce9397 --- /dev/null +++ b/lib/util/logging.dart @@ -0,0 +1,16 @@ +import 'package:workouttest_util/util/env.dart'; +import 'package:intl/intl.dart'; + +mixin Logging { + void log(String message) { + DateTime time = DateTime.now(); + print(DateFormat('yyyy-MM-dd HH:mm:ss ').format(time) + message); + } + + void trace(String message) { + String testEnv = EnvironmentConfig.test_env; + if (testEnv == "1") { + log(message); + } + } +} diff --git a/lib/util/not_found_exception.dart b/lib/util/not_found_exception.dart new file mode 100644 index 0000000..9366aed --- /dev/null +++ b/lib/util/not_found_exception.dart @@ -0,0 +1,13 @@ +class NotFoundException implements Exception { + final String message; + const NotFoundException({required this.message}); +} + +class WorkoutTestException implements Exception { + static const String CUSTOMER_EXISTS = "customer-exists"; + static const String LOGIN_CANCELLED = "login-cancelled"; + + final String message; + final String code; + const WorkoutTestException({required this.message, required this.code}); +} diff --git a/lib/util/string_extension.dart b/lib/util/string_extension.dart new file mode 100644 index 0000000..d48c06a --- /dev/null +++ b/lib/util/string_extension.dart @@ -0,0 +1,5 @@ +extension StringExtension on String { + String capitalize() { + return "${this[0].toUpperCase()}${this.substring(1).toLowerCase()}"; + } +} diff --git a/lib/util/track.dart b/lib/util/track.dart new file mode 100644 index 0000000..f58b06b --- /dev/null +++ b/lib/util/track.dart @@ -0,0 +1,53 @@ +import 'package:workouttest_util/model/cache.dart'; +import 'package:workouttest_util/util/logging.dart'; +import 'package:workouttest_util/service/tracking_service.dart'; +import 'package:workouttest_util/util/enums.dart'; +import 'package:workouttest_util/model/tracking.dart' as model; +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:posthog_session/posthog_session.dart'; +import 'package:matomo_tracker/matomo_tracker.dart'; +import 'package:flutter/foundation.dart'; + +class Track with Logging { + static final Track _singleton = Track._internal(); + static FirebaseAnalytics analytics = FirebaseAnalytics.instance; + + factory Track() { + return _singleton; + } + + Track._internal(); + + void track(TrackingEvent event, {String eventValue = ""}) { + model.Tracking tracking = model.Tracking(); + tracking.customerId = Cache().userLoggedIn == null ? 0 : Cache().userLoggedIn!.customerId!; + if (kReleaseMode) { + tracking.event = event.enumToString(); + if (eventValue.isNotEmpty) { + tracking.eventValue = eventValue; + } + tracking.dateAdd = DateTime.now(); + + TrackingApi().saveTracking(tracking); + + FirebaseMessaging.instance.subscribeToTopic(event.enumToString()); + analytics.logEvent(name: event.enumToString(), parameters: {"value": eventValue}); + + if (eventValue.isNotEmpty) { + MatomoTracker.instance.trackEvent(eventCategory: "wt", action: event.enumToString(), eventName: eventValue); + } else { + MatomoTracker.instance.trackEvent(eventCategory: "wt", action: event.enumToString()); + } + Posthog().capture( + eventName: event.enumToString(), + properties: { + 'eventValue': eventValue, + 'customer': tracking.customerId, + }, + ); + + } + + } +} diff --git a/lib/workouttest_util.dart b/lib/workouttest_util.dart new file mode 100644 index 0000000..f9b8475 --- /dev/null +++ b/lib/workouttest_util.dart @@ -0,0 +1 @@ +library workouttest_util; \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..2c487d7 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,73 @@ +name: workouttest_util +description: Workout Test app and web functions. +version: 0.0.1 +homepage: + +environment: + sdk: '>=2.18.6 <3.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + firebase_auth: ^4.2.5 + firebase_analytics: ^10.1.0 + firebase_messaging: ^14.2.1 + firebase_remote_config: ^3.0.9 + flutter_facebook_auth: ^5.0.7 + google_sign_in: ^5.4.3 + sign_in_with_apple: ^4.3.0 + + matomo_tracker: ^2.0.0 + + package_info_plus: ^3.0.2 + + sentry_flutter: ^6.9.1 + + posthog_session: + git: https://bossanyit@git.workouttest.org/bossanyit/posthog_session.git + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + intl: ^0.17.0 + shared_preferences: ^2.0.5 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/test/workouttest_util_test.dart b/test/workouttest_util_test.dart new file mode 100644 index 0000000..55500ed --- /dev/null +++ b/test/workouttest_util_test.dart @@ -0,0 +1,9 @@ +import 'package:flutter_test/flutter_test.dart'; + +import 'package:workouttest_util/workouttest_util.dart'; + +void main() { + test('adds one to input values', () { + + }); +}