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/'; static String baseUrlLocal = 'http://localhost:8443/api/'; late String baseUrl; static const String mediaUrl = 'https://admin.workouttest.org/media/'; static const String username = 'bosi'; static const String password = 'andio2009'; String authToken = ""; AccessToken? accessTokenFacebook; Customer? userLoggedIn; String? firebaseUid; String? firebaseMessageToken; LoginType? loginType; PackageInfo? packageInfo; bool hasPurchased = false; bool firstLoad = true; List? _exerciseTypes; List? _exerciseTree; List? evaluations; List? _exercises; ExercisePlan? _myExercisePlan; List? _properties; List? _sports; List? _products; List _purchases = []; List _splitTests = []; List _trainingPlanDays = []; List _exercisePlanTemplates = []; ExercisePlan? activeExercisePlan; CustomerTrainingPlan? myTrainingPlan; List? activeExercisePlanDetails; List? _devices; List? _customerDevices; List? _customerActivities; List? _customerTrainingPlans; List? _customerPropertyAll; List? _tutorials; List? _descriptions; List? _faqs; List? _trainingPlans; LinkedHashMap _myExercisesPlanDetails = LinkedHashMap(); LinkedHashMap _tree = LinkedHashMap(); double _percentExercises = -1; Customer? _trainee; List? _exercisesTrainee; ExercisePlan? _traineeExercisePlan; FirebaseRemoteConfig? remoteConfig; LinkedHashMap _badges = LinkedHashMap(); List? deviceLanguages; String startPage = "home"; late String testEnvironment; bool liveServer = true; bool? hasHardware = false; HashMap activitiesDone = HashMap(); factory Cache() { return _singleton; } Cache._internal() { String testEnv = EnvironmentConfig.test_env; testEnvironment = testEnv; log("testEnv $testEnv"); if (testEnv == "1") { baseUrl = baseUrlTest; liveServer = false; } else if ( testEnv == "2") { baseUrl = baseUrlLocal; liveServer = false; } for (var element in ActivityDone.values) { activitiesDone[element.toStr()] = false; } } void setTestBaseUrl() { baseUrl = baseUrlTest; } void setLocalBaseUrl() { baseUrl = baseUrlLocal; } String getAuthToken() { return authToken; } Future deleteCustomerId(int customerId) async { Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences = await prefs; sharedPreferences.remove(Cache.customerIdKey); } Future saveActiveExercisePlan(ExercisePlan exercisePlan, List exercisePlanDetails) async { activeExercisePlan = exercisePlan; activeExercisePlanDetails = exercisePlanDetails; String exercisePlanJson = const JsonEncoder().convert(exercisePlan.toJson()); String detailsJson = jsonEncode(exercisePlanDetails.map((i) => i.toJsonWithExerciseList()).toList()).toString(); Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences; sharedPreferences = await prefs; final DateTime now = DateTime.now(); sharedPreferences.setString(Cache.activeExercisePlanKey, exercisePlanJson); sharedPreferences.setString(Cache.activeExercisePlanDetailsKey, detailsJson); String savingDay = DateFormat("yyyy-MM-dd HH:mm:ss").format(now); sharedPreferences.setString(Cache.activeExercisePlanDateKey, savingDay); } Future saveMyTrainingPlan() async { if (myTrainingPlan == null) { return; } String myTrainingPlanJson = const JsonEncoder().convert(myTrainingPlan!.toJsonWithDetails()); Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences; sharedPreferences = await prefs; sharedPreferences.setString(Cache.myTrainingPlanKey, myTrainingPlanJson); } Future deleteMyTrainingPlan() async { if (myTrainingPlan == null) { return; } Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences; sharedPreferences = await prefs; sharedPreferences.remove(Cache.myTrainingPlanKey); } Future getMyTrainingPlan() async { Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences; sharedPreferences = await prefs; final String? savedTrainingPlanJson = sharedPreferences.getString(Cache.myTrainingPlanKey); if (savedTrainingPlanJson == null) { return; } //String jsonPlan = savedTrainingPlanJson.replaceAllMapped(RegExp(r'[a-zA-Z]+\:'), (Match m) => "\"${m[0]}\""); Map map; try { map = const JsonDecoder().convert(savedTrainingPlanJson); //log("Training plan: $savedTrainingPlanJson"); myTrainingPlan = CustomerTrainingPlan.fromJsonWithDetails(map); } on Exception catch (e) { log(e.toString()); } } Future deleteActiveExercisePlan() async { Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences; sharedPreferences = await prefs; sharedPreferences.remove(Cache.activeExercisePlanDateKey); activeExercisePlan = null; activeExercisePlanDetails = null; } Future getActiveExercisePlan() async { Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences; sharedPreferences = await prefs; final savedPlanDateString = sharedPreferences.getString(Cache.activeExercisePlanDateKey); if (savedPlanDateString == null) { return; } DateFormat format = DateFormat("yyyy-MM-dd HH:mm:ss"); DateTime savedPlanDate; savedPlanDate = format.parse(savedPlanDateString); log("Saved plan: $savedPlanDate"); final DateTime now = DateTime.now(); final DateTime added = savedPlanDate.add(const Duration(days: 1)); if (added.isBefore(now)) { return; } String? exercisePlanJson = sharedPreferences.getString(Cache.activeExercisePlanKey); if (exercisePlanJson != null) { final Map map = const JsonDecoder().convert(exercisePlanJson); activeExercisePlan = ExercisePlan.fromJson(map); } String? detailsJson = sharedPreferences.getString(Cache.activeExercisePlanDetailsKey); if (detailsJson != null) { Iterable json = jsonDecode(detailsJson); activeExercisePlanDetails = json.map((details) => ExercisePlanDetail.fromJsonWithExerciseList(details)).toList(); } } Future setServer(bool live) async { if (testEnvironment == "1") { liveServer = false; live = false; } Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences; sharedPreferences = await prefs; liveServer = live; sharedPreferences.setBool(Cache.serverKey, live); } void getHardware(SharedPreferences prefs) { final bool? hasHardware = prefs.getBool(Cache.hardwareKey); this.hasHardware = hasHardware; if (hasHardware == null) { this.hasHardware = false; } } Future selectedHardwareBefore() async { Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences = await prefs; final bool? selectedHardware = sharedPreferences.getBool(Cache.hardwareKey); return selectedHardware == null; } Future setHardware(bool hasHardware) async { Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences; sharedPreferences = await prefs; sharedPreferences.setBool(Cache.hardwareKey, hasHardware); hasHardware = hasHardware; } void setServerAddress(SharedPreferences prefs) { if (testEnvironment == "1") { baseUrl = baseUrlTest; log("TestEnv $baseUrl"); return; } else if ( testEnvironment == "2") { baseUrl = baseUrlLocal; log("TestEnv $baseUrl"); return; } final bool? live = prefs.getBool(Cache.serverKey); if (live == null) { baseUrl = baseUrlLive; log("Live Env $baseUrl"); liveServer = true; return; } liveServer = live; if (live) { baseUrl = baseUrlLive; } else { baseUrl = baseUrlTest; } log("Env $baseUrl"); } Future setLoginTypeFromPrefs() async { Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences = await prefs; final String? loginType = sharedPreferences.getString(Cache.loginTypeKey); LoginType type = LoginType.email; if (loginType == LoginType.apple.toString()) { type = LoginType.apple; } else if (loginType == LoginType.google.toString()) { type = LoginType.google; } else if (loginType == LoginType.fb.toString()) { type = LoginType.fb; } else if (loginType == LoginType.email.toString()) { type = LoginType.email; } //log("LoginType: " + loginType == null ? "NULL" : loginType); Cache().setLoginType(type); } static String? getToken(SharedPreferences prefs) { return prefs.getString(authTokenKey); } String getBaseUrl() { return baseUrl; } static String getMediaUrl() { return mediaUrl; } afterRegistration(Customer customer) async { Future prefs = SharedPreferences.getInstance(); userLoggedIn = customer; final String uid = Cache().firebaseUid!; SharedPreferences sharedPreferences = await prefs; sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString()); await setPreferences(prefs, SharePrefsChange.registration, customer.customerId!, uid); } afterLogin(Customer customer) async { Future prefs = SharedPreferences.getInstance(); userLoggedIn = customer; SharedPreferences sharedPreferences = await prefs; sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString()); await setPreferences(prefs, SharePrefsChange.login, customer.customerId!, Cache().firebaseUid!); } afterFirebaseLogin() async { Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences = await prefs; sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString()); await setPreferences(prefs, SharePrefsChange.login, userLoggedIn!.customerId!, Cache().firebaseUid!); } afterFacebookLogin() async { Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences = await prefs; sharedPreferences.setString(Cache.loginTypeKey, Cache().getLoginType().toString()); await setPreferences(prefs, SharePrefsChange.login, userLoggedIn!.customerId!, Cache().firebaseUid!); } logout() async { if (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}"); Future prefs = SharedPreferences.getInstance(); await setPreferences(prefs, SharePrefsChange.logout, 0, ""); } Future setPreferences(Future prefs, SharePrefsChange type, int customerId, String firebaseUid) async { SharedPreferences sharedPreferences; sharedPreferences = await prefs; DateTime now = DateTime.now(); sharedPreferences.setString(Cache.lastStoreDateKey, now.toString()); if (type == SharePrefsChange.registration) { sharedPreferences.setInt(Cache.customerIdKey, customerId); sharedPreferences.setBool(Cache.isRegisteredKey, true); sharedPreferences.setBool(Cache.isLoggedInKey, true); sharedPreferences.setString(Cache.firebaseUidKey, firebaseUid); await initCustomer(customerId); } else if (type == SharePrefsChange.login) { sharedPreferences.setInt(Cache.customerIdKey, customerId); sharedPreferences.setString(Cache.firebaseUidKey, firebaseUid); sharedPreferences.setBool(Cache.isLoggedInKey, true); await initCustomer(customerId); } else if (type == SharePrefsChange.logout) { sharedPreferences.setBool(Cache.isLoggedInKey, false); sharedPreferences.setInt(Cache.customerIdKey, 0); sharedPreferences.setString(Cache.firebaseUidKey, ""); sharedPreferences.setString(authTokenKey, ""); } initBadges(); } void setExerciseTypes(List exerciseTypes) { _exerciseTypes = exerciseTypes; } void setExerciseTree(List exerciseTree) { _exerciseTree = exerciseTree; } void setExercises(List exercises) => _exercises = exercises; void setExercisesTrainee(List exercises) { _exercisesTrainee = exercises; } void setWorkoutMenuTree(LinkedHashMap tree) { _tree = tree; } List? getExerciseTypes() => _exerciseTypes; ExerciseType? getExerciseTypeById(int exerciseTypeId) { ExerciseType? exerciseType; if (_exerciseTypes != null) { for (var element in _exerciseTypes!) { if (element.exerciseTypeId == exerciseTypeId) { exerciseType = element; } } } return exerciseType; } List? getExerciseTree() => _exerciseTree; List? getExercises() => _exercises; List? getExercisesTrainee() => _exercisesTrainee; LinkedHashMap getWorkoutMenuTree() => _tree; void setPercentExercises(double percent) => _percentExercises = percent; double getPercentExercises() => _percentExercises; void addExercise(Exercise exercise) => _exercises!.add(exercise); void addExerciseTrainee(Exercise exercise) => _exercisesTrainee!.add(exercise); Customer? getTrainee() => _trainee; void setTrainee(Customer trainee) => _trainee = trainee; void setTraineeExercisePlan(ExercisePlan exercisePlan) => _traineeExercisePlan = exercisePlan; ExercisePlan? getTraineesExercisePlan() => _traineeExercisePlan; void setMyExercisePlan(ExercisePlan exercisePlan) => _myExercisePlan = exercisePlan; ExercisePlan? getMyExercisePlan() => _myExercisePlan; void setMyExercisePlanDetails(LinkedHashMap listExercisePlanDetail) => _myExercisesPlanDetails = listExercisePlanDetail; void addToMyExercisePlanDetails(ExercisePlanDetail detail) => _myExercisesPlanDetails[detail.exerciseTypeId] = detail; LinkedHashMap getMyExercisePlanDetails() => _myExercisesPlanDetails; void resetMyExercisePlanDetails() => _myExercisesPlanDetails = LinkedHashMap(); void updateMyExercisePlanDetail(ExercisePlanDetail detail) { addToMyExercisePlanDetails(detail); } void deleteMyExercisePlanDetail(ExercisePlanDetail detail) => deleteMyExercisePlanDetailByExerciseTypeId(detail.exerciseTypeId); void deletedMyExercisePlanDetail(ExercisePlanDetail detail) => _myExercisesPlanDetails[detail.exerciseTypeId]!.change = ModelChange.deleted; void deleteMyExercisePlanDetailByExerciseTypeId(int exerciseTypeId) { _myExercisesPlanDetails[exerciseTypeId]!.change = ModelChange.delete; } void setProperties(List properties) => _properties = properties; List? getProperties() => _properties; List? getSports() => _sports; void setSports(List sports) => _sports = sports; void setDevices(List devices) => _devices = devices; List? getDevices() => _devices; void setCustomerDevices(List devices) => _customerDevices = devices; List? getCustomerDevices() => _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(); //log("endo " + _endo.toString() + " mezo " + _mezo.toString()); if (userLoggedIn != null) { if (userLoggedIn!.birthYear == null || userLoggedIn!.birthYear == 0) { setBadge("personalData", true); setBadge("account", true); } if (_customerDevices == null || _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 (_exercises == null || _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 (_exercises != null && _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"); } List? get products => _products; void setProducts(List value) => _products = value; List get purchases => _purchases; setPurchases(List value) => _purchases = value; Future initCustomer(int customerId) async { log(" *** initCustomer"); try { await PackageApi().getCustomerPackage(customerId); } on Exception catch (_) { return; } if (kReleaseMode) { //FlurryData.setUserId(customerId.toString()); //FlutterUxcam.setUserProperty("username", customerId.toString()); //FlutterUxcam.setUserIdentity(customerId.toString()); //Smartlook.setUserIdentifier(customerId.toString()); //Smartlook.instance. Track().track(TrackingEvent.enter); MatomoTracker.instance.setVisitorUserId(customerId.toString()); MatomoTracker.instance.trackEvent(eventCategory: "wt", action: TrackingEvent.enter.enumToString()); Posthog().identify(userId: customerId.toString()); Posthog().capture(eventName: TrackingEvent.enter.enumToString()); } await Future.forEach(ActivityDone.values, (element) async { ActivityDone activity = element; await isActivityDonePrefs(activity); }); log("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) => accessTokenFacebook = accessTokenFacebook; LoginType? getLoginType() => loginType; void setLoginType(LoginType type) => loginType = type; List get exercisePlanTemplates => _exercisePlanTemplates; setExercisePlanTemplates(value) => _exercisePlanTemplates = value; isActivityDonePrefs(ActivityDone activity) async { Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences = await prefs; if (sharedPreferences.getBool(activity.toStr()) != null) { activitiesDone[activity.toStr()] = sharedPreferences.getBool(activity.toStr())!; } return activitiesDone[activity.toStr()]!; } setActivityDonePrefs(ActivityDone activity) async { Future prefs = SharedPreferences.getInstance(); SharedPreferences sharedPreferences = await prefs; activitiesDone[activity.toStr()] = true; sharedPreferences.setBool(activity.toStr(), true); } bool isActivityDone(ActivityDone activity) => activitiesDone[activity.toStr()] == true; List? get customerActivities => _customerActivities; setCustomerActivities(List? value) => _customerActivities = value; List? get tutorials => _tutorials; setTutorials(List? value) => _tutorials = value; FirebaseRemoteConfig? getRemoteConfig() => remoteConfig; setRemoteConfig(FirebaseRemoteConfig? remoteConfig) => remoteConfig = remoteConfig; List? getDescriptions() => _descriptions; setDescriptions(List? value) => _descriptions = value; List? getFaqs() => _faqs; setFaqs(List? value) => _faqs = value; List? getTrainingPlans() => _trainingPlans; setTrainingPlans(List? value) => _trainingPlans = value; List? getCustomerTrainingPlans() => _customerTrainingPlans; setCustomerTrainingPlans(value) => _customerTrainingPlans = value; List getSplitTests() => _splitTests; setSplitTests(value) => _splitTests = value; List getTrainingPlanDays() => _trainingPlanDays; setTrainingPlanDays(value) => _trainingPlanDays = value; List? getCustomerPropertyAll() => _customerPropertyAll; setCustomerPropertyAll(value) => _customerPropertyAll = value; addCustomerProperty(CustomerProperty property) { _customerPropertyAll ??= []; _customerPropertyAll!.add(property); } }