WT 1.1.8+1 TrainingPlan

This commit is contained in:
bossanyit 2021-05-28 15:49:58 +02:00
parent 4b6b4dafc7
commit d388228caa
50 changed files with 2610 additions and 265 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -477,6 +477,15 @@
"Try free for 3 days!":"Try it without risk for 3 days! In this period you can cancel any time without lasting your account.", "Try free for 3 days!":"Try it without risk for 3 days! In this period you can cancel any time without lasting your account.",
"View other alternatives":"View other alternatives", "View other alternatives":"View other alternatives",
"Please log in, because we can calculate the best suggestions for you":"Please log in, because we can calculate the best suggestions for you" "Please log in, because we can calculate the best suggestions for you":"Please log in, because we can calculate the best suggestions for you",
"My Active Training":"My Active Training",
"My Custom Plan":"My Custom Plan",
"Training Plans for Beginners":"Training Plans for Beginners",
"Training Plans for Home":"Training Plans for Home",
"Training Plans Advanced":"Training Plans Advanced",
"Training Plans for Women":"Training Plans for Women",
"Training Plans of Celebrities":"Training Plans of Celebrities",
"Training Plans for Gain Strength":"Training Plans for Gain Strength"
} }

View File

@ -469,5 +469,14 @@
"Try free for 3 days!":"Próbáld ki kockázat nélkül 3 napig! Ebben az időszakban bármikor lemondhatod, anélkül, hogy megterhelnénk a számládat.", "Try free for 3 days!":"Próbáld ki kockázat nélkül 3 napig! Ebben az időszakban bármikor lemondhatod, anélkül, hogy megterhelnénk a számládat.",
"View other alternatives":"Megnézek egy másik lehetőséget", "View other alternatives":"Megnézek egy másik lehetőséget",
"Please log in, because we can calculate the best suggestions for you":"Kérlek jelentkezz be, mert csak így tudjuk neked a legjobb gyakorlatokat kalkulálni" "Please log in, because we can calculate the best suggestions for you":"Kérlek jelentkezz be, mert csak így tudjuk neked a legjobb gyakorlatokat kalkulálni",
"My Active Training":"Aktív edzésem",
"My Custom Plan":"Egyéni edzésterv",
"Training Plans for Beginners":"Kezdő edzésprogramok",
"Training Plans for Home":"Otthoni edzésprogramok",
"Training Plans Advanced":"Haladó edzésprogramok",
"Training Plans for Women":"Edzésprogramok nőknek",
"Training Plans of Celebrities":"Celebek edzésprogramjai",
"Training Plans for Gain Strength":"Erőnövelő edzésprogramok"
} }

View File

@ -18,112 +18,106 @@ PODS:
- FBSDKLoginKit/Login (= 9.1.0) - FBSDKLoginKit/Login (= 9.1.0)
- FBSDKLoginKit/Login (9.1.0): - FBSDKLoginKit/Login (9.1.0):
- FBSDKCoreKit (~> 9.1.0) - FBSDKCoreKit (~> 9.1.0)
- Firebase/Analytics (7.11.0): - Firebase/Analytics (8.0.0):
- Firebase/Core - Firebase/Core
- Firebase/Auth (7.11.0): - Firebase/Auth (8.0.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseAuth (~> 7.11.0) - FirebaseAuth (~> 8.0.0)
- Firebase/Core (7.11.0): - Firebase/Core (8.0.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseAnalytics (~> 7.11.0) - FirebaseAnalytics (~> 8.0.0)
- Firebase/CoreOnly (7.11.0): - Firebase/CoreOnly (8.0.0):
- FirebaseCore (= 7.11.0) - FirebaseCore (= 8.0.0)
- Firebase/Messaging (7.11.0): - Firebase/Messaging (8.0.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseMessaging (~> 7.11.0) - FirebaseMessaging (~> 8.0.0)
- Firebase/RemoteConfig (7.11.0): - Firebase/RemoteConfig (8.0.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseRemoteConfig (~> 7.11.0) - FirebaseRemoteConfig (~> 8.0.0)
- firebase_analytics (8.0.2): - firebase_analytics (8.1.0):
- Firebase/Analytics (= 7.11.0) - Firebase/Analytics (= 8.0.0)
- firebase_core - firebase_core
- Flutter - Flutter
- firebase_auth (1.1.2): - firebase_auth (1.2.0):
- Firebase/Auth (= 7.11.0) - Firebase/Auth (= 8.0.0)
- firebase_core - firebase_core
- Flutter - Flutter
- firebase_core (1.1.0): - firebase_core (1.2.0):
- Firebase/CoreOnly (= 7.11.0) - Firebase/CoreOnly (= 8.0.0)
- Flutter - Flutter
- firebase_messaging (9.1.3): - firebase_messaging (10.0.0):
- Firebase/Messaging (= 7.11.0) - Firebase/Messaging (= 8.0.0)
- firebase_core - firebase_core
- Flutter - Flutter
- firebase_remote_config (0.10.0-dev.2): - firebase_remote_config (0.10.0):
- Firebase/RemoteConfig (= 7.11.0) - Firebase/RemoteConfig (= 8.0.0)
- firebase_core - firebase_core
- Flutter - Flutter
- FirebaseABTesting (7.11.0): - FirebaseABTesting (8.0.0):
- FirebaseCore (~> 7.0) - FirebaseCore (~> 8.0)
- FirebaseAnalytics (7.11.0): - FirebaseAnalytics (8.0.0):
- FirebaseAnalytics/AdIdSupport (= 7.11.0) - FirebaseAnalytics/AdIdSupport (= 8.0.0)
- FirebaseCore (~> 7.0) - FirebaseCore (~> 8.0)
- FirebaseInstallations (~> 7.0) - FirebaseInstallations (~> 8.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
- GoogleUtilities/MethodSwizzler (~> 7.0) - GoogleUtilities/MethodSwizzler (~> 7.4)
- GoogleUtilities/Network (~> 7.0) - GoogleUtilities/Network (~> 7.4)
- "GoogleUtilities/NSData+zlib (~> 7.0)" - "GoogleUtilities/NSData+zlib (~> 7.4)"
- nanopb (~> 2.30908.0) - nanopb (~> 2.30908.0)
- FirebaseAnalytics/AdIdSupport (7.11.0): - FirebaseAnalytics/AdIdSupport (8.0.0):
- FirebaseAnalytics/Base (= 7.11.0) - FirebaseAnalytics/Base (= 8.0.0)
- FirebaseCore (~> 7.0) - FirebaseCore (~> 8.0)
- FirebaseInstallations (~> 7.0) - FirebaseInstallations (~> 8.0)
- GoogleAppMeasurement/AdIdSupport (= 7.11.0) - GoogleAppMeasurement (= 8.0.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
- GoogleUtilities/MethodSwizzler (~> 7.0) - GoogleUtilities/MethodSwizzler (~> 7.4)
- GoogleUtilities/Network (~> 7.0) - GoogleUtilities/Network (~> 7.4)
- "GoogleUtilities/NSData+zlib (~> 7.0)" - "GoogleUtilities/NSData+zlib (~> 7.4)"
- nanopb (~> 2.30908.0) - nanopb (~> 2.30908.0)
- FirebaseAnalytics/Base (7.11.0): - FirebaseAnalytics/Base (8.0.0):
- FirebaseCore (~> 7.0) - FirebaseCore (~> 8.0)
- FirebaseInstallations (~> 7.0) - FirebaseInstallations (~> 8.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
- GoogleUtilities/MethodSwizzler (~> 7.0) - GoogleUtilities/MethodSwizzler (~> 7.4)
- GoogleUtilities/Network (~> 7.0) - GoogleUtilities/Network (~> 7.4)
- "GoogleUtilities/NSData+zlib (~> 7.0)" - "GoogleUtilities/NSData+zlib (~> 7.4)"
- nanopb (~> 2.30908.0) - nanopb (~> 2.30908.0)
- FirebaseAuth (7.11.0): - FirebaseAuth (8.0.0):
- FirebaseCore (~> 7.0) - FirebaseCore (~> 8.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
- GoogleUtilities/Environment (~> 7.0) - GoogleUtilities/Environment (~> 7.4)
- GTMSessionFetcher/Core (~> 1.4) - GTMSessionFetcher/Core (~> 1.5)
- FirebaseCore (7.11.0): - FirebaseCore (8.0.0):
- FirebaseCoreDiagnostics (~> 7.4) - FirebaseCoreDiagnostics (~> 8.0)
- GoogleUtilities/Environment (~> 7.0) - GoogleUtilities/Environment (~> 7.4)
- GoogleUtilities/Logger (~> 7.0) - GoogleUtilities/Logger (~> 7.4)
- FirebaseCoreDiagnostics (7.11.0): - FirebaseCoreDiagnostics (8.0.0):
- GoogleDataTransport (~> 8.4) - GoogleDataTransport (~> 9.0)
- GoogleUtilities/Environment (~> 7.0) - GoogleUtilities/Environment (~> 7.4)
- GoogleUtilities/Logger (~> 7.0) - GoogleUtilities/Logger (~> 7.4)
- nanopb (~> 2.30908.0) - nanopb (~> 2.30908.0)
- FirebaseInstallations (7.11.0): - FirebaseInstallations (8.0.0):
- FirebaseCore (~> 7.0) - FirebaseCore (~> 8.0)
- GoogleUtilities/Environment (~> 7.0) - GoogleUtilities/Environment (~> 7.4)
- GoogleUtilities/UserDefaults (~> 7.0) - GoogleUtilities/UserDefaults (~> 7.4)
- PromisesObjC (~> 1.2) - PromisesObjC (~> 1.2)
- FirebaseInstanceID (7.11.0): - FirebaseMessaging (8.0.0):
- FirebaseCore (~> 7.0) - FirebaseCore (~> 8.0)
- FirebaseInstallations (~> 7.0) - FirebaseInstallations (~> 8.0)
- GoogleUtilities/Environment (~> 7.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
- GoogleUtilities/UserDefaults (~> 7.0) - GoogleUtilities/Environment (~> 7.4)
- FirebaseMessaging (7.11.0): - GoogleUtilities/Reachability (~> 7.4)
- FirebaseCore (~> 7.0) - GoogleUtilities/UserDefaults (~> 7.4)
- FirebaseInstallations (~> 7.0) - FirebaseRemoteConfig (8.0.0):
- FirebaseInstanceID (~> 7.0) - FirebaseABTesting (~> 8.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.0) - FirebaseCore (~> 8.0)
- GoogleUtilities/Environment (~> 7.0) - FirebaseInstallations (~> 8.0)
- GoogleUtilities/Reachability (~> 7.0) - GoogleUtilities/Environment (~> 7.4)
- GoogleUtilities/UserDefaults (~> 7.0) - "GoogleUtilities/NSData+zlib (~> 7.4)"
- FirebaseRemoteConfig (7.11.0):
- FirebaseABTesting (~> 7.0)
- FirebaseCore (~> 7.0)
- FirebaseInstallations (~> 7.0)
- GoogleUtilities/Environment (~> 7.0)
- "GoogleUtilities/NSData+zlib (~> 7.0)"
- flurry (0.0.4): - flurry (0.0.4):
- Flurry-iOS-SDK/FlurrySDK - Flurry-iOS-SDK/FlurrySDK
- Flutter - Flutter
- Flurry-iOS-SDK/FlurrySDK (11.2.0) - 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
@ -144,13 +138,20 @@ PODS:
- google_sign_in (0.0.1): - google_sign_in (0.0.1):
- Flutter - Flutter
- GoogleSignIn (~> 5.0) - GoogleSignIn (~> 5.0)
- GoogleAppMeasurement/AdIdSupport (7.11.0): - GoogleAppMeasurement (8.0.0):
- GoogleUtilities/AppDelegateSwizzler (~> 7.0) - GoogleAppMeasurement/AdIdSupport (= 8.0.0)
- GoogleUtilities/MethodSwizzler (~> 7.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
- GoogleUtilities/Network (~> 7.0) - GoogleUtilities/MethodSwizzler (~> 7.4)
- "GoogleUtilities/NSData+zlib (~> 7.0)" - GoogleUtilities/Network (~> 7.4)
- "GoogleUtilities/NSData+zlib (~> 7.4)"
- nanopb (~> 2.30908.0) - nanopb (~> 2.30908.0)
- GoogleDataTransport (8.4.0): - GoogleAppMeasurement/AdIdSupport (8.0.0):
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
- GoogleUtilities/MethodSwizzler (~> 7.4)
- GoogleUtilities/Network (~> 7.4)
- "GoogleUtilities/NSData+zlib (~> 7.4)"
- nanopb (~> 2.30908.0)
- GoogleDataTransport (9.0.0):
- GoogleUtilities/Environment (~> 7.2) - GoogleUtilities/Environment (~> 7.2)
- nanopb (~> 2.30908.0) - nanopb (~> 2.30908.0)
- PromisesObjC (~> 1.2) - PromisesObjC (~> 1.2)
@ -158,33 +159,29 @@ PODS:
- AppAuth (~> 1.2) - AppAuth (~> 1.2)
- GTMAppAuth (~> 1.0) - GTMAppAuth (~> 1.0)
- GTMSessionFetcher/Core (~> 1.1) - GTMSessionFetcher/Core (~> 1.1)
- GoogleUtilities/AppDelegateSwizzler (7.4.0): - GoogleUtilities/AppDelegateSwizzler (7.4.1):
- GoogleUtilities/Environment - GoogleUtilities/Environment
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Network - GoogleUtilities/Network
- GoogleUtilities/Environment (7.4.0): - GoogleUtilities/Environment (7.4.1):
- PromisesObjC (~> 1.2) - PromisesObjC (~> 1.2)
- GoogleUtilities/Logger (7.4.0): - GoogleUtilities/Logger (7.4.1):
- GoogleUtilities/Environment - GoogleUtilities/Environment
- GoogleUtilities/MethodSwizzler (7.4.0): - GoogleUtilities/MethodSwizzler (7.4.1):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Network (7.4.0): - GoogleUtilities/Network (7.4.1):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib" - "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability - GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (7.4.0)" - "GoogleUtilities/NSData+zlib (7.4.1)"
- GoogleUtilities/Reachability (7.4.0): - GoogleUtilities/Reachability (7.4.1):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (7.4.0): - GoogleUtilities/UserDefaults (7.4.1):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GTMAppAuth (1.1.0): - GTMAppAuth (1.2.2):
- AppAuth/Core (~> 1.4) - AppAuth/Core (~> 1.4)
- GTMSessionFetcher (~> 1.4) - GTMSessionFetcher/Core (~> 1.5)
- GTMSessionFetcher (1.5.0):
- GTMSessionFetcher/Full (= 1.5.0)
- GTMSessionFetcher/Core (1.5.0) - GTMSessionFetcher/Core (1.5.0)
- GTMSessionFetcher/Full (1.5.0):
- GTMSessionFetcher/Core (= 1.5.0)
- modal_progress_hud_nsn (0.0.1): - modal_progress_hud_nsn (0.0.1):
- Flutter - Flutter
- nanopb (2.30908.0): - nanopb (2.30908.0):
@ -199,20 +196,21 @@ PODS:
- path_provider (0.0.1): - path_provider (0.0.1):
- Flutter - Flutter
- PromisesObjC (1.2.12) - PromisesObjC (1.2.12)
- Purchases (3.10.7): - Purchases (3.11.1):
- PurchasesCoreSwift (= 3.10.7) - PurchasesCoreSwift (= 3.11.1)
- purchases_flutter (3.2.1): - purchases_flutter (3.2.2):
- Flutter - Flutter
- PurchasesHybridCommon (= 1.6.2) - PurchasesHybridCommon (= 1.6.3)
- PurchasesCoreSwift (3.10.7) - PurchasesCoreSwift (3.11.1)
- PurchasesHybridCommon (1.6.2): - PurchasesHybridCommon (1.6.3):
- Purchases (= 3.10.7) - Purchases (= 3.11.1)
- Sentry (6.2.1): - Sentry (7.0.3):
- Sentry/Core (= 6.2.1) - Sentry/Core (= 7.0.3)
- Sentry/Core (6.2.1) - Sentry/Core (7.0.3)
- sentry_flutter (0.0.1): - sentry_flutter (0.0.1):
- Flutter - Flutter
- Sentry (~> 6.2.1) - FlutterMacOS
- Sentry (~> 7.0.3)
- shared_preferences (0.0.1): - shared_preferences (0.0.1):
- Flutter - Flutter
- sqflite (0.0.2): - sqflite (0.0.2):
@ -269,7 +267,6 @@ SPEC REPOS:
- FirebaseCore - FirebaseCore
- FirebaseCoreDiagnostics - FirebaseCoreDiagnostics
- FirebaseInstallations - FirebaseInstallations
- FirebaseInstanceID
- FirebaseMessaging - FirebaseMessaging
- FirebaseRemoteConfig - FirebaseRemoteConfig
- Flurry-iOS-SDK - Flurry-iOS-SDK
@ -350,23 +347,22 @@ SPEC CHECKSUMS:
devicelocale: b22617f40038496deffba44747101255cee005b0 devicelocale: b22617f40038496deffba44747101255cee005b0
FBSDKCoreKit: a00fe2efd780c195a5e09201bf51c56106245b40 FBSDKCoreKit: a00fe2efd780c195a5e09201bf51c56106245b40
FBSDKLoginKit: d98498c598ec09de657385a9349a1f21119b7f86 FBSDKLoginKit: d98498c598ec09de657385a9349a1f21119b7f86
Firebase: c121feb35e4126c0b355e3313fa9b487d47319fd Firebase: 73c3e3b216ec1ecbc54d2ffdd4670c65c749edb1
firebase_analytics: 620e8cc1705feb6b9c40b6127bea9b39e03e3970 firebase_analytics: 221d3bc4e8f1b5144a4bd4cc6b33790ee51bd543
firebase_auth: e7065954aa2a7c8ef1a8502fba3009bcdd8fc91a firebase_auth: f960df4ddd8cb415859dbc01a02d7859925ddef0
firebase_core: 84dcd80ac6d29c3d1039071b7306ee99688eb9c7 firebase_core: e4d3efb030a2b2021819f8faa538bb23deb46695
firebase_messaging: 7aecb08eada5e5cde85b10875141706a8d18b818 firebase_messaging: 3b6e0657b21261a57a1cd041fafa713f2aa6923f
firebase_remote_config: f855065886b7d6ccc38144c9a3cecbdc7887f33e firebase_remote_config: 3a6e2db440f0e95baba3dfc3d4118b1a4bc792c4
FirebaseABTesting: e66f1f80747792630d9b292966de206d5df9853b FirebaseABTesting: daebc95ec8829607d07dfe5e92dc3285aca29bc4
FirebaseAnalytics: cd3bd84d722a24a8923918af8af8e5236f615d77 FirebaseAnalytics: dcb92c7c9ef4fa7ffac276e8f87bd4fc8c97f1b8
FirebaseAuth: 5fe4585c2ed847319f0ea68bd1d82c77e49ff9a0 FirebaseAuth: b8cd992fca5b53dc6eec09e873a3f375f000c5a1
FirebaseCore: 907447d8917a4d3eb0cce2829c5a0ad21d90b432 FirebaseCore: 3f09591d51292843e2a46f18358d60bf4e996255
FirebaseCoreDiagnostics: 68ad972f99206cef818230f3f3179d52ccfb7f8c FirebaseCoreDiagnostics: a31d987ba0fe16d59886a5dbadc2f1de871f88c8
FirebaseInstallations: a58d4f72ec5861840b84df489f2668d970df558a FirebaseInstallations: c4aab1005d6547b00a7529777fe52f5d4d45165b
FirebaseInstanceID: ad5135045a498d7775903efd39762d2cdfa1be27 FirebaseMessaging: 1a33b4af3c8042ed6ddacb6c031894af2064bfab
FirebaseMessaging: 163435fb6db065e3b6228f1e577b10ed2cc506d2 FirebaseRemoteConfig: 055f6b5ba1751547596ded5032c4d5c6054ca501
FirebaseRemoteConfig: 0ea30de5fb0231df8c1bdcdf3b6c23bdc5066131
flurry: 15b01f664ab1367c62b50291541ea7f78ca85aad flurry: 15b01f664ab1367c62b50291541ea7f78ca85aad
Flurry-iOS-SDK: 6636d30c30f12010e7c7c71d84b443416a168efc Flurry-iOS-SDK: 5831da8fc6bedb31fa1f94aac6fd204d36dd351d
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68 flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68
flutter_facebook_auth: 4b170c07b7fce791497093fcc3f134fb215f3f07 flutter_facebook_auth: 4b170c07b7fce791497093fcc3f134fb215f3f07
@ -375,11 +371,11 @@ SPEC CHECKSUMS:
flutter_uxcam: ab8e5d3954eb448febd581375e2622e9eecb1066 flutter_uxcam: ab8e5d3954eb448febd581375e2622e9eecb1066
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc
GoogleAppMeasurement: fd19169c3034975cb934e865e5667bfdce59df7f GoogleAppMeasurement: c6bbc9753d046b5456dd4f940057fbad2c28419e
GoogleDataTransport: cd9db2180fcecd8da1b561aea31e3e56cf834aa7 GoogleDataTransport: 11e3a5f2c190327df1a4a5d7e7ae3d4d5b9c9e4c
GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213 GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
GoogleUtilities: 284cddc7fffc14ae1907efb6f78ab95c1fccaedc GoogleUtilities: f8a43108b38a68eebe8b3540e1f4f2d28843ce20
GTMAppAuth: 197a8dabfea5d665224aa00d17f164fc2248dab9 GTMAppAuth: ad5c2b70b9a8689e1a04033c9369c4915bfcbe89
GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52 GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
@ -387,12 +383,12 @@ SPEC CHECKSUMS:
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97 PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
Purchases: b8b8fb6e856ac8166e217f6e014df894d821dda1 Purchases: 6351f9ff6bd514e5ec5aa0f989ea181effa94bf5
purchases_flutter: 0130970b895c903e4e0aad793dd3a4c1b70bb434 purchases_flutter: 627527b070d80cdaf486fabe8b3d1dbe8d5cad92
PurchasesCoreSwift: 8ae0f08e020f0bc97c1befa4e38a0dbc8e9732e0 PurchasesCoreSwift: ee857e4c21e6254b09d7e303a756fcf2b9164408
PurchasesHybridCommon: 5f5c1c245b12fc5e8760af7d11cb10f888109a9b PurchasesHybridCommon: d65a799a61d688588534b80338edbcbf604ca93d
Sentry: 9b922b396b0e0bca8516a10e36b0ea3ebea5faf7 Sentry: 5b16f877da362d23716d827e04db642455b26b40
sentry_flutter: 5b3c6d717db5b7482504a313c831b318297d4d37 sentry_flutter: 602dc1902e152269256115e2386e1029511f3440
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef

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 = 2; CURRENT_PROJECT_VERSION = 1;
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.17; MARKETING_VERSION = 1.1.18;
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 = 2; CURRENT_PROJECT_VERSION = 1;
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.17; MARKETING_VERSION = 1.1.18;
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 = 2; CURRENT_PROJECT_VERSION = 1;
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.17; MARKETING_VERSION = 1.1.18;
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

@ -1,7 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:collection'; import 'dart:collection';
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_ability.dart'; import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart'; import 'package:aitrainer_app/model/workout_menu_tree.dart';

View File

@ -309,7 +309,6 @@ class TestSetExecuteBloc extends Bloc<TestSetExecuteEvent, TestSetExecuteState>
bool existsActivePlan() { bool existsActivePlan() {
final bool exists = exercisePlan != null && exercisePlanDetails != null && exercisePlanDetails!.isNotEmpty; final bool exists = exercisePlan != null && exercisePlanDetails != null && exercisePlanDetails!.isNotEmpty;
print("Exists active plan: $exists");
return exists; return exists;
} }

View File

@ -0,0 +1,160 @@
import 'dart:async';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer_training_plan.dart';
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/model/customer_training_plan_exercise.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/service/exercise_service.dart';
import 'package:aitrainer_app/service/training_plan_service.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
part 'training_plan_event.dart';
part 'training_plan_state.dart';
class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
final TrainingPlanRepository trainingPlanRepository;
final MenuBloc menuBloc;
TrainingPlanBloc({required this.trainingPlanRepository, required this.menuBloc}) : super(TrainingPlanInitial());
CustomerTrainingPlan? myPlan;
bool started = false;
CustomerTrainingPlan? getMyPlan() => this.myPlan;
setMyPlan(CustomerTrainingPlan myPlan) => this.myPlan = myPlan;
@override
Stream<TrainingPlanState> mapEventToState(TrainingPlanEvent event) async* {
try {
if (event is TrainingPlanActivate) {
yield TrainingPlanLoading();
myPlan = await trainingPlanRepository.activateTrainingPlan(event.trainingPlanId);
Cache().myTrainingPlan = myPlan;
await Cache().saveMyTrainingPlan();
yield TrainingPlanFinished();
} else if (event is TrainingPlanWeightChange) {
yield TrainingPlanLoading();
event.detail.weight = event.weight;
yield TrainingPlanReady();
} else if (event is TrainingPlanRepeatsChange) {
yield TrainingPlanLoading();
event.detail.repeats = event.repeats;
yield TrainingPlanReady();
} else if (event is TrainingPlanSaveExercise) {
yield TrainingPlanLoading();
event.detail.state = ExercisePlanDetailState.inProgress;
final Exercise exercise = Exercise();
exercise.customerId = Cache().userLoggedIn!.customerId!;
exercise.exerciseTypeId = event.detail.exerciseTypeId;
exercise.quantity = event.detail.repeats!.toDouble();
exercise.unit = event.detail.exerciseType!.unit;
exercise.unitQuantity = event.detail.weight;
exercise.dateAdd = DateTime.now();
event.detail.exercises.add(exercise);
if (event.detail.exercises.length >= event.detail.set!) {
event.detail.state = ExercisePlanDetailState.finished;
} else if (event.detail.exercises.length >= 0) {
event.detail.state = ExercisePlanDetailState.inProgress;
}
exercise.trainingPlanDetailsId = myPlan!.trainingPlanId;
// save Exercise
await ExerciseApi().addExercise(exercise);
Cache().addExercise(exercise);
Cache().myTrainingPlan = myPlan;
await Cache().saveMyTrainingPlan();
yield TrainingPlanReady();
}
} on Exception catch (e) {
yield TrainingPlanError(message: e.toString());
}
}
CustomerTrainingPlanDetails? getTrainingPlanDetail(int trainingPlanDetailsId) {
CustomerTrainingPlanDetails? detail;
if (myPlan == null || myPlan!.details.isEmpty) {
return null;
}
for (final det in this.myPlan!.details) {
if (det.customerTrainingPlanDetailsId == trainingPlanDetailsId) {
detail = det;
break;
}
}
return detail;
}
int? getActualWorkoutTreeId(int exerciseTypeId) {
final WorkoutMenuTree? workoutTree = this.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(exerciseTypeId);
if (workoutTree == null) {
return null;
}
return workoutTree.id;
}
String getActualImageName(int exerciseTypeId) {
if (exerciseTypeId <= 0) {
return "";
}
final WorkoutMenuTree? workoutTree = this.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(exerciseTypeId);
if (workoutTree == null) {
return "";
}
return workoutTree.imageName;
}
CustomerTrainingPlanDetails? getNext() {
if (myPlan == null || myPlan!.details.isEmpty) {
return null;
}
CustomerTrainingPlanDetails? next;
int minStep = 99;
for (final detail in this.myPlan!.details) {
if (!detail.state.equalsTo(ExercisePlanDetailState.finished)) {
if (detail.exercises.isEmpty) {
next = detail;
minStep = 1;
break;
} else {
final int step = detail.exercises.length;
if (step < minStep) {
next = detail;
minStep = step;
if (detail.parallel != true) {
break;
}
}
}
}
}
return next;
}
bool isStarted() {
if (myPlan == null || myPlan!.details.isEmpty) {
return false;
}
if (myPlan!.details[0].state == ExercisePlanDetailState.start) {
return false;
} else {
return true;
}
}
}

View File

@ -0,0 +1,54 @@
part of 'training_plan_bloc.dart';
abstract class TrainingPlanEvent extends Equatable {
const TrainingPlanEvent();
@override
List<Object> get props => [];
}
class TrainingPlanLoad extends TrainingPlanEvent {
const TrainingPlanLoad();
}
class TrainingPlanActivate extends TrainingPlanEvent {
final int trainingPlanId;
const TrainingPlanActivate({required this.trainingPlanId});
@override
List<Object> get props => [trainingPlanId];
}
class TrainingPlanWeightChange extends TrainingPlanEvent {
final CustomerTrainingPlanDetails detail;
final double weight;
const TrainingPlanWeightChange({required this.weight, required this.detail});
@override
List<Object> get props => [weight, detail];
}
class TrainingPlanRepeatsChange extends TrainingPlanEvent {
final CustomerTrainingPlanDetails detail;
final int repeats;
const TrainingPlanRepeatsChange({required this.repeats, required this.detail});
@override
List<Object> get props => [repeats, detail];
}
class TrainingPlanSaveExercise extends TrainingPlanEvent {
final CustomerTrainingPlanDetails detail;
const TrainingPlanSaveExercise({required this.detail});
@override
List<Object> get props => [detail];
}
class TrainingPlanFinishTraining extends TrainingPlanEvent {
const TrainingPlanFinishTraining();
}
class TrainingPlanSkipExercise extends TrainingPlanEvent {
const TrainingPlanSkipExercise();
}

View File

@ -0,0 +1,32 @@
part of 'training_plan_bloc.dart';
abstract class TrainingPlanState extends Equatable {
const TrainingPlanState();
@override
List<Object> get props => [];
}
class TrainingPlanInitial extends TrainingPlanState {
const TrainingPlanInitial();
}
class TrainingPlanLoading extends TrainingPlanState {
const TrainingPlanLoading();
}
class TrainingPlanReady extends TrainingPlanState {
const TrainingPlanReady();
}
class TrainingPlanFinished extends TrainingPlanState {
const TrainingPlanFinished();
}
class TrainingPlanError extends TrainingPlanState {
final String message;
const TrainingPlanError({required this.message});
@override
List<Object> get props => [message];
}

View File

@ -1,9 +1,11 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; 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/tutorial/tutorial_bloc.dart'; import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
import 'package:aitrainer_app/push_notifications.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/workout_tree_repository.dart'; import 'package:aitrainer_app/repository/workout_tree_repository.dart';
import 'package:aitrainer_app/service/firebase_api.dart'; import 'package:aitrainer_app/service/firebase_api.dart';
import 'package:aitrainer_app/util/session.dart'; import 'package:aitrainer_app/util/session.dart';
@ -24,6 +26,7 @@ import 'package:aitrainer_app/view/exercise_plan_custom_detail_add_page.dart';
import 'package:aitrainer_app/view/faq_page.dart'; import 'package:aitrainer_app/view/faq_page.dart';
import 'package:aitrainer_app/view/login.dart'; import 'package:aitrainer_app/view/login.dart';
import 'package:aitrainer_app/view/exercise_new_page.dart'; import 'package:aitrainer_app/view/exercise_new_page.dart';
import 'package:aitrainer_app/view/my_training_plans_page.dart';
import 'package:aitrainer_app/view/mydevelopment_body_page.dart'; import 'package:aitrainer_app/view/mydevelopment_body_page.dart';
import 'package:aitrainer_app/view/mydevelopment_muscle_page.dart'; import 'package:aitrainer_app/view/mydevelopment_muscle_page.dart';
import 'package:aitrainer_app/view/mydevelopment_page.dart'; import 'package:aitrainer_app/view/mydevelopment_page.dart';
@ -37,6 +40,9 @@ import 'package:aitrainer_app/view/test_set_control.dart';
import 'package:aitrainer_app/view/test_set_edit.dart'; import 'package:aitrainer_app/view/test_set_edit.dart';
import 'package:aitrainer_app/view/test_set_execute.dart'; import 'package:aitrainer_app/view/test_set_execute.dart';
import 'package:aitrainer_app/view/test_set_new.dart'; import 'package:aitrainer_app/view/test_set_new.dart';
import 'package:aitrainer_app/view/training_plan_activate_page.dart';
import 'package:aitrainer_app/view/training_plan_execute_page.dart';
import 'package:aitrainer_app/view/training_plan_exercise.dart';
import 'package:aitrainer_app/widgets/home.dart'; 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';
@ -178,6 +184,10 @@ Future<Null> main() async {
create: (BuildContext context) => TestSetExecuteBloc(), create: (BuildContext context) => TestSetExecuteBloc(),
), ),
BlocProvider<TutorialBloc>(create: (BuildContext context) => TutorialBloc(tutorialName: ActivityDone.tutorialBasic.toStr())), BlocProvider<TutorialBloc>(create: (BuildContext context) => TutorialBloc(tutorialName: ActivityDone.tutorialBasic.toStr())),
BlocProvider<TrainingPlanBloc>(create: (context) {
final MenuBloc menuBloc = BlocProvider.of<MenuBloc>(context);
return TrainingPlanBloc(menuBloc: menuBloc, trainingPlanRepository: TrainingPlanRepository());
}),
], ],
child: WorkoutTestApp(), child: WorkoutTestApp(),
)); ));
@ -262,6 +272,10 @@ class WorkoutTestApp extends StatelessWidget {
'testSetNew': (context) => TestSetNew(), 'testSetNew': (context) => TestSetNew(),
'testSetControl': (context) => TestSetControl(), 'testSetControl': (context) => TestSetControl(),
'faqPage': (context) => FaqPage(), 'faqPage': (context) => FaqPage(),
'myTrainingPlans': (context) => MyTrainingPlans(),
'myTrainingPlanActivate': (context) => TrainingPlanActivatePage(),
'myTrainingPlanExecute': (context) => TrainingPlanExecutePage(),
'myTrainingPlanExercise': (context) => TrainingPlanExercise(),
}, },
initialRoute: 'home', initialRoute: 'home',
title: 'WorkoutTest', title: 'WorkoutTest',

View File

@ -2,6 +2,7 @@ import 'dart:collection';
import 'dart:convert'; import 'dart:convert';
import 'package:aitrainer_app/model/customer.dart'; import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/model/customer_activity.dart'; import 'package:aitrainer_app/model/customer_activity.dart';
import 'package:aitrainer_app/model/customer_training_plan.dart';
import 'package:aitrainer_app/model/description.dart'; import 'package:aitrainer_app/model/description.dart';
import 'package:aitrainer_app/model/evaluation.dart'; import 'package:aitrainer_app/model/evaluation.dart';
import 'package:aitrainer_app/model/exercise_plan.dart'; import 'package:aitrainer_app/model/exercise_plan.dart';
@ -17,6 +18,7 @@ import 'package:aitrainer_app/model/product_test.dart';
import 'package:aitrainer_app/model/property.dart'; 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/sport.dart'; import 'package:aitrainer_app/model/sport.dart';
import 'package:aitrainer_app/model/training_plan.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';
@ -104,6 +106,7 @@ class Cache with Logging {
static final String activeExercisePlanKey = "active_exercise_plan"; static final String activeExercisePlanKey = "active_exercise_plan";
static final String activeExercisePlanDateKey = "active_exercise_plan_date"; static final String activeExercisePlanDateKey = "active_exercise_plan_date";
static final String activeExercisePlanDetailsKey = "active_exercise_details_plan"; static final String activeExercisePlanDetailsKey = "active_exercise_details_plan";
static final String myTrainingPlanKey = "myTrainingPlan";
static String baseUrlLive = 'https://aitrainer.info:8943/api/'; static String baseUrlLive = 'https://aitrainer.info:8943/api/';
static String baseUrlTest = 'https://aitrainer.info:8843/api/'; static String baseUrlTest = 'https://aitrainer.info:8843/api/';
@ -137,14 +140,19 @@ class Cache with Logging {
List<ExercisePlanTemplate> _exercisePlanTemplates = []; List<ExercisePlanTemplate> _exercisePlanTemplates = [];
ExercisePlan? activeExercisePlan; ExercisePlan? activeExercisePlan;
CustomerTrainingPlan? myTrainingPlan;
List<ExercisePlanDetail>? activeExercisePlanDetails; List<ExercisePlanDetail>? activeExercisePlanDetails;
List<ExerciseDevice>? _devices; List<ExerciseDevice>? _devices;
List<CustomerExerciseDevice>? _customerDevices; List<CustomerExerciseDevice>? _customerDevices;
List<CustomerActivity>? _customerActivities; List<CustomerActivity>? _customerActivities;
List<CustomerTrainingPlan>? _customerTrainingPlans;
List<Tutorial>? _tutorials; List<Tutorial>? _tutorials;
List<Description>? _descriptions; List<Description>? _descriptions;
List<Faq>? _faqs; List<Faq>? _faqs;
List<TrainingPlan>? _trainingPlans;
LinkedHashMap<int, ExercisePlanDetail> _myExercisesPlanDetails = LinkedHashMap<int, ExercisePlanDetail>(); LinkedHashMap<int, ExercisePlanDetail> _myExercisesPlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
@ -209,6 +217,33 @@ class Cache with Logging {
sharedPreferences.setString(Cache.activeExercisePlanDateKey, savingDay); sharedPreferences.setString(Cache.activeExercisePlanDateKey, savingDay);
} }
Future<void> saveMyTrainingPlan() async {
if (myTrainingPlan == null) {
return;
}
String myTrainingPlanJson = JsonEncoder().convert(myTrainingPlan!.toJsonWithDetails());
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
SharedPreferences sharedPreferences;
sharedPreferences = await prefs;
sharedPreferences.setString(Cache.myTrainingPlanKey, myTrainingPlanJson);
}
Future<void> getMyTrainingPlan() async {
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
SharedPreferences sharedPreferences;
sharedPreferences = await prefs;
final String? savedTrainingPlanJson = sharedPreferences.getString(Cache.myTrainingPlanKey);
if (savedTrainingPlanJson == null) {
return;
}
final Map<String, dynamic> map = JsonDecoder().convert(savedTrainingPlanJson);
print("Training plan: $savedTrainingPlanJson");
this.myTrainingPlan = CustomerTrainingPlan.fromJsonWithDetails(map);
}
Future<void> deleteActiveExercisePlan() async { Future<void> deleteActiveExercisePlan() async {
Future<SharedPreferences> prefs = SharedPreferences.getInstance(); Future<SharedPreferences> prefs = SharedPreferences.getInstance();
SharedPreferences sharedPreferences; SharedPreferences sharedPreferences;
@ -644,6 +679,8 @@ class Cache with Logging {
await isActivityDonePrefs(activity); await isActivityDonePrefs(activity);
}); });
await getMyTrainingPlan();
Cache().startPage = "home"; Cache().startPage = "home";
} }
@ -690,4 +727,10 @@ class Cache with Logging {
List<Faq>? getFaqs() => this._faqs; List<Faq>? getFaqs() => this._faqs;
setFaqs(List<Faq>? value) => this._faqs = value; setFaqs(List<Faq>? value) => this._faqs = value;
List<TrainingPlan>? getTrainingPlans() => this._trainingPlans;
setTrainingPlans(List<TrainingPlan>? value) => this._trainingPlans = value;
List<CustomerTrainingPlan>? getCustomerTrainingPlans() => this._customerTrainingPlans;
setCustomerTrainingPlans(value) => this._customerTrainingPlans = value;
} }

View File

@ -0,0 +1,78 @@
import 'dart:convert';
import 'package:intl/intl.dart';
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
class CustomerTrainingPlan {
int? customerTrainingPlanId;
int? customerId;
int? trainingPlanId;
DateTime? dateAdd;
bool? active;
String? status;
String? name;
CustomerTrainingPlan();
List<CustomerTrainingPlanDetails> details = [];
CustomerTrainingPlan.fromJson(Map json) {
this.customerTrainingPlanId = json['customerTrainingPlanId'];
this.customerId = json['customerId'];
this.trainingPlanId = json['trainingPlanId'];
this.dateAdd = DateTime.parse(json['dateAdd']);
this.active = json['active'];
this.status = json['status'];
this.name = json['name'];
}
CustomerTrainingPlan.fromJsonWithDetails(Map json) {
this.customerTrainingPlanId = json['customerTrainingPlanId'];
this.customerId = json['customerId'];
this.trainingPlanId = json['trainingPlanId'];
this.dateAdd = json['dateAdd'] != null ? DateTime.parse(json['dateAdd']) : DateTime.now();
this.active = json['active'];
this.status = json['status'];
this.name = json['name'];
try {
final String details = json['details'];
String jsonDetails = details.replaceAllMapped(
RegExp(r'([a-zA-Z]+|[0-9]{4}\-[0-9]{2}\-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})'), (Match m) => "\"${m[0]}\"");
jsonDetails = jsonDetails.replaceAll(r'\"null\"', 'null');
jsonDetails = jsonDetails.replaceAll(r'\"false\"', 'false');
jsonDetails = jsonDetails.replaceAll(r'\"true\"', 'true');
Iterable iterable = jsonDecode(jsonDetails);
this.details = iterable.map((detail) => CustomerTrainingPlanDetails.fromJsonWithExerciseList(detail)).toList();
} on Exception catch (e) {
print("JsonDecode error " + e.toString());
}
}
Map<String, dynamic> toJson() => {
"customerTrainingPlanId": this.customerTrainingPlanId,
"customerId": this.customerId,
"trainingPlanId": this.trainingPlanId,
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!),
"name": this.name,
"active": this.active,
"status": this.status
};
Map<String, dynamic> toJsonWithDetails() => {
"customerTrainingPlanId": this.customerTrainingPlanId,
"customerId": this.customerId,
"trainingPlanId": this.trainingPlanId,
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!),
"name": this.name,
"active": this.active,
"status": this.status,
'details': details.isEmpty ? [].toString() : details.map((detail) => detail.toJsonWithExercises()).toList().toString(),
};
@override
String toString() => this.toJson().toString();
}

View File

@ -0,0 +1,114 @@
import 'dart:convert';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
class CustomerTrainingPlanDetails {
/// customerTrainingPlanDetails
int? customerTrainingPlanDetailsId;
/// exerciseTypeId
int? exerciseTypeId;
/// set
int? set;
/// repeats
int? repeats;
/// weight
double? weight;
int? restingTime;
bool? parallel;
String? day;
/// exerciseType
ExerciseType? exerciseType;
ExercisePlanDetailState state = ExercisePlanDetailState.start;
List<Exercise> exercises = [];
CustomerTrainingPlanDetails();
CustomerTrainingPlanDetails.fromJson(Map json) {
this.customerTrainingPlanDetailsId = json['customerTrainingPlanDetailsId'];
this.exerciseTypeId = json['exerciseTypeId'];
this.set = json['set'];
this.repeats = json['repeats'];
this.weight = json['weight'];
this.restingTime = json['restingTime'];
this.parallel = json['parallel'];
this.day = json['day'];
}
CustomerTrainingPlanDetails.fromJsonWithExerciseList(Map json) {
this.customerTrainingPlanDetailsId = json['customerTrainingPlanDetailsId'] == "null" || json['customerTrainingPlanDetailsId'] == null
? 0
: json['customerTrainingPlanDetailsId'];
this.exerciseTypeId = json['exerciseTypeId'];
this.set = json['set'];
this.repeats = json['repeats'];
this.weight = json['weight'];
this.restingTime = json['restingTime'];
this.parallel = json['parallel'] == "false"
? false
: json['parallel'] == "true"
? true
: null;
this.day = json['day'];
try {
Iterable iterable = json['exercises'];
this.exercises = iterable.map((exercise) => Exercise.fromJson(exercise)).toList();
} on Exception catch (e) {
print("JsonDecode error " + e.toString());
}
if (exercises.length >= this.set!) {
this.state = ExercisePlanDetailState.finished;
} else if (exercises.length > 0) {
this.state = ExercisePlanDetailState.inProgress;
} else {
this.state = ExercisePlanDetailState.start;
}
this.exerciseType = Cache().getExerciseTypeById(exerciseTypeId!);
}
ExerciseType? getExerciseType() => exerciseType;
Map<String, dynamic> toJson() => {
"customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId,
"exerciseTypeId": this.exerciseTypeId,
"set": this.set,
"repeats": this.repeats,
"weight": this.weight,
"restingTime": this.restingTime,
"parallel": this.parallel,
"day": this.day == null ? '1.' : this.day,
};
Map<String, dynamic> toJsonWithExercises() {
final Map<String, dynamic> jsonMap = {
"customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId,
"exerciseTypeId": this.exerciseTypeId,
"set": this.set,
"repeats": this.repeats,
"weight": this.weight,
"restingTime": this.restingTime,
"parallel": this.parallel,
'exercises': exercises.isEmpty ? [].toString() : exercises.map((exercise) => exercise.toJson()).toList().toString(),
};
if (this.day != null && this.day!.isNotEmpty) {
jsonMap["day"] = this.day;
}
//print("Detail $jsonMap");
return jsonMap;
}
@override
String toString() => this.toJson().toString();
}

View File

@ -0,0 +1,30 @@
class CustomerTrainingPlanExercise {
int? customerTrainingPlanExerciseId;
int? customerTrainingPlanDetailsId;
int? customerId;
int? exerciseId;
double? weight;
int? repeats;
CustomerTrainingPlanExercise();
CustomerTrainingPlanExercise.fromJson(Map json) {
this.customerTrainingPlanExerciseId = json['customerTrainingPlanExerciseId'];
this.customerTrainingPlanDetailsId = json['customerTrainingPlanDetailsId'];
this.customerId = json['customerId'];
this.exerciseId = json['exerciseId'];
this.repeats = json['repeats'];
this.weight = json['weight'];
}
Map<String, dynamic> toJson() => {
"customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId,
"customerId": this.customerId,
"exerciseId": this.exerciseId,
"weight": this.weight,
"repeats": this.repeats
};
@override
String toString() => this.toJson().toString();
}

View File

@ -9,6 +9,7 @@ class Exercise {
double? unitQuantity; double? unitQuantity;
DateTime? dateAdd; DateTime? dateAdd;
int? exercisePlanDetailId; int? exercisePlanDetailId;
int? trainingPlanDetailsId;
String? datePart; String? datePart;
double? calculated; double? calculated;
@ -26,6 +27,8 @@ class Exercise {
this.dateAdd = DateTime.parse(json['dateAdd']); this.dateAdd = DateTime.parse(json['dateAdd']);
this.datePart = DateFormat('yyyy-MM-dd').format(this.dateAdd!); this.datePart = DateFormat('yyyy-MM-dd').format(this.dateAdd!);
this.calculated = quantity; this.calculated = quantity;
this.exercisePlanDetailId = json['exercisePlanDetailId'] == "null" ? null : json['exercisePlanDetailId'];
this.trainingPlanDetailsId = json['trainingPlanDetailsId'] == "null" ? null : json['trainingPlanDetailsId'];
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
@ -36,6 +39,7 @@ class Exercise {
"unitQuantity": unitQuantity, "unitQuantity": unitQuantity,
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!), "dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!),
"exercisePlanDetailId": exercisePlanDetailId, "exercisePlanDetailId": exercisePlanDetailId,
"trainingPlanDetailsId": trainingPlanDetailsId,
}; };
Map<String, dynamic> toJsonDatePart() => { Map<String, dynamic> toJsonDatePart() => {

View File

@ -18,7 +18,12 @@ class ExerciseTree {
late String nameTranslation; late String nameTranslation;
/// sort /// sort
late int? sort; int? sort;
String? internalName;
String? description;
String? descriptionTranslation;
ExerciseTree(); ExerciseTree();
@ -29,7 +34,12 @@ class ExerciseTree {
this.imageUrl = json['imageUrl']; this.imageUrl = json['imageUrl'];
this.active = json['active']; this.active = json['active'];
this.nameTranslation = json['translations'] != null && (json['translations']).length > 0 ? json['translations'][0]['name'] : this.name; this.nameTranslation = json['translations'] != null && (json['translations']).length > 0 ? json['translations'][0]['name'] : this.name;
this.descriptionTranslation =
json['translations'] != null && (json['translations']).length > 0 && json['translations'][0]['description'] != null
? json['translations'][0]['description']
: this.description;
this.sort = 99; this.sort = 99;
this.internalName = json['internalName'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -37,13 +47,18 @@ class ExerciseTree {
"treeId": treeId, "treeId": treeId,
"parentId": parentId, "parentId": parentId,
"name": name, "name": name,
"description": description,
"imageUrl": imageUrl, "imageUrl": imageUrl,
"active": active.toString(), "active": active.toString(),
"nameTranslation": nameTranslation, "nameTranslation": nameTranslation,
"descriptionTranslation": descriptionTranslation,
"sort": sort, "sort": sort,
}; };
} }
@override
String toString() => this.toJson().toString();
ExerciseTree copy(int parentId) { ExerciseTree copy(int parentId) {
ExerciseTree newTree = ExerciseTree(); ExerciseTree newTree = ExerciseTree();
newTree.treeId = this.treeId; newTree.treeId = this.treeId;

View File

@ -0,0 +1,71 @@
import 'dart:collection';
import 'package:aitrainer_app/model/training_plan_detail.dart';
class TrainingPlan {
late int trainingPlanId;
late String type;
late String name;
late String internalName;
late String description;
late bool free;
int? treeId;
HashMap<String, String> nameTranslations = HashMap();
HashMap<String, String> descriptionTranslations = HashMap();
List<TrainingPlanDetail>? details;
TrainingPlan.fromJson(Map<String, dynamic> json) {
this.trainingPlanId = json['trainingPlanId'];
this.name = json['name'];
this.type = json['type'];
this.internalName = json['internalName'];
this.description = json['description'];
this.free = json['free'];
this.treeId = json['treeId'];
nameTranslations['en'] = name;
descriptionTranslations['en'] = description;
if (json['translations'] != null && json['translations'].length > 0) {
json['translations'].forEach((translation) {
nameTranslations[translation['languageCode']] = translation['nameTranslation'];
descriptionTranslations[translation['languageCode']] = translation['descriptionTranslation'];
});
}
if (json['details'] != null && json['details'].length > 0) {
details = json['details'].map<TrainingPlanDetail>((detail) => TrainingPlanDetail.fromJson(detail)).toList();
if (details != null && details!.isNotEmpty) {
details!.sort((a, b) {
if (a.sort == 0 || b.sort == 0) {
if (a.trainingPlanDetailId <= b.trainingPlanDetailId) {
return -1;
} else {
return 1;
}
}
if (a.sort <= b.sort) {
return -1;
} else {
return 1;
}
});
}
}
}
Map<String, dynamic> toJson() => {
"trainingPlanId": this.trainingPlanId,
"treeId": this.treeId,
"name": this.name,
"type": this.type,
"internalName": this.internalName,
"free": this.free,
"description": this.description,
"nameTranslation": this.nameTranslations.toString(),
};
@override
String toString() => this.toJson().toString();
}

View File

@ -0,0 +1,40 @@
class TrainingPlanDetail {
late int trainingPlanDetailId;
late int trainingPlanId;
late int exerciseTypeId;
late int sort;
late int set;
late int repeats;
late double weight;
late int restingTime;
late bool parallel;
late String day;
TrainingPlanDetail.fromJson(Map<String, dynamic> json) {
this.trainingPlanDetailId = json['trainingPlanDetailId'];
this.trainingPlanId = json['trainingPlanId'];
this.exerciseTypeId = json['exerciseTypeId'];
this.sort = json['sort'];
this.set = json['set'];
this.repeats = json['repeats'];
this.weight = json['weight'];
this.restingTime = json['restingTime'];
this.parallel = json['parallel'];
this.day = json['day'];
}
Map<String, dynamic> toJson() => {
"trainingPlanDetailId": this.trainingPlanDetailId,
"trainingPlanId": this.trainingPlanId,
"exerciseType": this.exerciseTypeId,
"sort": this.sort,
"repeats": this.repeats,
"weight": this.weight,
"restingTime": this.restingTime,
"parallel": this.parallel,
"day": this.day,
};
@override
String toString() => this.toJson().toString();
}

View File

@ -0,0 +1,141 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer_training_plan.dart';
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_tree.dart';
import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/service/training_plan_service.dart';
import 'package:aitrainer_app/util/common.dart';
class TrainingPlanRepository {
ExerciseTree? parentTree;
List<TrainingPlan> getPlansByParent(String parent) {
final List<TrainingPlan> resultList = [];
final List<ExerciseTree>? exerciseTree = Cache().getExerciseTree();
int? parentId;
if (exerciseTree != null) {
exerciseTree.forEach((element) {
if (element.internalName == parent) {
parentId = element.treeId;
parentTree = element;
}
});
}
final List<TrainingPlan>? plans = Cache().getTrainingPlans();
if (plans != null && parentId != null) {
plans.forEach((element) {
if (element.treeId == parentId) {
resultList.add(element);
}
});
}
return resultList;
}
/// 1. deactivate old training plans - update all
/// 2. calculate customer_training_plan_details weights / repleats
/// 3. create new customer_training_plan
Future<CustomerTrainingPlan?> activateTrainingPlan(int trainingPlanId) async {
print(" **** Activate Plan: $trainingPlanId");
// 1. deactivate
if (Cache().getCustomerTrainingPlans() != null) {
Cache().getCustomerTrainingPlans()!.forEach((plan) {
plan.active = false;
if (plan.customerTrainingPlanId != null) {
TrainingPlanApi().updateCustomerTrainingPlan(plan, plan.customerTrainingPlanId!);
}
});
}
CustomerTrainingPlan plan = CustomerTrainingPlan();
plan.customerId = Cache().userLoggedIn!.customerId;
plan.trainingPlanId = trainingPlanId;
plan.active = true;
plan.status = "open";
plan.dateAdd = DateTime.now();
plan.name = getTrainingPlanById(trainingPlanId)!.nameTranslations["hu"];
TrainingPlan? trainingPlan = this.getTrainingPlanById(trainingPlanId);
if (trainingPlan == null || trainingPlan.details == null) {
return null;
}
// 3 calculate weights
trainingPlan.details!.forEach((elem) {
CustomerTrainingPlanDetails detail = CustomerTrainingPlanDetails();
detail.exerciseTypeId = elem.exerciseTypeId;
detail.repeats = elem.repeats;
detail.set = elem.set;
detail.day = elem.day;
detail.parallel = elem.parallel;
detail.restingTime = elem.restingTime;
detail.exerciseType = Cache().getExerciseTypeById(detail.exerciseTypeId!);
if (detail.exerciseType!.unitQuantityUnit != null) {
detail = getCalculatedWeightRepeats(elem.exerciseTypeId, detail);
} else {
detail.weight = 0;
}
//print("Detail $detail exerciseType: ${detail.exerciseType}");
detail.state = ExercisePlanDetailState.start;
plan.details.add(detail);
});
Cache().myTrainingPlan = plan;
//TrainingPlanApi().saveCustomerTrainingPlan(plan);
return plan;
}
TrainingPlan? getTrainingPlanById(int trainingPlanId) {
TrainingPlan? plan;
if (Cache().getTrainingPlans() == null) {
return plan;
}
for (var trainingPlan in Cache().getTrainingPlans()!) {
if (trainingPlan.trainingPlanId == trainingPlanId) {
plan = trainingPlan;
break;
}
}
return plan;
}
CustomerTrainingPlanDetails getCalculatedWeightRepeats(int exerciseTypeId, CustomerTrainingPlanDetails detail) {
double weight = -1;
if (Cache().getExercises() == null) {
detail.weight = weight;
return detail;
}
Exercise? lastExercise1RM;
Cache().getExercises()!.forEach((exercise) {
if (exercise.exercisePlanDetailId == 0 && exercise.exerciseTypeId == exerciseTypeId) {
detail.weight = weight;
lastExercise1RM = exercise;
}
});
if (lastExercise1RM == null || lastExercise1RM!.unitQuantity == null) {
detail.weight = weight;
return detail;
}
double oneRepMax = Common.calculate1RM(lastExercise1RM!.unitQuantity!, lastExercise1RM!.quantity!);
//print("Exercise $exerciseTypeId - 1RM : $oneRepMax");
weight = oneRepMax * Common.get1RMPercent(detail.repeats!);
//print("Exercise $exerciseTypeId - weight : $weight");
weight = Common.roundWeight(weight);
detail.repeats = Common.calculateQuantityByChangedWeight(oneRepMax, weight, detail.repeats!.toDouble());
detail.weight = weight;
return detail;
}
}

View File

@ -13,19 +13,19 @@ class ExerciseTreeApi with Logging {
Future<List<ExerciseTree>> getExerciseTree() async { Future<List<ExerciseTree>> getExerciseTree() async {
final String body = await _client.get("exercise_tree", ""); final String body = await _client.get("exercise_tree", "");
Iterable json = jsonDecode(body); Iterable json = jsonDecode(body);
List<ExerciseTree>? exerciseTree = json.map((exerciseTree) => ExerciseTree.fromJson(exerciseTree)).toList(); List<ExerciseTree>? exerciseTrees = json.map((exerciseTree) => ExerciseTree.fromJson(exerciseTree)).toList();
exerciseTree = await getExerciseTreeParents(exerciseTree); exerciseTrees = await getExerciseTreeParents(exerciseTrees);
await Future.forEach(exerciseTree, (element) async { await Future.forEach(exerciseTrees, (element) async {
ExerciseTree exerciseTree = element as ExerciseTree; ExerciseTree exerciseTree = element as ExerciseTree;
exerciseTree.imageUrl = await buildImage(exerciseTree.imageUrl, exerciseTree.treeId); exerciseTree.imageUrl = await buildImage(exerciseTree.imageUrl, exerciseTree.treeId);
}); });
exerciseTree = await getExerciseTreeParents(exerciseTree); exerciseTrees = await getExerciseTreeParents(exerciseTrees);
log("ExerciseTree downloaded"); log("ExerciseTree downloaded $exerciseTrees");
Cache().setExerciseTree(exerciseTree); Cache().setExerciseTree(exerciseTrees);
return exerciseTree; return exerciseTrees;
} }
Future<String> buildImage(String imageUrl, int treeId) async { Future<String> buildImage(String imageUrl, int treeId) async {

View File

@ -18,6 +18,7 @@ import 'package:aitrainer_app/model/product.dart';
import 'package:aitrainer_app/model/product_test.dart'; import 'package:aitrainer_app/model/product_test.dart';
import 'package:aitrainer_app/model/property.dart'; 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/training_plan.dart';
import 'package:aitrainer_app/model/tutorial.dart'; import 'package:aitrainer_app/model/tutorial.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';
@ -86,6 +87,11 @@ class PackageApi {
final List<Faq>? faqs = json.map((faq) => Faq.fromJson(faq)).toList(); final List<Faq>? faqs = json.map((faq) => Faq.fromJson(faq)).toList();
//print("Faq: $faqs"); //print("Faq: $faqs");
Cache().setFaqs(faqs); Cache().setFaqs(faqs);
} else if (headRecord[0] == "TrainingPlan") {
final Iterable json = jsonDecode(headRecord[1]);
final List<TrainingPlan>? plans = json.map((plan) => TrainingPlan.fromJson(plan)).toList();
Cache().setTrainingPlans(plans);
} }
}); });
@ -95,6 +101,7 @@ 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);
return; return;

View File

@ -0,0 +1,34 @@
import 'dart:convert';
import 'package:aitrainer_app/model/customer_training_plan.dart';
import 'package:aitrainer_app/model/customer_training_plan_exercise.dart';
import 'package:aitrainer_app/service/api.dart';
import 'package:aitrainer_app/service/logging.dart';
class TrainingPlanApi with Logging {
final APIClient _client = new APIClient();
Future<CustomerTrainingPlan> saveCustomerTrainingPlan(CustomerTrainingPlan plan) async {
String body = JsonEncoder().convert(plan.toJson());
log(" ===== saving customer training plan:" + body);
final String response = await _client.post("customer_training_plan/", body);
final CustomerTrainingPlan saved = CustomerTrainingPlan.fromJson(jsonDecode(response));
return saved;
}
Future<CustomerTrainingPlanExercise> saveCustomerTrainingPlanExercise(CustomerTrainingPlanExercise planExercise) async {
String body = JsonEncoder().convert(planExercise.toJson());
log(" ===== saving customer training plan exercise:" + body);
final String response = await _client.post("customer_training_plan_exercise/", body);
final CustomerTrainingPlanExercise saved = CustomerTrainingPlanExercise.fromJson(jsonDecode(response));
return saved;
}
Future<CustomerTrainingPlan> updateCustomerTrainingPlan(CustomerTrainingPlan plan, int customerTrainingPlanId) async {
String body = JsonEncoder().convert(plan.toJson());
log(" ===== update customer training plan:" + body);
final String response = await _client.post("customer_training_plan/update/$customerTrainingPlanId", body);
final CustomerTrainingPlan saved = CustomerTrainingPlan.fromJson(jsonDecode(response));
return saved;
}
}

View File

@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'package:aitrainer_app/util/app_language.dart'; import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_type.dart'; import 'package:aitrainer_app/model/exercise_type.dart';
@ -144,4 +143,62 @@ mixin Common {
value = value.replaceAll(RegExp(r'[^0-9.]'), ""); value = value.replaceAll(RegExp(r'[^0-9.]'), "");
return value; return value;
} }
static double calculate1RM(double weight, double repeat) {
if (weight == 0 || repeat == 0) {
return 0;
}
double rmWendler = weight * repeat * 0.0333 + weight;
double rmOconner = weight * (1 + repeat / 40);
//print("Weight: $weight repeat: $repeat, $rmWendler, Oconner: $rmOconner");
double average = (rmWendler + rmOconner) / 2;
return average;
}
static double get1RMPercent(int repeats) {
double percent = 1;
if (repeats >= 35) {
percent = 0.50;
} else if (repeats > 12) {
percent = (100 - 2 * repeats) / 100;
} else {
percent = (100.0 - 2 * repeats) / 100;
}
//print("1RM Percent: $percent repeats: $repeats");
return percent;
}
static double roundWeight(double weight) {
double rounded = weight.round().toDouble();
if (weight > 35) {
final double remainder = weight % 5;
if (remainder < 1.25) {
rounded = ((weight / 5).floor() * 5).toDouble();
} else if (remainder > 1.25 && remainder <= 2.5) {
rounded = (weight / 5).floor() * 5 + 2.5;
} else if (remainder > 2.5 && remainder < 3.75) {
rounded = (weight / 5).floor() * 5 + 2.5;
} else {
rounded = (((weight / 5).ceil() * 5) + 5).toDouble();
}
}
return rounded;
}
static int calculateQuantityByChangedWeight(double initialRM, double weight, double repeat) {
final double rmWendler = weight * repeat * 0.0333 + weight;
final double rmOconner = weight * (1 + repeat / 40);
//print("Weight: $weight oneRepQuantity: $repeat, $rmWendler, Oconner: $rmOconner");
final double repeatWendler = (rmWendler - weight) / 0.0333 / weight;
final double repeatOconner = (rmOconner / weight - 1) * 40;
final newRepeat = ((repeatOconner + repeatWendler) / 2).ceil();
//print("Initial 1RM: $initialRM Weight: $weight repeatWendler: $repeatWendler repeat Oconner: $repeatOconner. NEW REPEAT: $newRepeat");
return newRepeat;
}
} }

View File

@ -151,7 +151,7 @@ class AccountPage extends StatelessWidget with Trans {
), ),
devices(context, accountBloc), devices(context, accountBloc),
loginOut(context, accountBloc), loginOut(context, accountBloc),
getMyTrainees(context, accountBloc), //getMyTrainees(context, accountBloc),
]); ]);
} }

View File

@ -141,9 +141,9 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
unitQuantityUnit: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit, unitQuantityUnit: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit,
hasUnitQuantity: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit != null, hasUnitQuantity: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit != null,
onQuantityChanged: (value) { onQuantityChanged: (value) {
exerciseBloc.add(ExerciseNewQuantityChange(quantity: double.parse(value))); exerciseBloc.add(ExerciseNewQuantityChange(quantity: value));
}, },
onUnitQuantityChanged: (value) => exerciseBloc.add(ExerciseNewQuantityUnitChange(quantity: double.parse(value))), onUnitQuantityChanged: (value) => exerciseBloc.add(ExerciseNewQuantityUnitChange(quantity: value)),
//onSubmit: () => confirmationDialog(exerciseBloc, menuBloc), //onSubmit: () => confirmationDialog(exerciseBloc, menuBloc),
exerciseTypeId: exerciseType.exerciseTypeId, exerciseTypeId: exerciseType.exerciseTypeId,
)), )),

View File

@ -0,0 +1,125 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/image_button.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
// ignore: must_be_immutable
class MyTrainingPlans extends StatelessWidget with Trans, Logging {
@override
Widget build(BuildContext context) {
setContext(context);
return Scaffold(
appBar: AppBarNav(depth: 0),
body: Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_menu_dark.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: BlocConsumer<TrainingPlanBloc, TrainingPlanState>(
listener: (context, state) {
if (state is TrainingPlanError) {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: true,
title: t("Warning"),
descriptions: t(state.message),
text: "OK",
onTap: () => Navigator.of(context).pushNamed("login"),
onCancel: () => {
Navigator.of(context).pop(),
},
);
});
} else if (state is TrainingPlanFinished) {
Navigator.of(context).pop();
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
Navigator.of(context).pushNamed("myTrainingPlanExecute", arguments: bloc);
}
},
builder: (context, state) {
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
return ModalProgressHUD(
child: getPrograms(bloc),
inAsyncCall: state is TrainingPlanLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
),
),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 2));
}
Widget getPrograms(TrainingPlanBloc bloc) {
return CustomScrollView(scrollDirection: Axis.vertical, slivers: [
SliverGrid(
delegate: SliverChildListDelegate([
getTrainingPlan(t("My Active Training"), "asset/image/exercise_plan_execute.jpg", "",
color: Colors.yellow[400]!, route: "myTrainingPlanExecute"),
getTrainingPlan(t("My Custom Plan"), "asset/image/exercise_plan_custom.jpg", ""),
getTrainingPlan(t("Training Plans for Beginners"), "asset/menu/training_plans_q_beginner.jpg", "beginner"),
getTrainingPlan(t("Training Plans for Home"), "asset/menu/training_plans_q_home.jpg", "home"),
getTrainingPlan(t("Training Plans Advanced"), "asset/menu/training_plans_q_advanced.jpg", "advanced"),
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 for Gain Strength"), "asset/menu/training_plans_q_gain_strength.jpg", "gain_strength"),
]),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 15.0,
crossAxisSpacing: 15.0,
childAspectRatio: 1.0,
),
)
]);
}
Widget getTrainingPlan(String name, String imageUrl, String parentName,
{Color color = Colors.white, String route = "myTrainingPlanActivate"}) {
double mediaWidth = MediaQuery.of(context).size.width;
double imageWidth = (mediaWidth - 45) / 2;
return ImageButton(
width: imageWidth,
textAlignment: Alignment.topLeft,
text: name,
style: GoogleFonts.robotoMono(
textStyle: TextStyle(fontSize: 14, color: color, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4))),
image: imageUrl,
left: 5,
textColor: color,
onTap: () {
if (Cache().userLoggedIn != null) {
if (route == "myTrainingPlanActivate") {
HashMap<String, dynamic> args = HashMap();
args['parentName'] = parentName;
Navigator.of(context).pushNamed("myTrainingPlanActivate", arguments: args);
} else {
Navigator.of(context).pushNamed(route);
}
}
},
isLocked: false,
);
}
}

View File

@ -99,9 +99,9 @@ class TestSetNew extends StatelessWidget with Trans {
unitQuantityUnit: bloc.exerciseType.unitQuantityUnit, unitQuantityUnit: bloc.exerciseType.unitQuantityUnit,
hasUnitQuantity: bloc.exerciseType.unitQuantityUnit != null, hasUnitQuantity: bloc.exerciseType.unitQuantityUnit != null,
onQuantityChanged: (value) { onQuantityChanged: (value) {
bloc.add(TestSetNewChangeQuantity(quantity: double.parse(value))); bloc.add(TestSetNewChangeQuantity(quantity: value));
}, },
onUnitQuantityChanged: (value) => bloc.add(TestSetNewChangeQuantityUnit(quantity: double.parse(value))), onUnitQuantityChanged: (value) => bloc.add(TestSetNewChangeQuantityUnit(quantity: value)),
exerciseTypeId: bloc.exerciseType.exerciseTypeId, exerciseTypeId: bloc.exerciseType.exerciseTypeId,
/* onSubmit: () { /* onSubmit: () {
Navigator.of(context).pop(); Navigator.of(context).pop();

View File

@ -0,0 +1,483 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/library/tree_view.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:aitrainer_app/widgets/treeview_parent_widget.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html/style.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
// ignore: must_be_immutable
class TrainingPlanActivatePage extends StatelessWidget with Trans {
late String parentName;
TrainingPlanActivatePage();
@override
Widget build(BuildContext context) {
setContext(context);
final HashMap<String, dynamic> args = ModalRoute.of(context)!.settings.arguments as HashMap<String, dynamic>;
parentName = args['parentName'];
return Scaffold(
appBar: AppBarNav(depth: 1),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: BlocConsumer<TrainingPlanBloc, TrainingPlanState>(
listener: (context, state) {
if (state is TrainingPlanError) {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: true,
title: t("Warning"),
descriptions: t(state.message),
text: "OK",
onTap: () => Navigator.of(context).pushNamed("login"),
onCancel: () => {
Navigator.of(context).pop(),
},
);
});
} else if (state is TrainingPlanFinished) {
Navigator.of(context).pop();
Navigator.of(context).pushNamed("myTrainingPlanExecute");
}
},
builder: (context, state) {
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
return ModalProgressHUD(
child: getPlans(bloc),
inAsyncCall: state is TrainingPlanLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
),
),
);
}
Widget getPlans(TrainingPlanBloc bloc) {
return TreeView(
startExpanded: false,
children: _getTreeChildren(bloc),
);
}
List<Widget> _getTreeChildren(TrainingPlanBloc bloc) {
final List<TrainingPlan> plans = bloc.trainingPlanRepository.getPlansByParent(parentName);
final String parentTitle =
bloc.trainingPlanRepository.parentTree != null ? bloc.trainingPlanRepository.parentTree!.nameTranslation : "";
final String parentDescription =
bloc.trainingPlanRepository.parentTree != null && bloc.trainingPlanRepository.parentTree!.descriptionTranslation != null
? bloc.trainingPlanRepository.parentTree!.descriptionTranslation!
: "";
List<Widget> listWidget = [];
Card explanation = Card(
color: Colors.white60,
child: Container(
padding: EdgeInsets.only(left: 10, right: 5, top: 12, bottom: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Row(
children: [
Icon(
Icons.info,
color: Colors.orangeAccent,
),
Text(" "),
Flexible(
child: Text(
parentTitle,
maxLines: 2,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
)),
],
),
Divider(
color: Colors.transparent,
),
Html(
data: parentDescription,
//Optional parameters:
style: {
"p": Style(
color: Colors.black,
fontSize: FontSize(12),
padding: const EdgeInsets.only(left: 20, right: 8, bottom: 4),
),
"strong": Style(
color: Colors.indigo,
fontWeight: FontWeight.bold,
fontSize: FontSize(14),
),
"h3": Style(
color: Colors.yellow[600],
fontSize: FontSize(16),
textAlign: TextAlign.center,
padding: const EdgeInsets.all(12),
),
"li": Style(
color: Colors.white,
fontSize: FontSize(14),
padding: const EdgeInsets.only(left: 20, bottom: 10, right: 8),
//before: "*",
display: Display.LIST_ITEM),
"h2": Style(
color: Colors.yellow[600],
fontWeight: FontWeight.bold,
fontSize: FontSize(24),
textAlign: TextAlign.center,
//padding: const EdgeInsets.all(4),
),
"h1": Style(
color: Colors.yellow[400],
fontWeight: FontWeight.bold,
fontSize: FontSize.larger,
alignment: Alignment.center,
padding: const EdgeInsets.all(4),
),
},
), //
],
)));
listWidget.add(explanation);
plans.forEach((element) {
listWidget.add(Container(
margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild(
startExpanded: false,
parent: TreeviewParentWidget(
text: element.nameTranslations[AppLanguage().appLocal.toString()] != null
? element.nameTranslations[AppLanguage().appLocal.toString()]!
: element.name,
fontSize: 18,
icon: Icon(Icons.list_sharp),
color: Colors.blue[800],
),
children: _getChildList(element, bloc),
)));
});
return listWidget;
}
List<Widget> _getChildList(TrainingPlan plan, TrainingPlanBloc bloc) {
List<Widget> list = [];
list.add(Card(
margin: EdgeInsets.only(left: 10, top: 5),
color: Colors.white60,
child: Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: Column(children: [
Html(
data: plan.descriptionTranslations[AppLanguage().appLocal.toString()] != null
? plan.descriptionTranslations[AppLanguage().appLocal.toString()]!
: plan.description,
//Optional parameters:
style: {
"p": Style(
color: Colors.black,
padding: const EdgeInsets.all(4),
),
"li": Style(
color: Colors.white,
//padding: const EdgeInsets.all(4),
),
"h2": Style(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: FontSize.larger,
//padding: const EdgeInsets.all(4),
),
"h1": Style(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: FontSize.larger,
alignment: Alignment.center,
padding: const EdgeInsets.all(4),
),
},
),
getPlanDetails(plan, bloc),
ElevatedButton(
style: ElevatedButton.styleFrom(
onPrimary: Colors.white,
primary: Colors.orange,
),
child: Text(t("Activate")),
onPressed: () {
if (Cache().myTrainingPlan != null) {
showCupertinoDialog(
useRootNavigator: true,
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text(t("You have an active Training Plan!")),
content: Column(children: [
Divider(),
Text(
t("Do you want to override it with "),
style: (TextStyle(color: Colors.blue)),
),
Text(
plan.nameTranslations[AppLanguage().appLocal.toString()]! + "?",
style: (TextStyle(color: Colors.blue[800], fontWeight: FontWeight.bold)),
),
]),
actions: [
TextButton(
child: Text(t("No")),
onPressed: () => Navigator.pop(context),
),
TextButton(
child: Text(t("Yes")),
onPressed: () {
Navigator.pop(context);
bloc.add(TrainingPlanActivate(trainingPlanId: plan.trainingPlanId));
},
)
],
));
} else {
bloc.add(TrainingPlanActivate(trainingPlanId: plan.trainingPlanId));
}
},
)
]),
)));
return list;
}
Widget getPlanDetails(TrainingPlan plan, TrainingPlanBloc bloc) {
return SfDataGrid(
headerRowHeight: 30,
rowHeight: 45,
source: TrainingPlanDetailSource(
plan: plan,
menuBloc: bloc.menuBloc,
onWeightTap: () => {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("Calculated Weight"),
descriptions: t("The weight is based on your previuos tests - if they exist."),
description2: t("If it does not exist, your very first exercise will be a test."),
text: "OK",
onTap: () => {
Navigator.of(context).pop(),
},
onCancel: () => {
Navigator.of(context).pop(),
},
);
})
},
onRepeatTap: () => {
print("Reps"),
}),
headerGridLinesVisibility: GridLinesVisibility.both,
gridLinesVisibility: GridLinesVisibility.both,
columns: [
GridTextColumn(
//columnWidthMode: ColumnWidthMode.lastColumnFill,
maximumWidth: 120,
columnName: 'exerciseImage',
label: Container(
color: Colors.green[50],
padding: EdgeInsets.only(left: 8.0),
alignment: Alignment.centerLeft,
child: Text(
'Exercise',
textAlign: TextAlign.start,
overflow: TextOverflow.ellipsis,
))),
GridTextColumn(
visible: false,
columnName: 'exerciseName',
label: Container(
color: Colors.green[50],
padding: EdgeInsets.symmetric(horizontal: 8.0),
alignment: Alignment.centerLeft,
child: Text(
'Exercise',
textAlign: TextAlign.start,
overflow: TextOverflow.ellipsis,
))),
GridTextColumn(
maximumWidth: 40,
columnName: 'set',
label: Container(
color: Colors.green[50],
padding: EdgeInsets.symmetric(horizontal: 2.0),
alignment: Alignment.centerLeft,
child: Text(
'Set',
overflow: TextOverflow.ellipsis,
))),
GridTextColumn(
maximumWidth: 50,
columnName: 'repeats',
label: Container(
color: Colors.green[50],
padding: EdgeInsets.symmetric(horizontal: 2.0),
alignment: Alignment.centerLeft,
child: Text(
'Reps',
overflow: TextOverflow.ellipsis,
))),
GridTextColumn(
maximumWidth: 60,
columnName: 'weight',
label: Container(
color: Colors.green[50],
padding: EdgeInsets.symmetric(horizontal: 2.0),
alignment: Alignment.centerLeft,
child: Text(
'Weight',
overflow: TextOverflow.ellipsis,
))),
GridTextColumn(
maximumWidth: 50,
columnName: 'day',
label: Container(
color: Colors.green[50],
padding: EdgeInsets.symmetric(horizontal: 8.0),
alignment: Alignment.centerLeft,
child: Text(
'Day',
overflow: TextOverflow.ellipsis,
))),
],
);
}
}
class TrainingPlanDetailSource extends DataGridSource {
final TrainingPlan plan;
final MenuBloc menuBloc;
final VoidCallback onWeightTap;
final VoidCallback onRepeatTap;
TrainingPlanDetailSource({
required this.plan,
required this.menuBloc,
required this.onWeightTap,
required this.onRepeatTap,
}) {
if (plan.details != null) {
dataGridRows = plan.details!.map((dataGridRow) {
WorkoutMenuTree? menuTree = menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(dataGridRow.exerciseTypeId);
if (menuTree == null) {
return DataGridRow(cells: []);
}
return DataGridRow(cells: [
DataGridCell<Widget>(
columnName: 'exerciseImage',
value: MenuImage(
imageName: menuTree.imageName,
workoutTreeId: menuTree.id,
radius: 8,
)),
DataGridCell<String>(columnName: 'exerciseName', value: menuTree.name),
DataGridCell<int>(columnName: 'set', value: dataGridRow.set),
DataGridCell<int>(columnName: 'reps', value: dataGridRow.repeats),
DataGridCell<double>(columnName: 'weight', value: dataGridRow.weight),
DataGridCell<String>(columnName: 'day', value: dataGridRow.day),
]);
}).toList();
}
}
List<DataGridRow> dataGridRows = [];
@override
List<DataGridRow> get rows => dataGridRows;
@override
DataGridRowAdapter? buildRow(DataGridRow row) {
if (row.getCells().isEmpty) {
return null;
}
String name = row.getCells()[1].value;
return DataGridRowAdapter(
color: Colors.white60,
cells: row.getCells().map<Widget>((dataGridCell) {
return Container(
alignment: dataGridCell.columnName == "exerciseImage" ? Alignment.centerLeft : Alignment.centerLeft,
padding: EdgeInsets.only(top: 2, bottom: 2, left: 4, right: 4),
child: dataGridCell.columnName == "exerciseImage"
? Stack(alignment: AlignmentDirectional.bottomStart, children: [
dataGridCell.value,
Container(
padding: EdgeInsets.only(left: 4, right: 8, bottom: 3),
child: Text(
name,
maxLines: 3,
overflow: TextOverflow.ellipsis,
style:
GoogleFonts.inter(fontSize: 10, color: Colors.yellow[600], fontWeight: FontWeight.bold, shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black,
),
]),
))
])
: dataGridCell.columnName == "weight" && dataGridCell.value == -1
? GestureDetector(
onTap: () {
onWeightTap();
},
child: Icon(
CustomIcon.question_circle,
color: Colors.indigo[300],
))
: dataGridCell.columnName == "reps" && dataGridCell.value == -1
? GestureDetector(
onTap: () {
onRepeatTap();
},
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());
}
}

View File

@ -0,0 +1,510 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:ezanimation/ezanimation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'package:timeline_tile/timeline_tile.dart';
// ignore: must_be_immutable
class TrainingPlanExecutePage extends StatelessWidget with Trans {
@override
Widget build(BuildContext context) {
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
setContext(context);
return Scaffold(
appBar: AppBarNav(depth: 0),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: BlocConsumer<TrainingPlanBloc, TrainingPlanState>(listener: (context, state) {
if (state is TrainingPlanError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is TrainingPlanFinished) {}
}, builder: (context, state) {
return ModalProgressHUD(
child: getExercises(bloc),
inAsyncCall: state is TrainingPlanLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => bloc.getNext() != null ? executeExercise(bloc, bloc.getNext()!) : Navigator.of(context).pushNamed('home'),
backgroundColor: Colors.orange[800],
icon: Icon(CustomIcon.weight_hanging),
label: Text(
t("Training!"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
),
),
);
}
Widget getExercises(TrainingPlanBloc bloc) {
return CustomScrollView(slivers: [
SliverList(delegate: SliverChildListDelegate(getTiles(bloc))),
]);
}
List<Widget> getTiles(TrainingPlanBloc bloc) {
List<Widget> tiles = [];
tiles.add(getStartTile(bloc));
tiles.addAll(getExerciseTiles(bloc, context));
if (bloc.myPlan != null) tiles.add(getEndTile());
return tiles;
}
Widget getStartTile(TrainingPlanBloc bloc) {
String startText = "";
String explainingText = "";
if (null == bloc.getMyPlan()) {
startText = "No Active Training Plan";
explainingText = "Please select one in the Training menu, or create your custom plan";
} else {
startText = bloc.isStarted() ? "Continue your training" : "Start your training";
explainingText = bloc.getMyPlan()!.name != null ? bloc.getMyPlan()!.name! : "";
}
return TimelineTile(
alignment: TimelineAlign.manual,
lineXY: 0.1,
isFirst: true,
afterLineStyle: const LineStyle(
color: Colors.orange,
thickness: 6,
),
indicatorStyle: IndicatorStyle(
width: 40,
color: Colors.orange,
padding: const EdgeInsets.all(8),
iconStyle: IconStyle(
color: Colors.white,
iconData: Icons.emoji_flags_rounded,
),
),
endChild: Container(
padding: EdgeInsets.only(top: 30),
constraints: const BoxConstraints(
minHeight: 120,
),
color: Colors.transparent,
child: RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
children: [
TextSpan(
text: startText,
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.yellow[400],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
TextSpan(
text: "\n",
style: GoogleFonts.inter(
fontSize: 16,
color: Colors.white,
)),
TextSpan(
text: explainingText,
style: GoogleFonts.inter(
fontSize: 16,
color: Colors.white,
)),
])),
),
);
}
Widget getEndTile() {
return Container(
color: Colors.transparent,
child: TimelineTile(
alignment: TimelineAlign.manual,
lineXY: 0.1,
isLast: true,
beforeLineStyle: const LineStyle(
color: Colors.orange,
thickness: 6,
),
indicatorStyle: IndicatorStyle(
width: 40,
color: Colors.orange,
padding: const EdgeInsets.all(8),
iconStyle: IconStyle(
color: Colors.white,
iconData: Icons.thumb_up,
),
),
endChild: Container(
padding: EdgeInsets.only(top: 50),
constraints: const BoxConstraints(
minHeight: 120,
),
color: Colors.transparent,
child: RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
children: [
TextSpan(
text: "Finish!",
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.yellow[400],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
])),
),
),
);
}
List<Widget> getExerciseTiles(TrainingPlanBloc bloc, BuildContext context) {
List<Widget> tiles = [];
if (bloc.myPlan != null && bloc.myPlan!.details.isNotEmpty) {
bloc.myPlan!.details.forEach((element) {
tiles.add(GestureDetector(
onTap: () => {},
child: ExerciseTile(
bloc: bloc,
detail: element,
)));
});
}
return tiles;
}
void executeExercise(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail) {
CustomerTrainingPlanDetails? next = bloc.getNext();
if (next != null) {
String title = "";
String description = "";
String description2 = "";
if (next.exerciseTypeId != detail.exerciseTypeId) {
title = t("Stop!");
description = t("Please continue with the next exercise in the queue:") + next.exerciseType!.nameTranslation;
description2 = t("Or, you can redifine this exercise queue in the Compact Test menu");
} else {
final HashMap args = HashMap();
args['exerciseType'] = next.exerciseType;
args['customerTrainingPlanDetails'] = detail;
Navigator.of(context).pushNamed('myTrainingPlanExercise', arguments: args);
return;
}
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return DialogCommon(
title: title,
descriptions: description,
description2: description2,
text: "OK",
onTap: () => {Navigator.of(context).pop()},
onCancel: () => {Navigator.of(context).pop()},
);
});
} else {
Navigator.of(context).pushNamed('home');
}
}
}
// ignore: must_be_immutable
class ExerciseTile extends StatefulWidget with Trans {
final TrainingPlanBloc bloc;
final CustomerTrainingPlanDetails detail;
ExerciseTile({required this.bloc, required this.detail});
@override
_ExerciseTileState createState() => _ExerciseTileState();
}
class _ExerciseTileState extends State<ExerciseTile> with Trans {
final EzAnimation animation = EzAnimation(1.0, 30.0, Duration(seconds: 3), reverseCurve: Curves.easeIn);
@override
void initState() {
animation.start();
animation.addStatusListener((status) {
if (status == AnimationStatus.completed) {}
});
super.initState();
}
@override
bool didUpdateWidget(ExerciseTile oldWidget) {
super.didUpdateWidget(oldWidget);
Future.delayed(Duration(milliseconds: 400)).then((value) => animation.start());
return true;
}
Widget getIndicator(ExercisePlanDetailState state) {
CustomerTrainingPlanDetails? next = widget.bloc.getNext();
bool actual = false;
if (next != null) {
if (next.exerciseTypeId == widget.detail.exerciseTypeId) {
actual = true;
}
}
if (state.equalsTo(ExercisePlanDetailState.inProgress)) {
return ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: actual ? Colors.green : Colors.orange,
child: Icon(
CustomIcon.calendar_2,
size: 28,
color: Colors.white,
)));
} else if (state.equalsTo(ExercisePlanDetailState.finished)) {
return ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: Colors.white,
child: Icon(
CustomIcon.ok_circled,
size: 40,
color: Colors.green,
)));
} else {
return Image.asset(
"asset/image/pict_reps_volumen_db.png",
);
}
}
@override
Widget build(BuildContext context) {
setContext(context);
final ExercisePlanDetailState state = widget.detail.state;
final bool done = state.equalsTo(ExercisePlanDetailState.finished);
final String countSerie = widget.detail.set.toString();
final String step = (widget.detail.exercises.length).toString();
String weight = widget.detail.weight!.toStringAsFixed(1);
String restingTime = widget.detail.restingTime == null ? "" : widget.detail.restingTime!.toStringAsFixed(0);
bool isTest = false;
if (widget.detail.weight! == -1) {
weight = t("TEST");
isTest = true;
}
setContext(context);
return Container(
color: Colors.transparent,
child: TimelineTile(
alignment: TimelineAlign.manual,
lineXY: 0.1,
beforeLineStyle: const LineStyle(
color: Color(0xffb4f500),
thickness: 6,
),
afterLineStyle: const LineStyle(
color: Color(0xffb4f500),
thickness: 6,
),
indicatorStyle: IndicatorStyle(
width: 40,
height: 40,
indicator: getIndicator(state),
),
endChild: Container(
padding: EdgeInsets.only(left: 10),
child: Row(children: [
Container(
width: 120,
height: 80,
child: MenuImage(
imageName: widget.bloc.getActualImageName(widget.detail.exerciseType!.exerciseTypeId),
workoutTreeId: widget.bloc.getActualWorkoutTreeId(widget.detail.exerciseType!.exerciseTypeId)!,
)),
SizedBox(
width: 10,
),
Expanded(
child: RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: done ? Colors.grey[400] : Colors.white,
),
children: [
TextSpan(
text: widget.detail.exerciseType!.nameTranslation,
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: done ? Colors.grey[400] : Colors.orange[500],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
widget.detail.exerciseType!.unitQuantityUnit != null
? TextSpan(
text: "\n",
)
: TextSpan(),
widget.detail.exerciseType!.unitQuantityUnit != null
? TextSpan(
text: t(widget.detail.exerciseType!.unitQuantityUnit!) + ": ",
style: GoogleFonts.inter(
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold))
: TextSpan(),
widget.detail.exerciseType!.unitQuantityUnit != null
? TextSpan(
text: weight,
style: GoogleFonts.inter(
fontSize: 12,
))
: TextSpan(),
TextSpan(
text: "\n",
),
TextSpan(
text: t(widget.detail.exerciseType!.unit) + ": ",
style: GoogleFonts.inter(
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)),
TextSpan(
text: widget.detail.repeats!.toString(),
style: GoogleFonts.inter(
fontSize: 12,
)),
TextSpan(
text: "\n",
),
TextSpan(
text: t("Set") + ": ",
style: GoogleFonts.inter(
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)),
TextSpan(
text: step + "/" + countSerie,
style: GoogleFonts.inter(
fontSize: 12,
)),
TextSpan(
text: "\n",
),
TextSpan(
text: t("Resting time") + ": ",
style: GoogleFonts.inter(
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)),
TextSpan(
text: restingTime + " " + t("min(s)"),
style: GoogleFonts.inter(fontSize: 12, color: done ? Colors.grey[100] : Colors.white, fontWeight: FontWeight.bold)),
]),
)),
done
? AnimatedBuilder(
animation: animation,
builder: (context, snapshot) {
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Image.asset(
"asset/image/kupa.png",
width: animation.value,
),
Text("Result", style: GoogleFonts.inter(fontSize: 10, color: Colors.white)),
]);
})
: Offstage(),
isTest
? 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("Why Test?"),
descriptions: t("This is your first exercise after at least 3 weeks."),
description2:
t("The first exercise will be a test. The following sets will be recalculated base on your test."),
description3: t("This is the most optimal way for your development"),
text: "OK",
onTap: () => Navigator.of(context).pop(),
onCancel: () => {
Navigator.of(context).pop(),
},
);
}),
child: Icon(
CustomIcon.question_circle,
color: Colors.yellowAccent[700],
size: 16,
)),
]);
})
: Offstage()
]),
),
),
);
}
}

View File

@ -0,0 +1,221 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/test_set_control/test_set_control_bloc.dart';
import 'package:aitrainer_app/bloc/test_set_execute/test_set_execute_bloc.dart';
import 'package:aitrainer_app/bloc/test_set_new/test_set_new_bloc.dart';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_bar_multiple_exercises.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_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
// ignore: must_be_immutable
class TrainingPlanExercise extends StatelessWidget with Trans {
@override
Widget build(BuildContext context) {
final HashMap args = ModalRoute.of(context)!.settings.arguments as HashMap;
final ExerciseType exerciseType = args['exerciseType'];
final CustomerTrainingPlanDetails detail = args['customerTrainingPlanDetails'];
// ignore: close_sinks
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
setContext(context);
return Scaffold(
appBar: AppBarNav(depth: 1),
body: Container(
height: double.infinity,
width: double.infinity,
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: Cache().userLoggedIn!.sex == "m"
? AssetImage("asset/image/WT_black_background.jpg")
: AssetImage("asset/image/WT_Results_for_female.jpg"),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: BlocConsumer<TrainingPlanBloc, TrainingPlanState>(listener: (context, state) {
if (state is TrainingPlanError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
}
}, builder: (context, state) {
return ModalProgressHUD(
child: getExercises(bloc, detail),
inAsyncCall: state is TrainingPlanLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => {
Navigator.of(context).pop(),
bloc.add(TrainingPlanSaveExercise(detail: detail)),
},
backgroundColor: Colors.orange[800],
icon: Icon(CustomIcon.save),
label: Text(
t("Save"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
),
),
/* bottomNavigationBar: BottomBarMultipleExercises(
//isSet: executeBloc.miniTestSet == true,
exerciseTypeId: exerciseType.exerciseTypeId,
), */
);
}
Widget getExercises(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail) {
final String noTestTextWithWeight = "Please try to execute this exercise with exact weight and repeats what is suggested";
final String noTestTextNoWeight = "Please try to execute this exercise with exact repeats what is suggested";
return ExerciseSave(
exerciseName: detail.exerciseType!.nameTranslation,
exerciseDescription: detail.exerciseType!.descriptionTranslation,
exerciseTask: detail.exerciseType!.unitQuantityUnit != null
? detail.weight == -1
? t("Please take a relative bigger weight and repeat 12-20 times and do your best! MAXIMIZE it!")
: noTestTextWithWeight
: detail.repeats == -1
? t("Please repeat as much times as you can! MAXIMIZE it!")
: noTestTextNoWeight,
unit: detail.exerciseType!.unit,
unitQuantityUnit: detail.exerciseType!.unitQuantityUnit,
hasUnitQuantity: detail.exerciseType!.unitQuantityUnit != null,
weight: detail.weight == -1 ? 30 : detail.weight,
repeats: detail.repeats == -1 ? 12 : detail.repeats,
onUnitQuantityChanged: (value) => bloc.add(TrainingPlanWeightChange(weight: value, detail: detail)),
onQuantityChanged: (value) => bloc.add(TrainingPlanRepeatsChange(repeats: value.toInt(), detail: detail)),
exerciseTypeId: detail.exerciseType!.exerciseTypeId,
);
}
Widget getExerciseForm(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail) {
return Container(
padding: const EdgeInsets.only(top: 10, left: 25, right: 25),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Text(
detail.exerciseType!.nameTranslation,
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
fontSize: 24,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
overflow: TextOverflow.fade,
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
),
Divider(
color: Colors.transparent,
),
Divider(),
detail.weight != -1 ? numberPickForm(bloc, detail) : numberPickForm(bloc, detail),
],
)));
}
Widget numberPickForm(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail) {
final String strTimes = detail.repeats!.toStringAsFixed(1); // : "maximum";
List<Widget> listWidgets = [
GestureDetector(
onTap: () => {},
child: RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Colors.yellow[300],
),
children: [
TextSpan(text: t("Please repeat with ")),
TextSpan(
text: detail.weight!.toStringAsFixed(1) + " " + detail.exerciseType!.unitQuantityUnit!,
style: GoogleFonts.inter(
decoration: TextDecoration.underline,
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.yellow[100],
),
),
TextSpan(text: t("hu_with") + " "),
TextSpan(
text: strTimes + " ",
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.yellow[100],
)),
TextSpan(
text: t(
"times!",
)),
]),
)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
NumberPickerWidget(
minValue: 0,
maxValue: 200,
initalValue: detail.repeats!,
unit: t("reps"),
color: Colors.yellow[50]!,
onChange: (value) => {}),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(0),
primary: Colors.white,
onSurface: Colors.blueAccent,
),
onPressed: () => {},
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_c.png', width: 140, height: 60),
Text(
t("Save"),
style: TextStyle(fontSize: 16, color: Colors.white),
),
],
)),
],
),
];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: listWidgets,
);
}
}

View File

@ -90,7 +90,7 @@ class _NawDrawerWidget extends State<BottomNavigator> with Trans, Logging {
case 2: case 2:
Navigator.of(context).pop(); Navigator.of(context).pop();
Track().track(TrackingEvent.my_exerciseplan); Track().track(TrackingEvent.my_exerciseplan);
Navigator.of(context).pushNamed('myExercisePlan'); Navigator.of(context).pushNamed('myTrainingPlans');
break; break;
case 3: case 3:

View File

@ -12,8 +12,8 @@ import 'dialog_html.dart';
// ignore: must_be_immutable // ignore: must_be_immutable
class ExerciseSave extends StatefulWidget { class ExerciseSave extends StatefulWidget {
final ValueChanged<dynamic> onQuantityChanged; final ValueChanged<double> onQuantityChanged;
final ValueChanged<dynamic>? onUnitQuantityChanged; final ValueChanged<double>? onUnitQuantityChanged;
final VoidCallback? onSubmit; final VoidCallback? onSubmit;
final bool hasUnitQuantity; final bool hasUnitQuantity;
final String? unitQuantityUnit; final String? unitQuantityUnit;
@ -22,18 +22,23 @@ class ExerciseSave extends StatefulWidget {
final String exerciseDescription; final String exerciseDescription;
final String exerciseTask; final String exerciseTask;
final int exerciseTypeId; final int exerciseTypeId;
final double? weight;
final int? repeats;
ExerciseSave( ExerciseSave({
{required this.onQuantityChanged, required this.onQuantityChanged,
this.onUnitQuantityChanged, this.onUnitQuantityChanged,
this.onSubmit, this.onSubmit,
required this.hasUnitQuantity, required this.hasUnitQuantity,
this.unitQuantityUnit, this.unitQuantityUnit,
required this.unit, required this.unit,
required this.exerciseName, required this.exerciseName,
required this.exerciseDescription, required this.exerciseDescription,
required this.exerciseTask, required this.exerciseTask,
required this.exerciseTypeId}); required this.exerciseTypeId,
this.weight,
this.repeats,
});
@override @override
_ExerciseSaveState createState() => _ExerciseSaveState(); _ExerciseSaveState createState() => _ExerciseSaveState();
} }
@ -53,11 +58,15 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
return getExerciseWidget(); return getExerciseWidget();
} }
//@override @override
initState() { initState() {
super.initState(); super.initState();
_controller1.text = "30"; _controller1.text = widget.weight == null
_controller2.text = "12"; ? "30"
: widget.weight! % widget.weight!.round() == 0
? widget.weight!.toStringAsFixed(0)
: widget.weight!.toStringAsFixed(1);
_controller2.text = widget.repeats == null ? "12" : widget.repeats!.toStringAsFixed(0);
_nodeText1.addListener(() { _nodeText1.addListener(() {
if (_nodeText1.hasFocus) { if (_nodeText1.hasFocus) {
_controller1.selection = TextSelection(baseOffset: 0, extentOffset: _controller1.text.length); _controller1.selection = TextSelection(baseOffset: 0, extentOffset: _controller1.text.length);
@ -69,7 +78,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
} }
}); });
if (widget.unit == "second") { if (widget.unit == "second") {
stopWatchTimer.rawTime.listen((value) => widget.onQuantityChanged((value / 1000).toString())); stopWatchTimer.rawTime.listen((value) => widget.onQuantityChanged((value / 1000)));
} }
} }
@ -190,6 +199,18 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
fontSize: 14, fontSize: 14,
color: Colors.orange, color: Colors.orange,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
), ),
maxLines: 3, maxLines: 3,
textAlign: TextAlign.center, textAlign: TextAlign.center,
@ -258,7 +279,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
onChanged: (value) => { onChanged: (value) => {
value = value.replaceFirst(",", "."), value = value.replaceFirst(",", "."),
value = value.replaceAll(RegExp(r'[^0-9.]'), ""), value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
widget.onUnitQuantityChanged!(value), widget.onUnitQuantityChanged!(double.parse(value)),
}), }),
])); ]));
} }
@ -273,7 +294,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
//padding: const EdgeInsets.only(bottom: 0), //padding: const EdgeInsets.only(bottom: 0),
child: StreamBuilder<int>( child: StreamBuilder<int>(
stream: stopWatchTimer.rawTime, stream: stopWatchTimer.rawTime,
initialData: stopWatchTimer.rawTime.valueWrapper?.value, initialData: stopWatchTimer.rawTime.value,
builder: (context, snap) { builder: (context, snap) {
final value = snap.data; final value = snap.data;
final displayTime = StopWatchTimer.getDisplayTime(value!, hours: false); final displayTime = StopWatchTimer.getDisplayTime(value!, hours: false);
@ -344,7 +365,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
Divider(), Divider(),
Divider(), Divider(),
Text(t("Or type the time manually:"), style: GoogleFonts.inter(color: Colors.white)), Text(t("Or type the time manually:"), style: GoogleFonts.inter(color: Colors.white)),
TimePickerWidget(onChange: (value) => widget.onQuantityChanged((value).toString())) TimePickerWidget(onChange: (value) => widget.onQuantityChanged((value)))
]); ]);
} }
Widget row = Container( Widget row = Container(
@ -369,7 +390,9 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.orange[200]), style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.orange[200]),
onChanged: (value) { onChanged: (value) {
widget.onQuantityChanged(value); value = value.replaceFirst(",", ".");
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
widget.onQuantityChanged(double.parse(value));
}, },
), ),
])); ]));

View File

@ -22,6 +22,7 @@ class ImageButton extends StatelessWidget {
final bool? isLocked; final bool? isLocked;
bool? isMarked; bool? isMarked;
int? buttonIndex; int? buttonIndex;
Color? textColor;
ImageButton( ImageButton(
{required this.text, {required this.text,
@ -37,11 +38,13 @@ class ImageButton extends StatelessWidget {
this.onTap, this.onTap,
this.buttonIndex, this.buttonIndex,
this.isMarked, this.isMarked,
required this.isLocked}) { required this.isLocked,
this.textColor}) {
width = width ?? 180; width = width ?? 180;
height = height ?? 180; height = height ?? 180;
isMarked = isMarked ?? false; isMarked = isMarked ?? false;
isShape = isShape ?? false; isShape = isShape ?? false;
textColor = textColor ?? Colors.white;
style = style ?? style = style ??
GoogleFonts.archivoBlack( GoogleFonts.archivoBlack(
fontSize: 14, fontSize: 14,
@ -54,10 +57,9 @@ class ImageButton extends StatelessWidget {
top = height! - (style!.fontSize! - 5) * text.length - 2 * left < 0 top = height! - (style!.fontSize! - 5) * text.length - 2 * left < 0
? height! - 2 * style!.fontSize! - 22 ? height! - 2 * style!.fontSize! - 22
: height! - style!.fontSize! - 37; : height! - style!.fontSize! - 37;
//print("Top: " + top.toStringAsFixed(0) + " length: " + ((style.fontSize - 5) * text.length).toString());
} }
final double width = MediaQuery.of(context).size.width; final double width = MediaQuery.of(context).size.width;
//print("Mediawidth: " + width.toStringAsFixed(0));
return Stack(alignment: AlignmentDirectional.bottomStart, children: [ return Stack(alignment: AlignmentDirectional.bottomStart, children: [
TextButton( TextButton(
style: TextButton.styleFrom( style: TextButton.styleFrom(
@ -93,7 +95,7 @@ class ImageButton extends StatelessWidget {
maxLines: 2, maxLines: 2,
style: GoogleFonts.archivoBlack( style: GoogleFonts.archivoBlack(
fontSize: 16, fontSize: 16,
color: Colors.white, color: textColor,
shadows: <Shadow>[ shadows: <Shadow>[
Shadow( Shadow(
offset: Offset(2.0, 2.0), offset: Offset(2.0, 2.0),

View File

@ -7,7 +7,12 @@ import 'package:aitrainer_app/library/transparent_image.dart';
class MenuImage extends StatelessWidget { class MenuImage extends StatelessWidget {
final int? workoutTreeId; final int? workoutTreeId;
final String imageName; final String imageName;
const MenuImage({required this.workoutTreeId, required this.imageName}); double radius;
MenuImage({
required this.workoutTreeId,
required this.imageName,
this.radius = 24,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -31,7 +36,7 @@ class MenuImage extends StatelessWidget {
if (imageName.contains("https")) { if (imageName.contains("https")) {
if (!wt.ImageCache().existsImageInMap(workoutTreeId!, imageName)) { if (!wt.ImageCache().existsImageInMap(workoutTreeId!, imageName)) {
widget = ClipRRect( widget = ClipRRect(
borderRadius: BorderRadius.circular(24.0), borderRadius: BorderRadius.circular(radius),
child: Container( child: Container(
color: Colors.transparent, color: Colors.transparent,
child: FadeInImage( child: FadeInImage(
@ -43,7 +48,7 @@ class MenuImage extends StatelessWidget {
} }
} else { } else {
widget = ClipRRect( widget = ClipRRect(
borderRadius: BorderRadius.circular(24.0), borderRadius: BorderRadius.circular(radius),
child: Container( child: Container(
color: Colors.transparent, color: Colors.transparent,
child: Image.asset(imageName), child: Image.asset(imageName),

View File

@ -1,5 +1,6 @@
import 'dart:collection'; import 'dart:collection';
import 'dart:ui'; import 'dart:ui';
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/model/exercise_ability.dart'; import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart'; import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
@ -47,7 +48,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
@override @override
void initState() { void initState() {
if (activeExercisePlan) { if (activeExercisePlan || Cache().myTrainingPlan != null) {
animation.start(); animation.start();
animation.addStatusListener((status) { animation.addStatusListener((status) {
if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) { if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) {
@ -313,6 +314,46 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
} }
}, },
), ),
Cache().myTrainingPlan != null
? GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("You have an active Training Plan"),
descriptions: Cache().myTrainingPlan!.name != null ? Cache().myTrainingPlan!.name! : "",
description2: t("Press OK to continue"),
text: "OK",
onTap: () {
Navigator.of(context).pop();
if (Cache().myTrainingPlan != null) {
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
bloc.myPlan = Cache().myTrainingPlan;
Navigator.of(context).pushNamed("myTrainingPlanExecute");
}
},
onCancel: () => {
Navigator.of(context).pop(),
},
);
}),
child: AnimatedBuilder(
animation: animation,
builder: (context, snapshot) {
return Center(
child: Container(
width: animation.value,
height: animation.value,
child: Image.asset("asset/image/pict_hypertrophy.png"),
),
);
}))
: Offstage(),
activeExercisePlan
? SizedBox(
width: 10,
)
: Offstage(),
Cache().activeExercisePlan != null Cache().activeExercisePlan != null
? GestureDetector( ? GestureDetector(
onTap: () => showDialog( onTap: () => showDialog(

View File

@ -56,7 +56,7 @@ packages:
name: badges name: badges
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.0-nullsafety.1" version: "2.0.1"
bloc: bloc:
dependency: transitive dependency: transitive
description: description:
@ -231,7 +231,7 @@ packages:
name: coverage name: coverage
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.15.2" version: "1.0.2"
crypto: crypto:
dependency: "direct main" dependency: "direct main"
description: description:
@ -239,13 +239,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.0" version: "3.0.0"
css_colors:
dependency: transitive
description:
name: css_colors
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
csslib: csslib:
dependency: transitive dependency: transitive
description: description:
@ -280,7 +273,7 @@ packages:
name: equatable name: equatable
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.0" version: "2.0.2"
ezanimation: ezanimation:
dependency: "direct main" dependency: "direct main"
description: description:
@ -322,98 +315,98 @@ packages:
name: firebase_analytics name: firebase_analytics
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "8.0.2" version: "8.1.0"
firebase_analytics_platform_interface: firebase_analytics_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: firebase_analytics_platform_interface name: firebase_analytics_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.0" version: "2.0.1"
firebase_analytics_web: firebase_analytics_web:
dependency: transitive dependency: transitive
description: description:
name: firebase_analytics_web name: firebase_analytics_web
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.0" version: "0.3.0+1"
firebase_auth: firebase_auth:
dependency: "direct main" dependency: "direct main"
description: description:
name: firebase_auth name: firebase_auth
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.2" version: "1.2.0"
firebase_auth_platform_interface: firebase_auth_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: firebase_auth_platform_interface name: firebase_auth_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.2.0" version: "4.2.3"
firebase_auth_web: firebase_auth_web:
dependency: transitive dependency: transitive
description: description:
name: firebase_auth_web name: firebase_auth_web
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.3"
firebase_core: firebase_core:
dependency: "direct main" dependency: "direct main"
description: description:
name: firebase_core name: firebase_core
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.2.0"
firebase_core_platform_interface: firebase_core_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: firebase_core_platform_interface name: firebase_core_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.0.0" version: "4.0.1"
firebase_core_web: firebase_core_web:
dependency: transitive dependency: transitive
description: description:
name: firebase_core_web name: firebase_core_web
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.2" version: "1.1.0"
firebase_messaging: firebase_messaging:
dependency: "direct main" dependency: "direct main"
description: description:
name: firebase_messaging name: firebase_messaging
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "9.1.3" version: "10.0.0"
firebase_messaging_platform_interface: firebase_messaging_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: firebase_messaging_platform_interface name: firebase_messaging_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.3" version: "3.0.0"
firebase_messaging_web: firebase_messaging_web:
dependency: transitive dependency: transitive
description: description:
name: firebase_messaging_web name: firebase_messaging_web
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.6" version: "2.0.0"
firebase_remote_config: firebase_remote_config:
dependency: "direct main" dependency: "direct main"
description: description:
name: firebase_remote_config name: firebase_remote_config
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.10.0-dev.2" version: "0.10.0"
firebase_remote_config_platform_interface: firebase_remote_config_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: firebase_remote_config_platform_interface name: firebase_remote_config_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.0-dev.2" version: "0.3.0"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
@ -427,7 +420,7 @@ packages:
name: fl_chart name: fl_chart
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.30.0" version: "0.36.1"
flurry: flurry:
dependency: "direct main" dependency: "direct main"
description: description:
@ -460,21 +453,21 @@ packages:
name: flutter_facebook_auth name: flutter_facebook_auth
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.3.2+2" version: "3.4.0"
flutter_facebook_auth_platform_interface: flutter_facebook_auth_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: flutter_facebook_auth_platform_interface name: flutter_facebook_auth_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.1" version: "2.6.0"
flutter_facebook_auth_web: flutter_facebook_auth_web:
dependency: transitive dependency: transitive
description: description:
name: flutter_facebook_auth_web name: flutter_facebook_auth_web
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.1+1" version: "2.6.0"
flutter_fadein: flutter_fadein:
dependency: "direct main" dependency: "direct main"
description: description:
@ -488,7 +481,7 @@ packages:
name: flutter_html name: flutter_html
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.0-nullsafety.0" version: "2.0.0"
flutter_launcher_icons: flutter_launcher_icons:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -509,7 +502,7 @@ packages:
name: flutter_local_notifications name: flutter_local_notifications
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "5.0.0" version: "5.0.0+4"
flutter_local_notifications_platform_interface: flutter_local_notifications_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -522,20 +515,27 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_math_fork:
dependency: transitive
description:
name: flutter_math_fork
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3"
flutter_secure_storage: flutter_secure_storage:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_secure_storage name: flutter_secure_storage
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.1.0" version: "4.2.0"
flutter_svg: flutter_svg:
dependency: transitive dependency: transitive
description: description:
name: flutter_svg name: flutter_svg
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.21.0-nullsafety.0" version: "0.22.0"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -566,14 +566,14 @@ packages:
name: google_fonts name: google_fonts
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.0" version: "2.1.0"
google_sign_in: google_sign_in:
dependency: "direct main" dependency: "direct main"
description: description:
name: google_sign_in name: google_sign_in
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "5.0.1" version: "5.0.3"
google_sign_in_platform_interface: google_sign_in_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -615,7 +615,7 @@ packages:
name: http_multi_server name: http_multi_server
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.2.0" version: "3.0.1"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@ -650,7 +650,7 @@ packages:
name: io name: io
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.4" version: "1.0.0"
js: js:
dependency: transitive dependency: transitive
description: description:
@ -699,7 +699,7 @@ packages:
name: mime name: mime
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.9.7" version: "1.0.0"
mockito: mockito:
dependency: "direct main" dependency: "direct main"
description: description:
@ -804,14 +804,14 @@ packages:
name: path_drawing name: path_drawing
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.5.0-nullsafety.0" version: "0.5.1"
path_parsing: path_parsing:
dependency: transitive dependency: transitive
description: description:
name: path_parsing name: path_parsing
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.0-nullsafety.0" version: "0.2.1"
path_provider: path_provider:
dependency: transitive dependency: transitive
description: description:
@ -923,7 +923,7 @@ packages:
name: purchases_flutter name: purchases_flutter
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.2.1" version: "3.2.2"
quiver: quiver:
dependency: transitive dependency: transitive
description: description:
@ -958,21 +958,21 @@ packages:
name: rxdart name: rxdart
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.26.0" version: "0.27.0"
sentry: sentry:
dependency: transitive dependency: transitive
description: description:
name: sentry name: sentry
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "5.0.0" version: "5.1.0-beta.1"
sentry_flutter: sentry_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
name: sentry_flutter name: sentry_flutter
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "5.0.0" version: "5.1.0-beta.1"
shared_preferences: shared_preferences:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -1028,21 +1028,21 @@ packages:
name: shelf_packages_handler name: shelf_packages_handler
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.1" version: "3.0.0"
shelf_static: shelf_static:
dependency: transitive dependency: transitive
description: description:
name: shelf_static name: shelf_static
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.9+2" version: "1.0.0"
shelf_web_socket: shelf_web_socket:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.4+1" version: "1.0.1"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -1110,7 +1110,7 @@ packages:
name: stop_watch_timer name: stop_watch_timer
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.2.0+1"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
@ -1138,7 +1138,14 @@ packages:
name: syncfusion_flutter_core name: syncfusion_flutter_core
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "19.1.63" version: "19.1.64"
syncfusion_flutter_datagrid:
dependency: "direct main"
description:
name: syncfusion_flutter_datagrid
url: "https://pub.dartlang.org"
source: hosted
version: "19.1.64-beta"
syncfusion_flutter_gauges: syncfusion_flutter_gauges:
dependency: "direct main" dependency: "direct main"
description: description:
@ -1194,7 +1201,7 @@ packages:
name: timezone name: timezone
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.7.0-nullsafety.0" version: "0.7.0"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -1209,6 +1216,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.9" version: "0.1.9"
tuple:
dependency: transitive
description:
name: tuple
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -1278,7 +1292,7 @@ packages:
name: video_player name: video_player
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0" version: "2.1.1"
video_player_platform_interface: video_player_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -1299,7 +1313,7 @@ packages:
name: vm_service name: vm_service
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "5.5.0" version: "6.2.0"
wakelock: wakelock:
dependency: "direct main" dependency: "direct main"
description: description:
@ -1341,7 +1355,7 @@ packages:
name: web_socket_channel name: web_socket_channel
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "2.1.0"
webkit_inspection_protocol: webkit_inspection_protocol:
dependency: transitive dependency: transitive
description: description:
@ -1355,7 +1369,7 @@ packages:
name: webview_flutter name: webview_flutter
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.2" version: "2.0.7"
win32: win32:
dependency: transitive dependency: transitive
description: description:

View File

@ -25,28 +25,28 @@ dependencies:
sdk: flutter sdk: flutter
cupertino_icons: ^1.0.0 cupertino_icons: ^1.0.0
google_fonts: ^2.0.0 google_fonts: ^2.1.0
devicelocale: ^0.4.1 devicelocale: ^0.4.1
sentry_flutter: ^5.0.0 sentry_flutter: ^5.1.0-beta.1
flutter_bloc: ^7.0.0 flutter_bloc: ^7.0.0
equatable: ^2.0.0 equatable: ^2.0.2
spider_chart: ^0.1.5 spider_chart: ^0.1.5
rainbow_color: ^2.0.1 rainbow_color: ^2.0.1
percent_indicator: ^ 3.3.0-nullsafety.1 percent_indicator: ^ 3.3.0-nullsafety.1
fl_chart: ^0.30.0 fl_chart: ^0.36.1
infinite_listview: ^1.1.0 infinite_listview: ^1.1.0
toggle_switch: ^0.1.9 toggle_switch: ^0.1.9
keyboard_actions: ^3.4.0 keyboard_actions: ^3.4.0
badges: ^ 2.0.0-nullsafety.1 badges: ^ 2.0.1
#health: ^3.0.0 #health: ^3.0.0
stop_watch_timer: ^1.0.0 stop_watch_timer: ^1.2.0+1
#location: ^3.2.4 #location: ^3.2.4
modal_progress_hud_nsn: ^0.1.0-nullsafety-1 modal_progress_hud_nsn: ^0.1.0-nullsafety-1
flutter_html: ^2.0.0-nullsafety.0 flutter_html: ^2.0.0
wakelock: ^ 0.4.0 wakelock: ^ 0.4.0
timeline_tile: ^2.0.0 timeline_tile: ^2.0.0
purchases_flutter: ^3.2.1 purchases_flutter: ^3.2.2
package_info: ^2.0.0 package_info: ^2.0.0
ezanimation: ^0.5.0 ezanimation: ^0.5.0
flutter_fadein: ^2.0.0 flutter_fadein: ^2.0.0
@ -59,18 +59,20 @@ dependencies:
#super_tooltip: ^1.0.1 #super_tooltip: ^1.0.1
url_launcher: ^6.0.3 url_launcher: ^6.0.3
firebase_core: ^1.1.0 firebase_core: ^1.2.0
firebase_analytics: ^8.0.2 firebase_analytics: ^8.1.0
firebase_messaging: ^9.1.3 firebase_messaging: ^10.0.0
flutter_local_notifications: ^5.0.0 flutter_local_notifications: ^5.0.0
firebase_auth: ^1.1.2 firebase_auth: ^1.2.0
firebase_remote_config: ^0.10.0-dev.2 firebase_remote_config: ^0.10.0
syncfusion_flutter_gauges: ^19.1.63 syncfusion_flutter_gauges: ^19.1.63
syncfusion_flutter_datagrid: ^19.1.63
flutter_facebook_auth: ^3.3.2 flutter_facebook_auth: ^3.4.0
google_sign_in: ^5.0.1 google_sign_in: ^5.0.3
apple_sign_in: ^0.1.0 apple_sign_in: ^0.1.0
#sign_in_with_apple: ^3.0.0
#smartlook: ^1.0.7 #smartlook: ^1.0.7
flurry: ^0.0.4 flurry: ^0.0.4
@ -80,7 +82,7 @@ dependencies:
mockito: ^5.0.3 mockito: ^5.0.3
sqflite: ^2.0.0+3 sqflite: ^2.0.0+3
flutter_secure_storage: ^4.1.0 flutter_secure_storage: ^4.2.0
#social_share: ^2.1.1 #social_share: ^2.1.1
flutter_localizations: flutter_localizations:
@ -383,6 +385,19 @@ flutter:
- asset/menu/test_center.jpg - asset/menu/test_center.jpg
- asset/menu/test_on_machines.jpg - asset/menu/test_on_machines.jpg
- asset/menu/thigh_adductor.jpg - asset/menu/thigh_adductor.jpg
- asset/menu/training_plans_menu.jpg
- asset/menu/training_plans_woman.jpg
- asset/menu/training_plans_home.jpg
- asset/menu/training_plans_celebrities.jpg
- asset/menu/training_plans_beginner.jpg
- asset/menu/training_plans_advanced.jpg
- asset/menu/training_plans_strength_gain.jpg
- asset/menu/training_plans_q_woman.jpg
- asset/menu/training_plans_q_home.jpg
- asset/menu/training_plans_q_celebrities.jpg
- asset/menu/training_plans_q_beginner.jpg
- asset/menu/training_plans_q_advanced.jpg
- asset/menu/training_plans_q_gain_strength.jpg
- asset/menu/triceps_extension_on_cable_with_rope.jpg - asset/menu/triceps_extension_on_cable_with_rope.jpg
- asset/menu/triceps_kickback.jpg - asset/menu/triceps_kickback.jpg
- asset/menu/triceps_pushdown.jpg - asset/menu/triceps_pushdown.jpg