WT 1.1.8+1 TrainingPlan

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,6 +18,7 @@ import 'package:aitrainer_app/model/product.dart';
import 'package:aitrainer_app/model/product_test.dart';
import 'package:aitrainer_app/model/property.dart';
import 'package:aitrainer_app/model/purchase.dart';
import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/model/tutorial.dart';
import 'package:aitrainer_app/service/api.dart';
import 'package:aitrainer_app/service/exercise_type_service.dart';
@ -86,6 +87,11 @@ class PackageApi {
final List<Faq>? faqs = json.map((faq) => Faq.fromJson(faq)).toList();
//print("Faq: $faqs");
Cache().setFaqs(faqs);
} else if (headRecord[0] == "TrainingPlan") {
final Iterable json = jsonDecode(headRecord[1]);
final List<TrainingPlan>? plans = json.map((plan) => TrainingPlan.fromJson(plan)).toList();
Cache().setTrainingPlans(plans);
}
});
@ -95,6 +101,7 @@ class PackageApi {
ExerciseTree tree = element as ExerciseTree;
tree.imageUrl = await ExerciseTreeApi().buildImage(tree.imageUrl, tree.treeId);
});
//print("tree: $exerciseTree");
Cache().setExerciseTree(exerciseTree);
return;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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