v1.0.0 outsourced from aitrainer_app
This commit is contained in:
commit
ca96abf8c0
37
.flutter-plugins
Normal file
37
.flutter-plugins
Normal file
@ -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\\
|
1
.flutter-plugins-dependencies
Normal file
1
.flutter-plugins-dependencies
Normal file
File diff suppressed because one or more lines are too long
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
@ -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/
|
10
.metadata
Normal file
10
.metadata
Normal file
@ -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
|
3
CHANGELOG.md
Normal file
3
CHANGELOG.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
## 0.0.1
|
||||||
|
|
||||||
|
* TODO: Describe initial release.
|
39
README.md
Normal file
39
README.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<!--
|
||||||
|
This README describes the package. If you publish this package to pub.dev,
|
||||||
|
this README's contents appear on the landing page for your package.
|
||||||
|
|
||||||
|
For information about how to write a good package README, see the guide for
|
||||||
|
[writing package pages](https://dart.dev/guides/libraries/writing-package-pages).
|
||||||
|
|
||||||
|
For general information about developing packages, see the Dart guide for
|
||||||
|
[creating packages](https://dart.dev/guides/libraries/create-library-packages)
|
||||||
|
and the Flutter guide for
|
||||||
|
[developing packages and plugins](https://flutter.dev/developing-packages).
|
||||||
|
-->
|
||||||
|
|
||||||
|
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.
|
4
analysis_options.yaml
Normal file
4
analysis_options.yaml
Normal file
@ -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
|
801
lib/model/cache.dart
Normal file
801
lib/model/cache.dart
Normal file
@ -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<ExerciseType>? _exerciseTypes;
|
||||||
|
List<ExerciseTree>? _exerciseTree;
|
||||||
|
List<Evaluation>? _evaluations;
|
||||||
|
|
||||||
|
List<Exercise>? _exercises;
|
||||||
|
ExercisePlan? _myExercisePlan;
|
||||||
|
List<Property>? _properties;
|
||||||
|
List<Sport>? _sports;
|
||||||
|
List<wt_product.Product>? _products;
|
||||||
|
List<Purchase> _purchases = [];
|
||||||
|
List<SplitTest> _splitTests = [];
|
||||||
|
List<TrainingPlanDay> _trainingPlanDays = [];
|
||||||
|
|
||||||
|
List<ExercisePlanTemplate> _exercisePlanTemplates = [];
|
||||||
|
|
||||||
|
ExercisePlan? activeExercisePlan;
|
||||||
|
CustomerTrainingPlan? myTrainingPlan;
|
||||||
|
List<ExercisePlanDetail>? activeExercisePlanDetails;
|
||||||
|
|
||||||
|
List<ExerciseDevice>? _devices;
|
||||||
|
|
||||||
|
List<CustomerExerciseDevice>? _customerDevices;
|
||||||
|
List<CustomerActivity>? _customerActivities;
|
||||||
|
List<CustomerTrainingPlan>? _customerTrainingPlans;
|
||||||
|
List<CustomerProperty>? _customerPropertyAll;
|
||||||
|
|
||||||
|
List<Tutorial>? _tutorials;
|
||||||
|
List<Description>? _descriptions;
|
||||||
|
List<Faq>? _faqs;
|
||||||
|
List<TrainingPlan>? _trainingPlans;
|
||||||
|
|
||||||
|
LinkedHashMap<int, ExercisePlanDetail> _myExercisesPlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
|
||||||
|
|
||||||
|
LinkedHashMap<String, WorkoutMenuTree> _tree = LinkedHashMap<String, WorkoutMenuTree>();
|
||||||
|
double _percentExercises = -1;
|
||||||
|
|
||||||
|
Customer? _trainee;
|
||||||
|
List<Exercise>? _exercisesTrainee;
|
||||||
|
ExercisePlan? _traineeExercisePlan;
|
||||||
|
|
||||||
|
FirebaseRemoteConfig? remoteConfig;
|
||||||
|
|
||||||
|
LinkedHashMap<String, int> _badges = LinkedHashMap();
|
||||||
|
|
||||||
|
List? deviceLanguages;
|
||||||
|
String startPage = "home";
|
||||||
|
late String testEnvironment;
|
||||||
|
bool liveServer = true;
|
||||||
|
bool? hasHardware = false;
|
||||||
|
|
||||||
|
HashMap<String, bool> 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<void> deleteCustomerId(int customerId) async {
|
||||||
|
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
|
SharedPreferences sharedPreferences = await prefs;
|
||||||
|
sharedPreferences.remove(Cache.customerIdKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> saveActiveExercisePlan(ExercisePlan exercisePlan, List<ExercisePlanDetail> exercisePlanDetails) async {
|
||||||
|
activeExercisePlan = exercisePlan;
|
||||||
|
activeExercisePlanDetails = exercisePlanDetails;
|
||||||
|
String exercisePlanJson = const JsonEncoder().convert(exercisePlan.toJson());
|
||||||
|
String detailsJson = jsonEncode(exercisePlanDetails.map((i) => i.toJsonWithExerciseList()).toList()).toString();
|
||||||
|
|
||||||
|
Future<SharedPreferences> 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<void> saveMyTrainingPlan() async {
|
||||||
|
if (myTrainingPlan == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String myTrainingPlanJson = const JsonEncoder().convert(myTrainingPlan!.toJsonWithDetails());
|
||||||
|
|
||||||
|
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
|
SharedPreferences sharedPreferences;
|
||||||
|
sharedPreferences = await prefs;
|
||||||
|
sharedPreferences.setString(Cache.myTrainingPlanKey, myTrainingPlanJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteMyTrainingPlan() async {
|
||||||
|
if (myTrainingPlan == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
|
SharedPreferences sharedPreferences;
|
||||||
|
sharedPreferences = await prefs;
|
||||||
|
sharedPreferences.remove(Cache.myTrainingPlanKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getMyTrainingPlan() async {
|
||||||
|
Future<SharedPreferences> 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<String, dynamic> map;
|
||||||
|
try {
|
||||||
|
map = JsonDecoder().convert(savedTrainingPlanJson);
|
||||||
|
//print("Training plan: $savedTrainingPlanJson");
|
||||||
|
this.myTrainingPlan = CustomerTrainingPlan.fromJsonWithDetails(map);
|
||||||
|
} on Exception catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteActiveExercisePlan() async {
|
||||||
|
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
|
SharedPreferences sharedPreferences;
|
||||||
|
sharedPreferences = await prefs;
|
||||||
|
|
||||||
|
sharedPreferences.remove(Cache.activeExercisePlanDateKey);
|
||||||
|
this.activeExercisePlan = null;
|
||||||
|
this.activeExercisePlanDetails = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getActiveExercisePlan() async {
|
||||||
|
Future<SharedPreferences> 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<String, dynamic> 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<void> setServer(bool live) async {
|
||||||
|
if (this.testEnvironment == "1") {
|
||||||
|
liveServer = false;
|
||||||
|
live = false;
|
||||||
|
}
|
||||||
|
Future<SharedPreferences> 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<bool> selectedHardwareBefore() async {
|
||||||
|
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
|
SharedPreferences sharedPreferences = await prefs;
|
||||||
|
|
||||||
|
final bool? selectedHardware = sharedPreferences.getBool(Cache.hardwareKey);
|
||||||
|
return selectedHardware == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setHardware(bool hasHardware) async {
|
||||||
|
Future<SharedPreferences> 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<void> setLoginTypeFromPrefs() async {
|
||||||
|
Future<SharedPreferences> 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<SharedPreferences> 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<SharedPreferences> 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<SharedPreferences> 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<SharedPreferences> 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<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
|
await setPreferences(prefs, SharePrefsChange.logout, 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setPreferences(Future<SharedPreferences> 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<ExerciseType> exerciseTypes) {
|
||||||
|
this._exerciseTypes = exerciseTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setExerciseTree(List<ExerciseTree> exerciseTree) {
|
||||||
|
this._exerciseTree = exerciseTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setExercises(List<Exercise> exercises) => this._exercises = exercises;
|
||||||
|
|
||||||
|
void setExercisesTrainee(List<Exercise> exercises) {
|
||||||
|
this._exercisesTrainee = exercises;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWorkoutMenuTree(LinkedHashMap<String, WorkoutMenuTree> tree) {
|
||||||
|
this._tree = tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ExerciseType>? 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<ExerciseTree>? getExerciseTree() => this._exerciseTree;
|
||||||
|
|
||||||
|
List<Exercise>? getExercises() => this._exercises;
|
||||||
|
|
||||||
|
List<Exercise>? getExercisesTrainee() => this._exercisesTrainee;
|
||||||
|
|
||||||
|
LinkedHashMap<String, WorkoutMenuTree> 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<int, ExercisePlanDetail> listExercisePlanDetail) =>
|
||||||
|
_myExercisesPlanDetails = listExercisePlanDetail;
|
||||||
|
|
||||||
|
void addToMyExercisePlanDetails(ExercisePlanDetail detail) => _myExercisesPlanDetails[detail.exerciseTypeId] = detail;
|
||||||
|
|
||||||
|
LinkedHashMap<int, ExercisePlanDetail> getMyExercisePlanDetails() => _myExercisesPlanDetails;
|
||||||
|
|
||||||
|
void resetMyExercisePlanDetails() => _myExercisesPlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
|
||||||
|
|
||||||
|
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<Property> properties) => this._properties = properties;
|
||||||
|
List<Property>? getProperties() => _properties;
|
||||||
|
|
||||||
|
List<Sport>? getSports() => _sports;
|
||||||
|
void setSports(List<Sport> sports) => this._sports = sports;
|
||||||
|
|
||||||
|
void setDevices(List<ExerciseDevice> devices) => this._devices = devices;
|
||||||
|
|
||||||
|
List<ExerciseDevice>? getDevices() => this._devices;
|
||||||
|
|
||||||
|
void setCustomerDevices(List<CustomerExerciseDevice> devices) => this._customerDevices = devices;
|
||||||
|
|
||||||
|
List<CustomerExerciseDevice>? 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<Product>? get products => _products;
|
||||||
|
void setProducts(List<wt_product.Product> value) => _products = value;
|
||||||
|
|
||||||
|
List<Purchase> get purchases => _purchases;
|
||||||
|
setPurchases(List<Purchase> value) => _purchases = value;
|
||||||
|
|
||||||
|
Future<void> 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<SharedPreferences> 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<SharedPreferences> 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<Evaluation>? get evaluations => this._evaluations;
|
||||||
|
set evaluations(List<Evaluation>? value) => this._evaluations = value;
|
||||||
|
|
||||||
|
List<CustomerActivity>? get customerActivities => this._customerActivities;
|
||||||
|
setCustomerActivities(List<CustomerActivity>? value) => this._customerActivities = value;
|
||||||
|
|
||||||
|
List<Tutorial>? get tutorials => this._tutorials;
|
||||||
|
setTutorials(List<Tutorial>? value) => this._tutorials = value;
|
||||||
|
|
||||||
|
FirebaseRemoteConfig? getRemoteConfig() => this.remoteConfig;
|
||||||
|
setRemoteConfig(FirebaseRemoteConfig? remoteConfig) => this.remoteConfig = remoteConfig;
|
||||||
|
|
||||||
|
List<Description>? getDescriptions() => this._descriptions;
|
||||||
|
setDescriptions(List<Description>? value) => this._descriptions = value;
|
||||||
|
|
||||||
|
List<Faq>? getFaqs() => this._faqs;
|
||||||
|
setFaqs(List<Faq>? value) => this._faqs = value;
|
||||||
|
|
||||||
|
List<TrainingPlan>? getTrainingPlans() => this._trainingPlans;
|
||||||
|
setTrainingPlans(List<TrainingPlan>? value) => this._trainingPlans = value;
|
||||||
|
|
||||||
|
List<CustomerTrainingPlan>? getCustomerTrainingPlans() => this._customerTrainingPlans;
|
||||||
|
setCustomerTrainingPlans(value) => this._customerTrainingPlans = value;
|
||||||
|
|
||||||
|
List<SplitTest> getSplitTests() => this._splitTests;
|
||||||
|
setSplitTests(value) => this._splitTests = value;
|
||||||
|
|
||||||
|
List<TrainingPlanDay> getTrainingPlanDays() => this._trainingPlanDays;
|
||||||
|
setTrainingPlanDays(value) => this._trainingPlanDays = value;
|
||||||
|
|
||||||
|
List<CustomerProperty>? getCustomerPropertyAll() => this._customerPropertyAll;
|
||||||
|
setCustomerPropertyAll(value) => this._customerPropertyAll = value;
|
||||||
|
addCustomerProperty(CustomerProperty property) {
|
||||||
|
if (this._customerPropertyAll == null) {
|
||||||
|
this._customerPropertyAll = [];
|
||||||
|
}
|
||||||
|
this._customerPropertyAll!.add(property);
|
||||||
|
}
|
||||||
|
}
|
128
lib/model/customer.dart
Normal file
128
lib/model/customer.dart
Normal file
@ -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<String, CustomerProperty> 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<String, dynamic> 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;
|
||||||
|
}
|
||||||
|
}
|
30
lib/model/customer_activity.dart
Normal file
30
lib/model/customer_activity.dart
Normal file
@ -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<String, dynamic> 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();
|
||||||
|
}
|
||||||
|
}
|
42
lib/model/customer_exercise_device.dart
Normal file
42
lib/model/customer_exercise_device.dart
Normal file
@ -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<String, dynamic> 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),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
69
lib/model/customer_property.dart
Normal file
69
lib/model/customer_property.dart
Normal file
@ -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<String, dynamic> 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<String, dynamic> 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();
|
||||||
|
}
|
||||||
|
}
|
97
lib/model/customer_training_plan.dart
Normal file
97
lib/model/customer_training_plan.dart
Normal file
@ -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<CustomerTrainingPlanDetails> details = [];
|
||||||
|
|
||||||
|
HashMap<String, List<CustomerTrainingPlanDetails>> 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<String, dynamic> toJson() => {
|
||||||
|
"customerTrainingPlanId": customerTrainingPlanId,
|
||||||
|
"customerId": customerId,
|
||||||
|
"trainingPlanId": trainingPlanId,
|
||||||
|
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(dateAdd!),
|
||||||
|
"name": name,
|
||||||
|
"active": active,
|
||||||
|
"status": status
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<String, dynamic> 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();
|
||||||
|
}
|
162
lib/model/customer_training_plan_details.dart
Normal file
162
lib/model/customer_training_plan_details.dart
Normal file
@ -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<Exercise> exercises = [];
|
||||||
|
|
||||||
|
bool isTest = false;
|
||||||
|
|
||||||
|
double baseOneRepMax = -1;
|
||||||
|
|
||||||
|
List<ExerciseType> 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<String, dynamic> 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<String, dynamic> toJsonWithExercises() {
|
||||||
|
final Map<String, dynamic> 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
lib/model/customer_training_plan_exercise.dart
Normal file
30
lib/model/customer_training_plan_exercise.dart
Normal file
@ -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<String, dynamic> toJson() => {
|
||||||
|
"customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId,
|
||||||
|
"customerId": this.customerId,
|
||||||
|
"exerciseId": this.exerciseId,
|
||||||
|
"weight": this.weight,
|
||||||
|
"repeats": this.repeats
|
||||||
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => this.toJson().toString();
|
||||||
|
}
|
40
lib/model/description.dart
Normal file
40
lib/model/description.dart
Normal file
@ -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<String, dynamic> 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();
|
||||||
|
}
|
28
lib/model/evaluation.dart
Normal file
28
lib/model/evaluation.dart
Normal file
@ -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<String, dynamic> json = {
|
||||||
|
'evaluationId': this.evaluationId,
|
||||||
|
'name': this.name,
|
||||||
|
'exerciseTypeId': this.exerciseTypeId,
|
||||||
|
'unit': this.unit
|
||||||
|
};
|
||||||
|
return json.toString();
|
||||||
|
}
|
||||||
|
}
|
41
lib/model/evaluation_attribute.dart
Normal file
41
lib/model/evaluation_attribute.dart
Normal file
@ -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<String, dynamic> 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();
|
||||||
|
}
|
||||||
|
}
|
68
lib/model/exercise.dart
Normal file
68
lib/model/exercise.dart
Normal file
@ -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<String, dynamic> 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<String, dynamic> 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();
|
||||||
|
}
|
||||||
|
}
|
25
lib/model/exercise_ability.dart
Normal file
25
lib/model/exercise_ability.dart
Normal file
@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
lib/model/exercise_device.dart
Normal file
21
lib/model/exercise_device.dart
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
70
lib/model/exercise_plan.dart
Normal file
70
lib/model/exercise_plan.dart
Normal file
@ -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<String, dynamic> 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<String, dynamic> json = toJson();
|
||||||
|
return json.toString();
|
||||||
|
}
|
||||||
|
}
|
91
lib/model/exercise_plan_detail.dart
Normal file
91
lib/model/exercise_plan_detail.dart
Normal file
@ -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<Exercise>
|
||||||
|
List<Exercise>? 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<String, dynamic> toJson() => {
|
||||||
|
"exercisePlanId": exercisePlanId == null ? 0 : exercisePlanId,
|
||||||
|
"exerciseTypeId": exerciseTypeId,
|
||||||
|
"serie": serie,
|
||||||
|
"repeats": repeats,
|
||||||
|
"weightEquation": weightEquation
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<String, dynamic> 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<String, dynamic> json = toJsonWithExerciseList();
|
||||||
|
return json.toString();
|
||||||
|
}
|
||||||
|
}
|
50
lib/model/exercise_plan_template.dart
Normal file
50
lib/model/exercise_plan_template.dart
Normal file
@ -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<int> 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<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
"exercisePlanTemplateId": exercisePlanTemplateId,
|
||||||
|
"name": name,
|
||||||
|
"description": "description",
|
||||||
|
"templateType": templateType,
|
||||||
|
"nameTranslation": nameTranslation,
|
||||||
|
"descriptionTranslation": descriptionTranslation,
|
||||||
|
"exerciseTypes": exerciseTypes.toString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
46
lib/model/exercise_result.dart
Normal file
46
lib/model/exercise_result.dart
Normal file
@ -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<String, dynamic> 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);
|
||||||
|
}
|
||||||
|
}
|
76
lib/model/exercise_tree.dart
Normal file
76
lib/model/exercise_tree.dart
Normal file
@ -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<String, dynamic> 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;
|
||||||
|
}
|
||||||
|
}
|
13
lib/model/exercise_tree_parents.dart
Normal file
13
lib/model/exercise_tree_parents.dart
Normal file
@ -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'];
|
||||||
|
}
|
||||||
|
}
|
134
lib/model/exercise_type.dart
Normal file
134
lib/model/exercise_type.dart
Normal file
@ -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<int> devices = [];
|
||||||
|
|
||||||
|
/// parents[]
|
||||||
|
List<int> parents = [];
|
||||||
|
|
||||||
|
/// alternatives []
|
||||||
|
List<int> 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<String, dynamic> 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();
|
||||||
|
}
|
||||||
|
}
|
11
lib/model/exercise_type_device.dart
Normal file
11
lib/model/exercise_type_device.dart
Normal file
@ -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'];
|
||||||
|
}
|
||||||
|
}
|
37
lib/model/faq.dart
Normal file
37
lib/model/faq.dart
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
|
class Faq {
|
||||||
|
late int faqId;
|
||||||
|
late String name;
|
||||||
|
late String description;
|
||||||
|
int? sort;
|
||||||
|
|
||||||
|
HashMap<String, String> nameTranslations = HashMap();
|
||||||
|
HashMap<String, String> 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<String, dynamic> toJson() => {
|
||||||
|
"faqId": this.faqId,
|
||||||
|
"name": this.name,
|
||||||
|
"description": this.description,
|
||||||
|
"nameTranslation": this.nameTranslations.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => this.toJson().toString();
|
||||||
|
}
|
67
lib/model/fitness_state.dart
Normal file
67
lib/model/fitness_state.dart
Normal file
@ -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<FitnessState> 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<FitnessState> 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;
|
||||||
|
}
|
||||||
|
}
|
46
lib/model/mautic.dart
Normal file
46
lib/model/mautic.dart
Normal file
@ -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<String, dynamic> 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();
|
||||||
|
}
|
7
lib/model/model_change.dart
Normal file
7
lib/model/model_change.dart
Normal file
@ -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";
|
||||||
|
}
|
53
lib/model/product.dart
Normal file
53
lib/model/product.dart
Normal file
@ -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<String, dynamic> 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();
|
||||||
|
}
|
||||||
|
}
|
28
lib/model/property.dart
Normal file
28
lib/model/property.dart
Normal file
@ -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<String, dynamic> json = {
|
||||||
|
"propertyId": propertyId,
|
||||||
|
"propertyName": propertyName,
|
||||||
|
"propertyUnit": propertyUnit
|
||||||
|
};
|
||||||
|
return json.toString();
|
||||||
|
}
|
||||||
|
}
|
31
lib/model/purchase.dart
Normal file
31
lib/model/purchase.dart
Normal file
@ -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<String, dynamic> toJson() => {
|
||||||
|
"purchaseId": purchaseId,
|
||||||
|
"customerId": customerId,
|
||||||
|
"productId": productId,
|
||||||
|
"purchaseSum": purchaseSum,
|
||||||
|
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd),
|
||||||
|
"currency": currency,
|
||||||
|
};
|
||||||
|
}
|
101
lib/model/result.dart
Normal file
101
lib/model/result.dart
Normal file
@ -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);
|
||||||
|
}
|
36
lib/model/split_test.dart
Normal file
36
lib/model/split_test.dart
Normal file
@ -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<String, dynamic> 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();
|
||||||
|
}
|
||||||
|
}
|
30
lib/model/sport.dart
Normal file
30
lib/model/sport.dart
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
|
class Sport {
|
||||||
|
late int sportId;
|
||||||
|
late String name;
|
||||||
|
|
||||||
|
HashMap<String, String> 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<String, dynamic> toJson() => {
|
||||||
|
"sportId": sportId,
|
||||||
|
"name": name,
|
||||||
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return this.toJson().toString();
|
||||||
|
}
|
||||||
|
}
|
24
lib/model/tracking.dart
Normal file
24
lib/model/tracking.dart
Normal file
@ -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<String, dynamic> 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 : ""
|
||||||
|
};
|
||||||
|
}
|
33
lib/model/training_evaluation_exercise.dart
Normal file
33
lib/model/training_evaluation_exercise.dart
Normal file
@ -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;
|
||||||
|
}
|
74
lib/model/training_plan.dart
Normal file
74
lib/model/training_plan.dart
Normal file
@ -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<String, String> nameTranslations = HashMap();
|
||||||
|
HashMap<String, String> descriptionTranslations = HashMap();
|
||||||
|
|
||||||
|
List<TrainingPlanDetail>? details;
|
||||||
|
|
||||||
|
TrainingPlan.fromJson(Map<String, dynamic> 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<TrainingPlanDetail>((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<String, dynamic> 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();
|
||||||
|
}
|
29
lib/model/training_plan_day.dart
Normal file
29
lib/model/training_plan_day.dart
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
|
class TrainingPlanDay {
|
||||||
|
late int dayId;
|
||||||
|
late String name;
|
||||||
|
|
||||||
|
HashMap<String, String> 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<String, dynamic> toJson() => {
|
||||||
|
"dayId": this.dayId,
|
||||||
|
"name": this.name,
|
||||||
|
"nameTranslation": this.nameTranslations.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => this.toJson().toString();
|
||||||
|
}
|
44
lib/model/training_plan_detail.dart
Normal file
44
lib/model/training_plan_detail.dart
Normal file
@ -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<String, dynamic> 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<String, dynamic> 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();
|
||||||
|
}
|
29
lib/model/training_result.dart
Normal file
29
lib/model/training_result.dart
Normal file
@ -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,
|
||||||
|
});
|
||||||
|
}
|
37
lib/model/tutorial.dart
Normal file
37
lib/model/tutorial.dart
Normal file
@ -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<TutorialStep>? steps;
|
||||||
|
|
||||||
|
Tutorial.fromJson(Map<String, dynamic> json) {
|
||||||
|
this.tutorialId = json['tutorialId'];
|
||||||
|
this.name = json['name'];
|
||||||
|
|
||||||
|
if (json['steps'] != null && json['steps'].length > 0) {
|
||||||
|
steps = json['steps'].map<TutorialStep>((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<String, dynamic> toJson() => {'tutorialId': this.tutorialId, 'name': this.name, 'steps': steps.toString()};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => this.toJson().toString();
|
||||||
|
}
|
98
lib/model/tutorial_step.dart
Normal file
98
lib/model/tutorial_step.dart
Normal file
@ -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<String, dynamic> 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<String, dynamic> 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();
|
||||||
|
}
|
14
lib/model/user.dart
Normal file
14
lib/model/user.dart
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class User {
|
||||||
|
String? email;
|
||||||
|
String? password;
|
||||||
|
int? customerId;
|
||||||
|
String? firebaseUid;
|
||||||
|
|
||||||
|
User();
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
"username": email,
|
||||||
|
"password": password,
|
||||||
|
"firebaseUid": firebaseUid,
|
||||||
|
};
|
||||||
|
}
|
86
lib/model/workout_menu_tree.dart
Normal file
86
lib/model/workout_menu_tree.dart
Normal file
@ -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<WorkoutType> 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<String, dynamic> 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();
|
||||||
|
}
|
||||||
|
}
|
74
lib/repository/customer_exercise_device_repository.dart
Normal file
74
lib/repository/customer_exercise_device_repository.dart
Normal file
@ -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<CustomerExerciseDevice> _devices = [];
|
||||||
|
|
||||||
|
List<CustomerExerciseDevice> getDevices() => this._devices;
|
||||||
|
|
||||||
|
void setDevices(List<CustomerExerciseDevice> devices) => this._devices = devices;
|
||||||
|
|
||||||
|
Future<List<CustomerExerciseDevice>?> getDBDevices() async {
|
||||||
|
if (Cache().userLoggedIn != null) {
|
||||||
|
final int customerId = Cache().userLoggedIn!.customerId!;
|
||||||
|
this._devices = await CustomerExerciseDeviceApi().getDevices(customerId);
|
||||||
|
}
|
||||||
|
return this._devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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<void> 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;
|
||||||
|
}
|
||||||
|
}
|
573
lib/repository/customer_repository.dart
Normal file
573
lib/repository/customer_repository.dart
Normal file
@ -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<Customer>? _trainees;
|
||||||
|
List<CustomerProperty>? _properties;
|
||||||
|
//List<CustomerProperty>? _allCustomerProperties;
|
||||||
|
final PropertyRepository propertyRepository = PropertyRepository();
|
||||||
|
final List<Property> womanSizes = [];
|
||||||
|
final List<Property> manSizes = [];
|
||||||
|
|
||||||
|
final double baseWidth = 312;
|
||||||
|
final double baseHeight = 675.2;
|
||||||
|
double mediaWidth = 0;
|
||||||
|
double mediaHeight = 0;
|
||||||
|
bool isMan = true;
|
||||||
|
|
||||||
|
//List<CustomerRepository> customerList = List<CustomerRepository>();
|
||||||
|
bool visibleDetails = false;
|
||||||
|
late List<GenderItem> 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<Sport>? 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<Sport>? 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<Sport>? 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<void> addCustomer() async {
|
||||||
|
if (this.customer == null) throw Exception("Initialize the customer object");
|
||||||
|
final Customer modelCustomer = customer!;
|
||||||
|
await CustomerApi().addCustomer(modelCustomer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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<void> saveProperties(LinkedHashMap<String, CustomerProperty> properties) async {
|
||||||
|
properties.forEach((propertyName, property) async {
|
||||||
|
if (property.newData == true) {
|
||||||
|
await CustomerApi().addProperty(property);
|
||||||
|
property.newData = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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<Customer?> getTraineeAsCustomer() async {
|
||||||
|
this._trainee = await CustomerApi().getTrainee(Cache().userLoggedIn!.customerId!);
|
||||||
|
return _trainee;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Customer?>?> getTrainees() async {
|
||||||
|
int trainerId = Cache().userLoggedIn!.customerId!;
|
||||||
|
final results = await CustomerApi().getTrainees(trainerId);
|
||||||
|
this._trainees = results;
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<CustomerProperty>> getAllCustomerProperties() async {
|
||||||
|
int customerId = Cache().userLoggedIn!.customerId!;
|
||||||
|
final results = await CustomerApi().getAllProperties(customerId);
|
||||||
|
this._properties = results;
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CustomerProperty>? getAllProperties() {
|
||||||
|
return this._properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Customer>? 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<List<Purchase>> getPurchase() async {
|
||||||
|
int customerId = Cache().userLoggedIn!.customerId!;
|
||||||
|
List<Purchase> purchases = await PurchaseApi().getPurchasesByCustomer(customerId);
|
||||||
|
return purchases;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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<Property>? 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<Property> 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<Property> sizes;
|
||||||
|
if (this.sex == "m") {
|
||||||
|
sizes = this.manSizes;
|
||||||
|
} else {
|
||||||
|
sizes = this.womanSizes;
|
||||||
|
}
|
||||||
|
|
||||||
|
sizes.forEach((element) {
|
||||||
|
if (element.propertyName == propertyName) {
|
||||||
|
element.value = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CustomerProperty> getAllCustomerPropertyByName(String propertyName) {
|
||||||
|
List<CustomerProperty> 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;
|
||||||
|
}
|
||||||
|
}
|
52
lib/repository/exercise_device_repository.dart
Normal file
52
lib/repository/exercise_device_repository.dart
Normal file
@ -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<ExerciseDevice> _devices = [];
|
||||||
|
|
||||||
|
List<ExerciseDevice> getDevices() {
|
||||||
|
return this._devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDevices(List<ExerciseDevice> list) {
|
||||||
|
_devices = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<ExerciseDevice>> 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<ExerciseDevice> getGymDevices() {
|
||||||
|
if (Cache().getDevices() == null) return [];
|
||||||
|
final List<ExerciseDevice> gymDevices = [];
|
||||||
|
if (_devices.isEmpty) {
|
||||||
|
_devices = Cache().getDevices()!;
|
||||||
|
}
|
||||||
|
_devices.forEach((element) {
|
||||||
|
if (isGymElement(element.name)) {
|
||||||
|
gymDevices.add(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return gymDevices;
|
||||||
|
}
|
||||||
|
}
|
538
lib/repository/exercise_repository.dart
Normal file
538
lib/repository/exercise_repository.dart
Normal file
@ -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<Exercise>? exerciseList;
|
||||||
|
List<Exercise>? exerciseLogList = [];
|
||||||
|
List<Exercise>? 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<Exercise> 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<void> deleteExercise(Exercise exercise) async {
|
||||||
|
await ExerciseApi().deleteExercise(exercise);
|
||||||
|
}
|
||||||
|
|
||||||
|
setCustomer(Customer customer) => this.customer = customer;
|
||||||
|
|
||||||
|
setExerciseType(ExerciseType exerciseType) => this.exerciseType = exerciseType;
|
||||||
|
|
||||||
|
Future<List<Exercise>> 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<Exercise>? getExerciseList() {
|
||||||
|
this.exerciseList = Cache().getExercises();
|
||||||
|
return this.exerciseList;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Exercise>? 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<WorkoutMenuTree> listByMuscle = list as List<WorkoutMenuTree>;
|
||||||
|
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<int> checkedExerciseTypeId = [];
|
||||||
|
List<int> baseTreeItem = [];
|
||||||
|
List<int> checkedBaseTreeItem = [];
|
||||||
|
int count1RMExercises = 0;
|
||||||
|
LinkedHashMap<String, WorkoutMenuTree> 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<Exercise>? 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<ExerciseType>? 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<Exercise> 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<Exercise> 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<Exercise> 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<Exercise> 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<Exercise> getExercisesByExerciseTypeId(int exerciseTypeId) {
|
||||||
|
List<Exercise> list = [];
|
||||||
|
List<Exercise>? allExercise = Cache().getExercises();
|
||||||
|
if (allExercise == null) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
allExercise.forEach((element) {
|
||||||
|
if (element.exerciseTypeId == exerciseTypeId) {
|
||||||
|
list.add(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
26
lib/repository/exercise_type_repository.dart
Normal file
26
lib/repository/exercise_type_repository.dart
Normal file
@ -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<ExerciseType> getExerciseTypeAlternatives(int? exerciseTypeId) {
|
||||||
|
if (exerciseTypeId == null || exerciseTypeId <= 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
List<ExerciseType> list = [];
|
||||||
|
List<ExerciseType>? 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;
|
||||||
|
}
|
||||||
|
}
|
93
lib/repository/mautic_repository.dart
Normal file
93
lib/repository/mautic_repository.dart
Normal file
@ -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<void> 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<void> 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<void> 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<void> 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<void> 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);
|
||||||
|
}
|
||||||
|
}
|
31
lib/repository/property_repository.dart
Normal file
31
lib/repository/property_repository.dart
Normal file
@ -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<Property>? _properties;
|
||||||
|
|
||||||
|
Future<List<Property>?> getDBProperties() async {
|
||||||
|
this._properties = await PropertyApi().getProperties();
|
||||||
|
return this._properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Property>? 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;
|
||||||
|
}
|
||||||
|
}
|
35
lib/repository/training_plan_day_repository.dart
Normal file
35
lib/repository/training_plan_day_repository.dart
Normal file
@ -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<TrainingPlan>? 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;
|
||||||
|
}
|
||||||
|
}
|
448
lib/repository/training_plan_repository.dart
Normal file
448
lib/repository/training_plan_repository.dart
Normal file
@ -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<TrainingPlan> getPlansByParent(String parent) {
|
||||||
|
final List<TrainingPlan> resultList = [];
|
||||||
|
final List<ExerciseTree>? exerciseTree = Cache().getExerciseTree();
|
||||||
|
int? parentId;
|
||||||
|
if (exerciseTree != null) {
|
||||||
|
exerciseTree.forEach((element) {
|
||||||
|
if (element.internalName == parent) {
|
||||||
|
parentId = element.treeId;
|
||||||
|
parentTree = element;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<TrainingPlan>? 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<CustomerTrainingPlanDetails> 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<CustomerTrainingPlanDetails> createDetail(CustomerTrainingPlan plan, TrainingPlanDetail elem, int exerciseTypeIdOrig, int index,
|
||||||
|
{bool changeExerciseType = false}) {
|
||||||
|
List<CustomerTrainingPlanDetails> 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<Exercise> 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<Exercise> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
224
lib/repository/user_repository.dart
Normal file
224
lib/repository/user_repository.dart
Normal file
@ -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<void> 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<void> addUserFB() async {
|
||||||
|
final User modelUser = this.user;
|
||||||
|
try {
|
||||||
|
Map<String, dynamic> 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<void> addUserGoogle() async {
|
||||||
|
final User modelUser = this.user;
|
||||||
|
try {
|
||||||
|
Map<String, dynamic> 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<void> addUserApple() async {
|
||||||
|
final User modelUser = this.user;
|
||||||
|
try {
|
||||||
|
Map<String, dynamic> 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<void> getUserByFB() async {
|
||||||
|
final User modelUser = this.user;
|
||||||
|
try {
|
||||||
|
Map<String, dynamic> 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<void> getUserByGoogle() async {
|
||||||
|
final User modelUser = this.user;
|
||||||
|
try {
|
||||||
|
Map<String, dynamic> 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<void> getUserByApple() async {
|
||||||
|
final User modelUser = this.user;
|
||||||
|
Map<String, dynamic> 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<void> 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<void> resetPassword() async {
|
||||||
|
final User modelUser = this.user;
|
||||||
|
await FirebaseApi().resetPassword(modelUser.email!);
|
||||||
|
}
|
||||||
|
}
|
141
lib/service/api.dart
Normal file
141
lib/service/api.dart
Normal file
@ -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<String> 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<String> 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
lib/service/customer_exercise_device_service.dart
Normal file
47
lib/service/customer_exercise_device_service.dart
Normal file
@ -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<List<CustomerExerciseDevice>> getDevices(int customerId) async {
|
||||||
|
List<CustomerExerciseDevice> 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<CustomerExerciseDevice> 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<void> 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;
|
||||||
|
}
|
||||||
|
}
|
240
lib/service/customer_service.dart
Normal file
240
lib/service/customer_service.dart
Normal file
@ -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<List<Customer>> getRealCustomers(String param) async {
|
||||||
|
final body = await _client.get("customers/", param);
|
||||||
|
final Iterable json = jsonDecode(body);
|
||||||
|
final List<Customer> customers = json.map((customer) => Customer.fromJson(customer)).toList();
|
||||||
|
|
||||||
|
return customers;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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<void> updateFirebaseUid(int customerId, String uid) async {
|
||||||
|
log(" ===== update Firebase uid : " + customerId.toString() + ": " + uid);
|
||||||
|
await _client.post("customers/update_firebase_uid/" + customerId.toString(), uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deactivateCustomer(int customerId) async {
|
||||||
|
log(" ===== deactivate : $customerId");
|
||||||
|
await _client.post("customers/deactivate/$customerId", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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<void> 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<void> 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<void> 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<CustomerProperty>? properties = await this.getActualProperties(customer.customerId!);
|
||||||
|
if (properties != null) {
|
||||||
|
this.initProperties(properties);
|
||||||
|
}
|
||||||
|
} on FormatException {
|
||||||
|
throw new Exception(responseBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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<CustomerProperty>? 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<CustomerProperty>? customerProperties) {
|
||||||
|
List<Property>? properties = Cache().getProperties();
|
||||||
|
Customer customer = Cache().userLoggedIn!;
|
||||||
|
customer.properties = LinkedHashMap<String, CustomerProperty>();
|
||||||
|
|
||||||
|
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<Customer> 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<List<Customer>> getTrainees(int trainerId) async {
|
||||||
|
List<Customer> 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<List<CustomerProperty>> getAllProperties(int customerId) async {
|
||||||
|
final body = await _client.get("customer_property/", customerId.toString());
|
||||||
|
final Iterable json = jsonDecode(body);
|
||||||
|
final List<CustomerProperty> properties = json.map((property) => CustomerProperty.fromJson(property)).toList();
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<CustomerProperty>?> getActualProperties(int customerId) async {
|
||||||
|
List<CustomerProperty>? 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<CustomerProperty> 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<CustomerProperty> 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;
|
||||||
|
}
|
||||||
|
}
|
17
lib/service/exercise_device_service.dart
Normal file
17
lib/service/exercise_device_service.dart
Normal file
@ -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<List<ExerciseDevice>> getDevices() async {
|
||||||
|
final body = await _client.get("exercise_device/", "");
|
||||||
|
final Iterable json = jsonDecode(body);
|
||||||
|
final List<ExerciseDevice> devices = json.map((device) => ExerciseDevice.fromJson(device)).toList();
|
||||||
|
Cache().setDevices(devices);
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
}
|
44
lib/service/exercise_service.dart
Normal file
44
lib/service/exercise_service.dart
Normal file
@ -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<void> 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<List<Exercise>> getExercisesByCustomer(int customerId) async {
|
||||||
|
final body = await _client.get("exercises/customer/", customerId.toString());
|
||||||
|
final Iterable json = jsonDecode(body);
|
||||||
|
final List<Exercise> exercises = json.map((exercise) {
|
||||||
|
Exercise item = Exercise.fromJson(exercise);
|
||||||
|
return item;
|
||||||
|
}).toList();
|
||||||
|
//exercises.sort( (a, b) => b.dateAdd.compareTo(a.dateAdd) );
|
||||||
|
|
||||||
|
return exercises;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Exercise> 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<void> 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;
|
||||||
|
}
|
||||||
|
}
|
82
lib/service/exercise_tree_service.dart
Normal file
82
lib/service/exercise_tree_service.dart
Normal file
@ -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<List<ExerciseTree>> getExerciseTree() async {
|
||||||
|
final String body = await _client.get("exercise_tree", "");
|
||||||
|
Iterable json = jsonDecode(body);
|
||||||
|
List<ExerciseTree>? 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<String> 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<List<ExerciseTree>> getExerciseTreeParents(List<ExerciseTree> exerciseTree) async {
|
||||||
|
List<ExerciseTree> copyList = this.copyList(exerciseTree);
|
||||||
|
|
||||||
|
final String body = await _client.get("exercise_tree_parents", "");
|
||||||
|
Iterable json = jsonDecode(body);
|
||||||
|
final List<ExerciseTreeParents> 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<ExerciseTree> copyList(List<ExerciseTree> tree) {
|
||||||
|
final List<ExerciseTree> copyList = [];
|
||||||
|
tree.forEach((element) {
|
||||||
|
final ExerciseTree copy = element.copy(-1);
|
||||||
|
copyList.add(copy);
|
||||||
|
});
|
||||||
|
|
||||||
|
return copyList;
|
||||||
|
}
|
||||||
|
}
|
40
lib/service/exercise_type_service.dart
Normal file
40
lib/service/exercise_type_service.dart
Normal file
@ -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<List<ExerciseType>> getExerciseTypes() async {
|
||||||
|
final body = await _client.get("exercise_type", "");
|
||||||
|
final Iterable json = jsonDecode(body);
|
||||||
|
final List<ExerciseType> 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<String> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
403
lib/service/firebase_api.dart
Normal file
403
lib/service/firebase_api.dart
Normal file
@ -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<void> 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<String> 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<String> 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<Map<String, dynamic>> signInWithApple() async {
|
||||||
|
Map<String, dynamic> 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<Map<String, dynamic>> registerWithApple() async {
|
||||||
|
Map<String, dynamic> 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<Map<String, dynamic>> signInWithGoogle() async {
|
||||||
|
Map<String, dynamic> 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<Map<String, dynamic>> registerWithGoogle() async {
|
||||||
|
Map<String, dynamic> 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<Map<String, dynamic>> signInWithFacebook() async {
|
||||||
|
Map<String, dynamic> 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<Map<String, dynamic>> registerWithFacebook() async {
|
||||||
|
Map<String, dynamic> 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<void> logOutFacebook() async {
|
||||||
|
await FacebookAuth.instance.logOut();
|
||||||
|
Cache().accessTokenFacebook = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> signOut() async {
|
||||||
|
await FirebaseAuth.instance.signOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> resetPassword(String email) async {
|
||||||
|
await FirebaseAuth.instance.sendPasswordResetEmail(email: email);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> 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(<String, dynamic>{
|
||||||
|
'sales_page_text_a': '',
|
||||||
|
'product_set_2': '',
|
||||||
|
'registration_skip_color': '',
|
||||||
|
'email_checkbox': '',
|
||||||
|
});
|
||||||
|
Cache().setRemoteConfig(remoteConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _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<void> _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<String, dynamic> 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);
|
||||||
|
}
|
||||||
|
} */
|
29
lib/service/mautic.dart
Normal file
29
lib/service/mautic.dart
Normal file
@ -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<void> 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!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
210
lib/service/package_service.dart
Normal file
210
lib/service/package_service.dart
Normal file
@ -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<void> getPackage() async {
|
||||||
|
late List<ExerciseTree> exerciseTree;
|
||||||
|
late List<ExerciseTreeParents> exerciseTreeParents;
|
||||||
|
final body = await _client.get("app_package/", "");
|
||||||
|
|
||||||
|
final List<String> models = body.split("|||");
|
||||||
|
await Future.forEach(models, (elem) async {
|
||||||
|
final String element = elem as String;
|
||||||
|
final List<String> headRecord = element.split("***");
|
||||||
|
final Iterable json = jsonDecode(headRecord[1]);
|
||||||
|
if (headRecord[0] == "ExerciseDevice") {
|
||||||
|
final List<ExerciseDevice> devices = json.map((device) => ExerciseDevice.fromJson(device)).toList();
|
||||||
|
Cache().setDevices(devices);
|
||||||
|
} else if (headRecord[0] == "Product") {
|
||||||
|
final List<Product> products = json.map((product) => Product.fromJson(product)).toList();
|
||||||
|
Cache().setProducts(products);
|
||||||
|
} else if (headRecord[0] == "Property") {
|
||||||
|
final List<Property> 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<ExerciseType> 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<ExercisePlanTemplate> 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<Evaluation> evaluations = json.map((evaluation) => Evaluation.fromJson(evaluation)).toList();
|
||||||
|
Cache().evaluations = evaluations;
|
||||||
|
} else if (headRecord[0] == "Sport") {
|
||||||
|
final List<Sport> sports = json.map((sport) => Sport.fromJson(sport)).toList();
|
||||||
|
Cache().setSports(sports);
|
||||||
|
} else if (headRecord[0] == "Tutorial") {
|
||||||
|
final Iterable json = jsonDecode(headRecord[1]);
|
||||||
|
final List<Tutorial> tutorials = json.map((tutorial) => Tutorial.fromJson(tutorial)).toList();
|
||||||
|
|
||||||
|
Cache().setTutorials(tutorials);
|
||||||
|
} else if (headRecord[0] == "Description") {
|
||||||
|
final Iterable json = jsonDecode(headRecord[1]);
|
||||||
|
final List<Description>? 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<Faq>? 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<TrainingPlan>? plans = json.map((plan) => TrainingPlan.fromJson(plan)).toList();
|
||||||
|
|
||||||
|
List<TrainingPlan> 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<SplitTest>? 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<TrainingPlanDay>? 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<ExerciseTree> getExerciseTreeParents(final List<ExerciseTree> exerciseTree, final List<ExerciseTreeParents> exerciseTreeParents) {
|
||||||
|
List<ExerciseTree> 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<void> getCustomerPackage(int customerId) async {
|
||||||
|
try {
|
||||||
|
final body = await _client.get("app_customer_package/" + customerId.toString(), "");
|
||||||
|
|
||||||
|
final List<String> models = body.split("|||");
|
||||||
|
await Future.forEach(models, (elem) async {
|
||||||
|
final String element = elem as String;
|
||||||
|
final List<String> 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<CustomerExerciseDevice> 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<Exercise> exercises = json.map((exerciseType) => Exercise.fromJson(exerciseType)).toList();
|
||||||
|
Cache().setExercises(exercises);
|
||||||
|
} else if (headRecord[0] == "Purchase") {
|
||||||
|
final Iterable json = jsonDecode(headRecord[1]);
|
||||||
|
final List<Purchase> purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList();
|
||||||
|
Cache().setPurchases(purchases);
|
||||||
|
} else if (headRecord[0] == "CustomerProperty") {
|
||||||
|
final Iterable json = jsonDecode(headRecord[1]);
|
||||||
|
final List<CustomerProperty> customerProperties = json.map((property) => CustomerProperty.fromJson(property)).toList();
|
||||||
|
CustomerApi().initProperties(customerProperties);
|
||||||
|
} else if (headRecord[0] == "CustomerPropertyAll") {
|
||||||
|
final Iterable json = jsonDecode(headRecord[1]);
|
||||||
|
final List<CustomerProperty> 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<ExerciseResult> 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<CustomerActivity> customerActivities = json.map((activity) => CustomerActivity.fromJson(activity)).toList();
|
||||||
|
Cache().setCustomerActivities(customerActivities);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} on NotFoundException catch (e) {
|
||||||
|
throw Exception("Please log in $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
lib/service/product_service.dart
Normal file
17
lib/service/product_service.dart
Normal file
@ -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<List<Product>> getProducts() async {
|
||||||
|
final body = await _client.get("product/", "");
|
||||||
|
final Iterable json = jsonDecode(body);
|
||||||
|
final List<Product> products = json.map((product) => Product.fromJson(product)).toList();
|
||||||
|
Cache().setProducts(products);
|
||||||
|
return products;
|
||||||
|
}
|
||||||
|
}
|
18
lib/service/property_service.dart
Normal file
18
lib/service/property_service.dart
Normal file
@ -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<List<Property>> getProperties() async {
|
||||||
|
final body = await _client.get("property/", "");
|
||||||
|
final Iterable json = jsonDecode(body);
|
||||||
|
final List<Property> properties = json.map((property) => Property.fromJson(property)).toList();
|
||||||
|
Cache().setProperties(properties);
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
29
lib/service/purchase_service.dart
Normal file
29
lib/service/purchase_service.dart
Normal file
@ -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<List<Purchase>> getPurchasesByCustomer(int customerId) async {
|
||||||
|
List<Purchase> purchases = [];
|
||||||
|
try {
|
||||||
|
final body = await _client.get("purchase/customer/" + customerId.toString(), "");
|
||||||
|
final Iterable json = jsonDecode(body);
|
||||||
|
final List<Purchase> purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList();
|
||||||
|
Cache().setPurchases(purchases);
|
||||||
|
} on NotFoundException catch (_) {
|
||||||
|
log("No purchases found");
|
||||||
|
}
|
||||||
|
return purchases;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> savePurchase(Purchase purchase) async {
|
||||||
|
String body = JsonEncoder().convert(purchase.toJson());
|
||||||
|
log(" ===== saving purchase:" + body);
|
||||||
|
await _client.post("purchase/", body);
|
||||||
|
}
|
||||||
|
}
|
18
lib/service/tracking_service.dart
Normal file
18
lib/service/tracking_service.dart
Normal file
@ -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<void> 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()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
lib/service/training_plan_service.dart
Normal file
34
lib/service/training_plan_service.dart
Normal file
@ -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<CustomerTrainingPlan> 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<CustomerTrainingPlanExercise> 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<CustomerTrainingPlan> 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;
|
||||||
|
}
|
||||||
|
}
|
68
lib/util/app_language.dart
Normal file
68
lib/util/app_language.dart
Normal file
@ -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<AppLanguage> getInstance() async {
|
||||||
|
return _singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
Locale get appLocal => _appLocale ?? Locale("en");
|
||||||
|
|
||||||
|
Future<void> 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());
|
||||||
|
}
|
||||||
|
}
|
78
lib/util/app_localization.dart
Normal file
78
lib/util/app_localization.dart
Normal file
@ -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<String, String> _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<AppLocalizations>(context, AppLocalizations);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static member to have a simple access to the delegate from the MaterialApp
|
||||||
|
static const LocalizationsDelegate<AppLocalizations> delegate = AppLocalizationsDelegate();
|
||||||
|
|
||||||
|
setLocale(Locale locale) {
|
||||||
|
this.locale = locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> 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<String, dynamic> jsonMap = json.decode(jsonString);
|
||||||
|
|
||||||
|
_localizedStrings = jsonMap.map((key, value) {
|
||||||
|
return MapEntry(key, value.toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<AppLocalizations> 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<AppLocalizations> {
|
||||||
|
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<AppLocalizations> 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;
|
||||||
|
}
|
176
lib/util/common.dart
Normal file
176
lib/util/common.dart
Normal file
@ -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<String, String> 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<int> 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 {}
|
129
lib/util/enums.dart
Normal file
129
lib/util/enums.dart
Normal file
@ -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<T>(Iterable<T> 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();
|
||||||
|
}
|
3
lib/util/env.dart
Normal file
3
lib/util/env.dart
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
class EnvironmentConfig {
|
||||||
|
static const test_env = String.fromEnvironment('test_env');
|
||||||
|
}
|
16
lib/util/logging.dart
Normal file
16
lib/util/logging.dart
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
lib/util/not_found_exception.dart
Normal file
13
lib/util/not_found_exception.dart
Normal file
@ -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});
|
||||||
|
}
|
5
lib/util/string_extension.dart
Normal file
5
lib/util/string_extension.dart
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
extension StringExtension on String {
|
||||||
|
String capitalize() {
|
||||||
|
return "${this[0].toUpperCase()}${this.substring(1).toLowerCase()}";
|
||||||
|
}
|
||||||
|
}
|
53
lib/util/track.dart
Normal file
53
lib/util/track.dart
Normal file
@ -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,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
1
lib/workouttest_util.dart
Normal file
1
lib/workouttest_util.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
library workouttest_util;
|
73
pubspec.yaml
Normal file
73
pubspec.yaml
Normal file
@ -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
|
9
test/workouttest_util_test.dart
Normal file
9
test/workouttest_util_test.dart
Normal file
@ -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', () {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user