diff --git a/asset/menu/training_plans_advanced.jpg b/asset/menu/training_plans_advanced.jpg
new file mode 100644
index 0000000..c1a8a29
Binary files /dev/null and b/asset/menu/training_plans_advanced.jpg differ
diff --git a/asset/menu/training_plans_beginner.jpg b/asset/menu/training_plans_beginner.jpg
new file mode 100644
index 0000000..9077c3f
Binary files /dev/null and b/asset/menu/training_plans_beginner.jpg differ
diff --git a/asset/menu/training_plans_celebrities.jpg b/asset/menu/training_plans_celebrities.jpg
new file mode 100644
index 0000000..2ca6dfb
Binary files /dev/null and b/asset/menu/training_plans_celebrities.jpg differ
diff --git a/asset/menu/training_plans_home.jpg b/asset/menu/training_plans_home.jpg
new file mode 100644
index 0000000..12ff110
Binary files /dev/null and b/asset/menu/training_plans_home.jpg differ
diff --git a/asset/menu/training_plans_menu.jpg b/asset/menu/training_plans_menu.jpg
new file mode 100644
index 0000000..7bad09d
Binary files /dev/null and b/asset/menu/training_plans_menu.jpg differ
diff --git a/asset/menu/training_plans_q_advanced.jpg b/asset/menu/training_plans_q_advanced.jpg
new file mode 100644
index 0000000..e69e746
Binary files /dev/null and b/asset/menu/training_plans_q_advanced.jpg differ
diff --git a/asset/menu/training_plans_q_beginner.jpg b/asset/menu/training_plans_q_beginner.jpg
new file mode 100644
index 0000000..852b6e9
Binary files /dev/null and b/asset/menu/training_plans_q_beginner.jpg differ
diff --git a/asset/menu/training_plans_q_celebrities.jpg b/asset/menu/training_plans_q_celebrities.jpg
new file mode 100644
index 0000000..1b2eba8
Binary files /dev/null and b/asset/menu/training_plans_q_celebrities.jpg differ
diff --git a/asset/menu/training_plans_q_gain_strength.jpg b/asset/menu/training_plans_q_gain_strength.jpg
new file mode 100644
index 0000000..7159111
Binary files /dev/null and b/asset/menu/training_plans_q_gain_strength.jpg differ
diff --git a/asset/menu/training_plans_q_home.jpg b/asset/menu/training_plans_q_home.jpg
new file mode 100644
index 0000000..6c68b9d
Binary files /dev/null and b/asset/menu/training_plans_q_home.jpg differ
diff --git a/asset/menu/training_plans_q_woman.jpg b/asset/menu/training_plans_q_woman.jpg
new file mode 100644
index 0000000..962211d
Binary files /dev/null and b/asset/menu/training_plans_q_woman.jpg differ
diff --git a/asset/menu/training_plans_strength_gain.jpg b/asset/menu/training_plans_strength_gain.jpg
new file mode 100644
index 0000000..bdebf10
Binary files /dev/null and b/asset/menu/training_plans_strength_gain.jpg differ
diff --git a/asset/menu/training_plans_woman.jpg b/asset/menu/training_plans_woman.jpg
new file mode 100644
index 0000000..8e6456a
Binary files /dev/null and b/asset/menu/training_plans_woman.jpg differ
diff --git a/i18n/en.json b/i18n/en.json
index 7b830c0..a0ee8f3 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -477,6 +477,15 @@
   "Try free for 3 days!":"Try it without risk for 3 days! In this period you can cancel any time without lasting your account.",
   "View other alternatives":"View other alternatives",
 
-  "Please log in, because we can calculate the best suggestions for you":"Please log in, because we can calculate the best suggestions for you"
+  "Please log in, because we can calculate the best suggestions for you":"Please log in, because we can calculate the best suggestions for you",
+
+  "My Active Training":"My Active Training",
+  "My Custom Plan":"My Custom Plan",
+  "Training Plans for Beginners":"Training Plans for Beginners",
+  "Training Plans for Home":"Training Plans for Home",
+  "Training Plans Advanced":"Training Plans Advanced",
+  "Training Plans for Women":"Training Plans for Women",
+  "Training Plans of Celebrities":"Training Plans of Celebrities",
+  "Training Plans for Gain Strength":"Training Plans for Gain Strength"
 
 }
\ No newline at end of file
diff --git a/i18n/hu.json b/i18n/hu.json
index f627cf1..b82ba8b 100644
--- a/i18n/hu.json
+++ b/i18n/hu.json
@@ -469,5 +469,14 @@
   "Try free for 3 days!":"Próbáld ki kockázat nélkül 3 napig! Ebben az időszakban bármikor lemondhatod, anélkül, hogy megterhelnénk a számládat.",
   "View other alternatives":"Megnézek egy másik lehetőséget",
 
-  "Please log in, because we can calculate the best suggestions for you":"Kérlek jelentkezz be, mert csak így tudjuk neked a legjobb gyakorlatokat kalkulálni"
+  "Please log in, because we can calculate the best suggestions for you":"Kérlek jelentkezz be, mert csak így tudjuk neked a legjobb gyakorlatokat kalkulálni",
+
+  "My Active Training":"Aktív edzésem",
+  "My Custom Plan":"Egyéni edzésterv",
+  "Training Plans for Beginners":"Kezdő edzésprogramok",
+  "Training Plans for Home":"Otthoni edzésprogramok",
+  "Training Plans Advanced":"Haladó edzésprogramok",
+  "Training Plans for Women":"Edzésprogramok nőknek",
+  "Training Plans of Celebrities":"Celebek edzésprogramjai",
+  "Training Plans for Gain Strength":"Erőnövelő edzésprogramok"
 }
\ No newline at end of file
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index b798013..90d462c 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -18,112 +18,106 @@ PODS:
     - FBSDKLoginKit/Login (= 9.1.0)
   - FBSDKLoginKit/Login (9.1.0):
     - FBSDKCoreKit (~> 9.1.0)
-  - Firebase/Analytics (7.11.0):
+  - Firebase/Analytics (8.0.0):
     - Firebase/Core
-  - Firebase/Auth (7.11.0):
+  - Firebase/Auth (8.0.0):
     - Firebase/CoreOnly
-    - FirebaseAuth (~> 7.11.0)
-  - Firebase/Core (7.11.0):
+    - FirebaseAuth (~> 8.0.0)
+  - Firebase/Core (8.0.0):
     - Firebase/CoreOnly
-    - FirebaseAnalytics (~> 7.11.0)
-  - Firebase/CoreOnly (7.11.0):
-    - FirebaseCore (= 7.11.0)
-  - Firebase/Messaging (7.11.0):
+    - FirebaseAnalytics (~> 8.0.0)
+  - Firebase/CoreOnly (8.0.0):
+    - FirebaseCore (= 8.0.0)
+  - Firebase/Messaging (8.0.0):
     - Firebase/CoreOnly
-    - FirebaseMessaging (~> 7.11.0)
-  - Firebase/RemoteConfig (7.11.0):
+    - FirebaseMessaging (~> 8.0.0)
+  - Firebase/RemoteConfig (8.0.0):
     - Firebase/CoreOnly
-    - FirebaseRemoteConfig (~> 7.11.0)
-  - firebase_analytics (8.0.2):
-    - Firebase/Analytics (= 7.11.0)
+    - FirebaseRemoteConfig (~> 8.0.0)
+  - firebase_analytics (8.1.0):
+    - Firebase/Analytics (= 8.0.0)
     - firebase_core
     - Flutter
-  - firebase_auth (1.1.2):
-    - Firebase/Auth (= 7.11.0)
+  - firebase_auth (1.2.0):
+    - Firebase/Auth (= 8.0.0)
     - firebase_core
     - Flutter
-  - firebase_core (1.1.0):
-    - Firebase/CoreOnly (= 7.11.0)
+  - firebase_core (1.2.0):
+    - Firebase/CoreOnly (= 8.0.0)
     - Flutter
-  - firebase_messaging (9.1.3):
-    - Firebase/Messaging (= 7.11.0)
+  - firebase_messaging (10.0.0):
+    - Firebase/Messaging (= 8.0.0)
     - firebase_core
     - Flutter
-  - firebase_remote_config (0.10.0-dev.2):
-    - Firebase/RemoteConfig (= 7.11.0)
+  - firebase_remote_config (0.10.0):
+    - Firebase/RemoteConfig (= 8.0.0)
     - firebase_core
     - Flutter
-  - FirebaseABTesting (7.11.0):
-    - FirebaseCore (~> 7.0)
-  - FirebaseAnalytics (7.11.0):
-    - FirebaseAnalytics/AdIdSupport (= 7.11.0)
-    - FirebaseCore (~> 7.0)
-    - FirebaseInstallations (~> 7.0)
-    - GoogleUtilities/AppDelegateSwizzler (~> 7.0)
-    - GoogleUtilities/MethodSwizzler (~> 7.0)
-    - GoogleUtilities/Network (~> 7.0)
-    - "GoogleUtilities/NSData+zlib (~> 7.0)"
+  - FirebaseABTesting (8.0.0):
+    - FirebaseCore (~> 8.0)
+  - FirebaseAnalytics (8.0.0):
+    - FirebaseAnalytics/AdIdSupport (= 8.0.0)
+    - FirebaseCore (~> 8.0)
+    - FirebaseInstallations (~> 8.0)
+    - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
+    - GoogleUtilities/MethodSwizzler (~> 7.4)
+    - GoogleUtilities/Network (~> 7.4)
+    - "GoogleUtilities/NSData+zlib (~> 7.4)"
     - nanopb (~> 2.30908.0)
-  - FirebaseAnalytics/AdIdSupport (7.11.0):
-    - FirebaseAnalytics/Base (= 7.11.0)
-    - FirebaseCore (~> 7.0)
-    - FirebaseInstallations (~> 7.0)
-    - GoogleAppMeasurement/AdIdSupport (= 7.11.0)
-    - GoogleUtilities/AppDelegateSwizzler (~> 7.0)
-    - GoogleUtilities/MethodSwizzler (~> 7.0)
-    - GoogleUtilities/Network (~> 7.0)
-    - "GoogleUtilities/NSData+zlib (~> 7.0)"
+  - FirebaseAnalytics/AdIdSupport (8.0.0):
+    - FirebaseAnalytics/Base (= 8.0.0)
+    - FirebaseCore (~> 8.0)
+    - FirebaseInstallations (~> 8.0)
+    - GoogleAppMeasurement (= 8.0.0)
+    - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
+    - GoogleUtilities/MethodSwizzler (~> 7.4)
+    - GoogleUtilities/Network (~> 7.4)
+    - "GoogleUtilities/NSData+zlib (~> 7.4)"
     - nanopb (~> 2.30908.0)
-  - FirebaseAnalytics/Base (7.11.0):
-    - FirebaseCore (~> 7.0)
-    - FirebaseInstallations (~> 7.0)
-    - GoogleUtilities/AppDelegateSwizzler (~> 7.0)
-    - GoogleUtilities/MethodSwizzler (~> 7.0)
-    - GoogleUtilities/Network (~> 7.0)
-    - "GoogleUtilities/NSData+zlib (~> 7.0)"
+  - FirebaseAnalytics/Base (8.0.0):
+    - FirebaseCore (~> 8.0)
+    - FirebaseInstallations (~> 8.0)
+    - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
+    - GoogleUtilities/MethodSwizzler (~> 7.4)
+    - GoogleUtilities/Network (~> 7.4)
+    - "GoogleUtilities/NSData+zlib (~> 7.4)"
     - nanopb (~> 2.30908.0)
-  - FirebaseAuth (7.11.0):
-    - FirebaseCore (~> 7.0)
-    - GoogleUtilities/AppDelegateSwizzler (~> 7.0)
-    - GoogleUtilities/Environment (~> 7.0)
-    - GTMSessionFetcher/Core (~> 1.4)
-  - FirebaseCore (7.11.0):
-    - FirebaseCoreDiagnostics (~> 7.4)
-    - GoogleUtilities/Environment (~> 7.0)
-    - GoogleUtilities/Logger (~> 7.0)
-  - FirebaseCoreDiagnostics (7.11.0):
-    - GoogleDataTransport (~> 8.4)
-    - GoogleUtilities/Environment (~> 7.0)
-    - GoogleUtilities/Logger (~> 7.0)
+  - FirebaseAuth (8.0.0):
+    - FirebaseCore (~> 8.0)
+    - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
+    - GoogleUtilities/Environment (~> 7.4)
+    - GTMSessionFetcher/Core (~> 1.5)
+  - FirebaseCore (8.0.0):
+    - FirebaseCoreDiagnostics (~> 8.0)
+    - GoogleUtilities/Environment (~> 7.4)
+    - GoogleUtilities/Logger (~> 7.4)
+  - FirebaseCoreDiagnostics (8.0.0):
+    - GoogleDataTransport (~> 9.0)
+    - GoogleUtilities/Environment (~> 7.4)
+    - GoogleUtilities/Logger (~> 7.4)
     - nanopb (~> 2.30908.0)
-  - FirebaseInstallations (7.11.0):
-    - FirebaseCore (~> 7.0)
-    - GoogleUtilities/Environment (~> 7.0)
-    - GoogleUtilities/UserDefaults (~> 7.0)
+  - FirebaseInstallations (8.0.0):
+    - FirebaseCore (~> 8.0)
+    - GoogleUtilities/Environment (~> 7.4)
+    - GoogleUtilities/UserDefaults (~> 7.4)
     - PromisesObjC (~> 1.2)
-  - FirebaseInstanceID (7.11.0):
-    - FirebaseCore (~> 7.0)
-    - FirebaseInstallations (~> 7.0)
-    - GoogleUtilities/Environment (~> 7.0)
-    - GoogleUtilities/UserDefaults (~> 7.0)
-  - FirebaseMessaging (7.11.0):
-    - FirebaseCore (~> 7.0)
-    - FirebaseInstallations (~> 7.0)
-    - FirebaseInstanceID (~> 7.0)
-    - GoogleUtilities/AppDelegateSwizzler (~> 7.0)
-    - GoogleUtilities/Environment (~> 7.0)
-    - GoogleUtilities/Reachability (~> 7.0)
-    - GoogleUtilities/UserDefaults (~> 7.0)
-  - FirebaseRemoteConfig (7.11.0):
-    - FirebaseABTesting (~> 7.0)
-    - FirebaseCore (~> 7.0)
-    - FirebaseInstallations (~> 7.0)
-    - GoogleUtilities/Environment (~> 7.0)
-    - "GoogleUtilities/NSData+zlib (~> 7.0)"
+  - FirebaseMessaging (8.0.0):
+    - FirebaseCore (~> 8.0)
+    - FirebaseInstallations (~> 8.0)
+    - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
+    - GoogleUtilities/Environment (~> 7.4)
+    - GoogleUtilities/Reachability (~> 7.4)
+    - GoogleUtilities/UserDefaults (~> 7.4)
+  - FirebaseRemoteConfig (8.0.0):
+    - FirebaseABTesting (~> 8.0)
+    - FirebaseCore (~> 8.0)
+    - FirebaseInstallations (~> 8.0)
+    - GoogleUtilities/Environment (~> 7.4)
+    - "GoogleUtilities/NSData+zlib (~> 7.4)"
   - flurry (0.0.4):
     - Flurry-iOS-SDK/FlurrySDK
     - Flutter
-  - Flurry-iOS-SDK/FlurrySDK (11.2.0)
+  - Flurry-iOS-SDK/FlurrySDK (11.2.1)
   - Flutter (1.0.0)
   - flutter_app_badger (0.0.1):
     - Flutter
@@ -144,13 +138,20 @@ PODS:
   - google_sign_in (0.0.1):
     - Flutter
     - GoogleSignIn (~> 5.0)
-  - GoogleAppMeasurement/AdIdSupport (7.11.0):
-    - GoogleUtilities/AppDelegateSwizzler (~> 7.0)
-    - GoogleUtilities/MethodSwizzler (~> 7.0)
-    - GoogleUtilities/Network (~> 7.0)
-    - "GoogleUtilities/NSData+zlib (~> 7.0)"
+  - GoogleAppMeasurement (8.0.0):
+    - GoogleAppMeasurement/AdIdSupport (= 8.0.0)
+    - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
+    - GoogleUtilities/MethodSwizzler (~> 7.4)
+    - GoogleUtilities/Network (~> 7.4)
+    - "GoogleUtilities/NSData+zlib (~> 7.4)"
     - nanopb (~> 2.30908.0)
-  - GoogleDataTransport (8.4.0):
+  - GoogleAppMeasurement/AdIdSupport (8.0.0):
+    - GoogleUtilities/AppDelegateSwizzler (~> 7.4)
+    - GoogleUtilities/MethodSwizzler (~> 7.4)
+    - GoogleUtilities/Network (~> 7.4)
+    - "GoogleUtilities/NSData+zlib (~> 7.4)"
+    - nanopb (~> 2.30908.0)
+  - GoogleDataTransport (9.0.0):
     - GoogleUtilities/Environment (~> 7.2)
     - nanopb (~> 2.30908.0)
     - PromisesObjC (~> 1.2)
@@ -158,33 +159,29 @@ PODS:
     - AppAuth (~> 1.2)
     - GTMAppAuth (~> 1.0)
     - GTMSessionFetcher/Core (~> 1.1)
-  - GoogleUtilities/AppDelegateSwizzler (7.4.0):
+  - GoogleUtilities/AppDelegateSwizzler (7.4.1):
     - GoogleUtilities/Environment
     - GoogleUtilities/Logger
     - GoogleUtilities/Network
-  - GoogleUtilities/Environment (7.4.0):
+  - GoogleUtilities/Environment (7.4.1):
     - PromisesObjC (~> 1.2)
-  - GoogleUtilities/Logger (7.4.0):
+  - GoogleUtilities/Logger (7.4.1):
     - GoogleUtilities/Environment
-  - GoogleUtilities/MethodSwizzler (7.4.0):
+  - GoogleUtilities/MethodSwizzler (7.4.1):
     - GoogleUtilities/Logger
-  - GoogleUtilities/Network (7.4.0):
+  - GoogleUtilities/Network (7.4.1):
     - GoogleUtilities/Logger
     - "GoogleUtilities/NSData+zlib"
     - GoogleUtilities/Reachability
-  - "GoogleUtilities/NSData+zlib (7.4.0)"
-  - GoogleUtilities/Reachability (7.4.0):
+  - "GoogleUtilities/NSData+zlib (7.4.1)"
+  - GoogleUtilities/Reachability (7.4.1):
     - GoogleUtilities/Logger
-  - GoogleUtilities/UserDefaults (7.4.0):
+  - GoogleUtilities/UserDefaults (7.4.1):
     - GoogleUtilities/Logger
-  - GTMAppAuth (1.1.0):
+  - GTMAppAuth (1.2.2):
     - AppAuth/Core (~> 1.4)
-    - GTMSessionFetcher (~> 1.4)
-  - GTMSessionFetcher (1.5.0):
-    - GTMSessionFetcher/Full (= 1.5.0)
+    - GTMSessionFetcher/Core (~> 1.5)
   - GTMSessionFetcher/Core (1.5.0)
-  - GTMSessionFetcher/Full (1.5.0):
-    - GTMSessionFetcher/Core (= 1.5.0)
   - modal_progress_hud_nsn (0.0.1):
     - Flutter
   - nanopb (2.30908.0):
@@ -199,20 +196,21 @@ PODS:
   - path_provider (0.0.1):
     - Flutter
   - PromisesObjC (1.2.12)
-  - Purchases (3.10.7):
-    - PurchasesCoreSwift (= 3.10.7)
-  - purchases_flutter (3.2.1):
+  - Purchases (3.11.1):
+    - PurchasesCoreSwift (= 3.11.1)
+  - purchases_flutter (3.2.2):
     - Flutter
-    - PurchasesHybridCommon (= 1.6.2)
-  - PurchasesCoreSwift (3.10.7)
-  - PurchasesHybridCommon (1.6.2):
-    - Purchases (= 3.10.7)
-  - Sentry (6.2.1):
-    - Sentry/Core (= 6.2.1)
-  - Sentry/Core (6.2.1)
+    - PurchasesHybridCommon (= 1.6.3)
+  - PurchasesCoreSwift (3.11.1)
+  - PurchasesHybridCommon (1.6.3):
+    - Purchases (= 3.11.1)
+  - Sentry (7.0.3):
+    - Sentry/Core (= 7.0.3)
+  - Sentry/Core (7.0.3)
   - sentry_flutter (0.0.1):
     - Flutter
-    - Sentry (~> 6.2.1)
+    - FlutterMacOS
+    - Sentry (~> 7.0.3)
   - shared_preferences (0.0.1):
     - Flutter
   - sqflite (0.0.2):
@@ -269,7 +267,6 @@ SPEC REPOS:
     - FirebaseCore
     - FirebaseCoreDiagnostics
     - FirebaseInstallations
-    - FirebaseInstanceID
     - FirebaseMessaging
     - FirebaseRemoteConfig
     - Flurry-iOS-SDK
@@ -350,23 +347,22 @@ SPEC CHECKSUMS:
   devicelocale: b22617f40038496deffba44747101255cee005b0
   FBSDKCoreKit: a00fe2efd780c195a5e09201bf51c56106245b40
   FBSDKLoginKit: d98498c598ec09de657385a9349a1f21119b7f86
-  Firebase: c121feb35e4126c0b355e3313fa9b487d47319fd
-  firebase_analytics: 620e8cc1705feb6b9c40b6127bea9b39e03e3970
-  firebase_auth: e7065954aa2a7c8ef1a8502fba3009bcdd8fc91a
-  firebase_core: 84dcd80ac6d29c3d1039071b7306ee99688eb9c7
-  firebase_messaging: 7aecb08eada5e5cde85b10875141706a8d18b818
-  firebase_remote_config: f855065886b7d6ccc38144c9a3cecbdc7887f33e
-  FirebaseABTesting: e66f1f80747792630d9b292966de206d5df9853b
-  FirebaseAnalytics: cd3bd84d722a24a8923918af8af8e5236f615d77
-  FirebaseAuth: 5fe4585c2ed847319f0ea68bd1d82c77e49ff9a0
-  FirebaseCore: 907447d8917a4d3eb0cce2829c5a0ad21d90b432
-  FirebaseCoreDiagnostics: 68ad972f99206cef818230f3f3179d52ccfb7f8c
-  FirebaseInstallations: a58d4f72ec5861840b84df489f2668d970df558a
-  FirebaseInstanceID: ad5135045a498d7775903efd39762d2cdfa1be27
-  FirebaseMessaging: 163435fb6db065e3b6228f1e577b10ed2cc506d2
-  FirebaseRemoteConfig: 0ea30de5fb0231df8c1bdcdf3b6c23bdc5066131
+  Firebase: 73c3e3b216ec1ecbc54d2ffdd4670c65c749edb1
+  firebase_analytics: 221d3bc4e8f1b5144a4bd4cc6b33790ee51bd543
+  firebase_auth: f960df4ddd8cb415859dbc01a02d7859925ddef0
+  firebase_core: e4d3efb030a2b2021819f8faa538bb23deb46695
+  firebase_messaging: 3b6e0657b21261a57a1cd041fafa713f2aa6923f
+  firebase_remote_config: 3a6e2db440f0e95baba3dfc3d4118b1a4bc792c4
+  FirebaseABTesting: daebc95ec8829607d07dfe5e92dc3285aca29bc4
+  FirebaseAnalytics: dcb92c7c9ef4fa7ffac276e8f87bd4fc8c97f1b8
+  FirebaseAuth: b8cd992fca5b53dc6eec09e873a3f375f000c5a1
+  FirebaseCore: 3f09591d51292843e2a46f18358d60bf4e996255
+  FirebaseCoreDiagnostics: a31d987ba0fe16d59886a5dbadc2f1de871f88c8
+  FirebaseInstallations: c4aab1005d6547b00a7529777fe52f5d4d45165b
+  FirebaseMessaging: 1a33b4af3c8042ed6ddacb6c031894af2064bfab
+  FirebaseRemoteConfig: 055f6b5ba1751547596ded5032c4d5c6054ca501
   flurry: 15b01f664ab1367c62b50291541ea7f78ca85aad
-  Flurry-iOS-SDK: 6636d30c30f12010e7c7c71d84b443416a168efc
+  Flurry-iOS-SDK: 5831da8fc6bedb31fa1f94aac6fd204d36dd351d
   Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
   flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68
   flutter_facebook_auth: 4b170c07b7fce791497093fcc3f134fb215f3f07
@@ -375,11 +371,11 @@ SPEC CHECKSUMS:
   flutter_uxcam: ab8e5d3954eb448febd581375e2622e9eecb1066
   FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
   google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc
-  GoogleAppMeasurement: fd19169c3034975cb934e865e5667bfdce59df7f
-  GoogleDataTransport: cd9db2180fcecd8da1b561aea31e3e56cf834aa7
+  GoogleAppMeasurement: c6bbc9753d046b5456dd4f940057fbad2c28419e
+  GoogleDataTransport: 11e3a5f2c190327df1a4a5d7e7ae3d4d5b9c9e4c
   GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
-  GoogleUtilities: 284cddc7fffc14ae1907efb6f78ab95c1fccaedc
-  GTMAppAuth: 197a8dabfea5d665224aa00d17f164fc2248dab9
+  GoogleUtilities: f8a43108b38a68eebe8b3540e1f4f2d28843ce20
+  GTMAppAuth: ad5c2b70b9a8689e1a04033c9369c4915bfcbe89
   GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
   modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde
   nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
@@ -387,12 +383,12 @@ SPEC CHECKSUMS:
   package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
   path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
   PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
-  Purchases: b8b8fb6e856ac8166e217f6e014df894d821dda1
-  purchases_flutter: 0130970b895c903e4e0aad793dd3a4c1b70bb434
-  PurchasesCoreSwift: 8ae0f08e020f0bc97c1befa4e38a0dbc8e9732e0
-  PurchasesHybridCommon: 5f5c1c245b12fc5e8760af7d11cb10f888109a9b
-  Sentry: 9b922b396b0e0bca8516a10e36b0ea3ebea5faf7
-  sentry_flutter: 5b3c6d717db5b7482504a313c831b318297d4d37
+  Purchases: 6351f9ff6bd514e5ec5aa0f989ea181effa94bf5
+  purchases_flutter: 627527b070d80cdaf486fabe8b3d1dbe8d5cad92
+  PurchasesCoreSwift: ee857e4c21e6254b09d7e303a756fcf2b9164408
+  PurchasesHybridCommon: d65a799a61d688588534b80338edbcbf604ca93d
+  Sentry: 5b16f877da362d23716d827e04db642455b26b40
+  sentry_flutter: 602dc1902e152269256115e2386e1029511f3440
   shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
   sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
   url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 459e2f4..fcc5215 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -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";
diff --git a/lib/bloc/menu/menu_bloc.dart b/lib/bloc/menu/menu_bloc.dart
index bb4bba2..5673052 100644
--- a/lib/bloc/menu/menu_bloc.dart
+++ b/lib/bloc/menu/menu_bloc.dart
@@ -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';
diff --git a/lib/bloc/test_set_execute/test_set_execute_bloc.dart b/lib/bloc/test_set_execute/test_set_execute_bloc.dart
index 4f6e7a6..ca6c6cd 100644
--- a/lib/bloc/test_set_execute/test_set_execute_bloc.dart
+++ b/lib/bloc/test_set_execute/test_set_execute_bloc.dart
@@ -309,7 +309,6 @@ class TestSetExecuteBloc extends Bloc<TestSetExecuteEvent, TestSetExecuteState>
 
   bool existsActivePlan() {
     final bool exists = exercisePlan != null && exercisePlanDetails != null && exercisePlanDetails!.isNotEmpty;
-    print("Exists active plan: $exists");
     return exists;
   }
 
diff --git a/lib/bloc/training_plan/training_plan_bloc.dart b/lib/bloc/training_plan/training_plan_bloc.dart
new file mode 100644
index 0000000..ae6f378
--- /dev/null
+++ b/lib/bloc/training_plan/training_plan_bloc.dart
@@ -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;
+    }
+  }
+}
diff --git a/lib/bloc/training_plan/training_plan_event.dart b/lib/bloc/training_plan/training_plan_event.dart
new file mode 100644
index 0000000..b4efe50
--- /dev/null
+++ b/lib/bloc/training_plan/training_plan_event.dart
@@ -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();
+}
diff --git a/lib/bloc/training_plan/training_plan_state.dart b/lib/bloc/training_plan/training_plan_state.dart
new file mode 100644
index 0000000..9d30710
--- /dev/null
+++ b/lib/bloc/training_plan/training_plan_state.dart
@@ -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];
+}
diff --git a/lib/main.dart b/lib/main.dart
index e4e6dd1..faabc77 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -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',
diff --git a/lib/model/cache.dart b/lib/model/cache.dart
index aaeb40f..4fc677a 100644
--- a/lib/model/cache.dart
+++ b/lib/model/cache.dart
@@ -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;
 }
diff --git a/lib/model/customer_training_plan.dart b/lib/model/customer_training_plan.dart
new file mode 100644
index 0000000..903e81d
--- /dev/null
+++ b/lib/model/customer_training_plan.dart
@@ -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();
+}
diff --git a/lib/model/customer_training_plan_details.dart b/lib/model/customer_training_plan_details.dart
new file mode 100644
index 0000000..46b8504
--- /dev/null
+++ b/lib/model/customer_training_plan_details.dart
@@ -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();
+}
diff --git a/lib/model/customer_training_plan_exercise.dart b/lib/model/customer_training_plan_exercise.dart
new file mode 100644
index 0000000..5c05fb6
--- /dev/null
+++ b/lib/model/customer_training_plan_exercise.dart
@@ -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();
+}
diff --git a/lib/model/exercise.dart b/lib/model/exercise.dart
index 0a0301e..79ee76e 100644
--- a/lib/model/exercise.dart
+++ b/lib/model/exercise.dart
@@ -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() => {
diff --git a/lib/model/exercise_tree.dart b/lib/model/exercise_tree.dart
index 5f8e91f..b2ad6b0 100644
--- a/lib/model/exercise_tree.dart
+++ b/lib/model/exercise_tree.dart
@@ -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;
diff --git a/lib/model/training_plan.dart b/lib/model/training_plan.dart
new file mode 100644
index 0000000..ed7619f
--- /dev/null
+++ b/lib/model/training_plan.dart
@@ -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();
+}
diff --git a/lib/model/training_plan_detail.dart b/lib/model/training_plan_detail.dart
new file mode 100644
index 0000000..d97a24e
--- /dev/null
+++ b/lib/model/training_plan_detail.dart
@@ -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();
+}
diff --git a/lib/repository/training_plan_repository.dart b/lib/repository/training_plan_repository.dart
new file mode 100644
index 0000000..1d9294d
--- /dev/null
+++ b/lib/repository/training_plan_repository.dart
@@ -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;
+  }
+}
diff --git a/lib/service/exercise_tree_service.dart b/lib/service/exercise_tree_service.dart
index 406e35a..8a511cc 100644
--- a/lib/service/exercise_tree_service.dart
+++ b/lib/service/exercise_tree_service.dart
@@ -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 {
diff --git a/lib/service/package_service.dart b/lib/service/package_service.dart
index d193279..14e8918 100644
--- a/lib/service/package_service.dart
+++ b/lib/service/package_service.dart
@@ -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;
diff --git a/lib/service/training_plan_service.dart b/lib/service/training_plan_service.dart
new file mode 100644
index 0000000..e0c2667
--- /dev/null
+++ b/lib/service/training_plan_service.dart
@@ -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;
+  }
+}
diff --git a/lib/util/common.dart b/lib/util/common.dart
index 83f1457..76b7a18 100644
--- a/lib/util/common.dart
+++ b/lib/util/common.dart
@@ -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;
+  }
 }
diff --git a/lib/view/account.dart b/lib/view/account.dart
index 791316d..00976c0 100644
--- a/lib/view/account.dart
+++ b/lib/view/account.dart
@@ -151,7 +151,7 @@ class AccountPage extends StatelessWidget with Trans {
       ),
       devices(context, accountBloc),
       loginOut(context, accountBloc),
-      getMyTrainees(context, accountBloc),
+      //getMyTrainees(context, accountBloc),
     ]);
   }
 
diff --git a/lib/view/exercise_new_page.dart b/lib/view/exercise_new_page.dart
index 12b0c91..c373ad8 100644
--- a/lib/view/exercise_new_page.dart
+++ b/lib/view/exercise_new_page.dart
@@ -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,
           )),
diff --git a/lib/view/my_training_plans_page.dart b/lib/view/my_training_plans_page.dart
new file mode 100644
index 0000000..44814e1
--- /dev/null
+++ b/lib/view/my_training_plans_page.dart
@@ -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,
+    );
+  }
+}
diff --git a/lib/view/test_set_new.dart b/lib/view/test_set_new.dart
index 01a5ea1..a8b246b 100644
--- a/lib/view/test_set_new.dart
+++ b/lib/view/test_set_new.dart
@@ -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();
diff --git a/lib/view/training_plan_activate_page.dart b/lib/view/training_plan_activate_page.dart
new file mode 100644
index 0000000..6ab8df5
--- /dev/null
+++ b/lib/view/training_plan_activate_page.dart
@@ -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());
+  }
+}
diff --git a/lib/view/training_plan_execute_page.dart b/lib/view/training_plan_execute_page.dart
new file mode 100644
index 0000000..a6e6bc4
--- /dev/null
+++ b/lib/view/training_plan_execute_page.dart
@@ -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()
+          ]),
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/view/training_plan_exercise.dart b/lib/view/training_plan_exercise.dart
new file mode 100644
index 0000000..93ed22f
--- /dev/null
+++ b/lib/view/training_plan_exercise.dart
@@ -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,
+    );
+  }
+}
diff --git a/lib/widgets/bottom_nav.dart b/lib/widgets/bottom_nav.dart
index a639439..8617cd6 100644
--- a/lib/widgets/bottom_nav.dart
+++ b/lib/widgets/bottom_nav.dart
@@ -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:
diff --git a/lib/widgets/exercise_save.dart b/lib/widgets/exercise_save.dart
index bf1b4c1..060966a 100644
--- a/lib/widgets/exercise_save.dart
+++ b/lib/widgets/exercise_save.dart
@@ -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));
             },
           ),
         ]));
diff --git a/lib/widgets/image_button.dart b/lib/widgets/image_button.dart
index a377a6a..86e6b32 100644
--- a/lib/widgets/image_button.dart
+++ b/lib/widgets/image_button.dart
@@ -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),
diff --git a/lib/widgets/menu_image.dart b/lib/widgets/menu_image.dart
index 3df5113..40e53f9 100644
--- a/lib/widgets/menu_image.dart
+++ b/lib/widgets/menu_image.dart
@@ -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),
diff --git a/lib/widgets/menu_page_widget.dart b/lib/widgets/menu_page_widget.dart
index 8e3899e..3846a36 100644
--- a/lib/widgets/menu_page_widget.dart
+++ b/lib/widgets/menu_page_widget.dart
@@ -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(
diff --git a/pubspec.lock b/pubspec.lock
index 8e967b3..97b7a7e 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -56,7 +56,7 @@ packages:
       name: badges
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.0-nullsafety.1"
+    version: "2.0.1"
   bloc:
     dependency: transitive
     description:
@@ -231,7 +231,7 @@ packages:
       name: coverage
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.15.2"
+    version: "1.0.2"
   crypto:
     dependency: "direct main"
     description:
@@ -239,13 +239,6 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "3.0.0"
-  css_colors:
-    dependency: transitive
-    description:
-      name: css_colors
-      url: "https://pub.dartlang.org"
-    source: hosted
-    version: "1.1.0"
   csslib:
     dependency: transitive
     description:
@@ -280,7 +273,7 @@ packages:
       name: equatable
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.0"
+    version: "2.0.2"
   ezanimation:
     dependency: "direct main"
     description:
@@ -322,98 +315,98 @@ packages:
       name: firebase_analytics
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "8.0.2"
+    version: "8.1.0"
   firebase_analytics_platform_interface:
     dependency: transitive
     description:
       name: firebase_analytics_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.0"
+    version: "2.0.1"
   firebase_analytics_web:
     dependency: transitive
     description:
       name: firebase_analytics_web
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.3.0"
+    version: "0.3.0+1"
   firebase_auth:
     dependency: "direct main"
     description:
       name: firebase_auth
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.2"
+    version: "1.2.0"
   firebase_auth_platform_interface:
     dependency: transitive
     description:
       name: firebase_auth_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "4.2.0"
+    version: "4.2.3"
   firebase_auth_web:
     dependency: transitive
     description:
       name: firebase_auth_web
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0"
+    version: "1.1.3"
   firebase_core:
     dependency: "direct main"
     description:
       name: firebase_core
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0"
+    version: "1.2.0"
   firebase_core_platform_interface:
     dependency: transitive
     description:
       name: firebase_core_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "4.0.0"
+    version: "4.0.1"
   firebase_core_web:
     dependency: transitive
     description:
       name: firebase_core_web
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.2"
+    version: "1.1.0"
   firebase_messaging:
     dependency: "direct main"
     description:
       name: firebase_messaging
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "9.1.3"
+    version: "10.0.0"
   firebase_messaging_platform_interface:
     dependency: transitive
     description:
       name: firebase_messaging_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.1.3"
+    version: "3.0.0"
   firebase_messaging_web:
     dependency: transitive
     description:
       name: firebase_messaging_web
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.6"
+    version: "2.0.0"
   firebase_remote_config:
     dependency: "direct main"
     description:
       name: firebase_remote_config
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.10.0-dev.2"
+    version: "0.10.0"
   firebase_remote_config_platform_interface:
     dependency: transitive
     description:
       name: firebase_remote_config_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.3.0-dev.2"
+    version: "0.3.0"
   fixnum:
     dependency: transitive
     description:
@@ -427,7 +420,7 @@ packages:
       name: fl_chart
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.30.0"
+    version: "0.36.1"
   flurry:
     dependency: "direct main"
     description:
@@ -460,21 +453,21 @@ packages:
       name: flutter_facebook_auth
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "3.3.2+2"
+    version: "3.4.0"
   flutter_facebook_auth_platform_interface:
     dependency: transitive
     description:
       name: flutter_facebook_auth_platform_interface
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.4.1"
+    version: "2.6.0"
   flutter_facebook_auth_web:
     dependency: transitive
     description:
       name: flutter_facebook_auth_web
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.4.1+1"
+    version: "2.6.0"
   flutter_fadein:
     dependency: "direct main"
     description:
@@ -488,7 +481,7 @@ packages:
       name: flutter_html
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.0-nullsafety.0"
+    version: "2.0.0"
   flutter_launcher_icons:
     dependency: "direct dev"
     description:
@@ -509,7 +502,7 @@ packages:
       name: flutter_local_notifications
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "5.0.0"
+    version: "5.0.0+4"
   flutter_local_notifications_platform_interface:
     dependency: transitive
     description:
@@ -522,20 +515,27 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_math_fork:
+    dependency: transitive
+    description:
+      name: flutter_math_fork
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.3.3"
   flutter_secure_storage:
     dependency: "direct main"
     description:
       name: flutter_secure_storage
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "4.1.0"
+    version: "4.2.0"
   flutter_svg:
     dependency: transitive
     description:
       name: flutter_svg
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.21.0-nullsafety.0"
+    version: "0.22.0"
   flutter_test:
     dependency: "direct dev"
     description: flutter
@@ -566,14 +566,14 @@ packages:
       name: google_fonts
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.0"
+    version: "2.1.0"
   google_sign_in:
     dependency: "direct main"
     description:
       name: google_sign_in
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "5.0.1"
+    version: "5.0.3"
   google_sign_in_platform_interface:
     dependency: transitive
     description:
@@ -615,7 +615,7 @@ packages:
       name: http_multi_server
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.2.0"
+    version: "3.0.1"
   http_parser:
     dependency: transitive
     description:
@@ -650,7 +650,7 @@ packages:
       name: io
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.3.4"
+    version: "1.0.0"
   js:
     dependency: transitive
     description:
@@ -699,7 +699,7 @@ packages:
       name: mime
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.9.7"
+    version: "1.0.0"
   mockito:
     dependency: "direct main"
     description:
@@ -804,14 +804,14 @@ packages:
       name: path_drawing
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.5.0-nullsafety.0"
+    version: "0.5.1"
   path_parsing:
     dependency: transitive
     description:
       name: path_parsing
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.2.0-nullsafety.0"
+    version: "0.2.1"
   path_provider:
     dependency: transitive
     description:
@@ -923,7 +923,7 @@ packages:
       name: purchases_flutter
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "3.2.1"
+    version: "3.2.2"
   quiver:
     dependency: transitive
     description:
@@ -958,21 +958,21 @@ packages:
       name: rxdart
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.26.0"
+    version: "0.27.0"
   sentry:
     dependency: transitive
     description:
       name: sentry
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "5.0.0"
+    version: "5.1.0-beta.1"
   sentry_flutter:
     dependency: "direct main"
     description:
       name: sentry_flutter
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "5.0.0"
+    version: "5.1.0-beta.1"
   shared_preferences:
     dependency: "direct dev"
     description:
@@ -1028,21 +1028,21 @@ packages:
       name: shelf_packages_handler
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.1"
+    version: "3.0.0"
   shelf_static:
     dependency: transitive
     description:
       name: shelf_static
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.2.9+2"
+    version: "1.0.0"
   shelf_web_socket:
     dependency: transitive
     description:
       name: shelf_web_socket
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.2.4+1"
+    version: "1.0.1"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -1110,7 +1110,7 @@ packages:
       name: stop_watch_timer
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.0"
+    version: "1.2.0+1"
   stream_channel:
     dependency: transitive
     description:
@@ -1138,7 +1138,14 @@ packages:
       name: syncfusion_flutter_core
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "19.1.63"
+    version: "19.1.64"
+  syncfusion_flutter_datagrid:
+    dependency: "direct main"
+    description:
+      name: syncfusion_flutter_datagrid
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "19.1.64-beta"
   syncfusion_flutter_gauges:
     dependency: "direct main"
     description:
@@ -1194,7 +1201,7 @@ packages:
       name: timezone
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.7.0-nullsafety.0"
+    version: "0.7.0"
   timing:
     dependency: transitive
     description:
@@ -1209,6 +1216,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "0.1.9"
+  tuple:
+    dependency: transitive
+    description:
+      name: tuple
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.0"
   typed_data:
     dependency: transitive
     description:
@@ -1278,7 +1292,7 @@ packages:
       name: video_player
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.1.0"
+    version: "2.1.1"
   video_player_platform_interface:
     dependency: transitive
     description:
@@ -1299,7 +1313,7 @@ packages:
       name: vm_service
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "5.5.0"
+    version: "6.2.0"
   wakelock:
     dependency: "direct main"
     description:
@@ -1341,7 +1355,7 @@ packages:
       name: web_socket_channel
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.2.0"
+    version: "2.1.0"
   webkit_inspection_protocol:
     dependency: transitive
     description:
@@ -1355,7 +1369,7 @@ packages:
       name: webview_flutter
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.2"
+    version: "2.0.7"
   win32:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index f76e5ce..63afae2 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -25,28 +25,28 @@ dependencies:
     sdk: flutter
 
   cupertino_icons: ^1.0.0
-  google_fonts: ^2.0.0
+  google_fonts: ^2.1.0
   devicelocale: ^0.4.1
-  sentry_flutter: ^5.0.0
+  sentry_flutter: ^5.1.0-beta.1
   flutter_bloc: ^7.0.0
-  equatable: ^2.0.0
+  equatable: ^2.0.2
 
   spider_chart: ^0.1.5
   rainbow_color: ^2.0.1
   percent_indicator: ^ 3.3.0-nullsafety.1
-  fl_chart: ^0.30.0
+  fl_chart: ^0.36.1
   infinite_listview: ^1.1.0
   toggle_switch: ^0.1.9
   keyboard_actions: ^3.4.0
-  badges: ^ 2.0.0-nullsafety.1
+  badges: ^ 2.0.1
   #health: ^3.0.0
-  stop_watch_timer: ^1.0.0
+  stop_watch_timer: ^1.2.0+1
   #location: ^3.2.4
   modal_progress_hud_nsn: ^0.1.0-nullsafety-1
-  flutter_html: ^2.0.0-nullsafety.0
+  flutter_html: ^2.0.0
   wakelock: ^ 0.4.0
   timeline_tile: ^2.0.0
-  purchases_flutter: ^3.2.1
+  purchases_flutter: ^3.2.2
   package_info: ^2.0.0  
   ezanimation: ^0.5.0
   flutter_fadein: ^2.0.0
@@ -59,18 +59,20 @@ dependencies:
   #super_tooltip: ^1.0.1
   url_launcher: ^6.0.3
     
-  firebase_core: ^1.1.0
-  firebase_analytics: ^8.0.2
-  firebase_messaging: ^9.1.3
+  firebase_core: ^1.2.0
+  firebase_analytics: ^8.1.0
+  firebase_messaging: ^10.0.0
   flutter_local_notifications: ^5.0.0
-  firebase_auth: ^1.1.2
-  firebase_remote_config: ^0.10.0-dev.2
+  firebase_auth: ^1.2.0
+  firebase_remote_config: ^0.10.0
 
   syncfusion_flutter_gauges: ^19.1.63
+  syncfusion_flutter_datagrid: ^19.1.63
   
-  flutter_facebook_auth: ^3.3.2
-  google_sign_in: ^5.0.1
+  flutter_facebook_auth: ^3.4.0
+  google_sign_in: ^5.0.3
   apple_sign_in: ^0.1.0
+  #sign_in_with_apple: ^3.0.0
     
   #smartlook: ^1.0.7
   flurry: ^0.0.4
@@ -80,7 +82,7 @@ dependencies:
 
   mockito: ^5.0.3
   sqflite: ^2.0.0+3
-  flutter_secure_storage: ^4.1.0
+  flutter_secure_storage: ^4.2.0
   #social_share: ^2.1.1
 
   flutter_localizations:
@@ -383,6 +385,19 @@ flutter:
      - asset/menu/test_center.jpg
      - asset/menu/test_on_machines.jpg
      - asset/menu/thigh_adductor.jpg
+     - asset/menu/training_plans_menu.jpg
+     - asset/menu/training_plans_woman.jpg
+     - asset/menu/training_plans_home.jpg
+     - asset/menu/training_plans_celebrities.jpg
+     - asset/menu/training_plans_beginner.jpg
+     - asset/menu/training_plans_advanced.jpg
+     - asset/menu/training_plans_strength_gain.jpg
+     - asset/menu/training_plans_q_woman.jpg
+     - asset/menu/training_plans_q_home.jpg
+     - asset/menu/training_plans_q_celebrities.jpg
+     - asset/menu/training_plans_q_beginner.jpg
+     - asset/menu/training_plans_q_advanced.jpg
+     - asset/menu/training_plans_q_gain_strength.jpg
      - asset/menu/triceps_extension_on_cable_with_rope.jpg
      - asset/menu/triceps_kickback.jpg
      - asset/menu/triceps_pushdown.jpg