WT 1.1.8+1 TrainingPlan
BIN
asset/menu/training_plans_advanced.jpg
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
asset/menu/training_plans_beginner.jpg
Normal file
After Width: | Height: | Size: 87 KiB |
BIN
asset/menu/training_plans_celebrities.jpg
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
asset/menu/training_plans_home.jpg
Normal file
After Width: | Height: | Size: 87 KiB |
BIN
asset/menu/training_plans_menu.jpg
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
asset/menu/training_plans_q_advanced.jpg
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
asset/menu/training_plans_q_beginner.jpg
Normal file
After Width: | Height: | Size: 99 KiB |
BIN
asset/menu/training_plans_q_celebrities.jpg
Normal file
After Width: | Height: | Size: 229 KiB |
BIN
asset/menu/training_plans_q_gain_strength.jpg
Normal file
After Width: | Height: | Size: 137 KiB |
BIN
asset/menu/training_plans_q_home.jpg
Normal file
After Width: | Height: | Size: 122 KiB |
BIN
asset/menu/training_plans_q_woman.jpg
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
asset/menu/training_plans_strength_gain.jpg
Normal file
After Width: | Height: | Size: 93 KiB |
BIN
asset/menu/training_plans_woman.jpg
Normal file
After Width: | Height: | Size: 76 KiB |
11
i18n/en.json
@ -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.",
|
||||
"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"
|
||||
|
||||
}
|
11
i18n/hu.json
@ -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.",
|
||||
"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"
|
||||
}
|
280
ios/Podfile.lock
@ -18,112 +18,106 @@ PODS:
|
||||
- FBSDKLoginKit/Login (= 9.1.0)
|
||||
- FBSDKLoginKit/Login (9.1.0):
|
||||
- FBSDKCoreKit (~> 9.1.0)
|
||||
- Firebase/Analytics (7.11.0):
|
||||
- Firebase/Analytics (8.0.0):
|
||||
- Firebase/Core
|
||||
- Firebase/Auth (7.11.0):
|
||||
- Firebase/Auth (8.0.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAuth (~> 7.11.0)
|
||||
- Firebase/Core (7.11.0):
|
||||
- FirebaseAuth (~> 8.0.0)
|
||||
- Firebase/Core (8.0.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAnalytics (~> 7.11.0)
|
||||
- Firebase/CoreOnly (7.11.0):
|
||||
- FirebaseCore (= 7.11.0)
|
||||
- Firebase/Messaging (7.11.0):
|
||||
- FirebaseAnalytics (~> 8.0.0)
|
||||
- Firebase/CoreOnly (8.0.0):
|
||||
- FirebaseCore (= 8.0.0)
|
||||
- Firebase/Messaging (8.0.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 7.11.0)
|
||||
- Firebase/RemoteConfig (7.11.0):
|
||||
- FirebaseMessaging (~> 8.0.0)
|
||||
- Firebase/RemoteConfig (8.0.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseRemoteConfig (~> 7.11.0)
|
||||
- firebase_analytics (8.0.2):
|
||||
- Firebase/Analytics (= 7.11.0)
|
||||
- FirebaseRemoteConfig (~> 8.0.0)
|
||||
- firebase_analytics (8.1.0):
|
||||
- Firebase/Analytics (= 8.0.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_auth (1.1.2):
|
||||
- Firebase/Auth (= 7.11.0)
|
||||
- firebase_auth (1.2.0):
|
||||
- Firebase/Auth (= 8.0.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_core (1.1.0):
|
||||
- Firebase/CoreOnly (= 7.11.0)
|
||||
- firebase_core (1.2.0):
|
||||
- Firebase/CoreOnly (= 8.0.0)
|
||||
- Flutter
|
||||
- firebase_messaging (9.1.3):
|
||||
- Firebase/Messaging (= 7.11.0)
|
||||
- firebase_messaging (10.0.0):
|
||||
- Firebase/Messaging (= 8.0.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- firebase_remote_config (0.10.0-dev.2):
|
||||
- Firebase/RemoteConfig (= 7.11.0)
|
||||
- firebase_remote_config (0.10.0):
|
||||
- Firebase/RemoteConfig (= 8.0.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseABTesting (7.11.0):
|
||||
- FirebaseCore (~> 7.0)
|
||||
- FirebaseAnalytics (7.11.0):
|
||||
- FirebaseAnalytics/AdIdSupport (= 7.11.0)
|
||||
- FirebaseCore (~> 7.0)
|
||||
- FirebaseInstallations (~> 7.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.0)
|
||||
- GoogleUtilities/Network (~> 7.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.0)"
|
||||
- FirebaseABTesting (8.0.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseAnalytics (8.0.0):
|
||||
- FirebaseAnalytics/AdIdSupport (= 8.0.0)
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||
- GoogleUtilities/Network (~> 7.4)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseAnalytics/AdIdSupport (7.11.0):
|
||||
- FirebaseAnalytics/Base (= 7.11.0)
|
||||
- FirebaseCore (~> 7.0)
|
||||
- FirebaseInstallations (~> 7.0)
|
||||
- GoogleAppMeasurement/AdIdSupport (= 7.11.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.0)
|
||||
- GoogleUtilities/Network (~> 7.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.0)"
|
||||
- FirebaseAnalytics/AdIdSupport (8.0.0):
|
||||
- FirebaseAnalytics/Base (= 8.0.0)
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleAppMeasurement (= 8.0.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||
- GoogleUtilities/Network (~> 7.4)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseAnalytics/Base (7.11.0):
|
||||
- FirebaseCore (~> 7.0)
|
||||
- FirebaseInstallations (~> 7.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.0)
|
||||
- GoogleUtilities/Network (~> 7.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.0)"
|
||||
- FirebaseAnalytics/Base (8.0.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||
- GoogleUtilities/Network (~> 7.4)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseAuth (7.11.0):
|
||||
- FirebaseCore (~> 7.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
||||
- GoogleUtilities/Environment (~> 7.0)
|
||||
- GTMSessionFetcher/Core (~> 1.4)
|
||||
- FirebaseCore (7.11.0):
|
||||
- FirebaseCoreDiagnostics (~> 7.4)
|
||||
- GoogleUtilities/Environment (~> 7.0)
|
||||
- GoogleUtilities/Logger (~> 7.0)
|
||||
- FirebaseCoreDiagnostics (7.11.0):
|
||||
- GoogleDataTransport (~> 8.4)
|
||||
- GoogleUtilities/Environment (~> 7.0)
|
||||
- GoogleUtilities/Logger (~> 7.0)
|
||||
- FirebaseAuth (8.0.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||
- GoogleUtilities/Environment (~> 7.4)
|
||||
- GTMSessionFetcher/Core (~> 1.5)
|
||||
- FirebaseCore (8.0.0):
|
||||
- FirebaseCoreDiagnostics (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.4)
|
||||
- GoogleUtilities/Logger (~> 7.4)
|
||||
- FirebaseCoreDiagnostics (8.0.0):
|
||||
- GoogleDataTransport (~> 9.0)
|
||||
- GoogleUtilities/Environment (~> 7.4)
|
||||
- GoogleUtilities/Logger (~> 7.4)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseInstallations (7.11.0):
|
||||
- FirebaseCore (~> 7.0)
|
||||
- GoogleUtilities/Environment (~> 7.0)
|
||||
- GoogleUtilities/UserDefaults (~> 7.0)
|
||||
- FirebaseInstallations (8.0.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.4)
|
||||
- GoogleUtilities/UserDefaults (~> 7.4)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- FirebaseInstanceID (7.11.0):
|
||||
- FirebaseCore (~> 7.0)
|
||||
- FirebaseInstallations (~> 7.0)
|
||||
- GoogleUtilities/Environment (~> 7.0)
|
||||
- GoogleUtilities/UserDefaults (~> 7.0)
|
||||
- FirebaseMessaging (7.11.0):
|
||||
- FirebaseCore (~> 7.0)
|
||||
- FirebaseInstallations (~> 7.0)
|
||||
- FirebaseInstanceID (~> 7.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
||||
- GoogleUtilities/Environment (~> 7.0)
|
||||
- GoogleUtilities/Reachability (~> 7.0)
|
||||
- GoogleUtilities/UserDefaults (~> 7.0)
|
||||
- FirebaseRemoteConfig (7.11.0):
|
||||
- FirebaseABTesting (~> 7.0)
|
||||
- FirebaseCore (~> 7.0)
|
||||
- FirebaseInstallations (~> 7.0)
|
||||
- GoogleUtilities/Environment (~> 7.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.0)"
|
||||
- FirebaseMessaging (8.0.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||
- GoogleUtilities/Environment (~> 7.4)
|
||||
- GoogleUtilities/Reachability (~> 7.4)
|
||||
- GoogleUtilities/UserDefaults (~> 7.4)
|
||||
- FirebaseRemoteConfig (8.0.0):
|
||||
- FirebaseABTesting (~> 8.0)
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.4)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||
- flurry (0.0.4):
|
||||
- Flurry-iOS-SDK/FlurrySDK
|
||||
- Flutter
|
||||
- Flurry-iOS-SDK/FlurrySDK (11.2.0)
|
||||
- Flurry-iOS-SDK/FlurrySDK (11.2.1)
|
||||
- Flutter (1.0.0)
|
||||
- flutter_app_badger (0.0.1):
|
||||
- Flutter
|
||||
@ -144,13 +138,20 @@ PODS:
|
||||
- google_sign_in (0.0.1):
|
||||
- Flutter
|
||||
- GoogleSignIn (~> 5.0)
|
||||
- GoogleAppMeasurement/AdIdSupport (7.11.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.0)
|
||||
- GoogleUtilities/Network (~> 7.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.0)"
|
||||
- GoogleAppMeasurement (8.0.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 (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)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- PromisesObjC (~> 1.2)
|
||||
@ -158,33 +159,29 @@ PODS:
|
||||
- AppAuth (~> 1.2)
|
||||
- GTMAppAuth (~> 1.0)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (7.4.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (7.4.1):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (7.4.0):
|
||||
- GoogleUtilities/Environment (7.4.1):
|
||||
- PromisesObjC (~> 1.2)
|
||||
- GoogleUtilities/Logger (7.4.0):
|
||||
- GoogleUtilities/Logger (7.4.1):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/MethodSwizzler (7.4.0):
|
||||
- GoogleUtilities/MethodSwizzler (7.4.1):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network (7.4.0):
|
||||
- GoogleUtilities/Network (7.4.1):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (7.4.0)"
|
||||
- GoogleUtilities/Reachability (7.4.0):
|
||||
- "GoogleUtilities/NSData+zlib (7.4.1)"
|
||||
- GoogleUtilities/Reachability (7.4.1):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (7.4.0):
|
||||
- GoogleUtilities/UserDefaults (7.4.1):
|
||||
- GoogleUtilities/Logger
|
||||
- GTMAppAuth (1.1.0):
|
||||
- GTMAppAuth (1.2.2):
|
||||
- AppAuth/Core (~> 1.4)
|
||||
- GTMSessionFetcher (~> 1.4)
|
||||
- GTMSessionFetcher (1.5.0):
|
||||
- GTMSessionFetcher/Full (= 1.5.0)
|
||||
- GTMSessionFetcher/Core (~> 1.5)
|
||||
- GTMSessionFetcher/Core (1.5.0)
|
||||
- GTMSessionFetcher/Full (1.5.0):
|
||||
- GTMSessionFetcher/Core (= 1.5.0)
|
||||
- modal_progress_hud_nsn (0.0.1):
|
||||
- Flutter
|
||||
- nanopb (2.30908.0):
|
||||
@ -199,20 +196,21 @@ PODS:
|
||||
- path_provider (0.0.1):
|
||||
- Flutter
|
||||
- PromisesObjC (1.2.12)
|
||||
- Purchases (3.10.7):
|
||||
- PurchasesCoreSwift (= 3.10.7)
|
||||
- purchases_flutter (3.2.1):
|
||||
- Purchases (3.11.1):
|
||||
- PurchasesCoreSwift (= 3.11.1)
|
||||
- purchases_flutter (3.2.2):
|
||||
- Flutter
|
||||
- PurchasesHybridCommon (= 1.6.2)
|
||||
- PurchasesCoreSwift (3.10.7)
|
||||
- PurchasesHybridCommon (1.6.2):
|
||||
- Purchases (= 3.10.7)
|
||||
- Sentry (6.2.1):
|
||||
- Sentry/Core (= 6.2.1)
|
||||
- Sentry/Core (6.2.1)
|
||||
- PurchasesHybridCommon (= 1.6.3)
|
||||
- PurchasesCoreSwift (3.11.1)
|
||||
- PurchasesHybridCommon (1.6.3):
|
||||
- Purchases (= 3.11.1)
|
||||
- Sentry (7.0.3):
|
||||
- Sentry/Core (= 7.0.3)
|
||||
- Sentry/Core (7.0.3)
|
||||
- sentry_flutter (0.0.1):
|
||||
- Flutter
|
||||
- Sentry (~> 6.2.1)
|
||||
- FlutterMacOS
|
||||
- Sentry (~> 7.0.3)
|
||||
- shared_preferences (0.0.1):
|
||||
- Flutter
|
||||
- sqflite (0.0.2):
|
||||
@ -269,7 +267,6 @@ SPEC REPOS:
|
||||
- FirebaseCore
|
||||
- FirebaseCoreDiagnostics
|
||||
- FirebaseInstallations
|
||||
- FirebaseInstanceID
|
||||
- FirebaseMessaging
|
||||
- FirebaseRemoteConfig
|
||||
- Flurry-iOS-SDK
|
||||
@ -350,23 +347,22 @@ SPEC CHECKSUMS:
|
||||
devicelocale: b22617f40038496deffba44747101255cee005b0
|
||||
FBSDKCoreKit: a00fe2efd780c195a5e09201bf51c56106245b40
|
||||
FBSDKLoginKit: d98498c598ec09de657385a9349a1f21119b7f86
|
||||
Firebase: c121feb35e4126c0b355e3313fa9b487d47319fd
|
||||
firebase_analytics: 620e8cc1705feb6b9c40b6127bea9b39e03e3970
|
||||
firebase_auth: e7065954aa2a7c8ef1a8502fba3009bcdd8fc91a
|
||||
firebase_core: 84dcd80ac6d29c3d1039071b7306ee99688eb9c7
|
||||
firebase_messaging: 7aecb08eada5e5cde85b10875141706a8d18b818
|
||||
firebase_remote_config: f855065886b7d6ccc38144c9a3cecbdc7887f33e
|
||||
FirebaseABTesting: e66f1f80747792630d9b292966de206d5df9853b
|
||||
FirebaseAnalytics: cd3bd84d722a24a8923918af8af8e5236f615d77
|
||||
FirebaseAuth: 5fe4585c2ed847319f0ea68bd1d82c77e49ff9a0
|
||||
FirebaseCore: 907447d8917a4d3eb0cce2829c5a0ad21d90b432
|
||||
FirebaseCoreDiagnostics: 68ad972f99206cef818230f3f3179d52ccfb7f8c
|
||||
FirebaseInstallations: a58d4f72ec5861840b84df489f2668d970df558a
|
||||
FirebaseInstanceID: ad5135045a498d7775903efd39762d2cdfa1be27
|
||||
FirebaseMessaging: 163435fb6db065e3b6228f1e577b10ed2cc506d2
|
||||
FirebaseRemoteConfig: 0ea30de5fb0231df8c1bdcdf3b6c23bdc5066131
|
||||
Firebase: 73c3e3b216ec1ecbc54d2ffdd4670c65c749edb1
|
||||
firebase_analytics: 221d3bc4e8f1b5144a4bd4cc6b33790ee51bd543
|
||||
firebase_auth: f960df4ddd8cb415859dbc01a02d7859925ddef0
|
||||
firebase_core: e4d3efb030a2b2021819f8faa538bb23deb46695
|
||||
firebase_messaging: 3b6e0657b21261a57a1cd041fafa713f2aa6923f
|
||||
firebase_remote_config: 3a6e2db440f0e95baba3dfc3d4118b1a4bc792c4
|
||||
FirebaseABTesting: daebc95ec8829607d07dfe5e92dc3285aca29bc4
|
||||
FirebaseAnalytics: dcb92c7c9ef4fa7ffac276e8f87bd4fc8c97f1b8
|
||||
FirebaseAuth: b8cd992fca5b53dc6eec09e873a3f375f000c5a1
|
||||
FirebaseCore: 3f09591d51292843e2a46f18358d60bf4e996255
|
||||
FirebaseCoreDiagnostics: a31d987ba0fe16d59886a5dbadc2f1de871f88c8
|
||||
FirebaseInstallations: c4aab1005d6547b00a7529777fe52f5d4d45165b
|
||||
FirebaseMessaging: 1a33b4af3c8042ed6ddacb6c031894af2064bfab
|
||||
FirebaseRemoteConfig: 055f6b5ba1751547596ded5032c4d5c6054ca501
|
||||
flurry: 15b01f664ab1367c62b50291541ea7f78ca85aad
|
||||
Flurry-iOS-SDK: 6636d30c30f12010e7c7c71d84b443416a168efc
|
||||
Flurry-iOS-SDK: 5831da8fc6bedb31fa1f94aac6fd204d36dd351d
|
||||
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
|
||||
flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68
|
||||
flutter_facebook_auth: 4b170c07b7fce791497093fcc3f134fb215f3f07
|
||||
@ -375,11 +371,11 @@ SPEC CHECKSUMS:
|
||||
flutter_uxcam: ab8e5d3954eb448febd581375e2622e9eecb1066
|
||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||
google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc
|
||||
GoogleAppMeasurement: fd19169c3034975cb934e865e5667bfdce59df7f
|
||||
GoogleDataTransport: cd9db2180fcecd8da1b561aea31e3e56cf834aa7
|
||||
GoogleAppMeasurement: c6bbc9753d046b5456dd4f940057fbad2c28419e
|
||||
GoogleDataTransport: 11e3a5f2c190327df1a4a5d7e7ae3d4d5b9c9e4c
|
||||
GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
|
||||
GoogleUtilities: 284cddc7fffc14ae1907efb6f78ab95c1fccaedc
|
||||
GTMAppAuth: 197a8dabfea5d665224aa00d17f164fc2248dab9
|
||||
GoogleUtilities: f8a43108b38a68eebe8b3540e1f4f2d28843ce20
|
||||
GTMAppAuth: ad5c2b70b9a8689e1a04033c9369c4915bfcbe89
|
||||
GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
|
||||
modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde
|
||||
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
|
||||
@ -387,12 +383,12 @@ SPEC CHECKSUMS:
|
||||
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
|
||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
|
||||
Purchases: b8b8fb6e856ac8166e217f6e014df894d821dda1
|
||||
purchases_flutter: 0130970b895c903e4e0aad793dd3a4c1b70bb434
|
||||
PurchasesCoreSwift: 8ae0f08e020f0bc97c1befa4e38a0dbc8e9732e0
|
||||
PurchasesHybridCommon: 5f5c1c245b12fc5e8760af7d11cb10f888109a9b
|
||||
Sentry: 9b922b396b0e0bca8516a10e36b0ea3ebea5faf7
|
||||
sentry_flutter: 5b3c6d717db5b7482504a313c831b318297d4d37
|
||||
Purchases: 6351f9ff6bd514e5ec5aa0f989ea181effa94bf5
|
||||
purchases_flutter: 627527b070d80cdaf486fabe8b3d1dbe8d5cad92
|
||||
PurchasesCoreSwift: ee857e4c21e6254b09d7e303a756fcf2b9164408
|
||||
PurchasesHybridCommon: d65a799a61d688588534b80338edbcbf604ca93d
|
||||
Sentry: 5b16f877da362d23716d827e04db642455b26b40
|
||||
sentry_flutter: 602dc1902e152269256115e2386e1029511f3440
|
||||
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
|
||||
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
|
||||
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
|
||||
|
@ -388,7 +388,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@ -405,7 +405,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.17;
|
||||
MARKETING_VERSION = 1.1.18;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@ -531,7 +531,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@ -548,7 +548,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.17;
|
||||
MARKETING_VERSION = 1.1.18;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@ -566,7 +566,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@ -583,7 +583,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.17;
|
||||
MARKETING_VERSION = 1.1.18;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
@ -1,7 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/exercise_ability.dart';
|
||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||
|
@ -309,7 +309,6 @@ class TestSetExecuteBloc extends Bloc<TestSetExecuteEvent, TestSetExecuteState>
|
||||
|
||||
bool existsActivePlan() {
|
||||
final bool exists = exercisePlan != null && exercisePlanDetails != null && exercisePlanDetails!.isNotEmpty;
|
||||
print("Exists active plan: $exists");
|
||||
return exists;
|
||||
}
|
||||
|
||||
|
160
lib/bloc/training_plan/training_plan_bloc.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
54
lib/bloc/training_plan/training_plan_event.dart
Normal 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();
|
||||
}
|
32
lib/bloc/training_plan/training_plan_state.dart
Normal 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];
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
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/push_notifications.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/service/firebase_api.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/login.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_muscle_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_execute.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/library/facebook_app_events/facebook_app_events.dart';
|
||||
import 'package:firebase_analytics/firebase_analytics.dart';
|
||||
@ -178,6 +184,10 @@ Future<Null> main() async {
|
||||
create: (BuildContext context) => TestSetExecuteBloc(),
|
||||
),
|
||||
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(),
|
||||
));
|
||||
@ -262,6 +272,10 @@ class WorkoutTestApp extends StatelessWidget {
|
||||
'testSetNew': (context) => TestSetNew(),
|
||||
'testSetControl': (context) => TestSetControl(),
|
||||
'faqPage': (context) => FaqPage(),
|
||||
'myTrainingPlans': (context) => MyTrainingPlans(),
|
||||
'myTrainingPlanActivate': (context) => TrainingPlanActivatePage(),
|
||||
'myTrainingPlanExecute': (context) => TrainingPlanExecutePage(),
|
||||
'myTrainingPlanExercise': (context) => TrainingPlanExercise(),
|
||||
},
|
||||
initialRoute: 'home',
|
||||
title: 'WorkoutTest',
|
||||
|
@ -2,6 +2,7 @@ import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
import 'package:aitrainer_app/model/customer.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/evaluation.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/purchase.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/workout_menu_tree.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 activeExercisePlanDateKey = "active_exercise_plan_date";
|
||||
static final String activeExercisePlanDetailsKey = "active_exercise_details_plan";
|
||||
static final String myTrainingPlanKey = "myTrainingPlan";
|
||||
|
||||
static String baseUrlLive = 'https://aitrainer.info:8943/api/';
|
||||
static String baseUrlTest = 'https://aitrainer.info:8843/api/';
|
||||
@ -137,14 +140,19 @@ class Cache with Logging {
|
||||
List<ExercisePlanTemplate> _exercisePlanTemplates = [];
|
||||
|
||||
ExercisePlan? activeExercisePlan;
|
||||
CustomerTrainingPlan? myTrainingPlan;
|
||||
List<ExercisePlanDetail>? activeExercisePlanDetails;
|
||||
|
||||
List<ExerciseDevice>? _devices;
|
||||
|
||||
List<CustomerExerciseDevice>? _customerDevices;
|
||||
List<CustomerActivity>? _customerActivities;
|
||||
List<CustomerTrainingPlan>? _customerTrainingPlans;
|
||||
|
||||
List<Tutorial>? _tutorials;
|
||||
List<Description>? _descriptions;
|
||||
List<Faq>? _faqs;
|
||||
List<TrainingPlan>? _trainingPlans;
|
||||
|
||||
LinkedHashMap<int, ExercisePlanDetail> _myExercisesPlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
|
||||
|
||||
@ -209,6 +217,33 @@ class Cache with Logging {
|
||||
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<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||
SharedPreferences sharedPreferences;
|
||||
@ -644,6 +679,8 @@ class Cache with Logging {
|
||||
await isActivityDonePrefs(activity);
|
||||
});
|
||||
|
||||
await getMyTrainingPlan();
|
||||
|
||||
Cache().startPage = "home";
|
||||
}
|
||||
|
||||
@ -690,4 +727,10 @@ class Cache with Logging {
|
||||
|
||||
List<Faq>? getFaqs() => this._faqs;
|
||||
setFaqs(List<Faq>? value) => this._faqs = value;
|
||||
|
||||
List<TrainingPlan>? getTrainingPlans() => this._trainingPlans;
|
||||
setTrainingPlans(List<TrainingPlan>? value) => this._trainingPlans = value;
|
||||
|
||||
List<CustomerTrainingPlan>? getCustomerTrainingPlans() => this._customerTrainingPlans;
|
||||
setCustomerTrainingPlans(value) => this._customerTrainingPlans = value;
|
||||
}
|
||||
|
78
lib/model/customer_training_plan.dart
Normal 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();
|
||||
}
|
114
lib/model/customer_training_plan_details.dart
Normal 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();
|
||||
}
|
30
lib/model/customer_training_plan_exercise.dart
Normal file
@ -0,0 +1,30 @@
|
||||
class CustomerTrainingPlanExercise {
|
||||
int? customerTrainingPlanExerciseId;
|
||||
int? customerTrainingPlanDetailsId;
|
||||
int? customerId;
|
||||
int? exerciseId;
|
||||
double? weight;
|
||||
int? repeats;
|
||||
|
||||
CustomerTrainingPlanExercise();
|
||||
|
||||
CustomerTrainingPlanExercise.fromJson(Map json) {
|
||||
this.customerTrainingPlanExerciseId = json['customerTrainingPlanExerciseId'];
|
||||
this.customerTrainingPlanDetailsId = json['customerTrainingPlanDetailsId'];
|
||||
this.customerId = json['customerId'];
|
||||
this.exerciseId = json['exerciseId'];
|
||||
this.repeats = json['repeats'];
|
||||
this.weight = json['weight'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId,
|
||||
"customerId": this.customerId,
|
||||
"exerciseId": this.exerciseId,
|
||||
"weight": this.weight,
|
||||
"repeats": this.repeats
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() => this.toJson().toString();
|
||||
}
|
@ -9,6 +9,7 @@ class Exercise {
|
||||
double? unitQuantity;
|
||||
DateTime? dateAdd;
|
||||
int? exercisePlanDetailId;
|
||||
int? trainingPlanDetailsId;
|
||||
|
||||
String? datePart;
|
||||
double? calculated;
|
||||
@ -26,6 +27,8 @@ class Exercise {
|
||||
this.dateAdd = DateTime.parse(json['dateAdd']);
|
||||
this.datePart = DateFormat('yyyy-MM-dd').format(this.dateAdd!);
|
||||
this.calculated = quantity;
|
||||
this.exercisePlanDetailId = json['exercisePlanDetailId'] == "null" ? null : json['exercisePlanDetailId'];
|
||||
this.trainingPlanDetailsId = json['trainingPlanDetailsId'] == "null" ? null : json['trainingPlanDetailsId'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
@ -36,6 +39,7 @@ class Exercise {
|
||||
"unitQuantity": unitQuantity,
|
||||
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!),
|
||||
"exercisePlanDetailId": exercisePlanDetailId,
|
||||
"trainingPlanDetailsId": trainingPlanDetailsId,
|
||||
};
|
||||
|
||||
Map<String, dynamic> toJsonDatePart() => {
|
||||
|
@ -18,7 +18,12 @@ class ExerciseTree {
|
||||
late String nameTranslation;
|
||||
|
||||
/// sort
|
||||
late int? sort;
|
||||
int? sort;
|
||||
|
||||
String? internalName;
|
||||
|
||||
String? description;
|
||||
String? descriptionTranslation;
|
||||
|
||||
ExerciseTree();
|
||||
|
||||
@ -29,7 +34,12 @@ class ExerciseTree {
|
||||
this.imageUrl = json['imageUrl'];
|
||||
this.active = json['active'];
|
||||
this.nameTranslation = json['translations'] != null && (json['translations']).length > 0 ? json['translations'][0]['name'] : this.name;
|
||||
this.descriptionTranslation =
|
||||
json['translations'] != null && (json['translations']).length > 0 && json['translations'][0]['description'] != null
|
||||
? json['translations'][0]['description']
|
||||
: this.description;
|
||||
this.sort = 99;
|
||||
this.internalName = json['internalName'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
@ -37,13 +47,18 @@ class ExerciseTree {
|
||||
"treeId": treeId,
|
||||
"parentId": parentId,
|
||||
"name": name,
|
||||
"description": description,
|
||||
"imageUrl": imageUrl,
|
||||
"active": active.toString(),
|
||||
"nameTranslation": nameTranslation,
|
||||
"descriptionTranslation": descriptionTranslation,
|
||||
"sort": sort,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => this.toJson().toString();
|
||||
|
||||
ExerciseTree copy(int parentId) {
|
||||
ExerciseTree newTree = ExerciseTree();
|
||||
newTree.treeId = this.treeId;
|
||||
|
71
lib/model/training_plan.dart
Normal 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();
|
||||
}
|
40
lib/model/training_plan_detail.dart
Normal 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();
|
||||
}
|
141
lib/repository/training_plan_repository.dart
Normal 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;
|
||||
}
|
||||
}
|
@ -13,19 +13,19 @@ class ExerciseTreeApi with Logging {
|
||||
Future<List<ExerciseTree>> getExerciseTree() async {
|
||||
final String body = await _client.get("exercise_tree", "");
|
||||
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.imageUrl = await buildImage(exerciseTree.imageUrl, exerciseTree.treeId);
|
||||
});
|
||||
exerciseTree = await getExerciseTreeParents(exerciseTree);
|
||||
log("ExerciseTree downloaded");
|
||||
Cache().setExerciseTree(exerciseTree);
|
||||
exerciseTrees = await getExerciseTreeParents(exerciseTrees);
|
||||
log("ExerciseTree downloaded $exerciseTrees");
|
||||
Cache().setExerciseTree(exerciseTrees);
|
||||
|
||||
return exerciseTree;
|
||||
return exerciseTrees;
|
||||
}
|
||||
|
||||
Future<String> buildImage(String imageUrl, int treeId) async {
|
||||
|
@ -18,6 +18,7 @@ import 'package:aitrainer_app/model/product.dart';
|
||||
import 'package:aitrainer_app/model/product_test.dart';
|
||||
import 'package:aitrainer_app/model/property.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/service/api.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();
|
||||
//print("Faq: $faqs");
|
||||
Cache().setFaqs(faqs);
|
||||
} else if (headRecord[0] == "TrainingPlan") {
|
||||
final Iterable json = jsonDecode(headRecord[1]);
|
||||
final List<TrainingPlan>? plans = json.map((plan) => TrainingPlan.fromJson(plan)).toList();
|
||||
|
||||
Cache().setTrainingPlans(plans);
|
||||
}
|
||||
});
|
||||
|
||||
@ -95,6 +101,7 @@ class PackageApi {
|
||||
ExerciseTree tree = element as ExerciseTree;
|
||||
tree.imageUrl = await ExerciseTreeApi().buildImage(tree.imageUrl, tree.treeId);
|
||||
});
|
||||
//print("tree: $exerciseTree");
|
||||
Cache().setExerciseTree(exerciseTree);
|
||||
|
||||
return;
|
||||
|
34
lib/service/training_plan_service.dart
Normal 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;
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||
@ -144,4 +143,62 @@ mixin Common {
|
||||
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ class AccountPage extends StatelessWidget with Trans {
|
||||
),
|
||||
devices(context, accountBloc),
|
||||
loginOut(context, accountBloc),
|
||||
getMyTrainees(context, accountBloc),
|
||||
//getMyTrainees(context, accountBloc),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -141,9 +141,9 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
|
||||
unitQuantityUnit: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit,
|
||||
hasUnitQuantity: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit != null,
|
||||
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),
|
||||
exerciseTypeId: exerciseType.exerciseTypeId,
|
||||
)),
|
||||
|
125
lib/view/my_training_plans_page.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
@ -99,9 +99,9 @@ class TestSetNew extends StatelessWidget with Trans {
|
||||
unitQuantityUnit: bloc.exerciseType.unitQuantityUnit,
|
||||
hasUnitQuantity: bloc.exerciseType.unitQuantityUnit != null,
|
||||
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,
|
||||
/* onSubmit: () {
|
||||
Navigator.of(context).pop();
|
||||
|
483
lib/view/training_plan_activate_page.dart
Normal 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());
|
||||
}
|
||||
}
|
510
lib/view/training_plan_execute_page.dart
Normal 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()
|
||||
]),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
221
lib/view/training_plan_exercise.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
@ -90,7 +90,7 @@ class _NawDrawerWidget extends State<BottomNavigator> with Trans, Logging {
|
||||
case 2:
|
||||
Navigator.of(context).pop();
|
||||
Track().track(TrackingEvent.my_exerciseplan);
|
||||
Navigator.of(context).pushNamed('myExercisePlan');
|
||||
Navigator.of(context).pushNamed('myTrainingPlans');
|
||||
|
||||
break;
|
||||
case 3:
|
||||
|
@ -12,8 +12,8 @@ import 'dialog_html.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class ExerciseSave extends StatefulWidget {
|
||||
final ValueChanged<dynamic> onQuantityChanged;
|
||||
final ValueChanged<dynamic>? onUnitQuantityChanged;
|
||||
final ValueChanged<double> onQuantityChanged;
|
||||
final ValueChanged<double>? onUnitQuantityChanged;
|
||||
final VoidCallback? onSubmit;
|
||||
final bool hasUnitQuantity;
|
||||
final String? unitQuantityUnit;
|
||||
@ -22,18 +22,23 @@ class ExerciseSave extends StatefulWidget {
|
||||
final String exerciseDescription;
|
||||
final String exerciseTask;
|
||||
final int exerciseTypeId;
|
||||
final double? weight;
|
||||
final int? repeats;
|
||||
|
||||
ExerciseSave(
|
||||
{required this.onQuantityChanged,
|
||||
this.onUnitQuantityChanged,
|
||||
this.onSubmit,
|
||||
required this.hasUnitQuantity,
|
||||
this.unitQuantityUnit,
|
||||
required this.unit,
|
||||
required this.exerciseName,
|
||||
required this.exerciseDescription,
|
||||
required this.exerciseTask,
|
||||
required this.exerciseTypeId});
|
||||
ExerciseSave({
|
||||
required this.onQuantityChanged,
|
||||
this.onUnitQuantityChanged,
|
||||
this.onSubmit,
|
||||
required this.hasUnitQuantity,
|
||||
this.unitQuantityUnit,
|
||||
required this.unit,
|
||||
required this.exerciseName,
|
||||
required this.exerciseDescription,
|
||||
required this.exerciseTask,
|
||||
required this.exerciseTypeId,
|
||||
this.weight,
|
||||
this.repeats,
|
||||
});
|
||||
@override
|
||||
_ExerciseSaveState createState() => _ExerciseSaveState();
|
||||
}
|
||||
@ -53,11 +58,15 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
||||
return getExerciseWidget();
|
||||
}
|
||||
|
||||
//@override
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
_controller1.text = "30";
|
||||
_controller2.text = "12";
|
||||
_controller1.text = widget.weight == null
|
||||
? "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(() {
|
||||
if (_nodeText1.hasFocus) {
|
||||
_controller1.selection = TextSelection(baseOffset: 0, extentOffset: _controller1.text.length);
|
||||
@ -69,7 +78,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
||||
}
|
||||
});
|
||||
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,
|
||||
color: Colors.orange,
|
||||
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,
|
||||
textAlign: TextAlign.center,
|
||||
@ -258,7 +279,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
||||
onChanged: (value) => {
|
||||
value = value.replaceFirst(",", "."),
|
||||
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),
|
||||
child: StreamBuilder<int>(
|
||||
stream: stopWatchTimer.rawTime,
|
||||
initialData: stopWatchTimer.rawTime.valueWrapper?.value,
|
||||
initialData: stopWatchTimer.rawTime.value,
|
||||
builder: (context, snap) {
|
||||
final value = snap.data;
|
||||
final displayTime = StopWatchTimer.getDisplayTime(value!, hours: false);
|
||||
@ -344,7 +365,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
||||
Divider(),
|
||||
Divider(),
|
||||
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(
|
||||
@ -369,7 +390,9 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
||||
textInputAction: TextInputAction.next,
|
||||
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.orange[200]),
|
||||
onChanged: (value) {
|
||||
widget.onQuantityChanged(value);
|
||||
value = value.replaceFirst(",", ".");
|
||||
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
|
||||
widget.onQuantityChanged(double.parse(value));
|
||||
},
|
||||
),
|
||||
]));
|
||||
|
@ -22,6 +22,7 @@ class ImageButton extends StatelessWidget {
|
||||
final bool? isLocked;
|
||||
bool? isMarked;
|
||||
int? buttonIndex;
|
||||
Color? textColor;
|
||||
|
||||
ImageButton(
|
||||
{required this.text,
|
||||
@ -37,11 +38,13 @@ class ImageButton extends StatelessWidget {
|
||||
this.onTap,
|
||||
this.buttonIndex,
|
||||
this.isMarked,
|
||||
required this.isLocked}) {
|
||||
required this.isLocked,
|
||||
this.textColor}) {
|
||||
width = width ?? 180;
|
||||
height = height ?? 180;
|
||||
isMarked = isMarked ?? false;
|
||||
isShape = isShape ?? false;
|
||||
textColor = textColor ?? Colors.white;
|
||||
style = style ??
|
||||
GoogleFonts.archivoBlack(
|
||||
fontSize: 14,
|
||||
@ -54,10 +57,9 @@ class ImageButton extends StatelessWidget {
|
||||
top = height! - (style!.fontSize! - 5) * text.length - 2 * left < 0
|
||||
? height! - 2 * style!.fontSize! - 22
|
||||
: height! - style!.fontSize! - 37;
|
||||
//print("Top: " + top.toStringAsFixed(0) + " length: " + ((style.fontSize - 5) * text.length).toString());
|
||||
}
|
||||
final double width = MediaQuery.of(context).size.width;
|
||||
//print("Mediawidth: " + width.toStringAsFixed(0));
|
||||
|
||||
return Stack(alignment: AlignmentDirectional.bottomStart, children: [
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
@ -93,7 +95,7 @@ class ImageButton extends StatelessWidget {
|
||||
maxLines: 2,
|
||||
style: GoogleFonts.archivoBlack(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
color: textColor,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(2.0, 2.0),
|
||||
|
@ -7,7 +7,12 @@ import 'package:aitrainer_app/library/transparent_image.dart';
|
||||
class MenuImage extends StatelessWidget {
|
||||
final int? workoutTreeId;
|
||||
final String imageName;
|
||||
const MenuImage({required this.workoutTreeId, required this.imageName});
|
||||
double radius;
|
||||
MenuImage({
|
||||
required this.workoutTreeId,
|
||||
required this.imageName,
|
||||
this.radius = 24,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -31,7 +36,7 @@ class MenuImage extends StatelessWidget {
|
||||
if (imageName.contains("https")) {
|
||||
if (!wt.ImageCache().existsImageInMap(workoutTreeId!, imageName)) {
|
||||
widget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: FadeInImage(
|
||||
@ -43,7 +48,7 @@ class MenuImage extends StatelessWidget {
|
||||
}
|
||||
} else {
|
||||
widget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Image.asset(imageName),
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:collection';
|
||||
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/model/exercise_ability.dart';
|
||||
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||
@ -47,7 +48,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
if (activeExercisePlan) {
|
||||
if (activeExercisePlan || Cache().myTrainingPlan != null) {
|
||||
animation.start();
|
||||
animation.addStatusListener((status) {
|
||||
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
|
||||
? GestureDetector(
|
||||
onTap: () => showDialog(
|
||||
|
120
pubspec.lock
@ -56,7 +56,7 @@ packages:
|
||||
name: badges
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0-nullsafety.1"
|
||||
version: "2.0.1"
|
||||
bloc:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -231,7 +231,7 @@ packages:
|
||||
name: coverage
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.15.2"
|
||||
version: "1.0.2"
|
||||
crypto:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -239,13 +239,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
css_colors:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: css_colors
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
csslib:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -280,7 +273,7 @@ packages:
|
||||
name: equatable
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "2.0.2"
|
||||
ezanimation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -322,98 +315,98 @@ packages:
|
||||
name: firebase_analytics
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "8.0.2"
|
||||
version: "8.1.0"
|
||||
firebase_analytics_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_analytics_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "2.0.1"
|
||||
firebase_analytics_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_analytics_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
version: "0.3.0+1"
|
||||
firebase_auth:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_auth
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.0"
|
||||
firebase_auth_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_auth_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.2.0"
|
||||
version: "4.2.3"
|
||||
firebase_auth_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_auth_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.3"
|
||||
firebase_core:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.2.0"
|
||||
firebase_core_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "4.0.1"
|
||||
firebase_core_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
version: "1.1.0"
|
||||
firebase_messaging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_messaging
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "9.1.3"
|
||||
version: "10.0.0"
|
||||
firebase_messaging_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
version: "3.0.0"
|
||||
firebase_messaging_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
version: "2.0.0"
|
||||
firebase_remote_config:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_remote_config
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.10.0-dev.2"
|
||||
version: "0.10.0"
|
||||
firebase_remote_config_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_remote_config_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.0-dev.2"
|
||||
version: "0.3.0"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -427,7 +420,7 @@ packages:
|
||||
name: fl_chart
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.30.0"
|
||||
version: "0.36.1"
|
||||
flurry:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -460,21 +453,21 @@ packages:
|
||||
name: flutter_facebook_auth
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.3.2+2"
|
||||
version: "3.4.0"
|
||||
flutter_facebook_auth_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_facebook_auth_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.6.0"
|
||||
flutter_facebook_auth_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_facebook_auth_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.1+1"
|
||||
version: "2.6.0"
|
||||
flutter_fadein:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -488,7 +481,7 @@ packages:
|
||||
name: flutter_html
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0-nullsafety.0"
|
||||
version: "2.0.0"
|
||||
flutter_launcher_icons:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -509,7 +502,7 @@ packages:
|
||||
name: flutter_local_notifications
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "5.0.0+4"
|
||||
flutter_local_notifications_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -522,20 +515,27 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_secure_storage
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
version: "4.2.0"
|
||||
flutter_svg:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_svg
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.21.0-nullsafety.0"
|
||||
version: "0.22.0"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@ -566,14 +566,14 @@ packages:
|
||||
name: google_fonts
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "2.1.0"
|
||||
google_sign_in:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: google_sign_in
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.1"
|
||||
version: "5.0.3"
|
||||
google_sign_in_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -615,7 +615,7 @@ packages:
|
||||
name: http_multi_server
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "3.0.1"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -650,7 +650,7 @@ packages:
|
||||
name: io
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.4"
|
||||
version: "1.0.0"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -699,7 +699,7 @@ packages:
|
||||
name: mime
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.9.7"
|
||||
version: "1.0.0"
|
||||
mockito:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -804,14 +804,14 @@ packages:
|
||||
name: path_drawing
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.0-nullsafety.0"
|
||||
version: "0.5.1"
|
||||
path_parsing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_parsing
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.0-nullsafety.0"
|
||||
version: "0.2.1"
|
||||
path_provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -923,7 +923,7 @@ packages:
|
||||
name: purchases_flutter
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
version: "3.2.2"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -958,21 +958,21 @@ packages:
|
||||
name: rxdart
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.26.0"
|
||||
version: "0.27.0"
|
||||
sentry:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sentry
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "5.1.0-beta.1"
|
||||
sentry_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sentry_flutter
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "5.1.0-beta.1"
|
||||
shared_preferences:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -1028,21 +1028,21 @@ packages:
|
||||
name: shelf_packages_handler
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.0"
|
||||
shelf_static:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_static
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.9+2"
|
||||
version: "1.0.0"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.4+1"
|
||||
version: "1.0.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -1110,7 +1110,7 @@ packages:
|
||||
name: stop_watch_timer
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.2.0+1"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1138,7 +1138,14 @@ packages:
|
||||
name: syncfusion_flutter_core
|
||||
url: "https://pub.dartlang.org"
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1194,7 +1201,7 @@ packages:
|
||||
name: timezone
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.7.0-nullsafety.0"
|
||||
version: "0.7.0"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1209,6 +1216,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.9"
|
||||
tuple:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: tuple
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1278,7 +1292,7 @@ packages:
|
||||
name: video_player
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.1"
|
||||
video_player_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1299,7 +1313,7 @@ packages:
|
||||
name: vm_service
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.5.0"
|
||||
version: "6.2.0"
|
||||
wakelock:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1341,7 +1355,7 @@ packages:
|
||||
name: web_socket_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "2.1.0"
|
||||
webkit_inspection_protocol:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1355,7 +1369,7 @@ packages:
|
||||
name: webview_flutter
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
version: "2.0.7"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
47
pubspec.yaml
@ -25,28 +25,28 @@ dependencies:
|
||||
sdk: flutter
|
||||
|
||||
cupertino_icons: ^1.0.0
|
||||
google_fonts: ^2.0.0
|
||||
google_fonts: ^2.1.0
|
||||
devicelocale: ^0.4.1
|
||||
sentry_flutter: ^5.0.0
|
||||
sentry_flutter: ^5.1.0-beta.1
|
||||
flutter_bloc: ^7.0.0
|
||||
equatable: ^2.0.0
|
||||
equatable: ^2.0.2
|
||||
|
||||
spider_chart: ^0.1.5
|
||||
rainbow_color: ^2.0.1
|
||||
percent_indicator: ^ 3.3.0-nullsafety.1
|
||||
fl_chart: ^0.30.0
|
||||
fl_chart: ^0.36.1
|
||||
infinite_listview: ^1.1.0
|
||||
toggle_switch: ^0.1.9
|
||||
keyboard_actions: ^3.4.0
|
||||
badges: ^ 2.0.0-nullsafety.1
|
||||
badges: ^ 2.0.1
|
||||
#health: ^3.0.0
|
||||
stop_watch_timer: ^1.0.0
|
||||
stop_watch_timer: ^1.2.0+1
|
||||
#location: ^3.2.4
|
||||
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
|
||||
timeline_tile: ^2.0.0
|
||||
purchases_flutter: ^3.2.1
|
||||
purchases_flutter: ^3.2.2
|
||||
package_info: ^2.0.0
|
||||
ezanimation: ^0.5.0
|
||||
flutter_fadein: ^2.0.0
|
||||
@ -59,18 +59,20 @@ dependencies:
|
||||
#super_tooltip: ^1.0.1
|
||||
url_launcher: ^6.0.3
|
||||
|
||||
firebase_core: ^1.1.0
|
||||
firebase_analytics: ^8.0.2
|
||||
firebase_messaging: ^9.1.3
|
||||
firebase_core: ^1.2.0
|
||||
firebase_analytics: ^8.1.0
|
||||
firebase_messaging: ^10.0.0
|
||||
flutter_local_notifications: ^5.0.0
|
||||
firebase_auth: ^1.1.2
|
||||
firebase_remote_config: ^0.10.0-dev.2
|
||||
firebase_auth: ^1.2.0
|
||||
firebase_remote_config: ^0.10.0
|
||||
|
||||
syncfusion_flutter_gauges: ^19.1.63
|
||||
syncfusion_flutter_datagrid: ^19.1.63
|
||||
|
||||
flutter_facebook_auth: ^3.3.2
|
||||
google_sign_in: ^5.0.1
|
||||
flutter_facebook_auth: ^3.4.0
|
||||
google_sign_in: ^5.0.3
|
||||
apple_sign_in: ^0.1.0
|
||||
#sign_in_with_apple: ^3.0.0
|
||||
|
||||
#smartlook: ^1.0.7
|
||||
flurry: ^0.0.4
|
||||
@ -80,7 +82,7 @@ dependencies:
|
||||
|
||||
mockito: ^5.0.3
|
||||
sqflite: ^2.0.0+3
|
||||
flutter_secure_storage: ^4.1.0
|
||||
flutter_secure_storage: ^4.2.0
|
||||
#social_share: ^2.1.1
|
||||
|
||||
flutter_localizations:
|
||||
@ -383,6 +385,19 @@ flutter:
|
||||
- asset/menu/test_center.jpg
|
||||
- asset/menu/test_on_machines.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_kickback.jpg
|
||||
- asset/menu/triceps_pushdown.jpg
|
||||
|