WT 1.1.20 Training Plan improvements, InApp Messageing

This commit is contained in:
bossanyit 2021-06-25 17:30:14 +02:00
parent a595ffb358
commit 211307e63e
36 changed files with 693 additions and 300 deletions

BIN
asset/menu/FG_2_edz.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
asset/menu/stretching.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
asset/menu/warmup.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@ -436,7 +436,7 @@
"Do you want to restart, or select a new Training Plan?": "Do you want to restart, or select a new Training Plan?", "Do you want to restart, or select a new Training Plan?": "Do you want to restart, or select a new Training Plan?",
"New Training Plan": "New Training Plan", "New Training Plan": "New Training Plan",
"Restart": "Restart", "Restart": "Restart",
"Training Day": "Training Day", "Training Day": "Day",
"No Active Training Plan": "No Active Training Plan", "No Active Training Plan": "No Active Training Plan",
"Please select one in the Training menu, or create your custom plan": "Please select one in the Training menu, or create your custom plan", "Please select one in the Training menu, or create your custom plan": "Please select one in the Training menu, or create your custom plan",
"Continue your training": "Continue your training", "Continue your training": "Continue your training",
@ -473,5 +473,8 @@
"A new version of Workout Test is available!": "A new version of Workout Test is available!", "A new version of Workout Test is available!": "A new version of Workout Test is available!",
"Update Now": "Update Now", "Update Now": "Update Now",
"Update App?": "Update App?", "Update App?": "Update App?",
"Want to update?": "Please update the app" "Want to update?": "Please update the app",
"Attention!": "Attention!",
"The safe and exact execution of this exercise you need a training buddy or a trainer": "The safe and exact execution of this exercise you need a training buddy or a trainer",
"Execution at your own risk!": "Execution at your own risk!"
} }

View File

@ -434,7 +434,7 @@
"Do you want to restart, or select a new Training Plan?": "Újra akarod indítani, vagy inkább egy másikat választasz?", "Do you want to restart, or select a new Training Plan?": "Újra akarod indítani, vagy inkább egy másikat választasz?",
"New Training Plan": "Másik edzésterv", "New Training Plan": "Másik edzésterv",
"Restart": "Újraindítom", "Restart": "Újraindítom",
"Training Day": "Edzésnap", "Training Day": "Nap",
"No Active Training Plan": "Nincs aktív edzésterv", "No Active Training Plan": "Nincs aktív edzésterv",
"Please select one in the Training menu, or create your custom plan": "Kérlek válassz egyet a Tréning menüben, vagy hozd létre a saját egyéni edzésedet", "Please select one in the Training menu, or create your custom plan": "Kérlek válassz egyet a Tréning menüben, vagy hozd létre a saját egyéni edzésedet",
"Continue your training": "Folytasd az edzést", "Continue your training": "Folytasd az edzést",
@ -471,5 +471,8 @@
"A new version of Workout Test is available!": "Egy új Workout Test verzió elérhető!", "A new version of Workout Test is available!": "Egy új Workout Test verzió elérhető!",
"Update Now": "Töltsd le most", "Update Now": "Töltsd le most",
"Update App?": "App frissítés", "Update App?": "App frissítés",
"Want to update?": "Kérlek töltsd le" "Want to update?": "Kérlek töltsd le",
"Attention!": "Figyelem!",
"The safe and exact execution of this exercise you need a training buddy or a trainer": "A gyakorlat biztonságos és maximális pontosságú végrehajtásához edzőtárs vagy edző segítsége szükséges",
"Execution at your own risk!": "Végrehajtás CSAK saját felelőségre!"
} }

View File

@ -4,7 +4,7 @@ PODS:
- AppAuth/ExternalUserAgent (= 1.4.0) - AppAuth/ExternalUserAgent (= 1.4.0)
- AppAuth/Core (1.4.0) - AppAuth/Core (1.4.0)
- AppAuth/ExternalUserAgent (1.4.0) - AppAuth/ExternalUserAgent (1.4.0)
- apple_sign_in (0.0.1): - awesome_notifications (0.0.2):
- Flutter - Flutter
- device_info (0.0.1): - device_info (0.0.1):
- Flutter - Flutter
@ -116,10 +116,10 @@ PODS:
- FirebaseInstallations (~> 8.0) - FirebaseInstallations (~> 8.0)
- GoogleUtilities/Environment (~> 7.4) - GoogleUtilities/Environment (~> 7.4)
- "GoogleUtilities/NSData+zlib (~> 7.4)" - "GoogleUtilities/NSData+zlib (~> 7.4)"
- flurry (0.0.4): - Flurry-iOS-SDK/FlurrySDK (11.2.1)
- flurry_data (0.0.1):
- Flurry-iOS-SDK/FlurrySDK - Flurry-iOS-SDK/FlurrySDK
- Flutter - Flutter
- Flurry-iOS-SDK/FlurrySDK (11.2.1)
- Flutter (1.0.0) - Flutter (1.0.0)
- flutter_app_badger (0.0.1): - flutter_app_badger (0.0.1):
- Flutter - Flutter
@ -127,8 +127,6 @@ PODS:
- FBSDKCoreKit (~> 9.1.0) - FBSDKCoreKit (~> 9.1.0)
- FBSDKLoginKit (~> 9.1.0) - FBSDKLoginKit (~> 9.1.0)
- Flutter - Flutter
- flutter_local_notifications (0.0.1):
- Flutter
- flutter_secure_storage (3.3.1): - flutter_secure_storage (3.3.1):
- Flutter - Flutter
- flutter_uxcam (2.0.0-beta.1): - flutter_uxcam (2.0.0-beta.1):
@ -215,6 +213,8 @@ PODS:
- Sentry (~> 7.0.3) - Sentry (~> 7.0.3)
- shared_preferences (0.0.1): - shared_preferences (0.0.1):
- Flutter - Flutter
- sign_in_with_apple (0.0.1):
- Flutter
- sqflite (0.0.2): - sqflite (0.0.2):
- Flutter - Flutter
- FMDB (>= 2.7.5) - FMDB (>= 2.7.5)
@ -229,7 +229,7 @@ PODS:
- Flutter - Flutter
DEPENDENCIES: DEPENDENCIES:
- apple_sign_in (from `.symlinks/plugins/apple_sign_in/ios`) - awesome_notifications (from `.symlinks/plugins/awesome_notifications/ios`)
- device_info (from `.symlinks/plugins/device_info/ios`) - device_info (from `.symlinks/plugins/device_info/ios`)
- devicelocale (from `.symlinks/plugins/devicelocale/ios`) - devicelocale (from `.symlinks/plugins/devicelocale/ios`)
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
@ -237,11 +237,10 @@ DEPENDENCIES:
- firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- firebase_remote_config (from `.symlinks/plugins/firebase_remote_config/ios`) - firebase_remote_config (from `.symlinks/plugins/firebase_remote_config/ios`)
- flurry (from `.symlinks/plugins/flurry/ios`) - flurry_data (from `.symlinks/plugins/flurry_data/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- flutter_app_badger (from `.symlinks/plugins/flutter_app_badger/ios`) - flutter_app_badger (from `.symlinks/plugins/flutter_app_badger/ios`)
- flutter_facebook_auth (from `.symlinks/plugins/flutter_facebook_auth/ios`) - flutter_facebook_auth (from `.symlinks/plugins/flutter_facebook_auth/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- flutter_uxcam (from `.symlinks/plugins/flutter_uxcam/ios`) - flutter_uxcam (from `.symlinks/plugins/flutter_uxcam/ios`)
- google_sign_in (from `.symlinks/plugins/google_sign_in/ios`) - google_sign_in (from `.symlinks/plugins/google_sign_in/ios`)
@ -252,6 +251,7 @@ DEPENDENCIES:
- purchases_flutter (from `.symlinks/plugins/purchases_flutter/ios`) - purchases_flutter (from `.symlinks/plugins/purchases_flutter/ios`)
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`) - sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`) - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
- video_player (from `.symlinks/plugins/video_player/ios`) - video_player (from `.symlinks/plugins/video_player/ios`)
@ -289,8 +289,8 @@ SPEC REPOS:
- UXCam - UXCam
EXTERNAL SOURCES: EXTERNAL SOURCES:
apple_sign_in: awesome_notifications:
:path: ".symlinks/plugins/apple_sign_in/ios" :path: ".symlinks/plugins/awesome_notifications/ios"
device_info: device_info:
:path: ".symlinks/plugins/device_info/ios" :path: ".symlinks/plugins/device_info/ios"
devicelocale: devicelocale:
@ -305,16 +305,14 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/firebase_messaging/ios" :path: ".symlinks/plugins/firebase_messaging/ios"
firebase_remote_config: firebase_remote_config:
:path: ".symlinks/plugins/firebase_remote_config/ios" :path: ".symlinks/plugins/firebase_remote_config/ios"
flurry: flurry_data:
:path: ".symlinks/plugins/flurry/ios" :path: ".symlinks/plugins/flurry_data/ios"
Flutter: Flutter:
:path: Flutter :path: Flutter
flutter_app_badger: flutter_app_badger:
:path: ".symlinks/plugins/flutter_app_badger/ios" :path: ".symlinks/plugins/flutter_app_badger/ios"
flutter_facebook_auth: flutter_facebook_auth:
:path: ".symlinks/plugins/flutter_facebook_auth/ios" :path: ".symlinks/plugins/flutter_facebook_auth/ios"
flutter_local_notifications:
:path: ".symlinks/plugins/flutter_local_notifications/ios"
flutter_secure_storage: flutter_secure_storage:
:path: ".symlinks/plugins/flutter_secure_storage/ios" :path: ".symlinks/plugins/flutter_secure_storage/ios"
flutter_uxcam: flutter_uxcam:
@ -335,6 +333,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/sentry_flutter/ios" :path: ".symlinks/plugins/sentry_flutter/ios"
shared_preferences: shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios" :path: ".symlinks/plugins/shared_preferences/ios"
sign_in_with_apple:
:path: ".symlinks/plugins/sign_in_with_apple/ios"
sqflite: sqflite:
:path: ".symlinks/plugins/sqflite/ios" :path: ".symlinks/plugins/sqflite/ios"
url_launcher: url_launcher:
@ -348,7 +348,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
AppAuth: 31bcec809a638d7bd2f86ea8a52bd45f6e81e7c7 AppAuth: 31bcec809a638d7bd2f86ea8a52bd45f6e81e7c7
apple_sign_in: 7716c7ddfa195aeab7dec0dc374ef4ff45d1adb4 awesome_notifications: 74462bc8e68b11f8235d78422266886759e9da61
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
devicelocale: b22617f40038496deffba44747101255cee005b0 devicelocale: b22617f40038496deffba44747101255cee005b0
FBSDKCoreKit: a00fe2efd780c195a5e09201bf51c56106245b40 FBSDKCoreKit: a00fe2efd780c195a5e09201bf51c56106245b40
@ -367,12 +367,11 @@ SPEC CHECKSUMS:
FirebaseInstallations: c4aab1005d6547b00a7529777fe52f5d4d45165b FirebaseInstallations: c4aab1005d6547b00a7529777fe52f5d4d45165b
FirebaseMessaging: 1a33b4af3c8042ed6ddacb6c031894af2064bfab FirebaseMessaging: 1a33b4af3c8042ed6ddacb6c031894af2064bfab
FirebaseRemoteConfig: 055f6b5ba1751547596ded5032c4d5c6054ca501 FirebaseRemoteConfig: 055f6b5ba1751547596ded5032c4d5c6054ca501
flurry: 15b01f664ab1367c62b50291541ea7f78ca85aad
Flurry-iOS-SDK: 5831da8fc6bedb31fa1f94aac6fd204d36dd351d Flurry-iOS-SDK: 5831da8fc6bedb31fa1f94aac6fd204d36dd351d
flurry_data: 49b7066a283aa41f4306974c1f2d74c61231ad74
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68 flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68
flutter_facebook_auth: 4b170c07b7fce791497093fcc3f134fb215f3f07 flutter_facebook_auth: 4b170c07b7fce791497093fcc3f134fb215f3f07
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
flutter_uxcam: ab8e5d3954eb448febd581375e2622e9eecb1066 flutter_uxcam: ab8e5d3954eb448febd581375e2622e9eecb1066
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
@ -396,6 +395,7 @@ SPEC CHECKSUMS:
Sentry: 5b16f877da362d23716d827e04db642455b26b40 Sentry: 5b16f877da362d23716d827e04db642455b26b40
sentry_flutter: 602dc1902e152269256115e2386e1029511f3440 sentry_flutter: 602dc1902e152269256115e2386e1029511f3440
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
sign_in_with_apple: 34f3f5456a45fd7ac5fb42905e2ad31dae061b4a
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
UXCam: c2c00873595ab89be227f197213dc3679ff88ae5 UXCam: c2c00873595ab89be227f197213dc3679ff88ae5

View File

@ -388,7 +388,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 11; CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = SFJJBDCU6Z; DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -405,7 +405,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.1.18; MARKETING_VERSION = 1.1.20;
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app; PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -531,7 +531,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 11; CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = SFJJBDCU6Z; DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -548,7 +548,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.1.18; MARKETING_VERSION = 1.1.20;
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app; PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -566,7 +566,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 11; CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = SFJJBDCU6Z; DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -583,7 +583,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.1.18; MARKETING_VERSION = 1.1.20;
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app; PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

View File

@ -87,9 +87,9 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
yield LoginSuccess(); yield LoginSuccess();
} else if (event is RegistrationSubmit) { } else if (event is RegistrationSubmit) {
yield LoginLoading(); yield LoginLoading();
if (!this.dataPolicyAllowed) { /* if (!this.dataPolicyAllowed) {
throw Exception("Please accept our data policy"); throw Exception("Please accept our data policy");
} } */
final String? validationError = validate(); final String? validationError = validate();
if (validationError != null) { if (validationError != null) {
yield LoginError(message: validationError); yield LoginError(message: validationError);
@ -104,9 +104,9 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
} }
} else if (event is RegistrationFB) { } else if (event is RegistrationFB) {
yield LoginLoading(); yield LoginLoading();
if (!this.dataPolicyAllowed) { /* if (!this.dataPolicyAllowed) {
throw Exception("Please accept our data policy"); throw Exception("Please accept our data policy");
} } */
Cache().setLoginType(LoginType.fb); Cache().setLoginType(LoginType.fb);
await userRepository.addUserFB(); await userRepository.addUserFB();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!)); accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
@ -116,9 +116,9 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
yield LoginSuccess(); yield LoginSuccess();
} else if (event is RegistrationGoogle) { } else if (event is RegistrationGoogle) {
yield LoginLoading(); yield LoginLoading();
if (!this.dataPolicyAllowed) { /* if (!this.dataPolicyAllowed) {
throw Exception("Please accept our data policy"); throw Exception("Please accept our data policy");
} } */
Cache().setLoginType(LoginType.google); Cache().setLoginType(LoginType.google);
await userRepository.addUserGoogle(); await userRepository.addUserGoogle();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!)); accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
@ -128,9 +128,9 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
yield LoginSuccess(); yield LoginSuccess();
} else if (event is RegistrationApple) { } else if (event is RegistrationApple) {
yield LoginLoading(); yield LoginLoading();
if (!this.dataPolicyAllowed) { /* if (!this.dataPolicyAllowed) {
throw Exception("Please accept our data policy"); throw Exception("Please accept our data policy");
} } */
Cache().setLoginType(LoginType.apple); Cache().setLoginType(LoginType.apple);
await userRepository.addUserApple(); await userRepository.addUserApple();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!)); accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));

View File

@ -58,15 +58,16 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
await Cache().saveMyTrainingPlan(); await Cache().saveMyTrainingPlan();
yield TrainingPlanFinished(); yield TrainingPlanFinished();
} else if (event is TrainingPlanWeightChange) { } else if (event is TrainingPlanWeightChange) {
yield TrainingPlanLoading(); yield TrainingPlanExerciseLoading();
event.detail.weight = event.weight; event.detail.weight = event.weight;
yield TrainingPlanExerciseReady();
yield TrainingPlanReady(); yield TrainingPlanReady();
} else if (event is TrainingPlanRepeatsChange) { } else if (event is TrainingPlanRepeatsChange) {
yield TrainingPlanLoading(); yield TrainingPlanExerciseLoading();
event.detail.repeats = event.repeats; event.detail.repeats = event.repeats;
yield TrainingPlanExerciseReady();
yield TrainingPlanReady(); yield TrainingPlanReady();
} else if (event is TrainingPlanSetChange) { } else if (event is TrainingPlanSetChange) {
yield TrainingPlanLoading(); yield TrainingPlanLoading();
@ -91,10 +92,13 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
} else if (event.detail.exercises.length >= 0) { } else if (event.detail.exercises.length >= 0) {
event.detail.state = ExercisePlanDetailState.inProgress; event.detail.state = ExercisePlanDetailState.inProgress;
} }
// recalculate the weight to the original planned repeats for the next details
// recalculate the weight to the original planned repeats if (exercise.unitQuantity != null && exercise.unitQuantity! > 0) {
if (event.detail.isTest && event.detail.exercises.length == 1) { for (var nextDetail in _myPlan!.details) {
trainingPlanRepository.recalculateDetail(_myPlan!.trainingPlanId!, event.detail); if (nextDetail.exerciseTypeId == event.detail.exerciseTypeId && nextDetail.weight == -2) {
trainingPlanRepository.recalculateDetail(_myPlan!.trainingPlanId!, event.detail, nextDetail);
}
}
} }
exercise.trainingPlanDetailsId = _myPlan!.trainingPlanId; exercise.trainingPlanDetailsId = _myPlan!.trainingPlanId;
@ -230,28 +234,61 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
dayNames.clear(); dayNames.clear();
_myPlan!.days.clear(); _myPlan!.days.clear();
String dayName = "."; String dayName = ".";
String previousDay = ".";
_myPlan!.details.forEach((element) { _myPlan!.details.forEach((element) {
if (element.day != null && element.day != dayName) { if (element.day != null && element.day != dayName) {
dayNames.add(element.day!); dayNames.add(element.day!);
dayName = element.day!; dayName = element.day!;
if (previousDay != ".") {
this.addExtraExerciseType("Stretching", previousDay);
}
} }
if (_myPlan!.days[dayName] == null) { if (_myPlan!.days[dayName] == null) {
if (dayName == ".") { if (dayName == ".") {
dayName = ""; dayName = "";
} }
_myPlan!.days[dayName] = []; _myPlan!.days[dayName] = [];
this.addExtraExerciseType("Warming Up", dayName);
previousDay = dayName;
} }
_myPlan!.days[dayName]!.add(element); _myPlan!.days[dayName]!.add(element);
}); });
if (dayNames.length == 0) { if (dayNames.length == 0) {
dayNames.add(""); dayName = "";
_myPlan!.days[""] = []; dayNames.add(dayName);
_myPlan!.days[""]!.addAll(_myPlan!.details); _myPlan!.days[dayName] = [];
_myPlan!.days[dayName]!.addAll(_myPlan!.details);
} }
getActiveDayIndex(); getActiveDayIndex();
} }
void addExtraExerciseType(String name, String dayName) {
if (Cache().getExerciseTypes() == null) {
return;
}
for (var exerciseType in Cache().getExerciseTypes()!) {
if (exerciseType.name == name) {
CustomerTrainingPlanDetails detail = CustomerTrainingPlanDetails();
detail.customerTrainingPlanDetailsId = 0;
detail.trainingPlanDetailsId = 0;
detail.exerciseTypeId = exerciseType.exerciseTypeId;
detail.repeats = 1;
detail.set = 1;
detail.day = "";
detail.parallel = false;
detail.restingTime = 0;
detail.exerciseType = exerciseType;
if (_myPlan!.days[dayName] == null) {
_myPlan!.days[dayName] = [];
}
_myPlan!.days[dayName]!.add(detail);
break;
}
}
}
CustomerTrainingPlanDetails? getTrainingPlanDetail(int trainingPlanDetailsId) { CustomerTrainingPlanDetails? getTrainingPlanDetail(int trainingPlanDetailsId) {
CustomerTrainingPlanDetails? detail; CustomerTrainingPlanDetails? detail;
if (_myPlan == null || _myPlan!.details.isEmpty) { if (_myPlan == null || _myPlan!.details.isEmpty) {
@ -297,13 +334,14 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
int minStep = 99; int minStep = 99;
for (final detail in this._myPlan!.details) { for (final detail in this._myPlan!.details) {
if (!detail.state.equalsTo(ExercisePlanDetailState.finished)) { if (!detail.state.equalsTo(ExercisePlanDetailState.finished)) {
if (detail.exercises.isEmpty && !detail.state.equalsTo(ExercisePlanDetailState.skipped)) { final day = dayNames[this.activeDayIndex];
if (detail.exercises.isEmpty && !detail.state.equalsTo(ExercisePlanDetailState.skipped) && day == detail.day) {
next = detail; next = detail;
minStep = 1; minStep = 1;
break; break;
} else { } else {
final int step = detail.exercises.length; final int step = detail.exercises.length;
if (step < minStep && !detail.state.equalsTo(ExercisePlanDetailState.skipped)) { if (step < minStep && !detail.state.equalsTo(ExercisePlanDetailState.skipped) && day == detail.day) {
next = detail; next = detail;
minStep = step; minStep = step;
if (detail.parallel != true) { if (detail.parallel != true) {
@ -313,7 +351,7 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
} }
} }
} }
print("Next detail $next"); //print("Next detail $next");
return next; return next;
} }
@ -379,20 +417,19 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
} }
int getActiveDayIndex() { int getActiveDayIndex() {
activeDayIndex = 0;
if (restarting) { if (restarting) {
return 0; return 0;
} }
if (_myPlan == null || _myPlan!.details.isEmpty) { if (_myPlan == null || _myPlan!.details.isEmpty) {
// throw Exception("No defined Training Plan");
return 0; return 0;
} }
if (dayNames.isEmpty || dayNames.length == 1) { if (dayNames.isEmpty || dayNames.length == 1) {
activeDayIndex = 0;
return 0; return 0;
} }
activeDayIndex = 0;
for (var day in dayNames) { for (var day in dayNames) {
if (_myPlan!.days[day] == null) { if (_myPlan!.days[day] == null) {
throw Exception("Wrong activated day: $day does not exist"); throw Exception("Wrong activated day: $day does not exist");
@ -413,7 +450,7 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
activeDayIndex = 0; activeDayIndex = 0;
this.add(TrainingPlanGoToRestart()); this.add(TrainingPlanGoToRestart());
} }
print("ActiveDayIndex $activeDayIndex");
return activeDayIndex; return activeDayIndex;
} }

View File

@ -15,10 +15,18 @@ class TrainingPlanLoading extends TrainingPlanState {
const TrainingPlanLoading(); const TrainingPlanLoading();
} }
class TrainingPlanExerciseLoading extends TrainingPlanState {
const TrainingPlanExerciseLoading();
}
class TrainingPlanReady extends TrainingPlanState { class TrainingPlanReady extends TrainingPlanState {
const TrainingPlanReady(); const TrainingPlanReady();
} }
class TrainingPlanExerciseReady extends TrainingPlanState {
const TrainingPlanExerciseReady();
}
class TrainingPlanFinished extends TrainingPlanState { class TrainingPlanFinished extends TrainingPlanState {
const TrainingPlanFinished(); const TrainingPlanFinished();
} }

View File

@ -3,7 +3,6 @@ import 'dart:io';
import 'package:aitrainer_app/bloc/test_set_execute/test_set_execute_bloc.dart'; import 'package:aitrainer_app/bloc/test_set_execute/test_set_execute_bloc.dart';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart'; import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart'; import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
import 'package:aitrainer_app/push_notifications.dart';
import 'package:aitrainer_app/repository/customer_repository.dart'; import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart'; import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/repository/workout_tree_repository.dart'; import 'package:aitrainer_app/repository/workout_tree_repository.dart';
@ -44,7 +43,7 @@ import 'package:aitrainer_app/widgets/home.dart';
import 'package:aitrainer_app/library/facebook_app_events/facebook_app_events.dart'; import 'package:aitrainer_app/library/facebook_app_events/facebook_app_events.dart';
import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_analytics/observer.dart'; import 'package:firebase_analytics/observer.dart';
import 'package:flurry/flurry.dart'; import 'package:flurry_data/flurry_data.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@ -110,6 +109,7 @@ Future<Null> main() async {
if (isInDebugMode) { if (isInDebugMode) {
// In development mode simply print to console. // In development mode simply print to console.
FlutterError.dumpErrorToConsole(details); FlutterError.dumpErrorToConsole(details);
FlurryData.logEvent("enter_test");
} else { } else {
// In production mode report to the application zone to report to // In production mode report to the application zone to report to
// Sentry. // Sentry.
@ -192,10 +192,9 @@ Future<Null> main() async {
Future<void> initThirdParty() async { Future<void> initThirdParty() async {
if (!isInDebugMode) { if (!isInDebugMode) {
await Flurry.initialize(androidKey: "JNYCTCWBT34FM3J8TV36", iosKey: "3QBG7BSMGPDH24S8TRQP", enableLog: true); await FlurryData.initialize(androidKey: "JNYCTCWBT34FM3J8TV36", iosKey: "3QBG7BSMGPDH24S8TRQP", enableLog: true);
FlutterUxcam.optIntoSchematicRecordings(); FlutterUxcam.optIntoSchematicRecordings();
} }
PushNotificationsManager().init();
} }
class WorkoutTestApp extends StatelessWidget { class WorkoutTestApp extends StatelessWidget {

View File

@ -19,6 +19,7 @@ import 'package:aitrainer_app/model/purchase.dart';
import 'package:aitrainer_app/model/split_test.dart'; import 'package:aitrainer_app/model/split_test.dart';
import 'package:aitrainer_app/model/sport.dart'; import 'package:aitrainer_app/model/sport.dart';
import 'package:aitrainer_app/model/training_plan.dart'; import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/model/training_plan_day.dart';
import 'package:aitrainer_app/model/tutorial.dart'; import 'package:aitrainer_app/model/tutorial.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart'; import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/customer_repository.dart'; import 'package:aitrainer_app/repository/customer_repository.dart';
@ -30,7 +31,7 @@ import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/env.dart'; import 'package:aitrainer_app/util/env.dart';
import 'package:aitrainer_app/util/track.dart'; import 'package:aitrainer_app/util/track.dart';
import 'package:firebase_remote_config/firebase_remote_config.dart'; import 'package:firebase_remote_config/firebase_remote_config.dart';
import 'package:flurry/flurry.dart'; import 'package:flurry_data/flurry_data.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart'; import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:flutter_uxcam/flutter_uxcam.dart'; import 'package:flutter_uxcam/flutter_uxcam.dart';
import 'package:package_info/package_info.dart'; import 'package:package_info/package_info.dart';
@ -137,6 +138,7 @@ class Cache with Logging {
List<wt_product.Product>? _products; List<wt_product.Product>? _products;
List<Purchase> _purchases = []; List<Purchase> _purchases = [];
List<SplitTest> _splitTests = []; List<SplitTest> _splitTests = [];
List<TrainingPlanDay> _trainingPlanDays = [];
List<ExercisePlanTemplate> _exercisePlanTemplates = []; List<ExercisePlanTemplate> _exercisePlanTemplates = [];
@ -184,6 +186,7 @@ class Cache with Logging {
String testEnv = EnvironmentConfig.test_env; String testEnv = EnvironmentConfig.test_env;
this.testEnvironment = testEnv; this.testEnvironment = testEnv;
if (testEnv == "1") { if (testEnv == "1") {
print("testEnv $testEnv");
baseUrl = baseUrlTest; baseUrl = baseUrlTest;
liveServer = false; liveServer = false;
} }
@ -668,7 +671,7 @@ class Cache with Logging {
await PackageApi().getCustomerPackage(customerId); await PackageApi().getCustomerPackage(customerId);
if (!isInDebugMode) { if (!isInDebugMode) {
Flurry.setUserId(customerId.toString()); FlurryData.setUserId(customerId.toString());
//Smartlook.setUserIdentifier(customerId.toString()); //Smartlook.setUserIdentifier(customerId.toString());
FlutterUxcam.setUserProperty("username", customerId.toString()); FlutterUxcam.setUserProperty("username", customerId.toString());
FlutterUxcam.setUserIdentity(customerId.toString()); FlutterUxcam.setUserIdentity(customerId.toString());
@ -737,4 +740,7 @@ class Cache with Logging {
List<SplitTest> getSplitTests() => this._splitTests; List<SplitTest> getSplitTests() => this._splitTests;
setSplitTests(value) => this._splitTests = value; setSplitTests(value) => this._splitTests = value;
List<TrainingPlanDay> getTrainingPlanDays() => this._trainingPlanDays;
setTrainingPlanDays(value) => this._trainingPlanDays = value;
} }

View File

@ -4,7 +4,7 @@ class CustomerProperty {
int? customerPropertyId; int? customerPropertyId;
late int propertyId; late int propertyId;
late int customerId; late int customerId;
late DateTime dateAdd; DateTime? dateAdd;
late double propertyValue; late double propertyValue;
bool newData = false; bool newData = false;
@ -14,7 +14,7 @@ class CustomerProperty {
this.customerPropertyId = json['customerPropertyId']; this.customerPropertyId = json['customerPropertyId'];
this.propertyId = json['propertyId']; this.propertyId = json['propertyId'];
this.customerId = json['customerId']; this.customerId = json['customerId'];
this.dateAdd = json['propertyName']; this.dateAdd = json['dataAdd'] ?? DateTime.now();
this.propertyValue = json['propertyValue']; this.propertyValue = json['propertyValue'];
} }
@ -24,14 +24,14 @@ class CustomerProperty {
"customerPropertyId": this.customerPropertyId, "customerPropertyId": this.customerPropertyId,
"propertyId": this.propertyId, "propertyId": this.propertyId,
"customerId": this.customerId, "customerId": this.customerId,
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd), "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!),
"propertyValue": this.propertyValue "propertyValue": this.propertyValue
}; };
} else { } else {
return { return {
"propertyId": this.propertyId, "propertyId": this.propertyId,
"customerId": this.customerId, "customerId": this.customerId,
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd), "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!),
"propertyValue": this.propertyValue "propertyValue": this.propertyValue
}; };
} }

View File

@ -2,6 +2,7 @@ import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise.dart'; import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart'; import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_type.dart'; import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/repository/training_plan_day_repository.dart';
class CustomerTrainingPlanDetails { class CustomerTrainingPlanDetails {
/// customerTrainingPlanDetails /// customerTrainingPlanDetails
@ -26,6 +27,8 @@ class CustomerTrainingPlanDetails {
bool? parallel; bool? parallel;
String? day; String? day;
int? dayId;
/// exerciseType /// exerciseType
ExerciseType? exerciseType; ExerciseType? exerciseType;
@ -63,10 +66,10 @@ class CustomerTrainingPlanDetails {
: json['parallel'] == "true" : json['parallel'] == "true"
? true ? true
: null; : null;
this.day = json['day'].toString(); this.dayId = json['dayId'] == "null" ? null : json['dayId'];
if (this.day == null || this.day == "null") { TrainingPlanDayRepository trainingPlanDayRepository = TrainingPlanDayRepository();
this.day = ""; this.day = trainingPlanDayRepository.getNameById(this.dayId);
}
try { try {
Iterable iterable = json['exercises']; Iterable iterable = json['exercises'];
this.exercises = iterable.map((exercise) => Exercise.fromJson(exercise)).toList(); this.exercises = iterable.map((exercise) => Exercise.fromJson(exercise)).toList();
@ -114,15 +117,30 @@ class CustomerTrainingPlanDetails {
'exercises': exercises.isEmpty ? [].toString() : exercises.map((exercise) => exercise.toJson()).toList().toString(), 'exercises': exercises.isEmpty ? [].toString() : exercises.map((exercise) => exercise.toJson()).toList().toString(),
'state': this.state.toStr(), 'state': this.state.toStr(),
"isTest": this.isTest, "isTest": this.isTest,
"dayId": this.dayId,
}; };
if (this.day != null && this.day!.isNotEmpty) {
jsonMap["day"] = this.day;
}
//print("Detail $jsonMap"); //print("Detail toJson $jsonMap");
return jsonMap; return jsonMap;
} }
@override @override
String toString() => this.toJsonWithExercises().toString(); 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;
}
} }

View File

@ -1,10 +1,10 @@
import 'package:aitrainer_app/model/evaluation_attribute.dart'; import 'package:aitrainer_app/model/evaluation_attribute.dart';
class Evaluation { class Evaluation {
late int evaluationId; int? evaluationId;
late String name; late String name;
late int exerciseTypeId; int? exerciseTypeId;
late String unit; String? unit;
late List attributes; late List attributes;
Evaluation.fromJson(Map json) { Evaluation.fromJson(Map json) {

View File

@ -1,6 +1,6 @@
class EvaluationAttribute { class EvaluationAttribute {
late int evaluationAttrId; late int evaluationAttrId;
late int evaluationId; int? evaluationId;
late String name; late String name;
late String sex; late String sex;
late int ageMin; late int ageMin;

View File

@ -17,7 +17,7 @@ class ExerciseType {
late String unit; late String unit;
/// unitQuantity /// unitQuantity
late String unitQuantity; String? unitQuantity;
/// unitQuantityUnit /// unitQuantityUnit
String? unitQuantityUnit; String? unitQuantityUnit;
@ -28,6 +28,8 @@ class ExerciseType {
/// base /// base
late bool base; late bool base;
late bool buddyWarning;
/// imageUrl /// imageUrl
String imageUrl = ""; String imageUrl = "";
@ -65,6 +67,7 @@ class ExerciseType {
this.unitQuantityUnit = json['unitQuantityUnit']; this.unitQuantityUnit = json['unitQuantityUnit'];
this.active = json['active']; this.active = json['active'];
this.base = json['base']; this.base = json['base'];
this.buddyWarning = json['buddyWarning'];
if (json['images'].length > 0) { if (json['images'].length > 0) {
this.imageUrl = json['images'][0]['url']; this.imageUrl = json['images'][0]['url'];
} }
@ -105,6 +108,8 @@ class ExerciseType {
"unitQuantity": unitQuantity, "unitQuantity": unitQuantity,
"unitQuantityUnit": unitQuantityUnit, "unitQuantityUnit": unitQuantityUnit,
"active": active, "active": active,
"base": base,
"buddyWarning": buddyWarning,
"devices": this.devices.toString(), "devices": this.devices.toString(),
"nameTranslation": this.nameTranslation, "nameTranslation": this.nameTranslation,
"parents": this.parents.toString() "parents": this.parents.toString()

View File

@ -4,10 +4,10 @@ import 'package:aitrainer_app/model/training_plan_detail.dart';
class TrainingPlan { class TrainingPlan {
late int trainingPlanId; late int trainingPlanId;
late String type; String? type;
late String name; late String name;
late String internalName; String? internalName;
late String description; String? description;
late bool free; late bool free;
late bool active; late bool active;
int? treeId; int? treeId;
@ -28,7 +28,7 @@ class TrainingPlan {
this.treeId = json['treeId']; this.treeId = json['treeId'];
nameTranslations['en'] = name; nameTranslations['en'] = name;
descriptionTranslations['en'] = description; descriptionTranslations['en'] = description ?? "";
if (json['translations'] != null && json['translations'].length > 0) { if (json['translations'] != null && json['translations'].length > 0) {
json['translations'].forEach((translation) { json['translations'].forEach((translation) {
nameTranslations[translation['languageCode']] = translation['nameTranslation']; nameTranslations[translation['languageCode']] = translation['nameTranslation'];

View 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();
}

View File

@ -1,14 +1,15 @@
class TrainingPlanDetail { class TrainingPlanDetail {
late int trainingPlanDetailId; late int trainingPlanDetailId;
late int trainingPlanId; int? trainingPlanId;
late int exerciseTypeId; late int exerciseTypeId;
late int sort; late int sort;
late int set; late int set;
late int repeats; int? repeats;
late double weight; double? weight;
late int restingTime; int? restingTime;
late bool parallel; bool? parallel;
late String day; int? dayId;
String? day;
TrainingPlanDetail.fromJson(Map<String, dynamic> json) { TrainingPlanDetail.fromJson(Map<String, dynamic> json) {
this.trainingPlanDetailId = json['trainingPlanDetailId']; this.trainingPlanDetailId = json['trainingPlanDetailId'];
@ -20,7 +21,7 @@ class TrainingPlanDetail {
this.weight = json['weight']; this.weight = json['weight'];
this.restingTime = json['restingTime']; this.restingTime = json['restingTime'];
this.parallel = json['parallel']; this.parallel = json['parallel'];
this.day = json['day']; this.dayId = json['dayId'];
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
@ -32,6 +33,7 @@ class TrainingPlanDetail {
"weight": this.weight, "weight": this.weight,
"restingTime": this.restingTime, "restingTime": this.restingTime,
"parallel": this.parallel, "parallel": this.parallel,
"dayId": this.dayId,
"day": this.day, "day": this.day,
}; };

View File

@ -1,34 +0,0 @@
import 'package:aitrainer_app/service/logging.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class PushNotificationsManager with Logging {
PushNotificationsManager._();
factory PushNotificationsManager() => _instance;
static final PushNotificationsManager _instance = PushNotificationsManager._();
Future<void> init() async {
log(" --- Firebase Messagein init..");
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
'This channel is used for important notifications.', // description
importance: Importance.max,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true, // Required to display a heads up notification
badge: true,
sound: true,
);
String? token = await FirebaseMessaging.instance.getToken();
log("FirebaseMessaging token $token");
}
}

View File

@ -0,0 +1,35 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/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;
}
}

View File

@ -5,6 +5,7 @@ import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart'; import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_tree.dart'; import 'package:aitrainer_app/model/exercise_tree.dart';
import 'package:aitrainer_app/model/training_plan.dart'; import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/repository/training_plan_day_repository.dart';
import 'package:aitrainer_app/service/training_plan_service.dart'; import 'package:aitrainer_app/service/training_plan_service.dart';
import 'package:aitrainer_app/util/common.dart'; import 'package:aitrainer_app/util/common.dart';
@ -66,6 +67,7 @@ class TrainingPlanRepository {
// 3 calculate weights // 3 calculate weights
int index = 0; int index = 0;
trainingPlan.details!.forEach((elem) { trainingPlan.details!.forEach((elem) {
CustomerTrainingPlanDetails detail = CustomerTrainingPlanDetails(); CustomerTrainingPlanDetails detail = CustomerTrainingPlanDetails();
detail.customerTrainingPlanDetailsId = ++index; detail.customerTrainingPlanDetailsId = ++index;
@ -73,7 +75,9 @@ class TrainingPlanRepository {
detail.exerciseTypeId = elem.exerciseTypeId; detail.exerciseTypeId = elem.exerciseTypeId;
detail.repeats = elem.repeats; detail.repeats = elem.repeats;
detail.set = elem.set; detail.set = elem.set;
detail.day = elem.day; detail.dayId = elem.dayId;
TrainingPlanDayRepository trainingPlanDayRepository = TrainingPlanDayRepository();
detail.day = trainingPlanDayRepository.getNameById(elem.dayId);
detail.parallel = elem.parallel; detail.parallel = elem.parallel;
detail.restingTime = elem.restingTime; detail.restingTime = elem.restingTime;
detail.exerciseType = Cache().getExerciseTypeById(detail.exerciseTypeId!); detail.exerciseType = Cache().getExerciseTypeById(detail.exerciseTypeId!);
@ -83,6 +87,13 @@ class TrainingPlanRepository {
} else { } else {
detail.weight = 0; 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 { } else {
detail.weight = elem.weight; detail.weight = elem.weight;
} }
@ -98,6 +109,19 @@ class TrainingPlanRepository {
return plan; return plan;
} }
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? getTrainingPlanById(int trainingPlanId) {
TrainingPlan? plan; TrainingPlan? plan;
if (Cache().getTrainingPlans() == null) { if (Cache().getTrainingPlans() == null) {
@ -148,8 +172,9 @@ class TrainingPlanRepository {
return detail; return detail;
} }
CustomerTrainingPlanDetails recalculateDetail(int trainingPlanId, CustomerTrainingPlanDetails detail) { CustomerTrainingPlanDetails recalculateDetail(
CustomerTrainingPlanDetails recalculatedDetail = detail; int trainingPlanId, CustomerTrainingPlanDetails detail, CustomerTrainingPlanDetails nextDetail) {
CustomerTrainingPlanDetails recalculatedDetail = nextDetail;
// 1. get original repeats // 1. get original repeats
@ -164,14 +189,14 @@ class TrainingPlanRepository {
plan.details!.forEach((element) { plan.details!.forEach((element) {
if (element.trainingPlanDetailId == detail.trainingPlanDetailsId) { if (element.trainingPlanDetailId == detail.trainingPlanDetailsId) {
print("element $element"); print("element $element");
originalRepeats = element.repeats; originalRepeats = element.repeats ?? 0;
} }
}); });
// 2 get recalculated repeats // 2 get recalculated repeats
recalculatedDetail.weight = recalculatedDetail.weight =
Common.calculateWeigthByChangedQuantity(detail.weight!, detail.repeats!.toDouble(), originalRepeats.toDouble()); Common.calculateWeigthByChangedQuantity(detail.weight!, detail.repeats!.toDouble(), originalRepeats.toDouble());
recalculatedDetail.weight = Common.roundWeight(recalculatedDetail.weight!);
print("recalculated repeats for $originalRepeats: ${recalculatedDetail.weight}"); print("recalculated repeats for $originalRepeats: ${recalculatedDetail.weight}");
recalculatedDetail.repeats = originalRepeats; recalculatedDetail.repeats = originalRepeats;

View File

@ -112,10 +112,10 @@ class WorkoutTreeRepository with Logging {
0, 0,
""); "");
this.tree[exerciseType.name] = menuItem; this.tree[exerciseType.name] = menuItem;
if (isRunning || is1RM) { if (isRunning || is1RM || exerciseType.name == "Warming Up" || exerciseType.name == "Stretching") {
menuAsExercise.add(menuItem); menuAsExercise.add(menuItem);
} }
//log("ExerciseType in Menu item ${exerciseType.toJson()} is1RM: $is1RM"); //log("ExerciseType in Menu item ${exerciseType.toJson()}");
}); });
} else { } else {
//log("No Parents " + exerciseType.toJson().toString()); //log("No Parents " + exerciseType.toJson().toString());

View File

@ -1,15 +1,20 @@
import 'dart:math' as math;
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart' as logging; import 'package:aitrainer_app/service/logging.dart' as logging;
import 'package:apple_sign_in/apple_sign_in.dart'; import 'package:sign_in_with_apple/sign_in_with_apple.dart';
import 'package:awesome_notifications/awesome_notifications.dart';
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart'; 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:firebase_remote_config/firebase_remote_config.dart';
import 'package:flutter/material.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart'; import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:google_sign_in/google_sign_in.dart'; import 'package:google_sign_in/google_sign_in.dart';
class FirebaseApi with logging.Logging { class FirebaseApi with logging.Logging {
bool appleSignInAvailable = false; bool appleSignInAvailable = false;
//late FirebaseApi _instance;
static final FirebaseAuth auth = FirebaseAuth.instance; static final FirebaseAuth auth = FirebaseAuth.instance;
@ -29,15 +34,69 @@ class FirebaseApi with logging.Logging {
Future<void> initializeFlutterFire() async { Future<void> initializeFlutterFire() async {
try { try {
// Wait for Firebase to initialize and set `_initialized` state to true // Wait for Firebase to initialize and set `_initialized` state to true
FirebaseApp app = await Firebase.initializeApp(); await Firebase.initializeApp();
this.appleSignInAvailable = await AppleSignIn.isAvailable(); this.appleSignInAvailable = await SignInWithApple.isAvailable();
AwesomeNotifications().initialize(
// set the icon to null if you want to use the default app icon
null,
[
NotificationChannel(
channelKey: 'basic_channel',
channelName: 'Basic notifications',
channelDescription: 'Notification channel for basic tests',
defaultColor: Color(0xFF9D50DD),
ledColor: Colors.white)
]);
AwesomeNotifications().isNotificationAllowed().then((isAllowed) {
if (!isAllowed) {
// Insert here your friendly dialog box before call the request method
// This is very important to not harm the user experience
AwesomeNotifications().requestPermissionToSendNotifications();
}
});
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true, // Required to display a heads up notification
badge: true,
sound: true,
);
String? token = await FirebaseMessaging.instance.getToken();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
log("FirebaseMessaging token $token");
} catch (e) { } catch (e) {
// Set `_error` state to true if Firebase initialization fails // Set `_error` state to true if Firebase initialization fails
log("Error initializing Firebase"); log("Error initializing Firebase");
} }
} }
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);
}
}
Future<String> signInEmail(String? email, String? password) async { Future<String> signInEmail(String? email, String? password) async {
if (email == null) { if (email == null) {
throw Exception("Please type an email address"); throw Exception("Please type an email address");
@ -85,20 +144,33 @@ class FirebaseApi with logging.Logging {
return rc; 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 { Future<Map<String, dynamic>> signInWithApple() async {
Map<String, dynamic> userData = Map(); Map<String, dynamic> userData = Map();
final AuthorizationResult result = await AppleSignIn.performRequests([ /* final apple.AuthorizationResult result = await SignInWithApple.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName]) apple.AppleIdRequest(requestedScopes: [apple.Scope.email, apple.Scope.fullName])
]); ]);
switch (result.status) { switch (result.status) {
case AuthorizationStatus.authorized: case apple.AuthorizationStatus.authorized:
print('User authorized'); print('User authorized');
break; break;
case AuthorizationStatus.error: case apple.AuthorizationStatus.error:
print('User error'); print('User error');
throw Exception("Apple Sign-In failed"); throw Exception("Apple Sign-In failed");
case AuthorizationStatus.cancelled: case apple.AuthorizationStatus.cancelled:
print('User cancelled'); print('User cancelled');
throw Exception("Apple Sign-In cancelled"); throw Exception("Apple Sign-In cancelled");
} }
@ -106,20 +178,36 @@ class FirebaseApi with logging.Logging {
// Create an `OAuthCredential` from the credential returned by Apple. // Create an `OAuthCredential` from the credential returned by Apple.
final oauthCredential = OAuthProvider("apple.com").credential( final oauthCredential = OAuthProvider("apple.com").credential(
idToken: String.fromCharCodes(result.credential.identityToken), idToken: String.fromCharCodes(result.credential.identityToken),
accessToken: String.fromCharCodes(result.credential.authorizationCode)); accessToken: String.fromCharCodes(result.credential.authorizationCode!));
*/
// 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,
);
// Sign in the user with Firebase. If the nonce we generated earlier does // Sign in the user with Firebase. If the nonce we generated earlier does
// not match the nonce in `appleCredential.identityToken`, sign in will fail. // not match the nonce in `appleCredential.identityToken`, sign in will fail.
UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential); UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential);
Cache().firebaseUid = userCredential.user!.uid; Cache().firebaseUid = userCredential.user!.uid;
log("userCredential: " + userCredential.toString()); log("userCredential: " + userCredential.toString());
log("Apple Credentials: " + log("Apple Credentials: ${appleCredential.userIdentifier} state ${appleCredential.state} email ${userCredential.user!.email!}");
result.credential.user.toString() +
" state " +
result.credential.state.toString() +
" email " +
userCredential.user!.email!);
userData['email'] = userCredential.user!.email; userData['email'] = userCredential.user!.email;
return userData; return userData;
@ -127,26 +215,43 @@ class FirebaseApi with logging.Logging {
Future<Map<String, dynamic>> registerWithApple() async { Future<Map<String, dynamic>> registerWithApple() async {
Map<String, dynamic> userData = Map(); Map<String, dynamic> userData = Map();
final AuthorizationResult result = await AppleSignIn.performRequests([ /* final apple.AuthorizationResult result = await apple.TheAppleSignIn.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName]) apple.AppleIdRequest(requestedScopes: [apple.Scope.email, apple.Scope.fullName])
]); ]);
switch (result.status) { switch (result.status) {
case AuthorizationStatus.authorized: case apple.AuthorizationStatus.authorized:
print('Apple User authorized'); print('Apple User authorized');
break; break;
case AuthorizationStatus.error: case apple.AuthorizationStatus.error:
print('Apple User error'); print('Apple User error');
throw Exception("Apple Sign-In failed"); throw Exception("Apple Sign-In failed");
case AuthorizationStatus.cancelled: case apple.AuthorizationStatus.cancelled:
print('User cancelled'); print('User cancelled');
throw Exception("Apple Sign-In cancelled"); throw Exception("Apple Sign-In cancelled");
} }
*/
final rawNonce = generateNonce();
final nonce = sha256ofString(rawNonce);
// Create an `OAuthCredential` from the credential returned by Apple. // 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,
);
/* // Create an `OAuthCredential` from the credential returned by Apple.
final oauthCredential = OAuthProvider("apple.com").credential( final oauthCredential = OAuthProvider("apple.com").credential(
idToken: String.fromCharCodes(result.credential.identityToken), idToken: String.fromCharCodes(result.credential.identityToken),
accessToken: String.fromCharCodes(result.credential.authorizationCode)); accessToken: String.fromCharCodes(result.credential.authorizationCode));
*/
// Sign in the user with Firebase. If the nonce we generated earlier does // Sign in the user with Firebase. If the nonce we generated earlier does
// not match the nonce in `appleCredential.identityToken`, sign in will fail. // not match the nonce in `appleCredential.identityToken`, sign in will fail.
UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential); UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential);

View File

@ -19,7 +19,9 @@ import 'package:aitrainer_app/model/property.dart';
import 'package:aitrainer_app/model/purchase.dart'; import 'package:aitrainer_app/model/purchase.dart';
import 'package:aitrainer_app/model/split_test.dart'; import 'package:aitrainer_app/model/split_test.dart';
import 'package:aitrainer_app/model/training_plan.dart'; import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/model/training_plan_day.dart';
import 'package:aitrainer_app/model/tutorial.dart'; import 'package:aitrainer_app/model/tutorial.dart';
import 'package:aitrainer_app/repository/training_plan_day_repository.dart';
import 'package:aitrainer_app/service/api.dart'; import 'package:aitrainer_app/service/api.dart';
import 'package:aitrainer_app/service/exercise_type_service.dart'; import 'package:aitrainer_app/service/exercise_type_service.dart';
import 'package:aitrainer_app/util/not_found_exception.dart'; import 'package:aitrainer_app/util/not_found_exception.dart';
@ -105,6 +107,10 @@ class PackageApi {
final List<SplitTest>? tests = json.map((test) => SplitTest.fromJson(test)).toList(); final List<SplitTest>? tests = json.map((test) => SplitTest.fromJson(test)).toList();
//print("A/B tests: $tests"); //print("A/B tests: $tests");
Cache().setSplitTests(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);
} }
}); });
@ -114,9 +120,11 @@ class PackageApi {
ExerciseTree tree = element as ExerciseTree; ExerciseTree tree = element as ExerciseTree;
tree.imageUrl = await ExerciseTreeApi().buildImage(tree.imageUrl, tree.treeId); tree.imageUrl = await ExerciseTreeApi().buildImage(tree.imageUrl, tree.treeId);
}); });
//print("tree: $exerciseTree");
Cache().setExerciseTree(exerciseTree); Cache().setExerciseTree(exerciseTree);
TrainingPlanDayRepository trainingPlanDayRepository = TrainingPlanDayRepository();
trainingPlanDayRepository.assignTrainingPlanDays();
return; return;
} }

View File

@ -5,7 +5,7 @@ import 'package:aitrainer_app/service/tracking_service.dart';
import 'package:aitrainer_app/util/enums.dart'; import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/model/tracking.dart' as model; import 'package:aitrainer_app/model/tracking.dart' as model;
import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flurry/flurry.dart'; import 'package:flurry_data/flurry_data.dart';
import 'package:flutter_uxcam/flutter_uxcam.dart'; import 'package:flutter_uxcam/flutter_uxcam.dart';
class Track with Logging { class Track with Logging {
@ -20,7 +20,7 @@ class Track with Logging {
void track(TrackingEvent event, {String eventValue = ""}) { void track(TrackingEvent event, {String eventValue = ""}) {
if (!isInDebugMode) { if (!isInDebugMode) {
Flurry.logEvent(event.toString()); FlurryData.logEvent(event.toString());
// Smartlook.setGlobalEventProperty(event.toString(), eventValue, false); // Smartlook.setGlobalEventProperty(event.toString(), eventValue, false);
FlutterUxcam.logEventWithProperties(event.enumToString(), {"value": eventValue}); FlutterUxcam.logEventWithProperties(event.enumToString(), {"value": eventValue});
model.Tracking tracking = model.Tracking(); model.Tracking tracking = model.Tracking();

View File

@ -202,8 +202,8 @@ class RegistrationPage extends StatelessWidget with Trans {
Divider( Divider(
color: Colors.transparent, color: Colors.transparent,
), ),
getDataProtection(loginBloc), // getDataProtection(loginBloc),
loginBloc.emailCheckbox ? getEmailSubscription(loginBloc) : Offstage(), // loginBloc.emailCheckbox ? getEmailSubscription(loginBloc) : Offstage(),
Divider( Divider(
color: Colors.transparent, color: Colors.transparent,
), ),

View File

@ -254,7 +254,7 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
ElevatedButton( ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
onPrimary: Colors.white, onPrimary: Colors.white,
primary: Colors.orange, primary: restricted ? Colors.grey[600] : Colors.orange,
), ),
child: Text(t("Start")), child: Text(t("Start")),
onPressed: () { onPressed: () {
@ -294,15 +294,25 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
} }
}, },
), ),
restricted /* restricted
? Container( ? Container(
padding: EdgeInsets.only(bottom: 8), padding: EdgeInsets.only(bottom: 8),
child: Text( child: Text(
t("This is a premium function"), t("This is a premium function"),
style: GoogleFonts.inter(color: Colors.blue[700]), style: GoogleFonts.inter(
color: Colors.deepOrange[800],
fontWeight: FontWeight.bold,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 4.0,
color: Colors.black54,
),
],
),
), ),
) )
: Offstage(), : Offstage(), */
]), ]),
))); )));
@ -352,7 +362,7 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
Widget getPlanDetails(TrainingPlan plan, TrainingPlanBloc bloc) { Widget getPlanDetails(TrainingPlan plan, TrainingPlanBloc bloc) {
return SfDataGrid( return SfDataGrid(
headerRowHeight: 30, headerRowHeight: 30,
rowHeight: 45, rowHeight: 60,
source: TrainingPlanDetailSource( source: TrainingPlanDetailSource(
plan: plan, plan: plan,
menuBloc: bloc.menuBloc, menuBloc: bloc.menuBloc,
@ -390,14 +400,33 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
Navigator.of(context).pop(), Navigator.of(context).pop(),
}, },
); );
}),
},
onDropsetTap: () => {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("Dropset"),
descriptions: t("A drop set is an advanced resistance training technique "),
description2:
t(" in which you focus on completing a set until failure - or the inability to do another repetition."),
text: "OK",
onTap: () => {
Navigator.of(context).pop(),
},
onCancel: () => {
Navigator.of(context).pop(),
},
);
}) })
}), }),
headerGridLinesVisibility: GridLinesVisibility.both, headerGridLinesVisibility: GridLinesVisibility.both,
gridLinesVisibility: GridLinesVisibility.both, gridLinesVisibility: GridLinesVisibility.both,
columns: [ columns: [
GridTextColumn( GridTextColumn(
//columnWidthMode: ColumnWidthMode.lastColumnFill, columnWidthMode: ColumnWidthMode.lastColumnFill,
maximumWidth: 120, maximumWidth: 160,
columnName: 'exerciseImage', columnName: 'exerciseImage',
label: Container( label: Container(
color: Colors.green[50], color: Colors.green[50],
@ -472,11 +501,13 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
class TrainingPlanDetailSource extends DataGridSource { class TrainingPlanDetailSource extends DataGridSource {
final TrainingPlan plan; final TrainingPlan plan;
final MenuBloc menuBloc; final MenuBloc menuBloc;
final VoidCallback onDropsetTap;
final VoidCallback onWeightTap; final VoidCallback onWeightTap;
final VoidCallback onRepeatTap; final VoidCallback onRepeatTap;
TrainingPlanDetailSource({ TrainingPlanDetailSource({
required this.plan, required this.plan,
required this.menuBloc, required this.menuBloc,
required this.onDropsetTap,
required this.onWeightTap, required this.onWeightTap,
required this.onRepeatTap, required this.onRepeatTap,
}) { }) {
@ -540,7 +571,7 @@ class TrainingPlanDetailSource extends DataGridSource {
]), ]),
)) ))
]) ])
: dataGridCell.columnName == "weight" && dataGridCell.value == -1 : dataGridCell.columnName == "weight" && (dataGridCell.value == -1 || dataGridCell.value == -2)
? GestureDetector( ? GestureDetector(
onTap: () { onTap: () {
onWeightTap(); onWeightTap();
@ -549,21 +580,30 @@ class TrainingPlanDetailSource extends DataGridSource {
CustomIcon.question_circle, CustomIcon.question_circle,
color: Colors.indigo[300], color: Colors.indigo[300],
)) ))
: dataGridCell.columnName == "reps" && dataGridCell.value == -1 : dataGridCell.columnName == "weight" && dataGridCell.value == -3
? GestureDetector( ? GestureDetector(
onTap: () { onTap: () {
onRepeatTap(); onDropsetTap();
}, },
child: Icon( child: Icon(
CustomIcon.question_circle, CustomIcon.question_circle,
color: Colors.indigo[600], color: Colors.orange[400],
)) ))
: Text(dataGridCell.value.toString(), : dataGridCell.columnName == "reps" && dataGridCell.value == -1
style: GoogleFonts.inter( ? GestureDetector(
fontSize: 14, onTap: () {
color: Colors.indigo, onRepeatTap();
fontWeight: FontWeight.bold, },
))); child: Icon(
CustomIcon.question_circle,
color: Colors.indigo[600],
))
: Text(dataGridCell.value.toString(),
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.indigo,
fontWeight: FontWeight.bold,
)));
}).toList()); }).toList());
} }
} }

View File

@ -8,8 +8,10 @@ import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart'; import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/dialog_html.dart';
import 'package:aitrainer_app/widgets/menu_image.dart'; import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:aitrainer_app/widgets/victory_widget.dart'; import 'package:aitrainer_app/widgets/victory_widget.dart';
import 'package:badges/badges.dart';
import 'package:extended_tabs/extended_tabs.dart'; import 'package:extended_tabs/extended_tabs.dart';
import 'package:ezanimation/ezanimation.dart'; import 'package:ezanimation/ezanimation.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
@ -125,6 +127,7 @@ class _ExerciseTabs extends State<ExerciseTabs> with TickerProviderStateMixin {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
print("init TAB ${widget.bloc.dayNames.length} index ${widget.bloc.activeDayIndex}");
tabController = TabController(length: widget.bloc.dayNames.length, vsync: this); tabController = TabController(length: widget.bloc.dayNames.length, vsync: this);
tabController.animateTo(widget.bloc.activeDayIndex, duration: Duration(milliseconds: 300)); tabController.animateTo(widget.bloc.activeDayIndex, duration: Duration(milliseconds: 300));
} }
@ -143,6 +146,13 @@ class _ExerciseTabs extends State<ExerciseTabs> with TickerProviderStateMixin {
Widget getTabs(TrainingPlanBloc bloc) { Widget getTabs(TrainingPlanBloc bloc) {
return Column(children: [ return Column(children: [
ExtendedTabBar( ExtendedTabBar(
indicator: BoxDecoration(
color: Colors.black87,
border: Border(
bottom: BorderSide(width: 4.0, color: Colors.blue),
top: BorderSide(width: 4.0, color: Colors.blue),
)),
labelPadding: EdgeInsets.only(left: 5, right: 5),
tabs: getTabNames(), tabs: getTabNames(),
controller: tabController, controller: tabController,
onTap: (index) => bloc.activeDayIndex = index, onTap: (index) => bloc.activeDayIndex = index,
@ -168,52 +178,57 @@ class _ExerciseTabs extends State<ExerciseTabs> with TickerProviderStateMixin {
List<Tab> getTabNames() { List<Tab> getTabNames() {
List<Tab> tabs = []; List<Tab> tabs = [];
widget.bloc.dayNames.forEach((element) { widget.bloc.dayNames.forEach((element) {
final Widget widget = RichText( final Widget widget = Container(
text: TextSpan( //height: 50,
style: GoogleFonts.inter( padding: EdgeInsets.only(top: 2, left: 5, right: 5, bottom: 2),
fontSize: 14, color: Colors.white24,
fontWeight: FontWeight.bold, child: RichText(
color: Colors.white, textScaleFactor: 0.8,
), text: TextSpan(
children: [ style: GoogleFonts.inter(
TextSpan( fontSize: 14,
text: AppLocalizations.of(context)!.translate("Training Day") + ": \n", fontWeight: FontWeight.bold,
style: GoogleFonts.inter( color: Colors.white,
fontSize: 14, ),
color: Colors.white, children: [
shadows: <Shadow>[ TextSpan(
Shadow( text: AppLocalizations.of(context)!.translate("Training Day") + ": \n",
offset: Offset(5.0, 5.0), style: GoogleFonts.inter(
blurRadius: 12.0, fontSize: 14,
color: Colors.black54, color: Colors.white,
), shadows: <Shadow>[
Shadow( Shadow(
offset: Offset(-3.0, 3.0), offset: Offset(5.0, 5.0),
blurRadius: 12.0, blurRadius: 12.0,
color: Colors.black54, color: Colors.black54,
), ),
], Shadow(
)), offset: Offset(-3.0, 3.0),
TextSpan( blurRadius: 12.0,
text: element, color: Colors.black54,
style: GoogleFonts.inter( ),
fontSize: 14, ],
fontWeight: FontWeight.bold, )),
color: Colors.yellow[400], TextSpan(
shadows: <Shadow>[ text: element,
Shadow( style: GoogleFonts.inter(
offset: Offset(5.0, 5.0), fontSize: 14,
blurRadius: 12.0, fontWeight: FontWeight.bold,
color: Colors.black54, color: Colors.yellow[400],
), shadows: <Shadow>[
Shadow( Shadow(
offset: Offset(-3.0, 3.0), offset: Offset(5.0, 5.0),
blurRadius: 12.0, blurRadius: 12.0,
color: Colors.black54, color: Colors.black54,
), ),
], Shadow(
)), offset: Offset(-3.0, 3.0),
])); blurRadius: 12.0,
color: Colors.black54,
),
],
)),
])));
tabs.add(Tab(child: widget)); tabs.add(Tab(child: widget));
}); });
@ -559,11 +574,17 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
setContext(context); setContext(context);
print("detail ${widget.detail}");
final ExercisePlanDetailState state = widget.detail.state; final ExercisePlanDetailState state = widget.detail.state;
final bool done = state.equalsTo(ExercisePlanDetailState.finished) || state.equalsTo(ExercisePlanDetailState.skipped); final bool done = state.equalsTo(ExercisePlanDetailState.finished) || state.equalsTo(ExercisePlanDetailState.skipped);
final String countSerie = widget.detail.set.toString(); final String countSerie = widget.detail.set.toString();
final String step = (widget.detail.exercises.length).toString(); final String step = (widget.detail.exercises.length).toString();
String weight = widget.detail.weight != null ? widget.detail.weight!.toStringAsFixed(1) : "-"; String weight = widget.detail.weight != null ? widget.detail.weight!.toStringAsFixed(1) : "-";
bool isDrop = false;
if (widget.detail.weight == -3) {
weight = t("DROP");
isDrop = true;
}
String restingTime = widget.detail.restingTime == null ? "" : widget.detail.restingTime!.toStringAsFixed(0); String restingTime = widget.detail.restingTime == null ? "" : widget.detail.restingTime!.toStringAsFixed(0);
bool isTest = false; bool isTest = false;
if (widget.detail.weight != null && widget.detail.weight! == -1) { if (widget.detail.weight != null && widget.detail.weight! == -1) {
@ -574,6 +595,9 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
if (widget.detail.repeats! == -1) { if (widget.detail.repeats! == -1) {
repeats = t("MAX"); repeats = t("MAX");
} }
final bool extraExercise = widget.detail.exerciseType!.name == "Warming Up" || widget.detail.exerciseType!.name == "Stretching";
bool buddyWarning = widget.detail.exerciseType == null ? false : widget.detail.exerciseType!.buddyWarning;
setContext(context); setContext(context);
return Container( return Container(
color: Colors.transparent, color: Colors.transparent,
@ -620,10 +644,58 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
Container( Container(
width: 120, width: 120,
height: 80, height: 80,
child: MenuImage( child: Badge(
imageName: widget.bloc.getActualImageName(widget.detail.exerciseType!.exerciseTypeId), elevation: 0,
workoutTreeId: widget.bloc.getActualWorkoutTreeId(widget.detail.exerciseType!.exerciseTypeId)!, padding: EdgeInsets.all(0),
), position: BadgePosition.bottomStart(start: -5),
animationDuration: Duration(milliseconds: 500),
animationType: BadgeAnimationType.slide,
badgeColor: Colors.transparent,
showBadge: true,
badgeContent: IconButton(
onPressed: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogHTML(
title: widget.detail.exerciseType!.nameTranslation,
htmlData: '<p>' + widget.detail.exerciseType!.descriptionTranslation + '</p>');
}),
icon: Icon(
Icons.info_outline,
color: Colors.yellow[200],
)),
child: Badge(
elevation: 0,
padding: EdgeInsets.all(0),
position: BadgePosition.topEnd(end: -8),
animationDuration: Duration(milliseconds: 500),
animationType: BadgeAnimationType.slide,
badgeColor: Colors.transparent,
showBadge: buddyWarning,
badgeContent: IconButton(
onPressed: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: true,
text: "Warning",
descriptions: t("Attention!"),
description2: t("The safe and exact execution of this exercise you need a training buddy or a trainer"),
description3: t("Execution at your own risk!"),
onTap: () => Navigator.of(context).pop(),
onCancel: () => Navigator.of(context).pop(),
title: t('Training Buddy'),
);
}),
icon: Icon(
CustomIcon.exclamation_circle,
color: Colors.red[800],
)),
child: MenuImage(
imageName: widget.bloc.getActualImageName(widget.detail.exerciseType!.exerciseTypeId),
workoutTreeId: widget.bloc.getActualWorkoutTreeId(widget.detail.exerciseType!.exerciseTypeId)!,
radius: 12,
))),
), ),
SizedBox( SizedBox(
width: 10, width: 10,
@ -656,18 +728,18 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
), ),
], ],
)), )),
widget.detail.exerciseType!.unitQuantityUnit != null widget.detail.exerciseType!.unitQuantityUnit != null && !extraExercise
? TextSpan( ? TextSpan(
text: "\n", text: "\n",
) )
: TextSpan(), : TextSpan(),
widget.detail.exerciseType!.unitQuantityUnit != null widget.detail.exerciseType!.unitQuantityUnit != null && !extraExercise
? TextSpan( ? TextSpan(
text: t(widget.detail.exerciseType!.unitQuantityUnit!) + ": ", text: t(widget.detail.exerciseType!.unitQuantityUnit!) + ": ",
style: GoogleFonts.inter( style: GoogleFonts.inter(
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)) fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold))
: TextSpan(), : TextSpan(),
widget.detail.exerciseType!.unitQuantityUnit != null widget.detail.exerciseType!.unitQuantityUnit != null && !extraExercise
? TextSpan( ? TextSpan(
text: weight, text: weight,
style: GoogleFonts.inter( style: GoogleFonts.inter(
@ -677,37 +749,50 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
TextSpan( TextSpan(
text: "\n", text: "\n",
), ),
TextSpan( !extraExercise
text: t(widget.detail.exerciseType!.unit) + ": ", ? TextSpan(
style: GoogleFonts.inter( text: t(widget.detail.exerciseType!.unit) + ": ",
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)), style: GoogleFonts.inter(
TextSpan( fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold))
text: repeats, : TextSpan(),
style: GoogleFonts.inter( !extraExercise
fontSize: 12, ? TextSpan(
)), text: repeats,
style: GoogleFonts.inter(
fontSize: 12,
))
: TextSpan(),
TextSpan( TextSpan(
text: "\n", text: "\n",
), ),
TextSpan( !extraExercise
text: t("Set") + ": ", ? TextSpan(
style: GoogleFonts.inter( text: t("Set") + ": ",
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)), style: GoogleFonts.inter(
TextSpan( fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold))
text: step + "/" + countSerie, : TextSpan(),
style: GoogleFonts.inter( !extraExercise
fontSize: 12, ? TextSpan(
)), text: step + "/" + countSerie,
style: GoogleFonts.inter(
fontSize: 12,
))
: TextSpan(),
TextSpan( TextSpan(
text: "\n", text: "\n",
), ),
TextSpan( !extraExercise
text: t("Resting time") + ": ", ? TextSpan(
style: GoogleFonts.inter( text: t("Resting time") + ": ",
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)), style: GoogleFonts.inter(
TextSpan( fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold))
text: restingTime + " " + t("min(s)"), : TextSpan(),
style: GoogleFonts.inter(fontSize: 12, color: done ? Colors.grey[100] : Colors.white, fontWeight: FontWeight.bold)), !extraExercise
? TextSpan(
text: restingTime + " " + t("min(s)"),
style:
GoogleFonts.inter(fontSize: 12, color: done ? Colors.grey[100] : Colors.white, fontWeight: FontWeight.bold))
: TextSpan(),
]), ]),
)), )),
isTest isTest
@ -740,7 +825,35 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
)), )),
]); ]);
}) })
: Offstage() : isDrop
? AnimatedBuilder(
animation: animation,
builder: (context, snapshot) {
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: false,
title: t("Drop set"),
descriptions: t("Drop set"),
description2: t("Recommended method:"),
text: "OK",
onTap: () => Navigator.of(context).pop(),
onCancel: () => {
Navigator.of(context).pop(),
},
);
}),
child: Icon(
CustomIcon.question_circle,
color: Colors.orange[200],
size: 16,
)),
]);
})
: Offstage()
]), ]),
), ),
), ),

View File

@ -6,7 +6,6 @@ import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/exercise_save.dart'; import 'package:aitrainer_app/widgets/exercise_save.dart';
import 'package:aitrainer_app/widgets/number_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
@ -43,7 +42,7 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
}, builder: (context, state) { }, builder: (context, state) {
return ModalProgressHUD( return ModalProgressHUD(
child: getExercises(bloc, detail), child: getExercises(bloc, detail),
inAsyncCall: state is TrainingPlanLoading, inAsyncCall: state is TrainingPlanExerciseLoading,
opacity: 0.5, opacity: 0.5,
color: Colors.black54, color: Colors.black54,
progressIndicator: CircularProgressIndicator(), progressIndicator: CircularProgressIndicator(),
@ -52,6 +51,7 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
), ),
floatingActionButton: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ floatingActionButton: Row(mainAxisAlignment: MainAxisAlignment.end, children: [
FloatingActionButton.extended( FloatingActionButton.extended(
heroTag: "skipButton",
onPressed: () => { onPressed: () => {
Navigator.of(context).pop(), Navigator.of(context).pop(),
bloc.add(TrainingPlanSkipExercise(detail: detail)), bloc.add(TrainingPlanSkipExercise(detail: detail)),
@ -67,6 +67,7 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
width: 20, width: 20,
), ),
FloatingActionButton.extended( FloatingActionButton.extended(
heroTag: "saveButton",
onPressed: () => { onPressed: () => {
Navigator.of(context).pop(), Navigator.of(context).pop(),
bloc.add(TrainingPlanSaveExercise(detail: detail)), bloc.add(TrainingPlanSaveExercise(detail: detail)),
@ -111,7 +112,7 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
); );
} }
Widget getExerciseForm(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail) { /* Widget getExerciseForm(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail) {
return Container( return Container(
padding: const EdgeInsets.only(top: 10, left: 25, right: 25), padding: const EdgeInsets.only(top: 10, left: 25, right: 25),
child: SingleChildScrollView( child: SingleChildScrollView(
@ -224,5 +225,5 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: listWidgets, children: listWidgets,
); );
} } */
} }

View File

@ -85,6 +85,7 @@ class MyTrainingPlans extends StatelessWidget with Trans, Logging {
getTrainingPlan(t("Training Plans for Women"), "asset/menu/training_plans_q_woman.jpg", "for_woman"), getTrainingPlan(t("Training Plans for Women"), "asset/menu/training_plans_q_woman.jpg", "for_woman"),
getTrainingPlan(t("Training Plans of Celebrities"), "asset/menu/training_plans_q_celebrities.jpg", "celebrities"), getTrainingPlan(t("Training Plans of Celebrities"), "asset/menu/training_plans_q_celebrities.jpg", "celebrities"),
getTrainingPlan(t("Training Plans for Gain Strength"), "asset/menu/training_plans_q_gain_strength.jpg", "gain_strength"), getTrainingPlan(t("Training Plans for Gain Strength"), "asset/menu/training_plans_q_gain_strength.jpg", "gain_strength"),
getTrainingPlan(t("Physical Prepare Program for Footgolfers"), "asset/menu/FG_2_edz.jpg", "footgolf"),
]), ]),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, crossAxisCount: 2,

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:aitrainer_app/library/image_cache.dart' as wt; import 'package:aitrainer_app/library/image_cache.dart' as wt;
import 'package:aitrainer_app/library/transparent_image.dart'; import 'package:aitrainer_app/library/transparent_image.dart';
// ignore: must_be_immutable
class MenuImage extends StatelessWidget { class MenuImage extends StatelessWidget {
final int? workoutTreeId; final int? workoutTreeId;
final String imageName; final String imageName;

View File

@ -25,10 +25,12 @@ class TreeviewParentWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget parentWidget = Text( Widget parentWidget = Text(this.text,
this.text, style: GoogleFonts.archivoBlack(
style: GoogleFonts.archivoBlack(fontSize: fontSize, color: color ?? Colors.blue[800]!, backgroundColor: Colors.transparent), fontSize: fontSize,
); color: color ?? Colors.blue[800]!,
backgroundColor: Colors.transparent,
));
return Card( return Card(
color: backgroundColor, color: backgroundColor,

View File

@ -22,13 +22,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.6" version: "1.0.6"
apple_sign_in:
dependency: "direct main"
description:
name: apple_sign_in
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
archive: archive:
dependency: transitive dependency: transitive
description: description:
@ -50,6 +43,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.6.1" version: "2.6.1"
awesome_notifications:
dependency: "direct main"
description:
name: awesome_notifications
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.6+9"
badges: badges:
dependency: "direct main" dependency: "direct main"
description: description:
@ -442,13 +442,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.36.1" version: "0.36.1"
flurry: flurry_data:
dependency: "direct main" dependency: "direct main"
description: description:
name: flurry name: flurry_data
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.7" version: "0.0.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -517,20 +517,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.0+4"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
flutter_localizations: flutter_localizations:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -1064,6 +1050,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
sign_in_with_apple:
dependency: "direct main"
description:
name: sign_in_with_apple
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -1216,13 +1209,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
timezone:
dependency: transitive
description:
name: timezone
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.0"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -1435,4 +1421,4 @@ packages:
version: "3.1.0" version: "3.1.0"
sdks: sdks:
dart: ">=2.12.0 <3.0.0" dart: ">=2.12.0 <3.0.0"
flutter: ">=2.0.0" flutter: ">=2.0.4"

View File

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.1.19+89 version: 1.1.19+90
environment: environment:
sdk: ">=2.12.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
@ -53,31 +53,28 @@ dependencies:
confetti: ^0.6.0-nullsafety confetti: ^0.6.0-nullsafety
crypto: ^3.0.0 crypto: ^3.0.0
carousel_slider: ^4.0.0-nullsafety.0 carousel_slider: ^4.0.0-nullsafety.0
#dropdown_search: ^0.5.0
convex_bottom_bar: ^3.0.0 convex_bottom_bar: ^3.0.0
flutter_app_badger: ^1.2.0 flutter_app_badger: ^1.2.0
#super_tooltip: ^1.0.1
url_launcher: ^6.0.3 url_launcher: ^6.0.3
extended_tabs: ^2.2.0 extended_tabs: ^2.2.0
upgrader: ^3.3.0 upgrader: ^3.3.0
firebase_core: ^1.2.0 firebase_core: ^1.2.0
firebase_analytics: ^8.1.0 firebase_analytics: ^8.1.0
firebase_messaging: ^10.0.0 firebase_messaging: ^10.0.0
flutter_local_notifications: ^5.0.0
firebase_auth: ^1.2.0 firebase_auth: ^1.2.0
firebase_remote_config: ^0.10.0 firebase_remote_config: ^0.10.0
awesome_notifications: ^0.0.6+9
syncfusion_flutter_gauges: ^19.1.63 syncfusion_flutter_gauges: ^19.1.63
syncfusion_flutter_datagrid: ^19.1.63 syncfusion_flutter_datagrid: ^19.1.63
flutter_facebook_auth: ^3.4.0 flutter_facebook_auth: ^3.4.0
google_sign_in: ^5.0.3 google_sign_in: ^5.0.3
apple_sign_in: ^0.1.0 sign_in_with_apple: ^3.0.0
#sign_in_with_apple: ^3.0.0
#smartlook: ^1.0.7 #smartlook: ^1.0.7
flurry: ^0.0.4 flurry_data: ^0.0.1
flutter_uxcam: ^2.0.0-beta.1 flutter_uxcam: ^2.0.0-beta.1
animated_widgets: ^1.0.6 animated_widgets: ^1.0.6
@ -249,6 +246,7 @@ flutter:
- asset/menu/400m.jpg - asset/menu/400m.jpg
- asset/menu/FG_1_test.jpg - asset/menu/FG_1_test.jpg
- asset/menu/FG_1_training.jpg - asset/menu/FG_1_training.jpg
- asset/menu/FG_2_edz.jpg
- asset/menu/alternate_dumbbell_presses.jpg - asset/menu/alternate_dumbbell_presses.jpg
- asset/menu/alternate_standing_shoulder_press.jpg - asset/menu/alternate_standing_shoulder_press.jpg
- asset/menu/arnold_press.jpg - asset/menu/arnold_press.jpg
@ -385,6 +383,7 @@ flutter:
- asset/menu/standing_triceps_extension.jpg - asset/menu/standing_triceps_extension.jpg
- asset/menu/stiff_legged_deadlift.jpg - asset/menu/stiff_legged_deadlift.jpg
- asset/menu/straight-arm_rope_pull-down.jpg - asset/menu/straight-arm_rope_pull-down.jpg
- asset/menu/stretching.jpg
- asset/menu/t_bar_rows.jpg - asset/menu/t_bar_rows.jpg
- asset/menu/test_center.jpg - asset/menu/test_center.jpg
- asset/menu/test_on_machines.jpg - asset/menu/test_on_machines.jpg
@ -411,6 +410,7 @@ flutter:
- asset/menu/upper_body.jpg - asset/menu/upper_body.jpg
- asset/menu/v_ups.jpg - asset/menu/v_ups.jpg
- asset/menu/wall_sit.jpg - asset/menu/wall_sit.jpg
- asset/menu/warmup.jpg
- asset/menu/warrior_stand.jpg - asset/menu/warrior_stand.jpg
- asset/menu/weight_free_test.jpg - asset/menu/weight_free_test.jpg
- asset/menu/weighted_bench_dip.jpg - asset/menu/weighted_bench_dip.jpg