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.",
|
"Try free for 3 days!":"Try it without risk for 3 days! In this period you can cancel any time without lasting your account.",
|
||||||
"View other alternatives":"View other alternatives",
|
"View other alternatives":"View other alternatives",
|
||||||
|
|
||||||
"Please log in, because we can calculate the best suggestions for you":"Please log in, because we can calculate the best suggestions for you"
|
"Please log in, because we can calculate the best suggestions for you":"Please log in, because we can calculate the best suggestions for you",
|
||||||
|
|
||||||
|
"My Active Training":"My Active Training",
|
||||||
|
"My Custom Plan":"My Custom Plan",
|
||||||
|
"Training Plans for Beginners":"Training Plans for Beginners",
|
||||||
|
"Training Plans for Home":"Training Plans for Home",
|
||||||
|
"Training Plans Advanced":"Training Plans Advanced",
|
||||||
|
"Training Plans for Women":"Training Plans for Women",
|
||||||
|
"Training Plans of Celebrities":"Training Plans of Celebrities",
|
||||||
|
"Training Plans for Gain Strength":"Training Plans for Gain Strength"
|
||||||
|
|
||||||
}
|
}
|
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.",
|
"Try free for 3 days!":"Próbáld ki kockázat nélkül 3 napig! Ebben az időszakban bármikor lemondhatod, anélkül, hogy megterhelnénk a számládat.",
|
||||||
"View other alternatives":"Megnézek egy másik lehetőséget",
|
"View other alternatives":"Megnézek egy másik lehetőséget",
|
||||||
|
|
||||||
"Please log in, because we can calculate the best suggestions for you":"Kérlek jelentkezz be, mert csak így tudjuk neked a legjobb gyakorlatokat kalkulálni"
|
"Please log in, because we can calculate the best suggestions for you":"Kérlek jelentkezz be, mert csak így tudjuk neked a legjobb gyakorlatokat kalkulálni",
|
||||||
|
|
||||||
|
"My Active Training":"Aktív edzésem",
|
||||||
|
"My Custom Plan":"Egyéni edzésterv",
|
||||||
|
"Training Plans for Beginners":"Kezdő edzésprogramok",
|
||||||
|
"Training Plans for Home":"Otthoni edzésprogramok",
|
||||||
|
"Training Plans Advanced":"Haladó edzésprogramok",
|
||||||
|
"Training Plans for Women":"Edzésprogramok nőknek",
|
||||||
|
"Training Plans of Celebrities":"Celebek edzésprogramjai",
|
||||||
|
"Training Plans for Gain Strength":"Erőnövelő edzésprogramok"
|
||||||
}
|
}
|
280
ios/Podfile.lock
@ -18,112 +18,106 @@ PODS:
|
|||||||
- FBSDKLoginKit/Login (= 9.1.0)
|
- FBSDKLoginKit/Login (= 9.1.0)
|
||||||
- FBSDKLoginKit/Login (9.1.0):
|
- FBSDKLoginKit/Login (9.1.0):
|
||||||
- FBSDKCoreKit (~> 9.1.0)
|
- FBSDKCoreKit (~> 9.1.0)
|
||||||
- Firebase/Analytics (7.11.0):
|
- Firebase/Analytics (8.0.0):
|
||||||
- Firebase/Core
|
- Firebase/Core
|
||||||
- Firebase/Auth (7.11.0):
|
- Firebase/Auth (8.0.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseAuth (~> 7.11.0)
|
- FirebaseAuth (~> 8.0.0)
|
||||||
- Firebase/Core (7.11.0):
|
- Firebase/Core (8.0.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseAnalytics (~> 7.11.0)
|
- FirebaseAnalytics (~> 8.0.0)
|
||||||
- Firebase/CoreOnly (7.11.0):
|
- Firebase/CoreOnly (8.0.0):
|
||||||
- FirebaseCore (= 7.11.0)
|
- FirebaseCore (= 8.0.0)
|
||||||
- Firebase/Messaging (7.11.0):
|
- Firebase/Messaging (8.0.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseMessaging (~> 7.11.0)
|
- FirebaseMessaging (~> 8.0.0)
|
||||||
- Firebase/RemoteConfig (7.11.0):
|
- Firebase/RemoteConfig (8.0.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseRemoteConfig (~> 7.11.0)
|
- FirebaseRemoteConfig (~> 8.0.0)
|
||||||
- firebase_analytics (8.0.2):
|
- firebase_analytics (8.1.0):
|
||||||
- Firebase/Analytics (= 7.11.0)
|
- Firebase/Analytics (= 8.0.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_auth (1.1.2):
|
- firebase_auth (1.2.0):
|
||||||
- Firebase/Auth (= 7.11.0)
|
- Firebase/Auth (= 8.0.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_core (1.1.0):
|
- firebase_core (1.2.0):
|
||||||
- Firebase/CoreOnly (= 7.11.0)
|
- Firebase/CoreOnly (= 8.0.0)
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_messaging (9.1.3):
|
- firebase_messaging (10.0.0):
|
||||||
- Firebase/Messaging (= 7.11.0)
|
- Firebase/Messaging (= 8.0.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_remote_config (0.10.0-dev.2):
|
- firebase_remote_config (0.10.0):
|
||||||
- Firebase/RemoteConfig (= 7.11.0)
|
- Firebase/RemoteConfig (= 8.0.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
- FirebaseABTesting (7.11.0):
|
- FirebaseABTesting (8.0.0):
|
||||||
- FirebaseCore (~> 7.0)
|
- FirebaseCore (~> 8.0)
|
||||||
- FirebaseAnalytics (7.11.0):
|
- FirebaseAnalytics (8.0.0):
|
||||||
- FirebaseAnalytics/AdIdSupport (= 7.11.0)
|
- FirebaseAnalytics/AdIdSupport (= 8.0.0)
|
||||||
- FirebaseCore (~> 7.0)
|
- FirebaseCore (~> 8.0)
|
||||||
- FirebaseInstallations (~> 7.0)
|
- FirebaseInstallations (~> 8.0)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 7.0)
|
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/Network (~> 7.0)
|
- GoogleUtilities/Network (~> 7.4)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 7.0)"
|
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||||
- nanopb (~> 2.30908.0)
|
- nanopb (~> 2.30908.0)
|
||||||
- FirebaseAnalytics/AdIdSupport (7.11.0):
|
- FirebaseAnalytics/AdIdSupport (8.0.0):
|
||||||
- FirebaseAnalytics/Base (= 7.11.0)
|
- FirebaseAnalytics/Base (= 8.0.0)
|
||||||
- FirebaseCore (~> 7.0)
|
- FirebaseCore (~> 8.0)
|
||||||
- FirebaseInstallations (~> 7.0)
|
- FirebaseInstallations (~> 8.0)
|
||||||
- GoogleAppMeasurement/AdIdSupport (= 7.11.0)
|
- GoogleAppMeasurement (= 8.0.0)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 7.0)
|
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/Network (~> 7.0)
|
- GoogleUtilities/Network (~> 7.4)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 7.0)"
|
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||||
- nanopb (~> 2.30908.0)
|
- nanopb (~> 2.30908.0)
|
||||||
- FirebaseAnalytics/Base (7.11.0):
|
- FirebaseAnalytics/Base (8.0.0):
|
||||||
- FirebaseCore (~> 7.0)
|
- FirebaseCore (~> 8.0)
|
||||||
- FirebaseInstallations (~> 7.0)
|
- FirebaseInstallations (~> 8.0)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 7.0)
|
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/Network (~> 7.0)
|
- GoogleUtilities/Network (~> 7.4)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 7.0)"
|
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||||
- nanopb (~> 2.30908.0)
|
- nanopb (~> 2.30908.0)
|
||||||
- FirebaseAuth (7.11.0):
|
- FirebaseAuth (8.0.0):
|
||||||
- FirebaseCore (~> 7.0)
|
- FirebaseCore (~> 8.0)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/Environment (~> 7.0)
|
- GoogleUtilities/Environment (~> 7.4)
|
||||||
- GTMSessionFetcher/Core (~> 1.4)
|
- GTMSessionFetcher/Core (~> 1.5)
|
||||||
- FirebaseCore (7.11.0):
|
- FirebaseCore (8.0.0):
|
||||||
- FirebaseCoreDiagnostics (~> 7.4)
|
- FirebaseCoreDiagnostics (~> 8.0)
|
||||||
- GoogleUtilities/Environment (~> 7.0)
|
- GoogleUtilities/Environment (~> 7.4)
|
||||||
- GoogleUtilities/Logger (~> 7.0)
|
- GoogleUtilities/Logger (~> 7.4)
|
||||||
- FirebaseCoreDiagnostics (7.11.0):
|
- FirebaseCoreDiagnostics (8.0.0):
|
||||||
- GoogleDataTransport (~> 8.4)
|
- GoogleDataTransport (~> 9.0)
|
||||||
- GoogleUtilities/Environment (~> 7.0)
|
- GoogleUtilities/Environment (~> 7.4)
|
||||||
- GoogleUtilities/Logger (~> 7.0)
|
- GoogleUtilities/Logger (~> 7.4)
|
||||||
- nanopb (~> 2.30908.0)
|
- nanopb (~> 2.30908.0)
|
||||||
- FirebaseInstallations (7.11.0):
|
- FirebaseInstallations (8.0.0):
|
||||||
- FirebaseCore (~> 7.0)
|
- FirebaseCore (~> 8.0)
|
||||||
- GoogleUtilities/Environment (~> 7.0)
|
- GoogleUtilities/Environment (~> 7.4)
|
||||||
- GoogleUtilities/UserDefaults (~> 7.0)
|
- GoogleUtilities/UserDefaults (~> 7.4)
|
||||||
- PromisesObjC (~> 1.2)
|
- PromisesObjC (~> 1.2)
|
||||||
- FirebaseInstanceID (7.11.0):
|
- FirebaseMessaging (8.0.0):
|
||||||
- FirebaseCore (~> 7.0)
|
- FirebaseCore (~> 8.0)
|
||||||
- FirebaseInstallations (~> 7.0)
|
- FirebaseInstallations (~> 8.0)
|
||||||
- GoogleUtilities/Environment (~> 7.0)
|
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/UserDefaults (~> 7.0)
|
- GoogleUtilities/Environment (~> 7.4)
|
||||||
- FirebaseMessaging (7.11.0):
|
- GoogleUtilities/Reachability (~> 7.4)
|
||||||
- FirebaseCore (~> 7.0)
|
- GoogleUtilities/UserDefaults (~> 7.4)
|
||||||
- FirebaseInstallations (~> 7.0)
|
- FirebaseRemoteConfig (8.0.0):
|
||||||
- FirebaseInstanceID (~> 7.0)
|
- FirebaseABTesting (~> 8.0)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
- FirebaseCore (~> 8.0)
|
||||||
- GoogleUtilities/Environment (~> 7.0)
|
- FirebaseInstallations (~> 8.0)
|
||||||
- GoogleUtilities/Reachability (~> 7.0)
|
- GoogleUtilities/Environment (~> 7.4)
|
||||||
- GoogleUtilities/UserDefaults (~> 7.0)
|
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||||
- FirebaseRemoteConfig (7.11.0):
|
|
||||||
- FirebaseABTesting (~> 7.0)
|
|
||||||
- FirebaseCore (~> 7.0)
|
|
||||||
- FirebaseInstallations (~> 7.0)
|
|
||||||
- GoogleUtilities/Environment (~> 7.0)
|
|
||||||
- "GoogleUtilities/NSData+zlib (~> 7.0)"
|
|
||||||
- flurry (0.0.4):
|
- flurry (0.0.4):
|
||||||
- Flurry-iOS-SDK/FlurrySDK
|
- Flurry-iOS-SDK/FlurrySDK
|
||||||
- Flutter
|
- Flutter
|
||||||
- Flurry-iOS-SDK/FlurrySDK (11.2.0)
|
- Flurry-iOS-SDK/FlurrySDK (11.2.1)
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_app_badger (0.0.1):
|
- flutter_app_badger (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
@ -144,13 +138,20 @@ PODS:
|
|||||||
- google_sign_in (0.0.1):
|
- google_sign_in (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- GoogleSignIn (~> 5.0)
|
- GoogleSignIn (~> 5.0)
|
||||||
- GoogleAppMeasurement/AdIdSupport (7.11.0):
|
- GoogleAppMeasurement (8.0.0):
|
||||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.0)
|
- GoogleAppMeasurement/AdIdSupport (= 8.0.0)
|
||||||
- GoogleUtilities/MethodSwizzler (~> 7.0)
|
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||||
- GoogleUtilities/Network (~> 7.0)
|
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||||
- "GoogleUtilities/NSData+zlib (~> 7.0)"
|
- GoogleUtilities/Network (~> 7.4)
|
||||||
|
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||||
- nanopb (~> 2.30908.0)
|
- nanopb (~> 2.30908.0)
|
||||||
- GoogleDataTransport (8.4.0):
|
- GoogleAppMeasurement/AdIdSupport (8.0.0):
|
||||||
|
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
|
||||||
|
- GoogleUtilities/MethodSwizzler (~> 7.4)
|
||||||
|
- GoogleUtilities/Network (~> 7.4)
|
||||||
|
- "GoogleUtilities/NSData+zlib (~> 7.4)"
|
||||||
|
- nanopb (~> 2.30908.0)
|
||||||
|
- GoogleDataTransport (9.0.0):
|
||||||
- GoogleUtilities/Environment (~> 7.2)
|
- GoogleUtilities/Environment (~> 7.2)
|
||||||
- nanopb (~> 2.30908.0)
|
- nanopb (~> 2.30908.0)
|
||||||
- PromisesObjC (~> 1.2)
|
- PromisesObjC (~> 1.2)
|
||||||
@ -158,33 +159,29 @@ PODS:
|
|||||||
- AppAuth (~> 1.2)
|
- AppAuth (~> 1.2)
|
||||||
- GTMAppAuth (~> 1.0)
|
- GTMAppAuth (~> 1.0)
|
||||||
- GTMSessionFetcher/Core (~> 1.1)
|
- GTMSessionFetcher/Core (~> 1.1)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (7.4.0):
|
- GoogleUtilities/AppDelegateSwizzler (7.4.1):
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Network
|
- GoogleUtilities/Network
|
||||||
- GoogleUtilities/Environment (7.4.0):
|
- GoogleUtilities/Environment (7.4.1):
|
||||||
- PromisesObjC (~> 1.2)
|
- PromisesObjC (~> 1.2)
|
||||||
- GoogleUtilities/Logger (7.4.0):
|
- GoogleUtilities/Logger (7.4.1):
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/MethodSwizzler (7.4.0):
|
- GoogleUtilities/MethodSwizzler (7.4.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Network (7.4.0):
|
- GoogleUtilities/Network (7.4.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- "GoogleUtilities/NSData+zlib"
|
- "GoogleUtilities/NSData+zlib"
|
||||||
- GoogleUtilities/Reachability
|
- GoogleUtilities/Reachability
|
||||||
- "GoogleUtilities/NSData+zlib (7.4.0)"
|
- "GoogleUtilities/NSData+zlib (7.4.1)"
|
||||||
- GoogleUtilities/Reachability (7.4.0):
|
- GoogleUtilities/Reachability (7.4.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/UserDefaults (7.4.0):
|
- GoogleUtilities/UserDefaults (7.4.1):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GTMAppAuth (1.1.0):
|
- GTMAppAuth (1.2.2):
|
||||||
- AppAuth/Core (~> 1.4)
|
- AppAuth/Core (~> 1.4)
|
||||||
- GTMSessionFetcher (~> 1.4)
|
- GTMSessionFetcher/Core (~> 1.5)
|
||||||
- GTMSessionFetcher (1.5.0):
|
|
||||||
- GTMSessionFetcher/Full (= 1.5.0)
|
|
||||||
- GTMSessionFetcher/Core (1.5.0)
|
- GTMSessionFetcher/Core (1.5.0)
|
||||||
- GTMSessionFetcher/Full (1.5.0):
|
|
||||||
- GTMSessionFetcher/Core (= 1.5.0)
|
|
||||||
- modal_progress_hud_nsn (0.0.1):
|
- modal_progress_hud_nsn (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- nanopb (2.30908.0):
|
- nanopb (2.30908.0):
|
||||||
@ -199,20 +196,21 @@ PODS:
|
|||||||
- path_provider (0.0.1):
|
- path_provider (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- PromisesObjC (1.2.12)
|
- PromisesObjC (1.2.12)
|
||||||
- Purchases (3.10.7):
|
- Purchases (3.11.1):
|
||||||
- PurchasesCoreSwift (= 3.10.7)
|
- PurchasesCoreSwift (= 3.11.1)
|
||||||
- purchases_flutter (3.2.1):
|
- purchases_flutter (3.2.2):
|
||||||
- Flutter
|
- Flutter
|
||||||
- PurchasesHybridCommon (= 1.6.2)
|
- PurchasesHybridCommon (= 1.6.3)
|
||||||
- PurchasesCoreSwift (3.10.7)
|
- PurchasesCoreSwift (3.11.1)
|
||||||
- PurchasesHybridCommon (1.6.2):
|
- PurchasesHybridCommon (1.6.3):
|
||||||
- Purchases (= 3.10.7)
|
- Purchases (= 3.11.1)
|
||||||
- Sentry (6.2.1):
|
- Sentry (7.0.3):
|
||||||
- Sentry/Core (= 6.2.1)
|
- Sentry/Core (= 7.0.3)
|
||||||
- Sentry/Core (6.2.1)
|
- Sentry/Core (7.0.3)
|
||||||
- sentry_flutter (0.0.1):
|
- sentry_flutter (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Sentry (~> 6.2.1)
|
- FlutterMacOS
|
||||||
|
- Sentry (~> 7.0.3)
|
||||||
- shared_preferences (0.0.1):
|
- shared_preferences (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- sqflite (0.0.2):
|
- sqflite (0.0.2):
|
||||||
@ -269,7 +267,6 @@ SPEC REPOS:
|
|||||||
- FirebaseCore
|
- FirebaseCore
|
||||||
- FirebaseCoreDiagnostics
|
- FirebaseCoreDiagnostics
|
||||||
- FirebaseInstallations
|
- FirebaseInstallations
|
||||||
- FirebaseInstanceID
|
|
||||||
- FirebaseMessaging
|
- FirebaseMessaging
|
||||||
- FirebaseRemoteConfig
|
- FirebaseRemoteConfig
|
||||||
- Flurry-iOS-SDK
|
- Flurry-iOS-SDK
|
||||||
@ -350,23 +347,22 @@ SPEC CHECKSUMS:
|
|||||||
devicelocale: b22617f40038496deffba44747101255cee005b0
|
devicelocale: b22617f40038496deffba44747101255cee005b0
|
||||||
FBSDKCoreKit: a00fe2efd780c195a5e09201bf51c56106245b40
|
FBSDKCoreKit: a00fe2efd780c195a5e09201bf51c56106245b40
|
||||||
FBSDKLoginKit: d98498c598ec09de657385a9349a1f21119b7f86
|
FBSDKLoginKit: d98498c598ec09de657385a9349a1f21119b7f86
|
||||||
Firebase: c121feb35e4126c0b355e3313fa9b487d47319fd
|
Firebase: 73c3e3b216ec1ecbc54d2ffdd4670c65c749edb1
|
||||||
firebase_analytics: 620e8cc1705feb6b9c40b6127bea9b39e03e3970
|
firebase_analytics: 221d3bc4e8f1b5144a4bd4cc6b33790ee51bd543
|
||||||
firebase_auth: e7065954aa2a7c8ef1a8502fba3009bcdd8fc91a
|
firebase_auth: f960df4ddd8cb415859dbc01a02d7859925ddef0
|
||||||
firebase_core: 84dcd80ac6d29c3d1039071b7306ee99688eb9c7
|
firebase_core: e4d3efb030a2b2021819f8faa538bb23deb46695
|
||||||
firebase_messaging: 7aecb08eada5e5cde85b10875141706a8d18b818
|
firebase_messaging: 3b6e0657b21261a57a1cd041fafa713f2aa6923f
|
||||||
firebase_remote_config: f855065886b7d6ccc38144c9a3cecbdc7887f33e
|
firebase_remote_config: 3a6e2db440f0e95baba3dfc3d4118b1a4bc792c4
|
||||||
FirebaseABTesting: e66f1f80747792630d9b292966de206d5df9853b
|
FirebaseABTesting: daebc95ec8829607d07dfe5e92dc3285aca29bc4
|
||||||
FirebaseAnalytics: cd3bd84d722a24a8923918af8af8e5236f615d77
|
FirebaseAnalytics: dcb92c7c9ef4fa7ffac276e8f87bd4fc8c97f1b8
|
||||||
FirebaseAuth: 5fe4585c2ed847319f0ea68bd1d82c77e49ff9a0
|
FirebaseAuth: b8cd992fca5b53dc6eec09e873a3f375f000c5a1
|
||||||
FirebaseCore: 907447d8917a4d3eb0cce2829c5a0ad21d90b432
|
FirebaseCore: 3f09591d51292843e2a46f18358d60bf4e996255
|
||||||
FirebaseCoreDiagnostics: 68ad972f99206cef818230f3f3179d52ccfb7f8c
|
FirebaseCoreDiagnostics: a31d987ba0fe16d59886a5dbadc2f1de871f88c8
|
||||||
FirebaseInstallations: a58d4f72ec5861840b84df489f2668d970df558a
|
FirebaseInstallations: c4aab1005d6547b00a7529777fe52f5d4d45165b
|
||||||
FirebaseInstanceID: ad5135045a498d7775903efd39762d2cdfa1be27
|
FirebaseMessaging: 1a33b4af3c8042ed6ddacb6c031894af2064bfab
|
||||||
FirebaseMessaging: 163435fb6db065e3b6228f1e577b10ed2cc506d2
|
FirebaseRemoteConfig: 055f6b5ba1751547596ded5032c4d5c6054ca501
|
||||||
FirebaseRemoteConfig: 0ea30de5fb0231df8c1bdcdf3b6c23bdc5066131
|
|
||||||
flurry: 15b01f664ab1367c62b50291541ea7f78ca85aad
|
flurry: 15b01f664ab1367c62b50291541ea7f78ca85aad
|
||||||
Flurry-iOS-SDK: 6636d30c30f12010e7c7c71d84b443416a168efc
|
Flurry-iOS-SDK: 5831da8fc6bedb31fa1f94aac6fd204d36dd351d
|
||||||
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
|
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
|
||||||
flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68
|
flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68
|
||||||
flutter_facebook_auth: 4b170c07b7fce791497093fcc3f134fb215f3f07
|
flutter_facebook_auth: 4b170c07b7fce791497093fcc3f134fb215f3f07
|
||||||
@ -375,11 +371,11 @@ SPEC CHECKSUMS:
|
|||||||
flutter_uxcam: ab8e5d3954eb448febd581375e2622e9eecb1066
|
flutter_uxcam: ab8e5d3954eb448febd581375e2622e9eecb1066
|
||||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||||
google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc
|
google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc
|
||||||
GoogleAppMeasurement: fd19169c3034975cb934e865e5667bfdce59df7f
|
GoogleAppMeasurement: c6bbc9753d046b5456dd4f940057fbad2c28419e
|
||||||
GoogleDataTransport: cd9db2180fcecd8da1b561aea31e3e56cf834aa7
|
GoogleDataTransport: 11e3a5f2c190327df1a4a5d7e7ae3d4d5b9c9e4c
|
||||||
GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
|
GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
|
||||||
GoogleUtilities: 284cddc7fffc14ae1907efb6f78ab95c1fccaedc
|
GoogleUtilities: f8a43108b38a68eebe8b3540e1f4f2d28843ce20
|
||||||
GTMAppAuth: 197a8dabfea5d665224aa00d17f164fc2248dab9
|
GTMAppAuth: ad5c2b70b9a8689e1a04033c9369c4915bfcbe89
|
||||||
GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
|
GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
|
||||||
modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde
|
modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde
|
||||||
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
|
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
|
||||||
@ -387,12 +383,12 @@ SPEC CHECKSUMS:
|
|||||||
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
|
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
|
||||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||||
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
|
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
|
||||||
Purchases: b8b8fb6e856ac8166e217f6e014df894d821dda1
|
Purchases: 6351f9ff6bd514e5ec5aa0f989ea181effa94bf5
|
||||||
purchases_flutter: 0130970b895c903e4e0aad793dd3a4c1b70bb434
|
purchases_flutter: 627527b070d80cdaf486fabe8b3d1dbe8d5cad92
|
||||||
PurchasesCoreSwift: 8ae0f08e020f0bc97c1befa4e38a0dbc8e9732e0
|
PurchasesCoreSwift: ee857e4c21e6254b09d7e303a756fcf2b9164408
|
||||||
PurchasesHybridCommon: 5f5c1c245b12fc5e8760af7d11cb10f888109a9b
|
PurchasesHybridCommon: d65a799a61d688588534b80338edbcbf604ca93d
|
||||||
Sentry: 9b922b396b0e0bca8516a10e36b0ea3ebea5faf7
|
Sentry: 5b16f877da362d23716d827e04db642455b26b40
|
||||||
sentry_flutter: 5b3c6d717db5b7482504a313c831b318297d4d37
|
sentry_flutter: 602dc1902e152269256115e2386e1029511f3440
|
||||||
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
|
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
|
||||||
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
|
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
|
||||||
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
|
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
|
||||||
|
@ -388,7 +388,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 2;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@ -405,7 +405,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.1.17;
|
MARKETING_VERSION = 1.1.18;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@ -531,7 +531,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 2;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@ -548,7 +548,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.1.17;
|
MARKETING_VERSION = 1.1.18;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@ -566,7 +566,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 2;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@ -583,7 +583,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.1.17;
|
MARKETING_VERSION = 1.1.18;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
|
||||||
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
|
|
||||||
import 'package:aitrainer_app/model/cache.dart';
|
import 'package:aitrainer_app/model/cache.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_ability.dart';
|
import 'package:aitrainer_app/model/exercise_ability.dart';
|
||||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||||
|
@ -309,7 +309,6 @@ class TestSetExecuteBloc extends Bloc<TestSetExecuteEvent, TestSetExecuteState>
|
|||||||
|
|
||||||
bool existsActivePlan() {
|
bool existsActivePlan() {
|
||||||
final bool exists = exercisePlan != null && exercisePlanDetails != null && exercisePlanDetails!.isNotEmpty;
|
final bool exists = exercisePlan != null && exercisePlanDetails != null && exercisePlanDetails!.isNotEmpty;
|
||||||
print("Exists active plan: $exists");
|
|
||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:aitrainer_app/bloc/test_set_execute/test_set_execute_bloc.dart';
|
import 'package:aitrainer_app/bloc/test_set_execute/test_set_execute_bloc.dart';
|
||||||
|
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
|
||||||
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
|
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
|
||||||
import 'package:aitrainer_app/push_notifications.dart';
|
import 'package:aitrainer_app/push_notifications.dart';
|
||||||
import 'package:aitrainer_app/repository/customer_repository.dart';
|
import 'package:aitrainer_app/repository/customer_repository.dart';
|
||||||
|
import 'package:aitrainer_app/repository/training_plan_repository.dart';
|
||||||
import 'package:aitrainer_app/repository/workout_tree_repository.dart';
|
import 'package:aitrainer_app/repository/workout_tree_repository.dart';
|
||||||
import 'package:aitrainer_app/service/firebase_api.dart';
|
import 'package:aitrainer_app/service/firebase_api.dart';
|
||||||
import 'package:aitrainer_app/util/session.dart';
|
import 'package:aitrainer_app/util/session.dart';
|
||||||
@ -24,6 +26,7 @@ import 'package:aitrainer_app/view/exercise_plan_custom_detail_add_page.dart';
|
|||||||
import 'package:aitrainer_app/view/faq_page.dart';
|
import 'package:aitrainer_app/view/faq_page.dart';
|
||||||
import 'package:aitrainer_app/view/login.dart';
|
import 'package:aitrainer_app/view/login.dart';
|
||||||
import 'package:aitrainer_app/view/exercise_new_page.dart';
|
import 'package:aitrainer_app/view/exercise_new_page.dart';
|
||||||
|
import 'package:aitrainer_app/view/my_training_plans_page.dart';
|
||||||
import 'package:aitrainer_app/view/mydevelopment_body_page.dart';
|
import 'package:aitrainer_app/view/mydevelopment_body_page.dart';
|
||||||
import 'package:aitrainer_app/view/mydevelopment_muscle_page.dart';
|
import 'package:aitrainer_app/view/mydevelopment_muscle_page.dart';
|
||||||
import 'package:aitrainer_app/view/mydevelopment_page.dart';
|
import 'package:aitrainer_app/view/mydevelopment_page.dart';
|
||||||
@ -37,6 +40,9 @@ import 'package:aitrainer_app/view/test_set_control.dart';
|
|||||||
import 'package:aitrainer_app/view/test_set_edit.dart';
|
import 'package:aitrainer_app/view/test_set_edit.dart';
|
||||||
import 'package:aitrainer_app/view/test_set_execute.dart';
|
import 'package:aitrainer_app/view/test_set_execute.dart';
|
||||||
import 'package:aitrainer_app/view/test_set_new.dart';
|
import 'package:aitrainer_app/view/test_set_new.dart';
|
||||||
|
import 'package:aitrainer_app/view/training_plan_activate_page.dart';
|
||||||
|
import 'package:aitrainer_app/view/training_plan_execute_page.dart';
|
||||||
|
import 'package:aitrainer_app/view/training_plan_exercise.dart';
|
||||||
import 'package:aitrainer_app/widgets/home.dart';
|
import 'package:aitrainer_app/widgets/home.dart';
|
||||||
import 'package:aitrainer_app/library/facebook_app_events/facebook_app_events.dart';
|
import 'package:aitrainer_app/library/facebook_app_events/facebook_app_events.dart';
|
||||||
import 'package:firebase_analytics/firebase_analytics.dart';
|
import 'package:firebase_analytics/firebase_analytics.dart';
|
||||||
@ -178,6 +184,10 @@ Future<Null> main() async {
|
|||||||
create: (BuildContext context) => TestSetExecuteBloc(),
|
create: (BuildContext context) => TestSetExecuteBloc(),
|
||||||
),
|
),
|
||||||
BlocProvider<TutorialBloc>(create: (BuildContext context) => TutorialBloc(tutorialName: ActivityDone.tutorialBasic.toStr())),
|
BlocProvider<TutorialBloc>(create: (BuildContext context) => TutorialBloc(tutorialName: ActivityDone.tutorialBasic.toStr())),
|
||||||
|
BlocProvider<TrainingPlanBloc>(create: (context) {
|
||||||
|
final MenuBloc menuBloc = BlocProvider.of<MenuBloc>(context);
|
||||||
|
return TrainingPlanBloc(menuBloc: menuBloc, trainingPlanRepository: TrainingPlanRepository());
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
child: WorkoutTestApp(),
|
child: WorkoutTestApp(),
|
||||||
));
|
));
|
||||||
@ -262,6 +272,10 @@ class WorkoutTestApp extends StatelessWidget {
|
|||||||
'testSetNew': (context) => TestSetNew(),
|
'testSetNew': (context) => TestSetNew(),
|
||||||
'testSetControl': (context) => TestSetControl(),
|
'testSetControl': (context) => TestSetControl(),
|
||||||
'faqPage': (context) => FaqPage(),
|
'faqPage': (context) => FaqPage(),
|
||||||
|
'myTrainingPlans': (context) => MyTrainingPlans(),
|
||||||
|
'myTrainingPlanActivate': (context) => TrainingPlanActivatePage(),
|
||||||
|
'myTrainingPlanExecute': (context) => TrainingPlanExecutePage(),
|
||||||
|
'myTrainingPlanExercise': (context) => TrainingPlanExercise(),
|
||||||
},
|
},
|
||||||
initialRoute: 'home',
|
initialRoute: 'home',
|
||||||
title: 'WorkoutTest',
|
title: 'WorkoutTest',
|
||||||
|
@ -2,6 +2,7 @@ import 'dart:collection';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:aitrainer_app/model/customer.dart';
|
import 'package:aitrainer_app/model/customer.dart';
|
||||||
import 'package:aitrainer_app/model/customer_activity.dart';
|
import 'package:aitrainer_app/model/customer_activity.dart';
|
||||||
|
import 'package:aitrainer_app/model/customer_training_plan.dart';
|
||||||
import 'package:aitrainer_app/model/description.dart';
|
import 'package:aitrainer_app/model/description.dart';
|
||||||
import 'package:aitrainer_app/model/evaluation.dart';
|
import 'package:aitrainer_app/model/evaluation.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_plan.dart';
|
import 'package:aitrainer_app/model/exercise_plan.dart';
|
||||||
@ -17,6 +18,7 @@ import 'package:aitrainer_app/model/product_test.dart';
|
|||||||
import 'package:aitrainer_app/model/property.dart';
|
import 'package:aitrainer_app/model/property.dart';
|
||||||
import 'package:aitrainer_app/model/purchase.dart';
|
import 'package:aitrainer_app/model/purchase.dart';
|
||||||
import 'package:aitrainer_app/model/sport.dart';
|
import 'package:aitrainer_app/model/sport.dart';
|
||||||
|
import 'package:aitrainer_app/model/training_plan.dart';
|
||||||
import 'package:aitrainer_app/model/tutorial.dart';
|
import 'package:aitrainer_app/model/tutorial.dart';
|
||||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||||
import 'package:aitrainer_app/repository/customer_repository.dart';
|
import 'package:aitrainer_app/repository/customer_repository.dart';
|
||||||
@ -104,6 +106,7 @@ class Cache with Logging {
|
|||||||
static final String activeExercisePlanKey = "active_exercise_plan";
|
static final String activeExercisePlanKey = "active_exercise_plan";
|
||||||
static final String activeExercisePlanDateKey = "active_exercise_plan_date";
|
static final String activeExercisePlanDateKey = "active_exercise_plan_date";
|
||||||
static final String activeExercisePlanDetailsKey = "active_exercise_details_plan";
|
static final String activeExercisePlanDetailsKey = "active_exercise_details_plan";
|
||||||
|
static final String myTrainingPlanKey = "myTrainingPlan";
|
||||||
|
|
||||||
static String baseUrlLive = 'https://aitrainer.info:8943/api/';
|
static String baseUrlLive = 'https://aitrainer.info:8943/api/';
|
||||||
static String baseUrlTest = 'https://aitrainer.info:8843/api/';
|
static String baseUrlTest = 'https://aitrainer.info:8843/api/';
|
||||||
@ -137,14 +140,19 @@ class Cache with Logging {
|
|||||||
List<ExercisePlanTemplate> _exercisePlanTemplates = [];
|
List<ExercisePlanTemplate> _exercisePlanTemplates = [];
|
||||||
|
|
||||||
ExercisePlan? activeExercisePlan;
|
ExercisePlan? activeExercisePlan;
|
||||||
|
CustomerTrainingPlan? myTrainingPlan;
|
||||||
List<ExercisePlanDetail>? activeExercisePlanDetails;
|
List<ExercisePlanDetail>? activeExercisePlanDetails;
|
||||||
|
|
||||||
List<ExerciseDevice>? _devices;
|
List<ExerciseDevice>? _devices;
|
||||||
|
|
||||||
List<CustomerExerciseDevice>? _customerDevices;
|
List<CustomerExerciseDevice>? _customerDevices;
|
||||||
List<CustomerActivity>? _customerActivities;
|
List<CustomerActivity>? _customerActivities;
|
||||||
|
List<CustomerTrainingPlan>? _customerTrainingPlans;
|
||||||
|
|
||||||
List<Tutorial>? _tutorials;
|
List<Tutorial>? _tutorials;
|
||||||
List<Description>? _descriptions;
|
List<Description>? _descriptions;
|
||||||
List<Faq>? _faqs;
|
List<Faq>? _faqs;
|
||||||
|
List<TrainingPlan>? _trainingPlans;
|
||||||
|
|
||||||
LinkedHashMap<int, ExercisePlanDetail> _myExercisesPlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
|
LinkedHashMap<int, ExercisePlanDetail> _myExercisesPlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
|
||||||
|
|
||||||
@ -209,6 +217,33 @@ class Cache with Logging {
|
|||||||
sharedPreferences.setString(Cache.activeExercisePlanDateKey, savingDay);
|
sharedPreferences.setString(Cache.activeExercisePlanDateKey, savingDay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> saveMyTrainingPlan() async {
|
||||||
|
if (myTrainingPlan == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String myTrainingPlanJson = JsonEncoder().convert(myTrainingPlan!.toJsonWithDetails());
|
||||||
|
|
||||||
|
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
|
SharedPreferences sharedPreferences;
|
||||||
|
sharedPreferences = await prefs;
|
||||||
|
sharedPreferences.setString(Cache.myTrainingPlanKey, myTrainingPlanJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getMyTrainingPlan() async {
|
||||||
|
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
|
SharedPreferences sharedPreferences;
|
||||||
|
sharedPreferences = await prefs;
|
||||||
|
|
||||||
|
final String? savedTrainingPlanJson = sharedPreferences.getString(Cache.myTrainingPlanKey);
|
||||||
|
if (savedTrainingPlanJson == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, dynamic> map = JsonDecoder().convert(savedTrainingPlanJson);
|
||||||
|
print("Training plan: $savedTrainingPlanJson");
|
||||||
|
this.myTrainingPlan = CustomerTrainingPlan.fromJsonWithDetails(map);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> deleteActiveExercisePlan() async {
|
Future<void> deleteActiveExercisePlan() async {
|
||||||
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
SharedPreferences sharedPreferences;
|
SharedPreferences sharedPreferences;
|
||||||
@ -644,6 +679,8 @@ class Cache with Logging {
|
|||||||
await isActivityDonePrefs(activity);
|
await isActivityDonePrefs(activity);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await getMyTrainingPlan();
|
||||||
|
|
||||||
Cache().startPage = "home";
|
Cache().startPage = "home";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,4 +727,10 @@ class Cache with Logging {
|
|||||||
|
|
||||||
List<Faq>? getFaqs() => this._faqs;
|
List<Faq>? getFaqs() => this._faqs;
|
||||||
setFaqs(List<Faq>? value) => this._faqs = value;
|
setFaqs(List<Faq>? value) => this._faqs = value;
|
||||||
|
|
||||||
|
List<TrainingPlan>? getTrainingPlans() => this._trainingPlans;
|
||||||
|
setTrainingPlans(List<TrainingPlan>? value) => this._trainingPlans = value;
|
||||||
|
|
||||||
|
List<CustomerTrainingPlan>? getCustomerTrainingPlans() => this._customerTrainingPlans;
|
||||||
|
setCustomerTrainingPlans(value) => this._customerTrainingPlans = value;
|
||||||
}
|
}
|
||||||
|
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;
|
double? unitQuantity;
|
||||||
DateTime? dateAdd;
|
DateTime? dateAdd;
|
||||||
int? exercisePlanDetailId;
|
int? exercisePlanDetailId;
|
||||||
|
int? trainingPlanDetailsId;
|
||||||
|
|
||||||
String? datePart;
|
String? datePart;
|
||||||
double? calculated;
|
double? calculated;
|
||||||
@ -26,6 +27,8 @@ class Exercise {
|
|||||||
this.dateAdd = DateTime.parse(json['dateAdd']);
|
this.dateAdd = DateTime.parse(json['dateAdd']);
|
||||||
this.datePart = DateFormat('yyyy-MM-dd').format(this.dateAdd!);
|
this.datePart = DateFormat('yyyy-MM-dd').format(this.dateAdd!);
|
||||||
this.calculated = quantity;
|
this.calculated = quantity;
|
||||||
|
this.exercisePlanDetailId = json['exercisePlanDetailId'] == "null" ? null : json['exercisePlanDetailId'];
|
||||||
|
this.trainingPlanDetailsId = json['trainingPlanDetailsId'] == "null" ? null : json['trainingPlanDetailsId'];
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
@ -36,6 +39,7 @@ class Exercise {
|
|||||||
"unitQuantity": unitQuantity,
|
"unitQuantity": unitQuantity,
|
||||||
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!),
|
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!),
|
||||||
"exercisePlanDetailId": exercisePlanDetailId,
|
"exercisePlanDetailId": exercisePlanDetailId,
|
||||||
|
"trainingPlanDetailsId": trainingPlanDetailsId,
|
||||||
};
|
};
|
||||||
|
|
||||||
Map<String, dynamic> toJsonDatePart() => {
|
Map<String, dynamic> toJsonDatePart() => {
|
||||||
|
@ -18,7 +18,12 @@ class ExerciseTree {
|
|||||||
late String nameTranslation;
|
late String nameTranslation;
|
||||||
|
|
||||||
/// sort
|
/// sort
|
||||||
late int? sort;
|
int? sort;
|
||||||
|
|
||||||
|
String? internalName;
|
||||||
|
|
||||||
|
String? description;
|
||||||
|
String? descriptionTranslation;
|
||||||
|
|
||||||
ExerciseTree();
|
ExerciseTree();
|
||||||
|
|
||||||
@ -29,7 +34,12 @@ class ExerciseTree {
|
|||||||
this.imageUrl = json['imageUrl'];
|
this.imageUrl = json['imageUrl'];
|
||||||
this.active = json['active'];
|
this.active = json['active'];
|
||||||
this.nameTranslation = json['translations'] != null && (json['translations']).length > 0 ? json['translations'][0]['name'] : this.name;
|
this.nameTranslation = json['translations'] != null && (json['translations']).length > 0 ? json['translations'][0]['name'] : this.name;
|
||||||
|
this.descriptionTranslation =
|
||||||
|
json['translations'] != null && (json['translations']).length > 0 && json['translations'][0]['description'] != null
|
||||||
|
? json['translations'][0]['description']
|
||||||
|
: this.description;
|
||||||
this.sort = 99;
|
this.sort = 99;
|
||||||
|
this.internalName = json['internalName'];
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
@ -37,13 +47,18 @@ class ExerciseTree {
|
|||||||
"treeId": treeId,
|
"treeId": treeId,
|
||||||
"parentId": parentId,
|
"parentId": parentId,
|
||||||
"name": name,
|
"name": name,
|
||||||
|
"description": description,
|
||||||
"imageUrl": imageUrl,
|
"imageUrl": imageUrl,
|
||||||
"active": active.toString(),
|
"active": active.toString(),
|
||||||
"nameTranslation": nameTranslation,
|
"nameTranslation": nameTranslation,
|
||||||
|
"descriptionTranslation": descriptionTranslation,
|
||||||
"sort": sort,
|
"sort": sort,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => this.toJson().toString();
|
||||||
|
|
||||||
ExerciseTree copy(int parentId) {
|
ExerciseTree copy(int parentId) {
|
||||||
ExerciseTree newTree = ExerciseTree();
|
ExerciseTree newTree = ExerciseTree();
|
||||||
newTree.treeId = this.treeId;
|
newTree.treeId = this.treeId;
|
||||||
|
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 {
|
Future<List<ExerciseTree>> getExerciseTree() async {
|
||||||
final String body = await _client.get("exercise_tree", "");
|
final String body = await _client.get("exercise_tree", "");
|
||||||
Iterable json = jsonDecode(body);
|
Iterable json = jsonDecode(body);
|
||||||
List<ExerciseTree>? exerciseTree = json.map((exerciseTree) => ExerciseTree.fromJson(exerciseTree)).toList();
|
List<ExerciseTree>? exerciseTrees = json.map((exerciseTree) => ExerciseTree.fromJson(exerciseTree)).toList();
|
||||||
|
|
||||||
exerciseTree = await getExerciseTreeParents(exerciseTree);
|
exerciseTrees = await getExerciseTreeParents(exerciseTrees);
|
||||||
|
|
||||||
await Future.forEach(exerciseTree, (element) async {
|
await Future.forEach(exerciseTrees, (element) async {
|
||||||
ExerciseTree exerciseTree = element as ExerciseTree;
|
ExerciseTree exerciseTree = element as ExerciseTree;
|
||||||
exerciseTree.imageUrl = await buildImage(exerciseTree.imageUrl, exerciseTree.treeId);
|
exerciseTree.imageUrl = await buildImage(exerciseTree.imageUrl, exerciseTree.treeId);
|
||||||
});
|
});
|
||||||
exerciseTree = await getExerciseTreeParents(exerciseTree);
|
exerciseTrees = await getExerciseTreeParents(exerciseTrees);
|
||||||
log("ExerciseTree downloaded");
|
log("ExerciseTree downloaded $exerciseTrees");
|
||||||
Cache().setExerciseTree(exerciseTree);
|
Cache().setExerciseTree(exerciseTrees);
|
||||||
|
|
||||||
return exerciseTree;
|
return exerciseTrees;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> buildImage(String imageUrl, int treeId) async {
|
Future<String> buildImage(String imageUrl, int treeId) async {
|
||||||
|
@ -18,6 +18,7 @@ import 'package:aitrainer_app/model/product.dart';
|
|||||||
import 'package:aitrainer_app/model/product_test.dart';
|
import 'package:aitrainer_app/model/product_test.dart';
|
||||||
import 'package:aitrainer_app/model/property.dart';
|
import 'package:aitrainer_app/model/property.dart';
|
||||||
import 'package:aitrainer_app/model/purchase.dart';
|
import 'package:aitrainer_app/model/purchase.dart';
|
||||||
|
import 'package:aitrainer_app/model/training_plan.dart';
|
||||||
import 'package:aitrainer_app/model/tutorial.dart';
|
import 'package:aitrainer_app/model/tutorial.dart';
|
||||||
import 'package:aitrainer_app/service/api.dart';
|
import 'package:aitrainer_app/service/api.dart';
|
||||||
import 'package:aitrainer_app/service/exercise_type_service.dart';
|
import 'package:aitrainer_app/service/exercise_type_service.dart';
|
||||||
@ -86,6 +87,11 @@ class PackageApi {
|
|||||||
final List<Faq>? faqs = json.map((faq) => Faq.fromJson(faq)).toList();
|
final List<Faq>? faqs = json.map((faq) => Faq.fromJson(faq)).toList();
|
||||||
//print("Faq: $faqs");
|
//print("Faq: $faqs");
|
||||||
Cache().setFaqs(faqs);
|
Cache().setFaqs(faqs);
|
||||||
|
} else if (headRecord[0] == "TrainingPlan") {
|
||||||
|
final Iterable json = jsonDecode(headRecord[1]);
|
||||||
|
final List<TrainingPlan>? plans = json.map((plan) => TrainingPlan.fromJson(plan)).toList();
|
||||||
|
|
||||||
|
Cache().setTrainingPlans(plans);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -95,6 +101,7 @@ class PackageApi {
|
|||||||
ExerciseTree tree = element as ExerciseTree;
|
ExerciseTree tree = element as ExerciseTree;
|
||||||
tree.imageUrl = await ExerciseTreeApi().buildImage(tree.imageUrl, tree.treeId);
|
tree.imageUrl = await ExerciseTreeApi().buildImage(tree.imageUrl, tree.treeId);
|
||||||
});
|
});
|
||||||
|
//print("tree: $exerciseTree");
|
||||||
Cache().setExerciseTree(exerciseTree);
|
Cache().setExerciseTree(exerciseTree);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
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 'dart:convert';
|
||||||
|
|
||||||
import 'package:aitrainer_app/util/app_language.dart';
|
import 'package:aitrainer_app/util/app_language.dart';
|
||||||
import 'package:aitrainer_app/model/cache.dart';
|
import 'package:aitrainer_app/model/cache.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_type.dart';
|
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||||
@ -144,4 +143,62 @@ mixin Common {
|
|||||||
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
|
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double calculate1RM(double weight, double repeat) {
|
||||||
|
if (weight == 0 || repeat == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rmWendler = weight * repeat * 0.0333 + weight;
|
||||||
|
double rmOconner = weight * (1 + repeat / 40);
|
||||||
|
//print("Weight: $weight repeat: $repeat, $rmWendler, Oconner: $rmOconner");
|
||||||
|
double average = (rmWendler + rmOconner) / 2;
|
||||||
|
|
||||||
|
return average;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double get1RMPercent(int repeats) {
|
||||||
|
double percent = 1;
|
||||||
|
|
||||||
|
if (repeats >= 35) {
|
||||||
|
percent = 0.50;
|
||||||
|
} else if (repeats > 12) {
|
||||||
|
percent = (100 - 2 * repeats) / 100;
|
||||||
|
} else {
|
||||||
|
percent = (100.0 - 2 * repeats) / 100;
|
||||||
|
}
|
||||||
|
//print("1RM Percent: $percent repeats: $repeats");
|
||||||
|
return percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double roundWeight(double weight) {
|
||||||
|
double rounded = weight.round().toDouble();
|
||||||
|
|
||||||
|
if (weight > 35) {
|
||||||
|
final double remainder = weight % 5;
|
||||||
|
if (remainder < 1.25) {
|
||||||
|
rounded = ((weight / 5).floor() * 5).toDouble();
|
||||||
|
} else if (remainder > 1.25 && remainder <= 2.5) {
|
||||||
|
rounded = (weight / 5).floor() * 5 + 2.5;
|
||||||
|
} else if (remainder > 2.5 && remainder < 3.75) {
|
||||||
|
rounded = (weight / 5).floor() * 5 + 2.5;
|
||||||
|
} else {
|
||||||
|
rounded = (((weight / 5).ceil() * 5) + 5).toDouble();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rounded;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int calculateQuantityByChangedWeight(double initialRM, double weight, double repeat) {
|
||||||
|
final double rmWendler = weight * repeat * 0.0333 + weight;
|
||||||
|
final double rmOconner = weight * (1 + repeat / 40);
|
||||||
|
//print("Weight: $weight oneRepQuantity: $repeat, $rmWendler, Oconner: $rmOconner");
|
||||||
|
|
||||||
|
final double repeatWendler = (rmWendler - weight) / 0.0333 / weight;
|
||||||
|
final double repeatOconner = (rmOconner / weight - 1) * 40;
|
||||||
|
final newRepeat = ((repeatOconner + repeatWendler) / 2).ceil();
|
||||||
|
//print("Initial 1RM: $initialRM Weight: $weight repeatWendler: $repeatWendler repeat Oconner: $repeatOconner. NEW REPEAT: $newRepeat");
|
||||||
|
return newRepeat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ class AccountPage extends StatelessWidget with Trans {
|
|||||||
),
|
),
|
||||||
devices(context, accountBloc),
|
devices(context, accountBloc),
|
||||||
loginOut(context, accountBloc),
|
loginOut(context, accountBloc),
|
||||||
getMyTrainees(context, accountBloc),
|
//getMyTrainees(context, accountBloc),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,9 +141,9 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
|
|||||||
unitQuantityUnit: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit,
|
unitQuantityUnit: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit,
|
||||||
hasUnitQuantity: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit != null,
|
hasUnitQuantity: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit != null,
|
||||||
onQuantityChanged: (value) {
|
onQuantityChanged: (value) {
|
||||||
exerciseBloc.add(ExerciseNewQuantityChange(quantity: double.parse(value)));
|
exerciseBloc.add(ExerciseNewQuantityChange(quantity: value));
|
||||||
},
|
},
|
||||||
onUnitQuantityChanged: (value) => exerciseBloc.add(ExerciseNewQuantityUnitChange(quantity: double.parse(value))),
|
onUnitQuantityChanged: (value) => exerciseBloc.add(ExerciseNewQuantityUnitChange(quantity: value)),
|
||||||
//onSubmit: () => confirmationDialog(exerciseBloc, menuBloc),
|
//onSubmit: () => confirmationDialog(exerciseBloc, menuBloc),
|
||||||
exerciseTypeId: exerciseType.exerciseTypeId,
|
exerciseTypeId: exerciseType.exerciseTypeId,
|
||||||
)),
|
)),
|
||||||
|
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,
|
unitQuantityUnit: bloc.exerciseType.unitQuantityUnit,
|
||||||
hasUnitQuantity: bloc.exerciseType.unitQuantityUnit != null,
|
hasUnitQuantity: bloc.exerciseType.unitQuantityUnit != null,
|
||||||
onQuantityChanged: (value) {
|
onQuantityChanged: (value) {
|
||||||
bloc.add(TestSetNewChangeQuantity(quantity: double.parse(value)));
|
bloc.add(TestSetNewChangeQuantity(quantity: value));
|
||||||
},
|
},
|
||||||
onUnitQuantityChanged: (value) => bloc.add(TestSetNewChangeQuantityUnit(quantity: double.parse(value))),
|
onUnitQuantityChanged: (value) => bloc.add(TestSetNewChangeQuantityUnit(quantity: value)),
|
||||||
exerciseTypeId: bloc.exerciseType.exerciseTypeId,
|
exerciseTypeId: bloc.exerciseType.exerciseTypeId,
|
||||||
/* onSubmit: () {
|
/* onSubmit: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
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:
|
case 2:
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
Track().track(TrackingEvent.my_exerciseplan);
|
Track().track(TrackingEvent.my_exerciseplan);
|
||||||
Navigator.of(context).pushNamed('myExercisePlan');
|
Navigator.of(context).pushNamed('myTrainingPlans');
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -12,8 +12,8 @@ import 'dialog_html.dart';
|
|||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class ExerciseSave extends StatefulWidget {
|
class ExerciseSave extends StatefulWidget {
|
||||||
final ValueChanged<dynamic> onQuantityChanged;
|
final ValueChanged<double> onQuantityChanged;
|
||||||
final ValueChanged<dynamic>? onUnitQuantityChanged;
|
final ValueChanged<double>? onUnitQuantityChanged;
|
||||||
final VoidCallback? onSubmit;
|
final VoidCallback? onSubmit;
|
||||||
final bool hasUnitQuantity;
|
final bool hasUnitQuantity;
|
||||||
final String? unitQuantityUnit;
|
final String? unitQuantityUnit;
|
||||||
@ -22,18 +22,23 @@ class ExerciseSave extends StatefulWidget {
|
|||||||
final String exerciseDescription;
|
final String exerciseDescription;
|
||||||
final String exerciseTask;
|
final String exerciseTask;
|
||||||
final int exerciseTypeId;
|
final int exerciseTypeId;
|
||||||
|
final double? weight;
|
||||||
|
final int? repeats;
|
||||||
|
|
||||||
ExerciseSave(
|
ExerciseSave({
|
||||||
{required this.onQuantityChanged,
|
required this.onQuantityChanged,
|
||||||
this.onUnitQuantityChanged,
|
this.onUnitQuantityChanged,
|
||||||
this.onSubmit,
|
this.onSubmit,
|
||||||
required this.hasUnitQuantity,
|
required this.hasUnitQuantity,
|
||||||
this.unitQuantityUnit,
|
this.unitQuantityUnit,
|
||||||
required this.unit,
|
required this.unit,
|
||||||
required this.exerciseName,
|
required this.exerciseName,
|
||||||
required this.exerciseDescription,
|
required this.exerciseDescription,
|
||||||
required this.exerciseTask,
|
required this.exerciseTask,
|
||||||
required this.exerciseTypeId});
|
required this.exerciseTypeId,
|
||||||
|
this.weight,
|
||||||
|
this.repeats,
|
||||||
|
});
|
||||||
@override
|
@override
|
||||||
_ExerciseSaveState createState() => _ExerciseSaveState();
|
_ExerciseSaveState createState() => _ExerciseSaveState();
|
||||||
}
|
}
|
||||||
@ -53,11 +58,15 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
|||||||
return getExerciseWidget();
|
return getExerciseWidget();
|
||||||
}
|
}
|
||||||
|
|
||||||
//@override
|
@override
|
||||||
initState() {
|
initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_controller1.text = "30";
|
_controller1.text = widget.weight == null
|
||||||
_controller2.text = "12";
|
? "30"
|
||||||
|
: widget.weight! % widget.weight!.round() == 0
|
||||||
|
? widget.weight!.toStringAsFixed(0)
|
||||||
|
: widget.weight!.toStringAsFixed(1);
|
||||||
|
_controller2.text = widget.repeats == null ? "12" : widget.repeats!.toStringAsFixed(0);
|
||||||
_nodeText1.addListener(() {
|
_nodeText1.addListener(() {
|
||||||
if (_nodeText1.hasFocus) {
|
if (_nodeText1.hasFocus) {
|
||||||
_controller1.selection = TextSelection(baseOffset: 0, extentOffset: _controller1.text.length);
|
_controller1.selection = TextSelection(baseOffset: 0, extentOffset: _controller1.text.length);
|
||||||
@ -69,7 +78,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (widget.unit == "second") {
|
if (widget.unit == "second") {
|
||||||
stopWatchTimer.rawTime.listen((value) => widget.onQuantityChanged((value / 1000).toString()));
|
stopWatchTimer.rawTime.listen((value) => widget.onQuantityChanged((value / 1000)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,6 +199,18 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
|||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Colors.orange,
|
color: Colors.orange,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
shadows: <Shadow>[
|
||||||
|
Shadow(
|
||||||
|
offset: Offset(2.0, 2.0),
|
||||||
|
blurRadius: 6.0,
|
||||||
|
color: Colors.black54,
|
||||||
|
),
|
||||||
|
Shadow(
|
||||||
|
offset: Offset(-3.0, 3.0),
|
||||||
|
blurRadius: 12.0,
|
||||||
|
color: Colors.black54,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
@ -258,7 +279,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
|||||||
onChanged: (value) => {
|
onChanged: (value) => {
|
||||||
value = value.replaceFirst(",", "."),
|
value = value.replaceFirst(",", "."),
|
||||||
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
||||||
widget.onUnitQuantityChanged!(value),
|
widget.onUnitQuantityChanged!(double.parse(value)),
|
||||||
}),
|
}),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
@ -273,7 +294,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
|||||||
//padding: const EdgeInsets.only(bottom: 0),
|
//padding: const EdgeInsets.only(bottom: 0),
|
||||||
child: StreamBuilder<int>(
|
child: StreamBuilder<int>(
|
||||||
stream: stopWatchTimer.rawTime,
|
stream: stopWatchTimer.rawTime,
|
||||||
initialData: stopWatchTimer.rawTime.valueWrapper?.value,
|
initialData: stopWatchTimer.rawTime.value,
|
||||||
builder: (context, snap) {
|
builder: (context, snap) {
|
||||||
final value = snap.data;
|
final value = snap.data;
|
||||||
final displayTime = StopWatchTimer.getDisplayTime(value!, hours: false);
|
final displayTime = StopWatchTimer.getDisplayTime(value!, hours: false);
|
||||||
@ -344,7 +365,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
|||||||
Divider(),
|
Divider(),
|
||||||
Divider(),
|
Divider(),
|
||||||
Text(t("Or type the time manually:"), style: GoogleFonts.inter(color: Colors.white)),
|
Text(t("Or type the time manually:"), style: GoogleFonts.inter(color: Colors.white)),
|
||||||
TimePickerWidget(onChange: (value) => widget.onQuantityChanged((value).toString()))
|
TimePickerWidget(onChange: (value) => widget.onQuantityChanged((value)))
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
Widget row = Container(
|
Widget row = Container(
|
||||||
@ -369,7 +390,9 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
|||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.orange[200]),
|
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.orange[200]),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
widget.onQuantityChanged(value);
|
value = value.replaceFirst(",", ".");
|
||||||
|
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
|
||||||
|
widget.onQuantityChanged(double.parse(value));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]));
|
]));
|
||||||
|
@ -22,6 +22,7 @@ class ImageButton extends StatelessWidget {
|
|||||||
final bool? isLocked;
|
final bool? isLocked;
|
||||||
bool? isMarked;
|
bool? isMarked;
|
||||||
int? buttonIndex;
|
int? buttonIndex;
|
||||||
|
Color? textColor;
|
||||||
|
|
||||||
ImageButton(
|
ImageButton(
|
||||||
{required this.text,
|
{required this.text,
|
||||||
@ -37,11 +38,13 @@ class ImageButton extends StatelessWidget {
|
|||||||
this.onTap,
|
this.onTap,
|
||||||
this.buttonIndex,
|
this.buttonIndex,
|
||||||
this.isMarked,
|
this.isMarked,
|
||||||
required this.isLocked}) {
|
required this.isLocked,
|
||||||
|
this.textColor}) {
|
||||||
width = width ?? 180;
|
width = width ?? 180;
|
||||||
height = height ?? 180;
|
height = height ?? 180;
|
||||||
isMarked = isMarked ?? false;
|
isMarked = isMarked ?? false;
|
||||||
isShape = isShape ?? false;
|
isShape = isShape ?? false;
|
||||||
|
textColor = textColor ?? Colors.white;
|
||||||
style = style ??
|
style = style ??
|
||||||
GoogleFonts.archivoBlack(
|
GoogleFonts.archivoBlack(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@ -54,10 +57,9 @@ class ImageButton extends StatelessWidget {
|
|||||||
top = height! - (style!.fontSize! - 5) * text.length - 2 * left < 0
|
top = height! - (style!.fontSize! - 5) * text.length - 2 * left < 0
|
||||||
? height! - 2 * style!.fontSize! - 22
|
? height! - 2 * style!.fontSize! - 22
|
||||||
: height! - style!.fontSize! - 37;
|
: height! - style!.fontSize! - 37;
|
||||||
//print("Top: " + top.toStringAsFixed(0) + " length: " + ((style.fontSize - 5) * text.length).toString());
|
|
||||||
}
|
}
|
||||||
final double width = MediaQuery.of(context).size.width;
|
final double width = MediaQuery.of(context).size.width;
|
||||||
//print("Mediawidth: " + width.toStringAsFixed(0));
|
|
||||||
return Stack(alignment: AlignmentDirectional.bottomStart, children: [
|
return Stack(alignment: AlignmentDirectional.bottomStart, children: [
|
||||||
TextButton(
|
TextButton(
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
@ -93,7 +95,7 @@ class ImageButton extends StatelessWidget {
|
|||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
style: GoogleFonts.archivoBlack(
|
style: GoogleFonts.archivoBlack(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: Colors.white,
|
color: textColor,
|
||||||
shadows: <Shadow>[
|
shadows: <Shadow>[
|
||||||
Shadow(
|
Shadow(
|
||||||
offset: Offset(2.0, 2.0),
|
offset: Offset(2.0, 2.0),
|
||||||
|
@ -7,7 +7,12 @@ import 'package:aitrainer_app/library/transparent_image.dart';
|
|||||||
class MenuImage extends StatelessWidget {
|
class MenuImage extends StatelessWidget {
|
||||||
final int? workoutTreeId;
|
final int? workoutTreeId;
|
||||||
final String imageName;
|
final String imageName;
|
||||||
const MenuImage({required this.workoutTreeId, required this.imageName});
|
double radius;
|
||||||
|
MenuImage({
|
||||||
|
required this.workoutTreeId,
|
||||||
|
required this.imageName,
|
||||||
|
this.radius = 24,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -31,7 +36,7 @@ class MenuImage extends StatelessWidget {
|
|||||||
if (imageName.contains("https")) {
|
if (imageName.contains("https")) {
|
||||||
if (!wt.ImageCache().existsImageInMap(workoutTreeId!, imageName)) {
|
if (!wt.ImageCache().existsImageInMap(workoutTreeId!, imageName)) {
|
||||||
widget = ClipRRect(
|
widget = ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(24.0),
|
borderRadius: BorderRadius.circular(radius),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: FadeInImage(
|
child: FadeInImage(
|
||||||
@ -43,7 +48,7 @@ class MenuImage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
widget = ClipRRect(
|
widget = ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(24.0),
|
borderRadius: BorderRadius.circular(radius),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: Image.asset(imageName),
|
child: Image.asset(imageName),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
|
||||||
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
|
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_ability.dart';
|
import 'package:aitrainer_app/model/exercise_ability.dart';
|
||||||
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||||
@ -47,7 +48,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
if (activeExercisePlan) {
|
if (activeExercisePlan || Cache().myTrainingPlan != null) {
|
||||||
animation.start();
|
animation.start();
|
||||||
animation.addStatusListener((status) {
|
animation.addStatusListener((status) {
|
||||||
if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) {
|
if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) {
|
||||||
@ -313,6 +314,46 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
Cache().myTrainingPlan != null
|
||||||
|
? GestureDetector(
|
||||||
|
onTap: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return DialogCommon(
|
||||||
|
title: t("You have an active Training Plan"),
|
||||||
|
descriptions: Cache().myTrainingPlan!.name != null ? Cache().myTrainingPlan!.name! : "",
|
||||||
|
description2: t("Press OK to continue"),
|
||||||
|
text: "OK",
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
if (Cache().myTrainingPlan != null) {
|
||||||
|
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
|
||||||
|
bloc.myPlan = Cache().myTrainingPlan;
|
||||||
|
Navigator.of(context).pushNamed("myTrainingPlanExecute");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCancel: () => {
|
||||||
|
Navigator.of(context).pop(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
child: AnimatedBuilder(
|
||||||
|
animation: animation,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
return Center(
|
||||||
|
child: Container(
|
||||||
|
width: animation.value,
|
||||||
|
height: animation.value,
|
||||||
|
child: Image.asset("asset/image/pict_hypertrophy.png"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}))
|
||||||
|
: Offstage(),
|
||||||
|
activeExercisePlan
|
||||||
|
? SizedBox(
|
||||||
|
width: 10,
|
||||||
|
)
|
||||||
|
: Offstage(),
|
||||||
Cache().activeExercisePlan != null
|
Cache().activeExercisePlan != null
|
||||||
? GestureDetector(
|
? GestureDetector(
|
||||||
onTap: () => showDialog(
|
onTap: () => showDialog(
|
||||||
|
120
pubspec.lock
@ -56,7 +56,7 @@ packages:
|
|||||||
name: badges
|
name: badges
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0-nullsafety.1"
|
version: "2.0.1"
|
||||||
bloc:
|
bloc:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -231,7 +231,7 @@ packages:
|
|||||||
name: coverage
|
name: coverage
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.2"
|
version: "1.0.2"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -239,13 +239,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
css_colors:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: css_colors
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.0"
|
|
||||||
csslib:
|
csslib:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -280,7 +273,7 @@ packages:
|
|||||||
name: equatable
|
name: equatable
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.2"
|
||||||
ezanimation:
|
ezanimation:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -322,98 +315,98 @@ packages:
|
|||||||
name: firebase_analytics
|
name: firebase_analytics
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.0.2"
|
version: "8.1.0"
|
||||||
firebase_analytics_platform_interface:
|
firebase_analytics_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_analytics_platform_interface
|
name: firebase_analytics_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.1"
|
||||||
firebase_analytics_web:
|
firebase_analytics_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_analytics_web
|
name: firebase_analytics_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.0"
|
version: "0.3.0+1"
|
||||||
firebase_auth:
|
firebase_auth:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: firebase_auth
|
name: firebase_auth
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.2.0"
|
||||||
firebase_auth_platform_interface:
|
firebase_auth_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_auth_platform_interface
|
name: firebase_auth_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.0"
|
version: "4.2.3"
|
||||||
firebase_auth_web:
|
firebase_auth_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_auth_web
|
name: firebase_auth_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.3"
|
||||||
firebase_core:
|
firebase_core:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: firebase_core
|
name: firebase_core
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.2.0"
|
||||||
firebase_core_platform_interface:
|
firebase_core_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_core_platform_interface
|
name: firebase_core_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "4.0.1"
|
||||||
firebase_core_web:
|
firebase_core_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_core_web
|
name: firebase_core_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "1.1.0"
|
||||||
firebase_messaging:
|
firebase_messaging:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: firebase_messaging
|
name: firebase_messaging
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.1.3"
|
version: "10.0.0"
|
||||||
firebase_messaging_platform_interface:
|
firebase_messaging_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_messaging_platform_interface
|
name: firebase_messaging_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.3"
|
version: "3.0.0"
|
||||||
firebase_messaging_web:
|
firebase_messaging_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_messaging_web
|
name: firebase_messaging_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.6"
|
version: "2.0.0"
|
||||||
firebase_remote_config:
|
firebase_remote_config:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: firebase_remote_config
|
name: firebase_remote_config
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.10.0-dev.2"
|
version: "0.10.0"
|
||||||
firebase_remote_config_platform_interface:
|
firebase_remote_config_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_remote_config_platform_interface
|
name: firebase_remote_config_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.0-dev.2"
|
version: "0.3.0"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -427,7 +420,7 @@ packages:
|
|||||||
name: fl_chart
|
name: fl_chart
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.30.0"
|
version: "0.36.1"
|
||||||
flurry:
|
flurry:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -460,21 +453,21 @@ packages:
|
|||||||
name: flutter_facebook_auth
|
name: flutter_facebook_auth
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.2+2"
|
version: "3.4.0"
|
||||||
flutter_facebook_auth_platform_interface:
|
flutter_facebook_auth_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_facebook_auth_platform_interface
|
name: flutter_facebook_auth_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.1"
|
version: "2.6.0"
|
||||||
flutter_facebook_auth_web:
|
flutter_facebook_auth_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_facebook_auth_web
|
name: flutter_facebook_auth_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.1+1"
|
version: "2.6.0"
|
||||||
flutter_fadein:
|
flutter_fadein:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -488,7 +481,7 @@ packages:
|
|||||||
name: flutter_html
|
name: flutter_html
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0-nullsafety.0"
|
version: "2.0.0"
|
||||||
flutter_launcher_icons:
|
flutter_launcher_icons:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -509,7 +502,7 @@ packages:
|
|||||||
name: flutter_local_notifications
|
name: flutter_local_notifications
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "5.0.0+4"
|
||||||
flutter_local_notifications_platform_interface:
|
flutter_local_notifications_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -522,20 +515,27 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_math_fork:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_math_fork
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.3"
|
||||||
flutter_secure_storage:
|
flutter_secure_storage:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_secure_storage
|
name: flutter_secure_storage
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
version: "4.2.0"
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_svg
|
name: flutter_svg
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.21.0-nullsafety.0"
|
version: "0.22.0"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -566,14 +566,14 @@ packages:
|
|||||||
name: google_fonts
|
name: google_fonts
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.1.0"
|
||||||
google_sign_in:
|
google_sign_in:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: google_sign_in
|
name: google_sign_in
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.1"
|
version: "5.0.3"
|
||||||
google_sign_in_platform_interface:
|
google_sign_in_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -615,7 +615,7 @@ packages:
|
|||||||
name: http_multi_server
|
name: http_multi_server
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "3.0.1"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -650,7 +650,7 @@ packages:
|
|||||||
name: io
|
name: io
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.4"
|
version: "1.0.0"
|
||||||
js:
|
js:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -699,7 +699,7 @@ packages:
|
|||||||
name: mime
|
name: mime
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.9.7"
|
version: "1.0.0"
|
||||||
mockito:
|
mockito:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -804,14 +804,14 @@ packages:
|
|||||||
name: path_drawing
|
name: path_drawing
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0-nullsafety.0"
|
version: "0.5.1"
|
||||||
path_parsing:
|
path_parsing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_parsing
|
name: path_parsing
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0-nullsafety.0"
|
version: "0.2.1"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -923,7 +923,7 @@ packages:
|
|||||||
name: purchases_flutter
|
name: purchases_flutter
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.1"
|
version: "3.2.2"
|
||||||
quiver:
|
quiver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -958,21 +958,21 @@ packages:
|
|||||||
name: rxdart
|
name: rxdart
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.26.0"
|
version: "0.27.0"
|
||||||
sentry:
|
sentry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sentry
|
name: sentry
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "5.1.0-beta.1"
|
||||||
sentry_flutter:
|
sentry_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sentry_flutter
|
name: sentry_flutter
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "5.1.0-beta.1"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -1028,21 +1028,21 @@ packages:
|
|||||||
name: shelf_packages_handler
|
name: shelf_packages_handler
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "3.0.0"
|
||||||
shelf_static:
|
shelf_static:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf_static
|
name: shelf_static
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.9+2"
|
version: "1.0.0"
|
||||||
shelf_web_socket:
|
shelf_web_socket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf_web_socket
|
name: shelf_web_socket
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.4+1"
|
version: "1.0.1"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -1110,7 +1110,7 @@ packages:
|
|||||||
name: stop_watch_timer
|
name: stop_watch_timer
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.2.0+1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1138,7 +1138,14 @@ packages:
|
|||||||
name: syncfusion_flutter_core
|
name: syncfusion_flutter_core
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "19.1.63"
|
version: "19.1.64"
|
||||||
|
syncfusion_flutter_datagrid:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: syncfusion_flutter_datagrid
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "19.1.64-beta"
|
||||||
syncfusion_flutter_gauges:
|
syncfusion_flutter_gauges:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1194,7 +1201,7 @@ packages:
|
|||||||
name: timezone
|
name: timezone
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.0-nullsafety.0"
|
version: "0.7.0"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1209,6 +1216,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.9"
|
version: "0.1.9"
|
||||||
|
tuple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: tuple
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1278,7 +1292,7 @@ packages:
|
|||||||
name: video_player
|
name: video_player
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.1"
|
||||||
video_player_platform_interface:
|
video_player_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1299,7 +1313,7 @@ packages:
|
|||||||
name: vm_service
|
name: vm_service
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.5.0"
|
version: "6.2.0"
|
||||||
wakelock:
|
wakelock:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1341,7 +1355,7 @@ packages:
|
|||||||
name: web_socket_channel
|
name: web_socket_channel
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "2.1.0"
|
||||||
webkit_inspection_protocol:
|
webkit_inspection_protocol:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1355,7 +1369,7 @@ packages:
|
|||||||
name: webview_flutter
|
name: webview_flutter
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.7"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
47
pubspec.yaml
@ -25,28 +25,28 @@ dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
cupertino_icons: ^1.0.0
|
cupertino_icons: ^1.0.0
|
||||||
google_fonts: ^2.0.0
|
google_fonts: ^2.1.0
|
||||||
devicelocale: ^0.4.1
|
devicelocale: ^0.4.1
|
||||||
sentry_flutter: ^5.0.0
|
sentry_flutter: ^5.1.0-beta.1
|
||||||
flutter_bloc: ^7.0.0
|
flutter_bloc: ^7.0.0
|
||||||
equatable: ^2.0.0
|
equatable: ^2.0.2
|
||||||
|
|
||||||
spider_chart: ^0.1.5
|
spider_chart: ^0.1.5
|
||||||
rainbow_color: ^2.0.1
|
rainbow_color: ^2.0.1
|
||||||
percent_indicator: ^ 3.3.0-nullsafety.1
|
percent_indicator: ^ 3.3.0-nullsafety.1
|
||||||
fl_chart: ^0.30.0
|
fl_chart: ^0.36.1
|
||||||
infinite_listview: ^1.1.0
|
infinite_listview: ^1.1.0
|
||||||
toggle_switch: ^0.1.9
|
toggle_switch: ^0.1.9
|
||||||
keyboard_actions: ^3.4.0
|
keyboard_actions: ^3.4.0
|
||||||
badges: ^ 2.0.0-nullsafety.1
|
badges: ^ 2.0.1
|
||||||
#health: ^3.0.0
|
#health: ^3.0.0
|
||||||
stop_watch_timer: ^1.0.0
|
stop_watch_timer: ^1.2.0+1
|
||||||
#location: ^3.2.4
|
#location: ^3.2.4
|
||||||
modal_progress_hud_nsn: ^0.1.0-nullsafety-1
|
modal_progress_hud_nsn: ^0.1.0-nullsafety-1
|
||||||
flutter_html: ^2.0.0-nullsafety.0
|
flutter_html: ^2.0.0
|
||||||
wakelock: ^ 0.4.0
|
wakelock: ^ 0.4.0
|
||||||
timeline_tile: ^2.0.0
|
timeline_tile: ^2.0.0
|
||||||
purchases_flutter: ^3.2.1
|
purchases_flutter: ^3.2.2
|
||||||
package_info: ^2.0.0
|
package_info: ^2.0.0
|
||||||
ezanimation: ^0.5.0
|
ezanimation: ^0.5.0
|
||||||
flutter_fadein: ^2.0.0
|
flutter_fadein: ^2.0.0
|
||||||
@ -59,18 +59,20 @@ dependencies:
|
|||||||
#super_tooltip: ^1.0.1
|
#super_tooltip: ^1.0.1
|
||||||
url_launcher: ^6.0.3
|
url_launcher: ^6.0.3
|
||||||
|
|
||||||
firebase_core: ^1.1.0
|
firebase_core: ^1.2.0
|
||||||
firebase_analytics: ^8.0.2
|
firebase_analytics: ^8.1.0
|
||||||
firebase_messaging: ^9.1.3
|
firebase_messaging: ^10.0.0
|
||||||
flutter_local_notifications: ^5.0.0
|
flutter_local_notifications: ^5.0.0
|
||||||
firebase_auth: ^1.1.2
|
firebase_auth: ^1.2.0
|
||||||
firebase_remote_config: ^0.10.0-dev.2
|
firebase_remote_config: ^0.10.0
|
||||||
|
|
||||||
syncfusion_flutter_gauges: ^19.1.63
|
syncfusion_flutter_gauges: ^19.1.63
|
||||||
|
syncfusion_flutter_datagrid: ^19.1.63
|
||||||
|
|
||||||
flutter_facebook_auth: ^3.3.2
|
flutter_facebook_auth: ^3.4.0
|
||||||
google_sign_in: ^5.0.1
|
google_sign_in: ^5.0.3
|
||||||
apple_sign_in: ^0.1.0
|
apple_sign_in: ^0.1.0
|
||||||
|
#sign_in_with_apple: ^3.0.0
|
||||||
|
|
||||||
#smartlook: ^1.0.7
|
#smartlook: ^1.0.7
|
||||||
flurry: ^0.0.4
|
flurry: ^0.0.4
|
||||||
@ -80,7 +82,7 @@ dependencies:
|
|||||||
|
|
||||||
mockito: ^5.0.3
|
mockito: ^5.0.3
|
||||||
sqflite: ^2.0.0+3
|
sqflite: ^2.0.0+3
|
||||||
flutter_secure_storage: ^4.1.0
|
flutter_secure_storage: ^4.2.0
|
||||||
#social_share: ^2.1.1
|
#social_share: ^2.1.1
|
||||||
|
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
@ -383,6 +385,19 @@ flutter:
|
|||||||
- asset/menu/test_center.jpg
|
- asset/menu/test_center.jpg
|
||||||
- asset/menu/test_on_machines.jpg
|
- asset/menu/test_on_machines.jpg
|
||||||
- asset/menu/thigh_adductor.jpg
|
- asset/menu/thigh_adductor.jpg
|
||||||
|
- asset/menu/training_plans_menu.jpg
|
||||||
|
- asset/menu/training_plans_woman.jpg
|
||||||
|
- asset/menu/training_plans_home.jpg
|
||||||
|
- asset/menu/training_plans_celebrities.jpg
|
||||||
|
- asset/menu/training_plans_beginner.jpg
|
||||||
|
- asset/menu/training_plans_advanced.jpg
|
||||||
|
- asset/menu/training_plans_strength_gain.jpg
|
||||||
|
- asset/menu/training_plans_q_woman.jpg
|
||||||
|
- asset/menu/training_plans_q_home.jpg
|
||||||
|
- asset/menu/training_plans_q_celebrities.jpg
|
||||||
|
- asset/menu/training_plans_q_beginner.jpg
|
||||||
|
- asset/menu/training_plans_q_advanced.jpg
|
||||||
|
- asset/menu/training_plans_q_gain_strength.jpg
|
||||||
- asset/menu/triceps_extension_on_cable_with_rope.jpg
|
- asset/menu/triceps_extension_on_cable_with_rope.jpg
|
||||||
- asset/menu/triceps_kickback.jpg
|
- asset/menu/triceps_kickback.jpg
|
||||||
- asset/menu/triceps_pushdown.jpg
|
- asset/menu/triceps_pushdown.jpg
|
||||||
|