WT 1.1.22 reengineering: Training Plan execution, registration

This commit is contained in:
bossanyit 2021-08-25 01:05:03 +02:00
parent 6b25fdfe0e
commit cebd83648b
51 changed files with 2605 additions and 663 deletions

View File

@ -78,5 +78,6 @@ dependencies {
implementation 'com.google.firebase:firebase-analytics:18.0.0'
implementation 'com.facebook.android:facebook-login:5.15.3'
implementation 'com.android.support:multidex:1.0.3'
implementation 'com.google.firebase:firebase-messaging:20.1.0'
}
sourceCompatibility = '1.8'

View File

@ -1,41 +1,23 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.aitrainer.aitrainer_app">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.aitrainer.aitrainer_app">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name="io.flutter.app.FlutterApplication"
android:label="WorkoutTest"
android:icon="@mipmap/launcher_icon">
<activity
android:name="com.aitrainer.aitrainer_app.MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
android:allowBackup="false"
android:fullBackupContent="false">
<application android:name="io.flutter.app.FlutterApplication" android:label="WorkoutTest" android:icon="@mipmap/launcher_icon">
<activity android:name="com.aitrainer.aitrainer_app.MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" android:allowBackup="false" android:fullBackupContent="false">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" />
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/launch_background" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@ -44,27 +26,26 @@
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<!-- Deep Links -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with YOUR_SCHEME://YOUR_HOST -->
<data android:scheme="https" android:host="aitrainer.page.link" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data android:name="flutterEmbedding" android:value="2" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="high_importance_channel" />
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="high_importance_channel" />
<meta-data android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id"/>
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
<activity android:name="com.facebook.FacebookActivity"
android:configChanges=
"keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="@string/app_name" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<activity android:name="com.facebook.FacebookActivity" android:configChanges=
"keyboard|keyboardHidden|screenLayout|screenSize|orientation" android:label="@string/app_name" />
<activity android:name="com.facebook.CustomTabActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />

BIN
asset/image/WT_zold.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View File

@ -15,7 +15,7 @@
"Exception: Please accept our data policy": "Please accept our data policy",
"Please accept our data protection policy.": "Please accept our data protection policy.",
"For more information please click on 'Privacy'": "For more information please click on 'Privacy'",
"SignUp": "SignUp with Email",
"SignUp": "We will generate your training plan for you. Please register in order to save and recall your data.",
"SignUpLink": "SignUp",
"Privacy": "Privacy",
"Change App Language": "Change App Language",
@ -436,7 +436,7 @@
"Do you want to restart, or select a new Training Plan?": "Do you want to restart, or select a new Training Plan?",
"New Training Plan": "New Training Plan",
"Restart": "Restart",
"Training Day": "Day",
"Training Day": "Training Day",
"No Active Training Plan": "No Active Training Plan",
"Please select one in the Training menu, or create your custom plan": "Please select one in the Training menu, or create your custom plan",
"Continue your training": "Continue your training",
@ -508,5 +508,6 @@
"Reach all basic functions, suggestions and": "Reach all basic functions, suggestions and",
"optimized training plans, customized to your fitness state and strength:": "optimized training plans, customized to your fitness state and strength:",
"Soon! Check back later for the plan details": "Soon! Check back later for the plan details",
"mins": "mins"
"mins": "mins",
"set": "set"
}

View File

@ -11,7 +11,7 @@
"Change Language": "Nyelv",
"Password too short": "A jelszó min. 9 karakterből álljon",
"Please type an email address": "Kérlek írj be egy email címet",
"SignUp": "Regisztráció",
"SignUp": "A megadott adatok alapján generáljuk az edzéstervedet. Kérlek regisztrálj, hogy az a tervet el tudd menteni és később betölteni.",
"SignUpLink": "Regisztráció",
"SignUp with Email": "Email Regisztráció",
"Exception: Please accept our data policy": "Kérlek fogadd el az adatvédelmi szabályzatunkat",
@ -434,7 +434,7 @@
"Do you want to restart, or select a new Training Plan?": "Újra akarod indítani, vagy inkább egy másikat választasz?",
"New Training Plan": "Másik edzésterv",
"Restart": "Újraindítom",
"Training Day": "Nap",
"Training Day": "Edzésnap",
"No Active Training Plan": "Nincs aktív edzésterv",
"Please select one in the Training menu, or create your custom plan": "Kérlek válassz egyet a Tréning menüben, vagy hozd létre a saját egyéni edzésedet",
"Continue your training": "Folytasd az edzést",
@ -506,5 +506,6 @@
"Reach all basic functions, suggestions and": "Kattints a regisztrációra, hogy elérd az alap funkciókat, javaslatokat,",
"optimized training plans, customized to your fitness state and strength:": "optiomalizált edzés terveket, amelyeket a te erő- és fitnesz állapododra szabunk:",
"Soon! Check back later for the plan details": "Nemsokára! Nézz vissza később, amikor már aktiváltuk az edzésterv részleteit",
"mins": "perc"
"mins": "perc",
"set": "sorozat"
}

View File

@ -4,61 +4,80 @@ PODS:
- AppAuth/ExternalUserAgent (= 1.4.0)
- AppAuth/Core (1.4.0)
- AppAuth/ExternalUserAgent (1.4.0)
- awesome_notifications (0.0.2):
- Flutter
- device_info (0.0.1):
- Flutter
- devicelocale (0.0.1):
- Flutter
- FBSDKCoreKit (9.1.0):
- FBSDKCoreKit/Basics (= 9.1.0)
- FBSDKCoreKit/Core (= 9.1.0)
- FBSDKCoreKit/Basics (9.1.0)
- FBSDKCoreKit/Core (9.1.0):
- FBSDKCoreKit/Basics
- FBSDKLoginKit (9.1.0):
- FBSDKLoginKit/Login (= 9.1.0)
- FBSDKLoginKit/Login (9.1.0):
- FBSDKCoreKit (~> 9.1.0)
- Firebase/Analytics (8.0.0):
- FBAEMKit (11.1.0):
- FBAEMKit/AEM (= 11.1.0)
- FBAEMKit/AEM (11.1.0):
- FBSDKCoreKit_Basics (~> 11.1.0)
- FBSDKCoreKit (11.1.0):
- FBSDKCoreKit/Core (= 11.1.0)
- FBSDKCoreKit/Core (11.1.0):
- FBAEMKit (~> 11.1.0)
- FBSDKCoreKit_Basics (~> 11.1.0)
- FBSDKCoreKit_Basics (11.1.0):
- FBSDKCoreKit_Basics/Basics (= 11.1.0)
- FBSDKCoreKit_Basics/Basics (11.1.0)
- FBSDKLoginKit (11.1.0):
- FBSDKLoginKit/Login (= 11.1.0)
- FBSDKLoginKit/Login (11.1.0):
- FBSDKCoreKit (~> 11.1.0)
- FBSDKCoreKit_Basics (~> 11.1.0)
- Firebase/Analytics (8.5.0):
- Firebase/Core
- Firebase/Auth (8.0.0):
- Firebase/Auth (8.5.0):
- Firebase/CoreOnly
- FirebaseAuth (~> 8.0.0)
- Firebase/Core (8.0.0):
- FirebaseAuth (~> 8.5.0)
- Firebase/Core (8.5.0):
- Firebase/CoreOnly
- FirebaseAnalytics (~> 8.0.0)
- Firebase/CoreOnly (8.0.0):
- FirebaseCore (= 8.0.0)
- Firebase/Messaging (8.0.0):
- FirebaseAnalytics (~> 8.5.0)
- Firebase/CoreOnly (8.5.0):
- FirebaseCore (= 8.5.0)
- Firebase/DynamicLinks (8.5.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 8.0.0)
- Firebase/RemoteConfig (8.0.0):
- FirebaseDynamicLinks (~> 8.5.0)
- Firebase/InAppMessaging (8.5.0):
- Firebase/CoreOnly
- FirebaseRemoteConfig (~> 8.0.0)
- firebase_analytics (8.1.0):
- Firebase/Analytics (= 8.0.0)
- FirebaseInAppMessaging (~> 8.5.0-beta)
- Firebase/Messaging (8.5.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 8.5.0)
- Firebase/RemoteConfig (8.5.0):
- Firebase/CoreOnly
- FirebaseRemoteConfig (~> 8.5.0)
- firebase_analytics (8.3.0):
- Firebase/Analytics (= 8.5.0)
- firebase_core
- Flutter
- firebase_auth (1.2.0):
- Firebase/Auth (= 8.0.0)
- firebase_auth (3.0.2):
- Firebase/Auth (= 8.5.0)
- firebase_core
- Flutter
- firebase_core (1.2.0):
- Firebase/CoreOnly (= 8.0.0)
- firebase_core (1.5.0):
- Firebase/CoreOnly (= 8.5.0)
- Flutter
- firebase_messaging (10.0.0):
- Firebase/Messaging (= 8.0.0)
- firebase_dynamic_links (2.0.8):
- Firebase/DynamicLinks (= 8.5.0)
- firebase_core
- Flutter
- firebase_remote_config (0.10.0):
- Firebase/RemoteConfig (= 8.0.0)
- firebase_in_app_messaging (0.5.0-8):
- Firebase/InAppMessaging (= 8.5.0)
- firebase_core
- Flutter
- FirebaseABTesting (8.0.0):
- firebase_messaging (10.0.5):
- Firebase/Messaging (= 8.5.0)
- firebase_core
- Flutter
- firebase_remote_config (0.10.0-4):
- Firebase/RemoteConfig (= 8.5.0)
- firebase_core
- Flutter
- FirebaseABTesting (8.6.0):
- FirebaseCore (~> 8.0)
- FirebaseAnalytics (8.0.0):
- FirebaseAnalytics/AdIdSupport (= 8.0.0)
- FirebaseAnalytics (8.5.0):
- FirebaseAnalytics/AdIdSupport (= 8.5.0)
- FirebaseCore (~> 8.0)
- FirebaseInstallations (~> 8.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
@ -66,51 +85,50 @@ PODS:
- GoogleUtilities/Network (~> 7.4)
- "GoogleUtilities/NSData+zlib (~> 7.4)"
- nanopb (~> 2.30908.0)
- FirebaseAnalytics/AdIdSupport (8.0.0):
- FirebaseAnalytics/Base (= 8.0.0)
- FirebaseAnalytics/AdIdSupport (8.5.0):
- FirebaseCore (~> 8.0)
- FirebaseInstallations (~> 8.0)
- GoogleAppMeasurement (= 8.0.0)
- GoogleAppMeasurement (= 8.5.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
- GoogleUtilities/MethodSwizzler (~> 7.4)
- GoogleUtilities/Network (~> 7.4)
- "GoogleUtilities/NSData+zlib (~> 7.4)"
- nanopb (~> 2.30908.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 (8.0.0):
- FirebaseAuth (8.5.0):
- FirebaseCore (~> 8.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
- GoogleUtilities/Environment (~> 7.4)
- GTMSessionFetcher/Core (~> 1.5)
- FirebaseCore (8.0.0):
- FirebaseCore (8.5.0):
- FirebaseCoreDiagnostics (~> 8.0)
- GoogleUtilities/Environment (~> 7.4)
- GoogleUtilities/Logger (~> 7.4)
- FirebaseCoreDiagnostics (8.0.0):
- FirebaseCoreDiagnostics (8.6.0):
- GoogleDataTransport (~> 9.0)
- GoogleUtilities/Environment (~> 7.4)
- GoogleUtilities/Logger (~> 7.4)
- nanopb (~> 2.30908.0)
- FirebaseInstallations (8.0.0):
- FirebaseDynamicLinks (8.5.0):
- FirebaseCore (~> 8.0)
- FirebaseInAppMessaging (8.5.0-beta):
- FirebaseABTesting (~> 8.0)
- FirebaseCore (~> 8.0)
- FirebaseInstallations (~> 8.0)
- GoogleUtilities/Environment (~> 7.4)
- nanopb (~> 2.30908.0)
- FirebaseInstallations (8.6.0):
- FirebaseCore (~> 8.0)
- GoogleUtilities/Environment (~> 7.4)
- GoogleUtilities/UserDefaults (~> 7.4)
- PromisesObjC (~> 1.2)
- FirebaseMessaging (8.0.0):
- PromisesObjC (< 3.0, >= 1.2)
- FirebaseMessaging (8.5.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):
- FirebaseRemoteConfig (8.5.0):
- FirebaseABTesting (~> 8.0)
- FirebaseCore (~> 8.0)
- FirebaseInstallations (~> 8.0)
@ -124,12 +142,12 @@ PODS:
- flutter_app_badger (0.0.1):
- Flutter
- flutter_facebook_auth (2.0.0):
- FBSDKCoreKit (~> 9.1.0)
- FBSDKLoginKit (~> 9.1.0)
- FBSDKCoreKit (~> 11.1.0)
- FBSDKLoginKit (~> 11.1.0)
- Flutter
- flutter_secure_storage (3.3.1):
- Flutter
- flutter_uxcam (2.0.0-beta.1):
- flutter_uxcam (2.0.0):
- Flutter
- UXCam (~> 3.3.4)
- FMDB (2.7.5):
@ -138,45 +156,45 @@ PODS:
- google_sign_in (0.0.1):
- Flutter
- GoogleSignIn (~> 5.0)
- GoogleAppMeasurement (8.0.0):
- GoogleAppMeasurement/AdIdSupport (= 8.0.0)
- GoogleAppMeasurement (8.5.0):
- GoogleAppMeasurement/AdIdSupport (= 8.5.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.4)
- GoogleUtilities/MethodSwizzler (~> 7.4)
- GoogleUtilities/Network (~> 7.4)
- "GoogleUtilities/NSData+zlib (~> 7.4)"
- nanopb (~> 2.30908.0)
- GoogleAppMeasurement/AdIdSupport (8.0.0):
- GoogleAppMeasurement/AdIdSupport (8.5.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):
- GoogleDataTransport (9.1.0):
- GoogleUtilities/Environment (~> 7.2)
- nanopb (~> 2.30908.0)
- PromisesObjC (~> 1.2)
- PromisesObjC (< 3.0, >= 1.2)
- GoogleSignIn (5.0.2):
- AppAuth (~> 1.2)
- GTMAppAuth (~> 1.0)
- GTMSessionFetcher/Core (~> 1.1)
- GoogleUtilities/AppDelegateSwizzler (7.4.1):
- GoogleUtilities/AppDelegateSwizzler (7.5.1):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Environment (7.4.1):
- PromisesObjC (~> 1.2)
- GoogleUtilities/Logger (7.4.1):
- GoogleUtilities/Environment (7.5.1):
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/Logger (7.5.1):
- GoogleUtilities/Environment
- GoogleUtilities/MethodSwizzler (7.4.1):
- GoogleUtilities/MethodSwizzler (7.5.1):
- GoogleUtilities/Logger
- GoogleUtilities/Network (7.4.1):
- GoogleUtilities/Network (7.5.1):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (7.4.1)"
- GoogleUtilities/Reachability (7.4.1):
- "GoogleUtilities/NSData+zlib (7.5.1)"
- GoogleUtilities/Reachability (7.5.1):
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (7.4.1):
- GoogleUtilities/UserDefaults (7.5.1):
- GoogleUtilities/Logger
- GTMAppAuth (1.2.2):
- AppAuth/Core (~> 1.4)
@ -195,7 +213,7 @@ PODS:
- Flutter
- path_provider (0.0.1):
- Flutter
- PromisesObjC (1.2.12)
- PromisesObjC (2.0.0)
- Purchases (3.11.1):
- PurchasesCoreSwift (= 3.11.1)
- purchases_flutter (3.2.2):
@ -231,12 +249,13 @@ PODS:
- Flutter
DEPENDENCIES:
- awesome_notifications (from `.symlinks/plugins/awesome_notifications/ios`)
- device_info (from `.symlinks/plugins/device_info/ios`)
- devicelocale (from `.symlinks/plugins/devicelocale/ios`)
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
- firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_dynamic_links (from `.symlinks/plugins/firebase_dynamic_links/ios`)
- firebase_in_app_messaging (from `.symlinks/plugins/firebase_in_app_messaging/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- firebase_remote_config (from `.symlinks/plugins/firebase_remote_config/ios`)
- flurry_data (from `.symlinks/plugins/flurry_data/ios`)
@ -264,7 +283,9 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- AppAuth
- FBAEMKit
- FBSDKCoreKit
- FBSDKCoreKit_Basics
- FBSDKLoginKit
- Firebase
- FirebaseABTesting
@ -272,6 +293,8 @@ SPEC REPOS:
- FirebaseAuth
- FirebaseCore
- FirebaseCoreDiagnostics
- FirebaseDynamicLinks
- FirebaseInAppMessaging
- FirebaseInstallations
- FirebaseMessaging
- FirebaseRemoteConfig
@ -292,8 +315,6 @@ SPEC REPOS:
- UXCam
EXTERNAL SOURCES:
awesome_notifications:
:path: ".symlinks/plugins/awesome_notifications/ios"
device_info:
:path: ".symlinks/plugins/device_info/ios"
devicelocale:
@ -304,6 +325,10 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/firebase_auth/ios"
firebase_core:
:path: ".symlinks/plugins/firebase_core/ios"
firebase_dynamic_links:
:path: ".symlinks/plugins/firebase_dynamic_links/ios"
firebase_in_app_messaging:
:path: ".symlinks/plugins/firebase_in_app_messaging/ios"
firebase_messaging:
:path: ".symlinks/plugins/firebase_messaging/ios"
firebase_remote_config:
@ -353,38 +378,43 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
AppAuth: 31bcec809a638d7bd2f86ea8a52bd45f6e81e7c7
awesome_notifications: 74462bc8e68b11f8235d78422266886759e9da61
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
devicelocale: b22617f40038496deffba44747101255cee005b0
FBSDKCoreKit: a00fe2efd780c195a5e09201bf51c56106245b40
FBSDKLoginKit: d98498c598ec09de657385a9349a1f21119b7f86
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
FBAEMKit: 5c8a8d08e5b2c79628490784883e0fcc75b12615
FBSDKCoreKit: 7ccb8b4bb2b5ee2ad94327b774dc23f03509675d
FBSDKCoreKit_Basics: 8f978bce195845f609b0ec6b425949d0d24f525b
FBSDKLoginKit: d65eb587a9eaa89295338fb0bb3b358bde0b7ae4
Firebase: ff8c73105b90e33e1dc6c8e5445d7adc2ccdc7c1
firebase_analytics: 3b7d92b8d1a3482f557c201e5e46c2f7fa2644ff
firebase_auth: 214ff86facd807bbb0ccff32f4b2d3865e3bc4f3
firebase_core: 82d486a6231b636aea229bd471bceca82cbe00a6
firebase_dynamic_links: 0768a32e69be5b6f9af258f8e072537dff6b8969
firebase_in_app_messaging: 04572963cf1ef212ac23e188cb0324316e948bf9
firebase_messaging: 0c5342aa6d92d09429ef67c81a1345189fcb76c9
firebase_remote_config: cd43874ff082605023b5913bb1d3206452f1ad48
FirebaseABTesting: c3e48ebf5e7e5c674c5a131c68e941d7921d83dc
FirebaseAnalytics: 96325c1e0acbd2bb805c6a613028b1fe599d6a37
FirebaseAuth: b152ea261b60eeb9419ae7e5bf34761382b33277
FirebaseCore: 1c1ca72483b59b17050f5b4cec4fb748425a3901
FirebaseCoreDiagnostics: 3721920bde3a9a6d5aa093c1d25e9d3e47f694af
FirebaseDynamicLinks: 6e406b3bb669f8c8a63e7254bb63251fa3f88a43
FirebaseInAppMessaging: ee6cd4397d1e81d34b14f90ec38697dc4ef9fe93
FirebaseInstallations: 0ede6ffcd215b8f93c19d9b06c1c54e2d4107e98
FirebaseMessaging: 0705ec705c21705efc51c071fba924c8e25c63e7
FirebaseRemoteConfig: 693c1f150408e9a727daf4d8c55c7f9c29ef9ad5
Flurry-iOS-SDK: 5831da8fc6bedb31fa1f94aac6fd204d36dd351d
flurry_data: 49b7066a283aa41f4306974c1f2d74c61231ad74
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68
flutter_facebook_auth: 4b170c07b7fce791497093fcc3f134fb215f3f07
flutter_facebook_auth: 528d51ea1324741b366fa87fa5dfd41016422364
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
flutter_uxcam: ab8e5d3954eb448febd581375e2622e9eecb1066
flutter_uxcam: 5b2418884a3bf41284a888c7ecc50317c8a84727
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc
GoogleAppMeasurement: c6bbc9753d046b5456dd4f940057fbad2c28419e
GoogleDataTransport: 11e3a5f2c190327df1a4a5d7e7ae3d4d5b9c9e4c
GoogleAppMeasurement: 8d10c1c470fcb0e5143ed74fddd164f0a0384800
GoogleDataTransport: 85fd18ff3019bb85d3f2c551d04c481dedf71fc9
GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
GoogleUtilities: f8a43108b38a68eebe8b3540e1f4f2d28843ce20
GoogleUtilities: 3df19e3c24f7bbc291d8b5809aa6b0d41e642437
GTMAppAuth: ad5c2b70b9a8689e1a04033c9369c4915bfcbe89
GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde
@ -392,7 +422,7 @@ SPEC CHECKSUMS:
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58
Purchases: 6351f9ff6bd514e5ec5aa0f989ea181effa94bf5
purchases_flutter: 627527b070d80cdaf486fabe8b3d1dbe8d5cad92
PurchasesCoreSwift: ee857e4c21e6254b09d7e303a756fcf2b9164408
@ -411,4 +441,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: f10c0438b63bc24e6bbc207956dc27d16c4408f2
COCOAPODS: 1.10.1
COCOAPODS: 1.11.0.beta.2

View File

@ -396,7 +396,7 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -405,12 +405,12 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 1.1.21;
MARKETING_VERSION = 1.1.22;
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
@ -539,7 +539,7 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -548,13 +548,13 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 1.1.21;
MARKETING_VERSION = 1.1.22;
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@ -574,7 +574,7 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -583,12 +583,12 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 1.1.21;
MARKETING_VERSION = 1.1.22;
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;

View File

@ -10,6 +10,9 @@ import Firebase
) -> Bool {
FirebaseApp.configure()
GeneratedPluginRegistrant.register(with: self)
if #available(iOS 12.0, *) {
UNUserNotificationCenter.current().delegate = self
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@ -1,75 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>WorkoutTest</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb584181112271127</string>
<string>com.googleusercontent.apps.926782702216-2nsi7d9at3pc5ts8gkobt5697v590kb9</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>FacebookAppID</key>
<string>584181112271127</string>
<key>FacebookDisplayName</key>
<string>Mobile Login</string>
<key>FirebaseAppDelegateProxyEnabled</key>
<string>NO</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>http</string>
</array>
<key>LSMinimumSystemVersion</key>
<string>11.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>WorkoutTest</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>aitrainer.page.link</string>
<key>CFBundleURLSchemes</key>
<array>
<string>wt001</string>
<string>fb584181112271127</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>FacebookAdvertiserIDCollectionEnabled</key>
<string>TRUE</string>
<key>FacebookAppID</key>
<string>584181112271127</string>
<key>FacebookAutoLogAppEventsEnabled</key>
<string>TRUE</string>
<key>FacebookDisplayName</key>
<string>Workout Test</string>
<key>FirebaseAppDelegateProxyEnabled</key>
<string>NO</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>http</string>
<string>fbapi</string>
<string>fbapi20130214</string>
<string>fbapi20130410</string>
<string>fbapi20130702</string>
<string>fbapi20131010</string>
<string>fbapi20131219</string>
<string>fbapi20140410</string>
<string>fbapi20140116</string>
<string>fbapi20150313</string>
<string>fbapi20150629</string>
<string>fbapi20160328</string>
<string>fb-messenger-share-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
<key>LSMinimumSystemVersion</key>
<string>11.0.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>Launch Screen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>Launch Screen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

@ -8,6 +8,10 @@
<array>
<string>Default</string>
</array>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:aitrainer.page.link</string>
</array>
<key>com.apple.developer.authentication-services.autofill-credential-provider</key>
<true/>
</dict>

View File

@ -29,8 +29,8 @@ class CustomerChangeBloc extends Bloc<CustomerChangeEvent, CustomerChangeState>
weight = this.customerRepository.getWeight() == 0 ? 60 : this.customerRepository.getWeight();
height = this.customerRepository.getHeight() == 0 ? 170 : this.customerRepository.getHeight();
selectedSport = customerRepository.getSport();
print("selected: $selectedFitnessItem sport: $selectedSport " + customerRepository.customer!.fitnessLevel.toString());
// selectedSport = customerRepository.getSport();
//print("selected: $selectedFitnessItem sport: $selectedSport " + customerRepository.customer!.fitnessLevel.toString());
}
Sport? selectedSport;
@ -41,6 +41,7 @@ class CustomerChangeBloc extends Bloc<CustomerChangeEvent, CustomerChangeState>
CustomerChangeEvent event,
) async* {
try {
print("Event: $event");
if (event is CustomerLoad) {
yield CustomerChangeLoading();
yield CustomerDataChanged();
@ -63,7 +64,7 @@ class CustomerChangeBloc extends Bloc<CustomerChangeEvent, CustomerChangeState>
year = event.year;
yield CustomerDataChanged();
} else if (event is CustomerWeightChange) {
yield CustomerChangeLoading();
//yield CustomerChangeLoading();
customerRepository.setWeight(event.weight);
weight = event.weight.toDouble();
yield CustomerDataChanged();
@ -88,12 +89,43 @@ class CustomerChangeBloc extends Bloc<CustomerChangeEvent, CustomerChangeState>
customerRepository.setName(event.name);
yield CustomerDataChanged();
} else if (event is CustomerGenderChange) {
yield CustomerChangeLoading();
customerRepository.setSex(event.gender == 0 ? "m" : "w");
yield CustomerDataChanged();
} else if (event is CustomerSportChange) {
yield CustomerChangeLoading();
selectedSport = event.sport;
yield CustomerDataChanged();
} else if (event is CustomerSaveFitness) {
yield CustomerChangeLoading();
if (customerRepository.customer!.fitnessLevel == null) {
throw Exception("Please select your fitness level");
}
yield CustomerSaveSuccess();
} else if (event is CustomerSaveGoal) {
yield CustomerChangeLoading();
if (customerRepository.customer!.goal == null) {
throw Exception("Please select your goal");
}
yield CustomerSaveSuccess();
} else if (event is CustomerSaveSex) {
yield CustomerChangeLoading();
if (customerRepository.customer!.sex == null) {
throw Exception("Please select your biologial gender");
}
yield CustomerSaveSuccess();
} else if (event is CustomerSaveWeight) {
yield CustomerChangeLoading();
if (customerRepository.customer!.getProperty("Weight") == null) {
throw Exception("Please select your weight");
}
yield CustomerSaveSuccess();
} else if (event is CustomerSaveHeight) {
yield CustomerChangeLoading();
if (customerRepository.customer!.getProperty("Height") == null) {
throw Exception("Please select your height");
}
yield CustomerSaveSuccess();
} else if (event is CustomerSave) {
yield CustomerSaving();
if (validation()) {

View File

@ -114,3 +114,23 @@ class CustomerLoad extends CustomerChangeEvent {
class CustomerSave extends CustomerChangeEvent {
const CustomerSave();
}
class CustomerSaveGoal extends CustomerChangeEvent {
const CustomerSaveGoal();
}
class CustomerSaveFitness extends CustomerChangeEvent {
const CustomerSaveFitness();
}
class CustomerSaveSex extends CustomerChangeEvent {
const CustomerSaveSex();
}
class CustomerSaveWeight extends CustomerChangeEvent {
const CustomerSaveWeight();
}
class CustomerSaveHeight extends CustomerChangeEvent {
const CustomerSaveHeight();
}

View File

@ -1,13 +1,17 @@
import 'dart:async';
import 'dart:collection';
import 'package:intl/intl.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';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/exercise_device_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/repository/workout_tree_repository.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
@ -111,6 +115,22 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
listFilterDevice.remove(deviceId);
}
yield MenuReady();
} else if (event is MenuStartTrial) {
yield MenuLoading();
final DateTime start = event.start;
CustomerRepository customerRepository = CustomerRepository();
customerRepository.customer = Cache().userLoggedIn;
customerRepository.customer!.trialDate = start;
Cache().userLoggedIn!.trialDate = start;
customerRepository.saveCustomer();
if (DateTime.now().difference(start).inHours < 1) {
Cache().hasPurchased = true;
log("Trial mode on!");
Track().track(TrackingEvent.trial, eventValue: DateFormat('yyyy-MM-dd HH:mm:ss').format(start));
}
yield MenuReady();
}
} on Exception catch (ex) {
yield MenuError(message: ex.toString());
@ -134,6 +154,9 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
case "my_body":
ability = ExerciseAbility.none;
break;
case "training_execute":
ability = ExerciseAbility.training_execute;
break;
}
log("Ability: " + ability.toString() + " name: " + name);
}

View File

@ -56,4 +56,15 @@ class MenuRecreateTree extends MenuEvent {
class MenuFilterExerciseType extends MenuEvent {
final int deviceId;
const MenuFilterExerciseType({required this.deviceId});
@override
List<Object> get props => [deviceId];
}
class MenuStartTrial extends MenuEvent {
final DateTime start;
const MenuStartTrial({required this.start});
@override
List<Object> get props => [start];
}

View File

@ -13,6 +13,7 @@ part 'session_state.dart';
class SessionBloc extends Bloc<SessionEvent, SessionState> with Logging {
final Session session;
StreamSubscription? _sub;
SessionBloc({required this.session}) : super(SessionInitial());
@ -41,6 +42,7 @@ class SessionBloc extends Bloc<SessionEvent, SessionState> with Logging {
@override
Future<void> close() async {
await this.close();
_sub?.cancel();
super.close();
}
}

View File

@ -59,10 +59,12 @@ class TrainingEvaluationBloc extends Bloc<TrainingEvaluationEvent, TrainingEvalu
trainingPlanBloc.getMyPlan()!.days[day]!.forEach((element) {
//if (!element.state.equalsTo(ExercisePlanDetailState.extra)) {
if (!findExerciseInEvaluationList(element.exerciseTypeId!)) {
addEvaluationExercise(element);
} else {
//editEvaluationExercise(element);
if (element.exerciseTypeId != null) {
if (!findExerciseInEvaluationList(element.exerciseTypeId!)) {
addEvaluationExercise(element);
} else {
//editEvaluationExercise(element);
}
}
//}
});
@ -93,7 +95,7 @@ class TrainingEvaluationBloc extends Bloc<TrainingEvaluationEvent, TrainingEvalu
exercise.type = TrainingEvaluationExerciseType.weightBased;
this.evaluationList.add(exercise);
} else {
if (detail.exerciseType!.unitQuantityUnit == null) {
if (detail.exerciseType!.unitQuantityUnit == null || detail.weight == null) {
exercise.type = TrainingEvaluationExerciseType.repeatBased;
exercise.repeats = detail.repeats;
exercise.maxRepeats = getMaxRepeatsByExerciseType(detail.exerciseTypeId!);

View File

@ -46,7 +46,7 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
try {
if (event is TrainingPlanActivate) {
yield TrainingPlanLoading();
_myPlan = await trainingPlanRepository.activateTrainingPlan(event.trainingPlanId);
_myPlan = trainingPlanRepository.activateTrainingPlan(event.trainingPlanId);
_myPlan!.type = CustomerTrainingPlanType.template;
menuBloc.menuTreeRepository.sortedTree.forEach((name, list) {
@ -72,7 +72,6 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
event.detail.repeats =
Common.reCalculateRepeatsByChangedWeight(event.detail.weight!, event.detail.repeats!.toDouble(), event.weight);
event.detail.weight = event.weight;
print(" weight: ${event.weight} new repeats: ${event.detail.repeats}");
yield TrainingPlanReady();
} else if (event is TrainingPlanRepeatsChange) {
@ -102,13 +101,12 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
exercise.unitQuantity = event.detail.weight;
exercise.dateAdd = DateTime.now();
event.detail.exercises.add(exercise);
if (event.detail.exercises.length >= event.detail.set!) {
if (this.isAllDetailsSameExerciseFinished(event.detail)) {
event.detail.state = ExercisePlanDetailState.finished;
} else if (event.detail.exercises.length >= 0) {
event.detail.state = ExercisePlanDetailState.inProgress;
}
// recalculate the weight to the original planned repeats for the next details
if (exercise.unitQuantity != null && exercise.unitQuantity! > 0) {
for (var nextDetail in _myPlan!.details) {
double weightFromPlan = trainingPlanRepository.getOriginalWeight(this.getMyPlan()!.trainingPlanId!, nextDetail);
@ -357,6 +355,23 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
return workoutTree.imageName;
}
int getStep(CustomerTrainingPlanDetails detail) {
List<CustomerTrainingPlanDetails> details = getAllDetailsSameExercise(detail);
int step = 0;
int indexElement = 0;
details.forEach((element) {
if (indexElement == 0) {
step = element.exercises.length;
} else {
step += element.exercises.length;
}
indexElement++;
});
//print("STEP: $step ");
return step;
}
CustomerTrainingPlanDetails? getNext() {
if (_myPlan == null || _myPlan!.details.isEmpty) {
return null;
@ -373,12 +388,16 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
break;
} else {
final int step = detail.exercises.length;
if (step < minStep && !detail.state.equalsTo(ExercisePlanDetailState.skipped) && day == detail.day) {
if (step < minStep &&
step < detail.set! &&
!isAllDetailsSameExerciseFinished(detail) &&
!detail.state.equalsTo(ExercisePlanDetailState.skipped) &&
day == detail.day) {
next = detail;
minStep = step;
if (detail.parallel != true) {
break;
}
//if (detail.parallel != true) {
break;
//}
}
}
}
@ -423,18 +442,23 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
int indexInProgress = 0;
int indexInStart = 0;
final String day = dayNames[this.activeDayIndex];
CustomerTrainingPlanDetails? prev;
for (var detail in _myPlan!.days[day]!) {
if (detail.state == ExercisePlanDetailState.inProgress) {
//print("Offset detail $detail");
if (detail.state == ExercisePlanDetailState.inProgress || detail.state == ExercisePlanDetailState.start) {
prev = detail;
break;
}
if (detail.state == ExercisePlanDetailState.start) {
break;
if (prev != null && prev.exerciseTypeId != detail.exerciseTypeId && detail.state != ExercisePlanDetailState.extra) {
//print(" --- offset + 1");
indexInStart++;
indexInProgress++;
}
indexInStart++;
indexInProgress++;
prev = detail;
}
int index = indexInStart > indexInProgress ? indexInStart : indexInProgress;
offset = index * 80;
offset = (index) * 270;
print("Offset: $offset day: $day ($indexInStart, $indexInProgress)");
return offset;
}
@ -573,4 +597,23 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
}
return exists;
}
List<CustomerTrainingPlanDetails> getAllDetailsSameExercise(CustomerTrainingPlanDetails detail) {
List<CustomerTrainingPlanDetails> list = [];
getMyPlan()!.details.forEach((element) {
if (detail.exerciseTypeId == element.exerciseTypeId) {
list.add(element);
}
});
return list;
}
bool isAllDetailsSameExerciseFinished(CustomerTrainingPlanDetails detail) {
bool allFinished = true;
List<CustomerTrainingPlanDetails> list = getAllDetailsSameExercise(detail);
for (var listDetail in list) {
allFinished = allFinished && listDetail.exercises.length >= listDetail.set!;
}
return allFinished;
}
}

View File

@ -13,7 +13,10 @@ import 'package:aitrainer_app/view/customer_bodytype_animation.dart';
import 'package:aitrainer_app/view/customer_exercise_device.dart';
import 'package:aitrainer_app/view/customer_fitness_page.dart';
import 'package:aitrainer_app/view/customer_goal_page.dart';
import 'package:aitrainer_app/view/customer_height_page.dart';
import 'package:aitrainer_app/view/customer_modify_page.dart';
import 'package:aitrainer_app/view/customer_sex_page.dart';
import 'package:aitrainer_app/view/customer_weight_page.dart';
import 'package:aitrainer_app/view/customer_welcome_page.dart';
import 'package:aitrainer_app/view/evaluation_page.dart';
import 'package:aitrainer_app/view/exercise_control_page.dart';
@ -23,6 +26,7 @@ import 'package:aitrainer_app/view/login.dart';
import 'package:aitrainer_app/view/exercise_new_page.dart';
import 'package:aitrainer_app/view/training_plan_custom.dart';
import 'package:aitrainer_app/view/training_plan_custom_add.dart';
import 'package:aitrainer_app/view/training_plan_execute.dart';
import 'package:aitrainer_app/view/training_plans_page.dart';
import 'package:aitrainer_app/view/mydevelopment_body_page.dart';
import 'package:aitrainer_app/view/mydevelopment_muscle_page.dart';
@ -146,7 +150,6 @@ Future<Null> main() async {
}
print(" -- FireBase init..");
await FirebaseApi().initializeFlutterFire();
runApp(MultiBlocProvider(
providers: [
@ -177,8 +180,8 @@ Future<Null> main() async {
BlocProvider<TestSetExecuteBloc>(
create: (BuildContext context) => TestSetExecuteBloc(),
),
BlocProvider<TutorialBloc>(
create: (BuildContext context) => TutorialBloc(tutorialName: ActivityDone.tutorialExecuteFirstTest.toStr())),
/* BlocProvider<TutorialBloc>(
create: (BuildContext context) => TutorialBloc(tutorialName: ActivityDone.tutorialExecuteFirstTest.toStr())), */
BlocProvider<TrainingPlanBloc>(create: (context) {
final MenuBloc menuBloc = BlocProvider.of<MenuBloc>(context);
return TrainingPlanBloc(menuBloc: menuBloc, trainingPlanRepository: TrainingPlanRepository());
@ -196,6 +199,7 @@ Future<void> initThirdParty() async {
await FlurryData.initialize(androidKey: "JNYCTCWBT34FM3J8TV36", iosKey: "3QBG7BSMGPDH24S8TRQP", enableLog: true);
FlutterUxcam.optIntoSchematicRecordings();
}
await FirebaseApi().initializeFlutterFire();
}
class WorkoutTestApp extends StatelessWidget {
@ -217,6 +221,7 @@ class WorkoutTestApp extends StatelessWidget {
//facebookAppEvents.setAdvertiserTracking(enabled: true);
initThirdParty();
return MaterialApp(
localizationsDelegates: [
// ... app-specific localization delegate[s] here
@ -249,6 +254,9 @@ class WorkoutTestApp extends StatelessWidget {
'customerModifyPage': (context) => CustomerModifyPage(),
'customerGoalPage': (context) => CustomerGoalPage(),
'customerFitnessPage': (context) => CustomerFitnessPage(),
'customerSexPage': (context) => CustomerSexPage(),
'customerWeightPage': (context) => CustomerWeightPage(),
'customerHeightPage': (context) => CustomerHeightPage(),
'customerBodyTypePage': (context) => CustomerBodyTypeAnimationPage(),
'customerWelcomePage': (context) => CustomerWelcomePage(),
'customerExerciseDevicePage': (context) => CustomerExerciseDevicePage(),
@ -275,7 +283,8 @@ class WorkoutTestApp extends StatelessWidget {
'myTrainingPlanCustom': (context) => TrainingPlanCustomPage(),
'myTrainingPlanCustomAdd': (context) => TrainingPlanCustomAddPage(),
'myTrainingPlanActivate': (context) => TrainingPlanActivatePage(),
'myTrainingPlanExecute': (context) => TrainingPlanExecutePage(),
'myTrainingPlanExecute2': (context) => TrainingPlanExecutePage(),
'myTrainingPlanExecute': (context) => TrainingPlanExecute(),
'myTrainingPlanExercise': (context) => TrainingPlanExercise(),
'myTrainingEvaluation': (context) => TrainingEvaluationPage(),
},

View File

@ -186,8 +186,8 @@ class Cache with Logging {
Cache._internal() {
String testEnv = EnvironmentConfig.test_env;
this.testEnvironment = testEnv;
print("testEnv $testEnv");
if (testEnv == "1") {
print("testEnv $testEnv");
baseUrl = baseUrlTest;
liveServer = false;
}
@ -234,6 +234,17 @@ class Cache with Logging {
sharedPreferences.setString(Cache.myTrainingPlanKey, myTrainingPlanJson);
}
Future<void> deleteMyTrainingPlan() async {
if (myTrainingPlan == null) {
return;
}
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
SharedPreferences sharedPreferences;
sharedPreferences = await prefs;
sharedPreferences.remove(Cache.myTrainingPlanKey);
}
Future<void> getMyTrainingPlan() async {
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
SharedPreferences sharedPreferences;
@ -744,4 +755,21 @@ class Cache with Logging {
List<TrainingPlanDay> getTrainingPlanDays() => this._trainingPlanDays;
setTrainingPlanDays(value) => this._trainingPlanDays = value;
bool canTrial() {
if (Cache().userLoggedIn == null) {
return false;
}
for (var element in _purchases) {
if (element.customerId == Cache().userLoggedIn!.customerId) {
return false;
}
}
if (userLoggedIn!.trialDate != null) {
return false;
}
return true;
}
}

View File

@ -24,6 +24,7 @@ class Customer {
DateTime? dateChange;
int? emailSubscription;
int? sportId;
DateTime? trialDate;
LinkedHashMap<String, CustomerProperty> properties = LinkedHashMap();
@ -70,6 +71,7 @@ class Customer {
this.dataPolicyAllowed = json['dataPolicyAllowed'];
this.emailSubscription = json['emailSubscription'];
this.sportId = json['sportId'];
this.trialDate = json['trialDate'] == null ? null : DateTime.parse(json['trialDate']);
this.dateAdd = json['dateAdd'] == null ? DateTime.parse("0000-00-00") : DateTime.parse(json['dateAdd']);
this.dateChange = json['dateChange'] == null ? DateTime.parse("0000-00-00") : DateTime.parse(json['dateChange']);
@ -93,7 +95,8 @@ class Customer {
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!),
"dateChange": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateChange!),
"emailSubscription": this.emailSubscription,
"sportId": this.sportId
"sportId": this.sportId,
"trialDate": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.trialDate!),
};
double getProperty(String propertyName) {

View File

@ -1,4 +1,4 @@
enum ExerciseAbility { oneRepMax, endurance, running, mini_test_set, paralell_test, training, none }
enum ExerciseAbility { oneRepMax, endurance, running, mini_test_set, paralell_test, training, training_execute, none }
extension ExerciseAbilityExt on ExerciseAbility {
String enumToString() => this.toString().split(".").last;

View File

@ -75,6 +75,7 @@ class WorkoutMenuTree {
"is1RM": is1RM.toString(),
"isRunning": isRunning.toString(),
"sort": sort,
"internalName": internalName,
};
}

View File

@ -168,7 +168,7 @@ class CustomerRepository with Logging {
if (this.customer!.properties[propertyName] == null) {
this.customer!.properties[propertyName] = CustomerProperty(
propertyId: propertyRepository.getPropertyByName("Height")!.propertyId,
customerId: this.customer!.customerId!,
customerId: this.customer!.customerId == null ? 0 : this.customer!.customerId!,
propertyValue: value,
dateAdd: DateTime.now());
} else {

View File

@ -4,9 +4,10 @@ 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/fitness_state.dart';
import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/repository/training_plan_day_repository.dart';
import 'package:aitrainer_app/service/training_plan_service.dart';
import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/util/common.dart';
class TrainingPlanRepository {
@ -40,14 +41,14 @@ class TrainingPlanRepository {
/// 2. calculate customer_training_plan_details weights / repleats
/// 3. create new customer_training_plan
Future<CustomerTrainingPlan?> activateTrainingPlan(int trainingPlanId) async {
CustomerTrainingPlan? activateTrainingPlan(int trainingPlanId) {
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!);
//TrainingPlanApi().updateCustomerTrainingPlan(plan, plan.customerTrainingPlanId!);
}
});
}
@ -58,7 +59,7 @@ class TrainingPlanRepository {
plan.active = true;
plan.status = "open";
plan.dateAdd = DateTime.now();
plan.name = getTrainingPlanById(trainingPlanId)!.nameTranslations["hu"];
plan.name = getTrainingPlanById(trainingPlanId)!.nameTranslations[AppLanguage().appLocal.toString()];
TrainingPlan? trainingPlan = this.getTrainingPlanById(trainingPlanId);
if (trainingPlan == null || trainingPlan.details == null) {
@ -138,6 +139,23 @@ class TrainingPlanRepository {
return plan;
}
int? getTrainingPlanByInternalName(String internalName) {
int? id;
if (Cache().getTrainingPlans() == null) {
return id;
}
for (var trainingPlan in Cache().getTrainingPlans()!) {
print("internal ${trainingPlan.internalName}");
if (trainingPlan.internalName == internalName) {
id = trainingPlan.trainingPlanId;
break;
}
}
return id;
}
CustomerTrainingPlanDetails getCalculatedWeightRepeats(int exerciseTypeId, CustomerTrainingPlanDetails detail) {
double weight = -1;
if (Cache().getExercises() == null) {
@ -247,4 +265,32 @@ class TrainingPlanRepository {
return recalculatedDetail;
}
void generateTrainingPlan() {
int? trainingPlanId;
if (Cache().userLoggedIn == null) {
return;
}
bool isWoman = Cache().userLoggedIn!.sex == "w";
if (Cache().userLoggedIn!.fitnessLevel == FitnessState.beginner) {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_beginner") : getTrainingPlanByInternalName("beginner_man");
} else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.intermediate) {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_beginner_split") : getTrainingPlanByInternalName("beginner_split");
} else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.advanced) {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_advanced") : getTrainingPlanByInternalName("man_routine4");
} else {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("5day") : getTrainingPlanByInternalName("5day");
}
print("Generated plan $trainingPlanId fitness ${Cache().userLoggedIn!.fitnessLevel} - ${FitnessState.beginner}");
if (trainingPlanId != null) {
CustomerTrainingPlan? customerTrainingPlan = activateTrainingPlan(trainingPlanId);
if (customerTrainingPlan != null) {
Cache().myTrainingPlan = customerTrainingPlan;
}
}
}
}

View File

@ -30,6 +30,7 @@ class ExerciseTreeApi with Logging {
Future<String> buildImage(String imageUrl, int treeId) async {
String assetImage = 'asset/menu/' + imageUrl.substring(7);
print("asset image $assetImage");
return await rootBundle.load(assetImage).then((value) {
return assetImage;
}).catchError((_) {

View File

@ -4,12 +4,10 @@ import 'package:crypto/crypto.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart' as logging;
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
import 'package:awesome_notifications/awesome_notifications.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:firebase_remote_config/firebase_remote_config.dart';
import 'package:flutter/material.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
@ -37,7 +35,8 @@ class FirebaseApi with logging.Logging {
await Firebase.initializeApp();
this.appleSignInAvailable = await SignInWithApple.isAvailable();
AwesomeNotifications().initialize(
/* AwesomeNotifications().initialize(
// set the icon to null if you want to use the default app icon
null,
[
@ -55,7 +54,7 @@ class FirebaseApi with logging.Logging {
// This is very important to not harm the user experience
AwesomeNotifications().requestPermissionToSendNotifications();
}
});
}); */
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true, // Required to display a heads up notification
@ -71,32 +70,6 @@ class FirebaseApi with logging.Logging {
}
}
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
print('Handling a background message: ${message.messageId}');
if (!StringUtils.isNullOrEmpty(message.notification?.title, considerWhiteSpaceAsEmpty: true) ||
!StringUtils.isNullOrEmpty(message.notification?.body, considerWhiteSpaceAsEmpty: true)) {
print('message also contained a notification: ${message.notification}');
String? imageUrl;
imageUrl ??= message.notification!.android?.imageUrl;
imageUrl ??= message.notification!.apple?.imageUrl;
Map<String, dynamic> notificationAdapter = {
NOTIFICATION_CHANNEL_KEY: 'basic_channel',
NOTIFICATION_ID: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_ID] ?? message.messageId ?? math.Random().nextInt(2147483647),
NOTIFICATION_TITLE: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_TITLE] ?? message.notification?.title,
NOTIFICATION_BODY: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_BODY] ?? message.notification?.body,
NOTIFICATION_LAYOUT: StringUtils.isNullOrEmpty(imageUrl) ? 'Default' : 'BigPicture',
NOTIFICATION_BIG_PICTURE: imageUrl
};
AwesomeNotifications().createNotificationFromJsonData(notificationAdapter);
} else {
AwesomeNotifications().createNotificationFromJsonData(message.data);
}
}
Future<String> signInEmail(String? email, String? password) async {
if (email == null) {
throw Exception("Please type an email address");
@ -395,7 +368,7 @@ class FirebaseApi with logging.Logging {
}
Future<void> setupRemoteConfig() async {
initializeFlutterFire();
//initializeFlutterFire();
RemoteConfig? remoteConfig;
try {
remoteConfig = RemoteConfig.instance;
@ -420,3 +393,35 @@ class FirebaseApi with logging.Logging {
}
}
}
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
print('Handling a background message ${message.messageId}');
}
/* Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
print('Handling a background message: ${message.messageId}');
if (!StringUtils.isNullOrEmpty(message.notification?.title, considerWhiteSpaceAsEmpty: true) ||
!StringUtils.isNullOrEmpty(message.notification?.body, considerWhiteSpaceAsEmpty: true)) {
print('message also contained a notification: ${message.notification}');
String? imageUrl;
imageUrl ??= message.notification!.android?.imageUrl;
imageUrl ??= message.notification!.apple?.imageUrl;
Map<String, dynamic> notificationAdapter = {
NOTIFICATION_CHANNEL_KEY: 'basic_channel',
NOTIFICATION_ID: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_ID] ?? message.messageId ?? math.Random().nextInt(2147483647),
NOTIFICATION_TITLE: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_TITLE] ?? message.notification?.title,
NOTIFICATION_BODY: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_BODY] ?? message.notification?.body,
NOTIFICATION_LAYOUT: StringUtils.isNullOrEmpty(imageUrl) ? 'Default' : 'BigPicture',
NOTIFICATION_BIG_PICTURE: imageUrl
};
AwesomeNotifications().createNotificationFromJsonData(notificationAdapter);
} else {
AwesomeNotifications().createNotificationFromJsonData(message.data);
}
} */

View File

@ -57,6 +57,7 @@ enum TrackingEvent {
training_plan_execute,
training_plan_finished,
training_plan_custom,
trial
}
T enumFromString<T>(Iterable<T> values, String value) {

View File

@ -46,7 +46,9 @@ class RevenueCatPurchases with Logging {
log("Purchaserinfo not reachable " + e.toString());
}
}
if (Cache().userLoggedIn!.admin == 1) {
bool inTrial = Cache().userLoggedIn!.trialDate != null && DateTime.now().difference(Cache().userLoggedIn!.trialDate!).inDays < 10;
log("Trial mode: $inTrial date: ${Cache().userLoggedIn!.trialDate}");
if (Cache().userLoggedIn!.admin == 1 || inTrial) {
Cache().hasPurchased = true;
}
}

View File

@ -19,12 +19,13 @@ class Track with Logging {
Track._internal();
void track(TrackingEvent event, {String eventValue = ""}) {
analytics.logEvent(name: event.enumToString(), parameters: {"value": eventValue});
if (!isInDebugMode) {
FlurryData.logEvent(event.toString());
// Smartlook.setGlobalEventProperty(event.toString(), eventValue, false);
FlutterUxcam.logEventWithProperties(event.enumToString(), {"value": eventValue});
model.Tracking tracking = model.Tracking();
analytics.logEvent(name: event.enumToString(), parameters: {"value": eventValue});
//analytics.logEvent(name: event.enumToString(), parameters: {"value": eventValue});
tracking.customerId = Cache().userLoggedIn == null ? 0 : Cache().userLoggedIn!.customerId!;
tracking.event = event.enumToString();
if (eventValue.isNotEmpty) {

View File

@ -12,6 +12,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:firebase_in_app_messaging/firebase_in_app_messaging.dart';
// ignore: must_be_immutable
class AccountPage extends StatelessWidget with Trans {
@ -151,6 +152,7 @@ class AccountPage extends StatelessWidget with Trans {
),
devices(context, accountBloc),
loginOut(context, accountBloc),
//messaging(),
//getMyTrainees(context, accountBloc),
]);
}
@ -180,6 +182,25 @@ class AccountPage extends StatelessWidget with Trans {
return element;
}
ListTile messaging() {
FirebaseInAppMessaging fiam = FirebaseInAppMessaging();
ListTile element = ListTile(
leading: Icon(Icons.message),
title: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.white38,
onSurface: Colors.grey,
),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(t("Trigger message"), style: TextStyle(color: Colors.purple)),
]),
onPressed: () => fiam.triggerEvent("mydevelopment"),
),
);
return element;
}
ListTile loginOut(BuildContext context, AccountBloc accountBloc) {
ListTile element = ListTile();

View File

@ -1,6 +1,7 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/sport.dart';
import 'package:aitrainer_app/util/app_localization.dart';
@ -14,6 +15,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.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 '../bloc/customer_change/customer_change_bloc.dart';
import '../library/dropdown_search/dropdown_search.dart';
@ -31,11 +33,13 @@ class CustomerFitnessPage extends StatefulWidget {
class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
String? selected;
bool fulldata = false;
late CustomerChangeBloc changeBloc;
late double cWidth;
@override
Widget build(BuildContext context) {
setContext(context);
final double cWidth = MediaQuery.of(context).size.width * 0.75;
cWidth = MediaQuery.of(context).size.width * 0.75;
CustomerRepository customerRepository;
dynamic args = ModalRoute.of(context)!.settings.arguments;
if (args is HashMap && args['personal_data'] != null) {
@ -49,186 +53,122 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
back: true,
);
if (!fulldata) {
_bar = AppBarProgress(max: 50, min: 26);
_bar = AppBarProgress(max: 30, min: 15);
}
final double h = 27;
return Scaffold(
appBar: _bar,
body: BlocProvider(
appBar: _bar,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
height: double.infinity,
width: double.infinity,
child: BlocProvider(
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
child: Builder(builder: (context) {
// ignore: close_sinks
CustomerChangeBloc changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
selected = changeBloc.selectedFitnessItem;
if (selected == null) {
selected = FitnessState.beginner;
}
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
padding: EdgeInsets.only(bottom: 200),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Divider(),
Wrap(
//runAlignment: WrapAlignment.center,
alignment: WrapAlignment.center,
children: [
Text(
t("Your Fitness State"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.orange,
fontSize: 30,
fontWeight: FontWeight.w900,
),
)
]),
Divider(),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, FitnessState.beginner),
),
child: Container(
width: cWidth,
child: Column(
children: [
Text(t("Beginner"),
textWidthBasis: TextWidthBasis.longestLine,
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900)),
Text(
t("I am beginner"),
style: TextStyle(color: Colors.black, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
],
)),
onPressed: () => {
setState(() {
selected = FitnessState.beginner;
changeBloc.add(CustomerFitnessChange(fitness: selected!));
}),
}),
Divider(),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, FitnessState.intermediate),
),
child: Container(
width: cWidth,
child: Column(
children: [
InkWell(
child: Text(
t("Intermediate"),
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
highlightColor: Colors.white,
),
InkWell(
child: Text(
t("I am intermediate"),
style: TextStyle(color: Colors.black, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
highlightColor: Colors.white,
),
],
),
),
onPressed: () => {
setState(() {
selected = FitnessState.intermediate;
changeBloc.add(CustomerFitnessChange(fitness: selected!));
print(selected);
}),
}),
Divider(),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, FitnessState.advanced),
),
child: Container(
width: cWidth,
child: Column(
children: [
InkWell(
child: Text(
t("Advanced"),
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
highlightColor: Colors.white,
),
InkWell(
child: Text(
t("I am advanced"),
style: TextStyle(color: Colors.black, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
highlightColor: Colors.white,
),
],
),
),
onPressed: () => {
setState(() {
selected = FitnessState.advanced;
changeBloc.add(CustomerFitnessChange(fitness: selected!));
print(selected);
}),
}),
Divider(),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, FitnessState.professional),
),
child: Container(
width: cWidth,
child: Column(
children: [
InkWell(
child: Text(
AppLocalizations.of(context)!.translate("Professional"),
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
highlightColor: Colors.white,
),
InkWell(
child: Text(
AppLocalizations.of(context)!.translate("I am professional"),
style: TextStyle(color: Colors.black, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
highlightColor: Colors.white,
),
],
),
),
onPressed: () => {
setState(() {
selected = FitnessState.professional;
changeBloc.add(CustomerFitnessChange(fitness: selected!));
print(selected);
}),
}),
Divider(),
Text(
t("Your Primary Sport") + ":",
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.orange,
fontSize: 20,
),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop();
Navigator.of(context).pushNamed("customerSexPage", arguments: changeBloc.customerRepository);
}
},
builder: (context, state) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return ModalProgressHUD(
child: getPage(),
inAsyncCall: state is CustomerChangeLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
),
)),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => {
if (!fulldata)
{
changeBloc.add(CustomerSaveFitness()),
}
else
{
changeBloc.add(CustomerSave()),
}
},
backgroundColor: Color(0xffb4f500),
icon: Icon(
CustomIcon.save,
color: Colors.black,
size: 26,
),
label: Text(
fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
),
),
);
}
Widget getPage() {
final double h = 27;
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: h,
),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("Your Fitness State"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.w900,
),
)
]),
SizedBox(
height: h,
),
getButton("Beginner", "I am beginner", FitnessState.beginner),
SizedBox(
height: h,
),
getButton("Intermediate", "I am intermediate", FitnessState.intermediate),
SizedBox(
height: h,
),
getButton("Advanced", "I am advanced", FitnessState.advanced),
SizedBox(
height: h,
),
getButton("Professional", "I am professional", FitnessState.professional),
/* Divider(),
Text(
t("Your Primary Sport") + ":",
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.orange,
fontSize: 20,
),
getSport(changeBloc),
Divider(),
), */
//getSport(changeBloc),
/* Divider(),
ElevatedButton(
style: ElevatedButton.styleFrom(
onPrimary: Colors.white,
@ -240,22 +180,58 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
Navigator.of(context).pop(),
if (!fulldata) {Navigator.of(context).pushNamed("customerBodyTypePage", arguments: customerRepository)}
},
)
],
),
) */
],
),
);
}
TextButton getButton(String title, String desc, String state) {
return TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, state),
),
child: Container(
width: cWidth,
child: Column(
children: [
InkWell(
child: Text(
AppLocalizations.of(context)!.translate(title),
style: TextStyle(color: Colors.white, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
);
})));
highlightColor: Colors.white,
),
InkWell(
child: Text(
AppLocalizations.of(context)!.translate(desc),
style: TextStyle(color: Colors.white, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
highlightColor: Colors.white,
),
],
),
),
onPressed: () => {
changeBloc.add(CustomerFitnessChange(fitness: state)),
});
}
dynamic getShape(CustomerChangeBloc changeBloc, String fitnessLevel) {
String? selected = changeBloc.selectedFitnessItem;
dynamic returnCode = (selected == fitnessLevel)
? RoundedRectangleBorder(
side: BorderSide(width: 4, color: Colors.orange),
side: BorderSide(
width: 4,
color: Color(0xffb4f500),
),
borderRadius: BorderRadius.circular(12),
)
: RoundedRectangleBorder(
side: BorderSide(width: 1, color: Colors.blue),
side: BorderSide(width: 4, color: Colors.white24),
borderRadius: BorderRadius.circular(12),
);
//return
return returnCode;

View File

@ -10,6 +10,7 @@ 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';
enum Goals { gain_muscle, weight_loss, endurance, muscle_endurance, flexibility, gain_strength, explosiveness, shape_forming }
@ -69,18 +70,21 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
CustomerRepository customerRepository;
dynamic args = ModalRoute.of(context)!.settings.arguments;
if (args is HashMap && args['personal_data'] != null) {
fulldata = args['personal_data'];
customerRepository = args['bloc'];
if (args != null) {
if (args is HashMap && args['personal_data'] != null) {
fulldata = args['personal_data'];
customerRepository = args['bloc'];
} else {
customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
}
} else {
customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
customerRepository = CustomerRepository();
}
PreferredSizeWidget _bar = AppBarMin(
back: true,
back: false,
);
if (!fulldata) {
_bar = AppBarProgress(max: 50, min: 26);
_bar = AppBarProgress(max: 14, min: 0);
}
return Scaffold(
@ -88,7 +92,7 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.jpg'),
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@ -97,75 +101,120 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
width: double.infinity,
child: BlocProvider(
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
child: Builder(builder: (context) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return SingleChildScrollView(
child: Center(
child: Column(
children: [
Divider(),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("Set Your Primary Goal"),
maxLines: 2,
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.orange,
fontSize: 30,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 3.0,
color: Colors.black87,
),
],
),
),
]),
Divider(),
getItem(changeBloc, Goals.gain_muscle),
Divider(),
getItem(changeBloc, Goals.weight_loss),
Divider(),
getItem(changeBloc, Goals.shape_forming),
Divider(),
getItem(changeBloc, Goals.endurance),
Divider(),
getItem(changeBloc, Goals.gain_strength),
Divider(),
getItem(changeBloc, Goals.muscle_endurance),
Divider(),
getItem(changeBloc, Goals.flexibility),
Divider(),
getItem(changeBloc, Goals.explosiveness),
Divider(),
],
),
));
}),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
Navigator.of(context).pushNamed("customerFitnessPage", arguments: changeBloc.customerRepository);
}
},
builder: (context, state) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return ModalProgressHUD(
child: getPage(),
inAsyncCall: state is CustomerChangeLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
),
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => {
//changingViewModel.saveCustomer(),
changeBloc.add(CustomerSave()),
Navigator.of(context).pop(),
if (!fulldata) {Navigator.of(context).pushNamed("customerFitnessPage", arguments: changeBloc.customerRepository)}
print("Fulldata: $fulldata bloc $changeBloc"),
if (!fulldata)
{
print("Savegoal"),
changeBloc.add(CustomerSaveGoal()),
}
else
{
changeBloc.add(CustomerSave()),
}
},
backgroundColor: Colors.orange[800],
backgroundColor: Color(0xffb4f500),
icon: Icon(
CustomIcon.save,
size: 20,
color: Colors.black,
size: 26,
),
label: Text(
fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 12),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
),
),
);
}
Widget getPage() {
final double h = 27;
return SingleChildScrollView(
child: Center(
child: Column(
children: [
Divider(),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("Set Your Primary Goal"),
maxLines: 2,
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.white,
fontSize: 30,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 3.0,
color: Colors.black87,
),
],
),
),
]),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.gain_muscle),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.weight_loss),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.shape_forming),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.endurance),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.gain_strength),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.muscle_endurance),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.flexibility),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.explosiveness),
SizedBox(
height: h,
),
],
),
));
}
Widget getItem(CustomerChangeBloc changeBloc, Goals goal) {
return Stack(alignment: Alignment.bottomLeft, children: [
TextButton(
@ -188,7 +237,7 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
child: Text(
t(goal.description(goal)),
style: GoogleFonts.archivoBlack(
color: Colors.yellow[300],
color: Colors.white,
fontSize: 28,
shadows: <Shadow>[
Shadow(
@ -204,13 +253,18 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
}
dynamic getShape(CustomerChangeBloc customerBloc, String goal) {
if (customerBloc.customerRepository.goal == null) return null;
dynamic baseCode = RoundedRectangleBorder(
side: BorderSide(width: 2, color: Colors.white24),
borderRadius: BorderRadius.circular(12),
);
if (customerBloc.customerRepository.goal == null) return baseCode;
String selectedGoal = customerBloc.customerRepository.goal!;
dynamic returnCode = (selectedGoal == goal)
? RoundedRectangleBorder(
side: BorderSide(width: 4, color: Colors.red),
side: BorderSide(width: 6, color: Color(0xffb4f500)),
borderRadius: BorderRadius.circular(12),
)
: null;
: baseCode;
//return
return returnCode;
}

View File

@ -0,0 +1,178 @@
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/app_bar_progress.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart';
import '../bloc/customer_change/customer_change_bloc.dart';
// ignore: must_be_immutable
class CustomerHeightPage extends StatefulWidget {
late _CustomerHeightPageState _state;
_CustomerHeightPageState createState() {
_state = _CustomerHeightPageState();
return _state;
}
}
class _CustomerHeightPageState extends State<CustomerHeightPage> with Trans {
String? selected;
bool fulldata = false;
late CustomerChangeBloc changeBloc;
late double cWidth;
@override
Widget build(BuildContext context) {
setContext(context);
final CustomerRepository customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
PreferredSizeWidget _bar = AppBarMin(
back: true,
);
if (!fulldata) {
_bar = AppBarProgress(max: 75, min: 60);
}
return Scaffold(
appBar: _bar,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
height: double.infinity,
width: double.infinity,
child: BlocProvider(
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop();
Navigator.of(context).pushNamed("registration", arguments: changeBloc.customerRepository);
}
},
builder: (context, state) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return getPage();
},
),
)),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => changeBloc.add(CustomerSaveHeight()),
backgroundColor: Color(0xffb4f500),
icon: Icon(
CustomIcon.save,
color: Colors.black,
size: 26,
),
label: Text(
fulldata ? t("Save") : t("Finish"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
),
),
);
}
Widget getPage() {
final double h = 27;
cWidth = MediaQuery.of(context).size.width * 0.75;
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: h,
),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("What is your height?"),
textAlign: TextAlign.center,
maxLines: 2,
style: GoogleFonts.archivoBlack(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.w900,
),
)
]),
SizedBox(
height: h,
),
getButton(),
],
),
);
}
Widget getButton() {
double mediaWidth = MediaQuery.of(context).size.width * .4;
double mediaHeight = MediaQuery.of(context).size.height * .4;
return Row(children: [
changeBloc.customerRepository.customer!.sex == "m"
? Image.asset(
"asset/image/test_picto_m.png",
height: mediaHeight,
width: mediaWidth,
)
: Image.asset(
"asset/image/test_picto_w.png",
height: mediaHeight,
width: mediaWidth,
),
SfLinearGauge(
minimum: 140,
maximum: 220,
markerPointers: [
LinearWidgetPointer(
value: changeBloc.height,
offset: 55,
position: LinearElementPosition.inside,
markerAlignment: LinearMarkerAlignment.center,
child: Container(
height: 25,
width: 55,
color: Colors.transparent,
child: Text(changeBloc.height.toString(),
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xffb4f500),
)),
),
),
LinearShapePointer(
height: 25,
width: 55,
color: Color(0xffb4f500),
value: changeBloc.height,
onValueChanged: (value) => {
changeBloc.add(CustomerHeightChange(height: value.toInt())),
},
),
],
orientation: LinearGaugeOrientation.vertical,
majorTickStyle: LinearTickStyle(length: 20, color: Colors.white),
axisLabelStyle: TextStyle(fontSize: 12.0, color: Colors.white),
axisTrackStyle:
LinearAxisTrackStyle(color: Colors.cyan, edgeStyle: LinearEdgeStyle.bothFlat, thickness: 1.0, borderColor: Colors.white))
]);
}
}

View File

@ -0,0 +1,185 @@
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/app_bar_progress.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.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 '../bloc/customer_change/customer_change_bloc.dart';
// ignore: must_be_immutable
class CustomerSexPage extends StatefulWidget {
late _CustomerSexPageState _state;
_CustomerSexPageState createState() {
_state = _CustomerSexPageState();
return _state;
}
}
class _CustomerSexPageState extends State<CustomerSexPage> with Trans {
String? selected;
bool fulldata = false;
late CustomerChangeBloc changeBloc;
late double cWidth;
@override
Widget build(BuildContext context) {
setContext(context);
final CustomerRepository customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
PreferredSizeWidget _bar = AppBarMin(
back: true,
);
if (!fulldata) {
_bar = AppBarProgress(max: 45, min: 30);
}
return Scaffold(
appBar: _bar,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
height: double.infinity,
width: double.infinity,
child: BlocProvider(
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop();
Navigator.of(context).pushNamed("customerWeightPage", arguments: changeBloc.customerRepository);
}
},
builder: (context, state) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return ModalProgressHUD(
child: getPage(),
inAsyncCall: state is CustomerChangeLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
),
)),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => {
changeBloc.add(CustomerSaveSex()),
},
backgroundColor: Color(0xffb4f500),
icon: Icon(
CustomIcon.save,
color: Colors.black,
size: 26,
),
label: Text(
fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
),
),
);
}
Widget getPage() {
final double h = 27;
cWidth = MediaQuery.of(context).size.width * 0.75;
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: h,
),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("What is your biological sex?"),
textAlign: TextAlign.center,
maxLines: 2,
style: GoogleFonts.archivoBlack(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.w900,
),
)
]),
SizedBox(
height: h,
),
getButton("Man", "", "m"),
SizedBox(
height: h,
),
getButton("Woman", "", "w"),
],
),
);
}
TextButton getButton(String title, String desc, String state) {
return TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, state),
),
child: Container(
width: cWidth,
child: Column(
children: [
InkWell(
child: ListTile(
leading: Icon(
state == "m" ? Icons.male_outlined : Icons.female,
color: Color(0xffb4f500),
size: 60,
),
title: Text(
AppLocalizations.of(context)!.translate(title),
style: TextStyle(color: Colors.white, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
)),
],
),
),
onPressed: () => {
print("Sex $state"),
changeBloc.add(CustomerGenderChange(gender: state == "m" ? 0 : 1)),
});
}
dynamic getShape(CustomerChangeBloc changeBloc, String sex) {
String? selected = changeBloc.customerRepository.customer!.sex;
dynamic returnCode = (selected == sex)
? RoundedRectangleBorder(
side: BorderSide(
width: 4,
color: Color(0xffb4f500),
),
borderRadius: BorderRadius.circular(12),
)
: RoundedRectangleBorder(
side: BorderSide(width: 4, color: Colors.white24),
borderRadius: BorderRadius.circular(12),
);
return returnCode;
}
}

View File

@ -0,0 +1,147 @@
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/app_bar_progress.dart';
import 'package:aitrainer_app/widgets/number_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.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 '../bloc/customer_change/customer_change_bloc.dart';
// ignore: must_be_immutable
class CustomerWeightPage extends StatefulWidget {
late _CustomerWeightPageState _state;
_CustomerWeightPageState createState() {
_state = _CustomerWeightPageState();
return _state;
}
}
class _CustomerWeightPageState extends State<CustomerWeightPage> with Trans {
String? selected;
bool fulldata = false;
late CustomerChangeBloc changeBloc;
late double cWidth;
@override
Widget build(BuildContext context) {
setContext(context);
final CustomerRepository customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
PreferredSizeWidget _bar = AppBarMin(
back: true,
);
if (!fulldata) {
_bar = AppBarProgress(max: 60, min: 45);
}
return Scaffold(
appBar: _bar,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
height: double.infinity,
width: double.infinity,
child: BlocProvider(
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop();
Navigator.of(context).pushNamed("customerHeightPage", arguments: changeBloc.customerRepository);
}
},
builder: (context, state) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return ModalProgressHUD(
child: getPage(),
inAsyncCall: state is CustomerChangeLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
),
)),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => {
changeBloc.add(CustomerSaveWeight()),
},
backgroundColor: Color(0xffb4f500),
icon: Icon(
CustomIcon.save,
color: Colors.black,
size: 26,
),
label: Text(
fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
),
),
);
}
Widget getPage() {
final double h = 27;
cWidth = MediaQuery.of(context).size.width * 0.75;
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: h,
),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("What is your weight?"),
textAlign: TextAlign.center,
maxLines: 2,
style: GoogleFonts.archivoBlack(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.w900,
),
)
]),
SizedBox(
height: h,
),
getButton(),
],
),
);
}
Widget getButton() {
return NumberPickerWidget(
minValue: 40,
maxValue: 150,
fontSize: 30,
diameterRatio: 1.1,
itemExtent: 40,
fontWeight: FontWeight.w700,
initalValue: changeBloc.weight.toInt(),
unit: t("kg"),
color: Color(0xffb4f500),
onChange: (value) => changeBloc.add(CustomerWeightChange(weight: value)));
}
}

View File

@ -1,6 +1,10 @@
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/library/button_animations.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:flutter/material.dart';
import 'package:flutter_fadein/flutter_fadein.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
// ignore: must_be_immutable
class CustomerWelcomePage extends StatefulWidget {
@ -12,11 +16,14 @@ class CustomerWelcomePage extends StatefulWidget {
}
}
class _CustomerWelcomePageState extends State<CustomerWelcomePage> {
class _CustomerWelcomePageState extends State<CustomerWelcomePage> with Trans {
@override
Widget build(BuildContext context) {
setContext(context);
return Scaffold(
appBar: AppBarMin(),
appBar: AppBarMin(
back: true,
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
@ -30,17 +37,64 @@ class _CustomerWelcomePageState extends State<CustomerWelcomePage> {
child: Center(
child: Column(
children: [
Divider(
color: Colors.transparent,
SizedBox(
height: 200,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.orange,
onSurface: Colors.white,
CircularPercentIndicator(
radius: 250.0,
animation: true,
animationDuration: 4800,
lineWidth: 20.0,
percent: 0.98,
curve: Curves.bounceInOut,
backgroundWidth: 4,
center: Text(
t("Training Plan Generation"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
fontSize: 28.0,
color: Colors.white,
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,
),
],
),
),
child: InkWell(child: Text(AppLocalizations.of(context)!.translate("Next"))),
onPressed: () => {Navigator.of(context).pop(), Navigator.of(context).pushNamed("home")},
)
circularStrokeCap: CircularStrokeCap.round,
progressColor: Color(0xffb4f500),
backgroundColor: Colors.black,
),
SizedBox(
height: 90,
),
FadeIn(
child: Container(
width: 160,
height: 80,
child: GestureDetector(
onTap: () => Navigator.of(context).popAndPushNamed("home"),
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_a.png', width: 140, height: 80),
Text(
t("Next"),
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.white),
),
],
),
)),
duration: Duration(seconds: 6),
),
],
),
))),

View File

@ -502,7 +502,7 @@ class EvaluationPage extends StatelessWidget with Trans {
Divider(color: Colors.transparent),
getSuggestionWidget(resultBloc, "Gain Strength", "asset/image/pict_weight_volumen_tonna.png", "3x4-8", 0.95, "3-5"),
Divider(color: Colors.transparent),
getSuggestionWidget(resultBloc, "Endurance", "asset/image/pict_reps_volumen_db.png", "4x25-35", 0.50, "3"),
getSuggestionWidget(resultBloc, "Muscle Endurance", "asset/image/pict_reps_volumen_db.png", "4x25-35", 0.50, "3"),
],
),
);

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/bloc/login/login_bloc.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/repository/user_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
@ -33,17 +34,18 @@ class RegistrationPage extends StatelessWidget with Trans {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(t(state.message), style: TextStyle(color: Colors.white))));
} else if (state is LoginSuccess) {
TrainingPlanRepository trainingPlanRepository = TrainingPlanRepository();
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("Successful Registration"),
descriptions: t("Now we would like to know you better to lift the experience of the app."),
description2: t("Please go through the pages, it will take couple of minutes!"),
descriptions: t("Based on your initial data, we will generate the personalized training plan for you."),
text: "OK",
onTap: () => {Navigator.of(context).pushNamed('customerModifyPage')},
onTap: () => {Navigator.of(context).pushNamed('customerWelcomePage')},
onCancel: () => {
Navigator.of(context).pushNamed("home"),
trainingPlanRepository.generateTrainingPlan(),
Navigator.of(context).pushNamed("customerWelcomePage"),
},
);
});
@ -83,7 +85,7 @@ class RegistrationPage extends StatelessWidget with Trans {
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_login.jpg'),
image: AssetImage('asset/image/WT_menu_dark.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@ -99,17 +101,32 @@ class RegistrationPage extends StatelessWidget with Trans {
child: Container(
padding: const EdgeInsets.only(left: 20, right: 20),
child: ListView(shrinkWrap: false, padding: EdgeInsets.only(top: 10.0), children: <Widget>[
GestureDetector(
onTap: () => loginBloc.add(LoginSkip()),
child: Text(
t("I Execute My First Test Now"),
textAlign: TextAlign.right,
style: GoogleFonts.inter(color: loginBloc.testColor, decoration: TextDecoration.underline, fontWeight: FontWeight.bold),
)),
SizedBox(
height: 120,
height: 100,
),
ListTile(
title: Text(
t("SignUp"),
style: GoogleFonts.inter(
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: <Shadow>[
Shadow(
offset: Offset(3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
],
),
)),
SizedBox(
height: 20,
),
ListTile(title: Text(t("SignUp"), style: GoogleFonts.inter())),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -140,7 +157,6 @@ class RegistrationPage extends StatelessWidget with Trans {
: Offstage(),
],
),
//ListTile(title: Text(t("OR"), style: GoogleFonts.inter())),
Divider(
color: Colors.transparent,
),
@ -149,6 +165,10 @@ class RegistrationPage extends StatelessWidget with Trans {
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 15, top: 15, bottom: 15),
labelText: t('Email'),
labelStyle: TextStyle(
fontSize: 14,
color: Color(0xffb4f500),
),
fillColor: Colors.white24,
filled: true,
border: OutlineInputBorder(
@ -165,7 +185,7 @@ class RegistrationPage extends StatelessWidget with Trans {
},
onChanged: (value) => loginBloc.add(LoginEmailChange(email: value)),
keyboardType: TextInputType.emailAddress,
style: new TextStyle(fontSize: 16, color: Colors.indigo),
style: new TextStyle(fontSize: 16, color: Colors.white),
),
Divider(
color: Colors.transparent,
@ -174,7 +194,10 @@ class RegistrationPage extends StatelessWidget with Trans {
key: LibraryKeys.loginPasswordField,
obscureText: loginBloc.obscure,
decoration: InputDecoration(
labelStyle: TextStyle(fontSize: 14),
labelStyle: TextStyle(
fontSize: 14,
color: Color(0xffb4f500),
),
contentPadding: EdgeInsets.only(left: 15, top: 15, bottom: 15),
suffixIcon: IconButton(
onPressed: () => {loginBloc.add(LoginPasswordChangeObscure())},
@ -197,7 +220,7 @@ class RegistrationPage extends StatelessWidget with Trans {
},
onChanged: (value) => loginBloc.add(LoginPasswordChange(password: value)),
keyboardType: TextInputType.visiblePassword,
style: new TextStyle(fontSize: 16, color: Colors.indigo),
style: new TextStyle(fontSize: 16, color: Colors.white),
),
Divider(
color: Colors.transparent,
@ -214,7 +237,22 @@ class RegistrationPage extends StatelessWidget with Trans {
),
title: Text(
t("With the registration I accept the data policy and the terms of use."),
style: GoogleFonts.inter(color: Colors.indigo),
style: GoogleFonts.inter(
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: <Shadow>[
Shadow(
offset: Offset(3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
],
),
),
),
Row(mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[
@ -242,7 +280,23 @@ class RegistrationPage extends StatelessWidget with Trans {
InkWell(
child: Text(
t('Login'),
style: GoogleFonts.inter(decoration: TextDecoration.underline),
style: GoogleFonts.inter(
decoration: TextDecoration.underline,
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: <Shadow>[
Shadow(
offset: Offset(3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
],
),
),
onTap: () => Navigator.of(context).pushNamed('login'),
),
@ -250,7 +304,23 @@ class RegistrationPage extends StatelessWidget with Trans {
InkWell(
child: Text(
t('Terms Of Use'),
style: GoogleFonts.inter(decoration: TextDecoration.underline),
style: GoogleFonts.inter(
decoration: TextDecoration.underline,
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: <Shadow>[
Shadow(
offset: Offset(3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
],
),
),
onTap: () => {
showDialog(
@ -263,7 +333,18 @@ class RegistrationPage extends StatelessWidget with Trans {
InkWell(
child: Text(
t('Privacy'),
style: GoogleFonts.inter(decoration: TextDecoration.underline),
style: GoogleFonts.inter(
decoration: TextDecoration.underline,
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 10.0,
color: Colors.black87,
),
],
),
),
onTap: () => {
showDialog(

View File

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
@ -17,7 +19,8 @@ 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:toggle_switch/toggle_switch.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter/services.dart';
import 'dart:async';
// ignore: must_be_immutable
class SettingsPage extends StatelessWidget with Trans {
@ -81,7 +84,7 @@ class SettingsPage extends StatelessWidget with Trans {
Track().track(TrackingEvent.settings_lang, eventValue: lang)
})),
getServer(settingsBloc),
getTuturialBasic(settingsBloc),
//getTuturialBasic(settingsBloc),
getTermsOfUse(),
getPrivacy(),
getFaq(),
@ -96,7 +99,7 @@ class SettingsPage extends StatelessWidget with Trans {
title: Container(),
);
}
print("Live: ${Cache().liveServer}");
return ListTile(
leading: Icon(Icons.data_usage_sharp),
subtitle: Text("For Test purpuses select Test-Server. After that please restart the the App"),
@ -260,4 +263,26 @@ class SettingsPage extends StatelessWidget with Trans {
),
);
}
Future<void> _printAndCopy(String cmd) async {
print(cmd);
await Clipboard.setData(ClipboardData(text: cmd));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Copied to Clipboard')),
);
}
void link1() {
String? cmd;
String cmdSuffix;
if (Platform.isIOS) {
cmd = '/usr/bin/xcrun simctl openurl booted';
} else if (Platform.isAndroid) {
cmd = '\$ANDROID_HOME/platform-tools/adb shell \'am start'
' -a android.intent.action.VIEW'
' -c android.intent.category.BROWSABLE -d';
cmdSuffix = "'";
}
}
}

View File

@ -128,7 +128,10 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
child: Text(
parentTitle,
maxLines: 2,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
)),
],
),

View File

@ -0,0 +1,649 @@
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/app_localization.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/dialog_html.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:badges/badges.dart';
import 'package:extended_tabs/extended_tabs.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';
class TrainingPlanExecute extends StatefulWidget {
const TrainingPlanExecute({Key? key}) : super(key: key);
@override
_TrainingPlanExecuteState createState() => _TrainingPlanExecuteState();
}
class _TrainingPlanExecuteState extends State<TrainingPlanExecute> with Trans {
@override
Widget build(BuildContext context) {
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
bloc.activateDays();
setContext(context);
return Scaffold(
appBar: AppBarNav(depth: 0),
body: Container(
padding: EdgeInsets.all(0),
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 TrainingPlanDayFinished) {
bloc.celebrating = false;
final HashMap args = HashMap();
args["bloc"] = bloc;
args["day"] = bloc.dayNames[bloc.activeDayIndex];
Navigator.of(context).pushNamed('myTrainingEvaluation', arguments: args);
} else if (state is TrainingPlanDayReadyToRestart) {
if (!bloc.celebrating) {
showCupertinoDialog(
useRootNavigator: true,
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text(t("The training is finished")),
content: Column(children: [Divider(), Text(t("Do you want to restart, or select a new Training Plan?"))]),
actions: [
TextButton(
child: Text(t("New Training Plan"), textAlign: TextAlign.center),
onPressed: () => {
Navigator.pop(context),
Navigator.of(context).popAndPushNamed('myTrainingPlans'),
bloc.restarting = false,
}),
TextButton(
child: Text(t("Restart")),
onPressed: () {
bloc.restart();
Navigator.pop(context);
Navigator.of(context).popAndPushNamed('home');
},
)
],
));
}
}
}, builder: (context, state) {
return ModalProgressHUD(
child: ExerciseTabs(bloc: bloc),
inAsyncCall: state is TrainingPlanLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
final HashMap args = HashMap();
args["bloc"] = bloc;
args["day"] = bloc.dayNames[bloc.activeDayIndex];
bloc.getNext() != null
? _ExerciseListState.executeExercise(bloc, bloc.getNext()!, context)
: Navigator.of(context).pushNamed('myTrainingEvaluation', arguments: args);
},
backgroundColor: Colors.orange[600], //Color(0xffb4f500),
icon: Icon(
CustomIcon.weight_hanging,
color: Colors.black,
),
label: Text(
t("Next Exercise"),
style: GoogleFonts.inter(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 16),
),
),
);
}
}
class ExerciseTabs extends StatefulWidget {
final TrainingPlanBloc bloc;
ExerciseTabs({required this.bloc});
@override
_ExerciseTabs createState() => _ExerciseTabs();
}
class _ExerciseTabs extends State<ExerciseTabs> with TickerProviderStateMixin {
late TabController tabController;
@override
void initState() {
super.initState();
tabController = TabController(length: widget.bloc.dayNames.length, vsync: this);
tabController.animateTo(widget.bloc.activeDayIndex, duration: Duration(milliseconds: 300));
}
@override
void dispose() {
tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return getTabs(widget.bloc);
}
Widget getTabs(TrainingPlanBloc bloc) {
return Column(children: [
Text(
bloc.getMyPlan()!.name!,
style: GoogleFonts.archivoBlack(
fontSize: 14,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black87,
),
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black87,
),
],
),
),
ExtendedTabBar(
indicator: BoxDecoration(
color: Colors.black87,
border: Border(
bottom: BorderSide(width: 4.0, color: Color(0xffb4f500)),
// top: BorderSide(width: 4.0, color: Colors.blue),
)),
labelPadding: EdgeInsets.only(left: 0, right: 0),
tabs: getTabNames(),
controller: tabController,
onTap: (index) => bloc.activeDayIndex = index,
),
Expanded(
child: ExtendedTabBarView(
children: getExerciseLists(),
controller: tabController,
/// if link is true and current tabbarview over scroll,
/// it will check and scroll ancestor or child tabbarView.
link: true,
/// cache page count
/// default is 0.
/// if cacheExtent is 1, it has two pages in cache
/// null is infinity, it will cache all pages
cacheExtent: 0,
)),
]);
}
List<Tab> getTabNames() {
List<Tab> tabs = [];
final int tabCount = widget.bloc.dayNames.length;
double cWidth = MediaQuery.of(context).size.width;
widget.bloc.dayNames.forEach((element) {
final Widget widget = Container(
//height: 40,
padding: EdgeInsets.only(top: 3, left: 10, right: 10, bottom: 3),
width: (cWidth / tabCount),
color: Colors.white10,
child: RichText(
textScaleFactor: 0.8,
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
children: [
TextSpan(
text: AppLocalizations.of(context)!.translate("Training Day") + ": \n",
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.white,
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: element,
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Color(0xffb4f500),
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,
),
],
)),
])));
tabs.add(Tab(child: widget));
});
return tabs;
}
List<Widget> getExerciseLists() {
List<Widget> list = [];
widget.bloc.dayNames.forEach((element) {
list.add(ExerciseList(bloc: widget.bloc, dayName: element));
});
return list;
}
}
class ExerciseList extends StatefulWidget {
final TrainingPlanBloc bloc;
final String dayName;
ExerciseList({required this.bloc, required this.dayName});
@override
_ExerciseListState createState() => _ExerciseListState();
}
class _ExerciseListState extends State<ExerciseList> with Trans {
final scrollController = ScrollController();
double offset = 5;
@override
void initState() {
WidgetsBinding.instance!.addPostFrameCallback((_) {
animate();
});
super.initState();
}
@override
void didUpdateWidget(ExerciseList page) {
super.didUpdateWidget(page);
WidgetsBinding.instance!.addPostFrameCallback((_) {
animate();
});
}
void animate() {
offset = widget.bloc.getOffset();
if (scrollController.hasClients) {
scrollController.animateTo(offset, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
}
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
static void executeExercise(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail, BuildContext context) {
CustomerTrainingPlanDetails? next = bloc.getNext();
if (next != null) {
String title = "";
String description = "";
String description2 = "";
if (next.exerciseTypeId != detail.exerciseTypeId) {
title = AppLocalizations.of(context)!.translate("Stop!");
description = AppLocalizations.of(context)!.translate("Please continue with the next exercise in the queue:") +
next.exerciseType!.nameTranslation;
} 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');
}
}
@override
Widget build(BuildContext context) {
setContext(context);
return CustomScrollView(controller: scrollController, slivers: [
SliverList(delegate: SliverChildListDelegate(getTiles(widget.bloc))),
]);
}
List<Widget> getTiles(TrainingPlanBloc bloc) {
List<Widget> tiles = [];
tiles.addAll(getExerciseTiles(bloc, context));
return tiles;
}
List<Widget> getExerciseTiles(TrainingPlanBloc bloc, BuildContext context) {
List<Widget> tiles = [];
CustomerTrainingPlanDetails? prev;
if (bloc.getMyPlan() != null &&
bloc.getMyPlan()!.details.isNotEmpty &&
bloc.getMyPlan()!.days[widget.dayName] != null &&
bloc.getMyPlan()!.days[widget.dayName]!.isNotEmpty) {
bloc.getMyPlan()!.days[widget.dayName]!.forEach((element) {
if (prev != null && prev!.exerciseTypeId != element.exerciseTypeId) {
tiles.add(GestureDetector(
onTap: () =>
bloc.getNext() != null ? executeExercise(bloc, bloc.getNext()!, context) : Navigator.of(context).pushNamed('home'),
child: ExerciseTile(bloc: bloc, detail: element)));
}
prev = element;
});
}
return tiles;
}
}
// ignore: must_be_immutable
class ExerciseTile extends StatelessWidget with Trans {
final TrainingPlanBloc bloc;
final CustomerTrainingPlanDetails detail;
ExerciseTile({required this.bloc, required this.detail});
Widget getExerciseQuantities(CustomerTrainingPlanDetails detail, int step, bool noFilter) {
bool skipped = detail.state == ExercisePlanDetailState.skipped;
String quantities = "";
String set = "";
List<TextSpan> spans = [];
if (detail.exerciseType!.name == "Warming Up") {
quantities = t("Min. 10 minutes");
spans.add(
TextSpan(text: quantities),
);
} else if (detail.exerciseType!.name == "Stretching") {
quantities = t("Recommended");
spans.add(
TextSpan(text: quantities),
);
} else {
set = detail.set! > 1 ? "${detail.set} " + t("set") : "";
List<CustomerTrainingPlanDetails> details = bloc.getAllDetailsSameExercise(detail);
int index = 0;
bool isWeight = true;
if (set.length > 0) {
spans.add(
TextSpan(
text: step.toString() + " ",
style: GoogleFonts.archivoBlack(
color: Colors.orange[600],
)),
);
spans.add(
TextSpan(text: "/ " + set),
);
}
details.forEach((element) {
quantities = "";
String delimiter = ",";
if (index == 0) {
delimiter = "";
}
if (element.repeats == -1) {
quantities += delimiter + " MAX ";
} else {
quantities += delimiter + " ${element.repeats}";
}
if (element.exerciseType!.unitQuantityUnit != null) {
quantities += "x";
if (element.weight == -1 || element.weight == -2 || element.weight == -3) {
quantities += "? kg";
} else {
num weight = element.weight! % element.weight!.round() == 0 ? element.weight!.round() : element.weight!;
quantities += "$weight kg";
}
} else {
isWeight = false;
}
if (step == index && noFilter) {
spans.add(
TextSpan(
text: quantities,
style: GoogleFonts.archivoBlack(
color: Colors.orange[600],
),
),
);
} else {
spans.add(
TextSpan(text: quantities),
);
}
index++;
});
if (isWeight) {
quantities += " kg";
}
}
return RichText(
text: TextSpan(
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: skipped ? Colors.grey : Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black87,
),
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black87,
),
],
),
children: spans),
);
}
@override
Widget build(BuildContext context) {
setContext(context);
final CustomerTrainingPlanDetails? next = bloc.getNext();
final bool noFilter = next != null && next.exerciseTypeId == detail.exerciseTypeId;
final bool done = detail.state == ExercisePlanDetailState.finished;
final int step = bloc.getStep(detail); //detail.exercises.length;
final bool buddyWarning = detail.exerciseType == null ? false : detail.exerciseType!.buddyWarning;
return Container(
child: Stack(alignment: Alignment.bottomLeft, children: [
Badge(
elevation: 0,
padding: EdgeInsets.all(0),
position: BadgePosition.topEnd(top: 5, end: 5),
animationDuration: Duration(milliseconds: 1500),
animationType: BadgeAnimationType.fade,
badgeColor: Colors.transparent,
showBadge: noFilter || done,
badgeContent: IconButton(
iconSize: 40,
onPressed: () => !done ? skip() : {},
icon: Icon(
done ? CustomIcon.ok_circled : Icons.cancel,
color: done ? Colors.green[600] : Colors.red[600],
)),
child: Badge(
elevation: 0,
padding: EdgeInsets.all(0),
position: BadgePosition.topStart(top: 5, start: 5),
animationDuration: Duration(milliseconds: 500),
animationType: BadgeAnimationType.slide,
badgeColor: Colors.transparent,
showBadge: true,
badgeContent: IconButton(
iconSize: 36,
onPressed: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogHTML(
title: detail.exerciseType!.nameTranslation,
htmlData: '<p>' + detail.exerciseType!.descriptionTranslation + '</p>');
}),
icon: Icon(
Icons.info_outline,
color: Colors.yellow[200],
)),
child: Badge(
elevation: 0,
padding: EdgeInsets.all(0),
position: BadgePosition.topEnd(top: 65, end: 1),
animationDuration: Duration(milliseconds: 500),
animationType: BadgeAnimationType.fade,
badgeColor: Colors.transparent,
showBadge: buddyWarning,
badgeContent: IconButton(
iconSize: 50,
onPressed: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: true,
text: "Warning",
descriptions: t("Attention!"),
description2: t("The safe and exact execution of this exercise you need a training buddy or a trainer"),
description3: t("Execution at your own risk!"),
onTap: () => Navigator.of(context).pop(),
onCancel: () => Navigator.of(context).pop(),
title: t('Training Buddy'),
);
}),
icon: Icon(
CustomIcon.exclamation_circle,
color: Colors.red[800],
)),
child: Column(children: [
MenuImage(
imageName: bloc.getActualImageName(detail.exerciseType!.exerciseTypeId),
workoutTreeId: bloc.getActualWorkoutTreeId(detail.exerciseType!.exerciseTypeId)!,
radius: 0,
filter: !noFilter,
),
Container(
padding: EdgeInsets.only(left: 20, top: 10, bottom: 0),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_zold.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
foregroundDecoration: !noFilter
? BoxDecoration(
color: Colors.black38,
backgroundBlendMode: BlendMode.darken,
)
: null,
height: 80,
width: double.infinity,
child: getExerciseQuantities(detail, step, noFilter),
)
])))),
Container(
padding: EdgeInsets.only(left: 15, bottom: 80, right: 15),
width: double.infinity,
color: Colors.transparent,
child: Text(
detail.exerciseType!.nameTranslation,
maxLines: 3,
style: GoogleFonts.archivoBlack(
color: noFilter ? Colors.white : Colors.grey,
fontSize: 36,
height: 1.1,
shadows: <Shadow>[
Shadow(
offset: Offset(16.0, 16.0),
blurRadius: 16.0,
color: Colors.black54,
),
Shadow(
offset: Offset(16.0, 16.0),
blurRadius: 16.0,
color: Colors.black54,
),
],
),
),
),
]),
);
}
void skip() {
showCupertinoDialog(
useRootNavigator: true,
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text(t("You want to skip really this exercise?")),
content: Column(children: [
Divider(),
]),
actions: [
TextButton(
child: Text(t("No")),
onPressed: () => {
Navigator.pop(context),
}),
TextButton(
child: Text(t("Yes")),
onPressed: () {
Navigator.pop(context);
bloc.add(TrainingPlanSkipExercise(detail: detail));
},
)
],
));
}
}

View File

@ -0,0 +1,170 @@
import 'package:aitrainer_app/util/trans.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
// ignore: must_be_immutable
class DialogTrialWidget extends StatefulWidget {
final String title, description;
final Widget widget;
final VoidCallback onTap;
final VoidCallback? onCancel;
DialogTrialWidget({Key? key, required this.title, required this.description, required this.widget, required this.onTap, this.onCancel})
: super(key: key);
@override
_DialogTrialWidgetState createState() {
return _DialogTrialWidgetState();
}
}
class _DialogTrialWidgetState extends State<DialogTrialWidget> with Trans {
@override
Widget build(BuildContext context) {
setContext(context);
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(31),
),
elevation: 0,
backgroundColor: Colors.transparent,
child: contentBox(context),
);
}
contentBox(context) {
return Stack(alignment: AlignmentDirectional.topStart, children: [
Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 20, top: 24, right: 20, bottom: 30),
margin: EdgeInsets.only(top: 30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
boxShadow: [BoxShadow(color: Colors.black, offset: Offset(0, 10), blurRadius: 10)],
image: DecorationImage(
image: AssetImage('asset/image/WT_black_G_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
height: 5,
),
Stack(
alignment: AlignmentDirectional.topEnd,
children: [
Text(
widget.title,
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
fontSize: 20,
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,
),
],
),
),
],
),
SizedBox(
height: 35,
),
Text(
widget.description,
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white,
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,
),
],
),
textAlign: TextAlign.center,
),
SizedBox(
height: 15,
),
widget.widget,
SizedBox(
height: 52,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: widget.onCancel,
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_lila_b.png', width: 100, height: 45),
Text(
t("Nem"),
style: TextStyle(fontSize: 16, color: Colors.white),
),
],
)),
GestureDetector(
onTap: widget.onTap,
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_c.png', width: 100, height: 45),
Text(
t("Igen"),
style: TextStyle(fontSize: 16, color: Colors.white),
),
],
))
],
),
],
),
),
],
),
GestureDetector(
onTap: () {
if (widget.onCancel == null) {
Navigator.of(context).pop();
} else {
widget.onCancel!();
}
},
child: CircleAvatar(
backgroundColor: Colors.transparent,
radius: 28,
child: Text(
"X",
style: GoogleFonts.archivoBlack(fontSize: 32, color: Colors.white54),
),
)),
]);
}
@override
void dispose() {
super.dispose();
}
}

View File

@ -98,7 +98,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
}
SchedulerBinding.instance!.addPostFrameCallback((_) {
final TutorialBloc bloc = BlocProvider.of<TutorialBloc>(context);
/* //final TutorialBloc bloc = BlocProvider.of<TutorialBloc>(context);
if (bloc.actualCheck == "directTest") {
Timer(
Duration(milliseconds: 2000),
@ -116,7 +116,7 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
);
})
});
}
} */
});
}

View File

@ -4,10 +4,11 @@ import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/view/customer_goal_page.dart';
import 'package:aitrainer_app/view/login.dart';
import 'package:aitrainer_app/view/menu_page.dart';
import 'package:aitrainer_app/view/registration.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
@ -37,6 +38,15 @@ class _HomePageState extends State<AitrainerHome> with Logging, Trans {
SchedulerBinding.instance!.addPostFrameCallback((_) {
runDelayedEvent();
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('-- FirebaseMessaging: Got a message whilst in the foreground!');
print('-- FirebaseMessaging: Message data: ${message.data}');
if (message.notification != null) {
print('-- FirebaseMessaging: Message also contained a notification: ${message.notification}');
}
});
}
Future runDelayedEvent() async {
@ -58,6 +68,7 @@ class _HomePageState extends State<AitrainerHome> with Logging, Trans {
final appcastURL = "https://raw.githubusercontent.com/bossanyit/appcast/main/android_rss.xml";
final cfg = AppcastConfiguration(url: appcastURL, supportedOS: ['android']);
print("Packageinfo ${Cache().packageInfo}");
return Scaffold(
key: _scaffoldKey,
body: UpgradeAlert(
@ -101,7 +112,7 @@ class _HomePageState extends State<AitrainerHome> with Logging, Trans {
if (Cache().startPage == 'login') {
return LoginPage();
} else if (Cache().startPage == 'registration') {
return RegistrationPage();
return CustomerGoalPage();
} else {
return MenuPage(parent: 0);
}

View File

@ -3,16 +3,19 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:aitrainer_app/library/image_cache.dart' as wt;
import 'package:aitrainer_app/library/transparent_image.dart';
import 'package:flutter_html/shims/dart_ui_real.dart';
// ignore: must_be_immutable
class MenuImage extends StatelessWidget {
final int? workoutTreeId;
final String imageName;
bool filter;
double radius;
MenuImage({
required this.workoutTreeId,
required this.imageName,
this.radius = 24,
this.filter = false,
});
@override
@ -23,10 +26,16 @@ class MenuImage extends StatelessWidget {
String? imageString = this.getImage(workoutTreeId!, imageName);
Widget? widget;
if (imageString != null) {
print("MemoryImage $workoutTreeId - $imageName");
widget = ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: Colors.transparent,
padding: EdgeInsets.zero,
color: Colors.black38,
foregroundDecoration: BoxDecoration(
color: Colors.black38,
backgroundBlendMode: BlendMode.darken,
),
child: FadeInImage(
fadeInDuration: Duration(milliseconds: 100),
image: MemoryImage(base64Decode(imageString)),
@ -35,10 +44,18 @@ class MenuImage extends StatelessWidget {
));
} else {
if (imageName.contains("https")) {
print("https image $workoutTreeId - $imageName");
if (!wt.ImageCache().existsImageInMap(workoutTreeId!, imageName)) {
widget = ClipRRect(
borderRadius: BorderRadius.circular(radius),
child: Container(
padding: EdgeInsets.zero,
foregroundDecoration: filter
? BoxDecoration(
color: Colors.black38,
backgroundBlendMode: BlendMode.darken,
)
: null,
color: Colors.transparent,
child: FadeInImage(
fadeInDuration: Duration(milliseconds: 500),
@ -51,7 +68,14 @@ class MenuImage extends StatelessWidget {
widget = ClipRRect(
borderRadius: BorderRadius.circular(radius),
child: Container(
padding: EdgeInsets.zero,
color: Colors.transparent,
foregroundDecoration: filter
? BoxDecoration(
color: Colors.black38,
backgroundBlendMode: BlendMode.darken,
)
: null,
child: Image.asset(imageName),
));
}

View File

@ -1,11 +1,12 @@
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';
import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/widgets/dialog_trial.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:aitrainer_app/widgets/menu_search_bar.dart';
import 'package:aitrainer_app/util/app_language.dart';
@ -15,9 +16,9 @@ import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/tutorial_widget.dart';
import 'package:badges/badges.dart';
import 'package:ezanimation/ezanimation.dart';
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
@ -39,7 +40,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
final double baseWidth = 312;
final double baseHeight = 675.2;
late MenuBloc menuBloc;
late TutorialBloc tutorialBloc;
//late TutorialBloc tutorialBloc;
final scrollController = ScrollController();
final bool activeExercisePlan = Cache().activeExercisePlan != null;
final EzAnimation animation = EzAnimation(35.0, 10.0, Duration(seconds: 2), reverseCurve: Curves.linear);
@ -59,41 +60,11 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
/// We require the initializers to run after the loading screen is rendered
SchedulerBinding.instance!.addPostFrameCallback((_) {
menuBloc.add(MenuCreate());
//runDelayedEvent();
});
super.initState();
}
Future runDelayedEvent() async {
bool isFirst = false;
await Future.delayed(Duration(milliseconds: 600), () async {
if (Cache().userLoggedIn != null) {
if (Cache().userLoggedIn!.sex == "m") {
tutorialBloc.tutorialName = ActivityDone.tutorialBasicChestPress.toStr();
} else {
tutorialBloc.tutorialName = ActivityDone.tutorialBasicLegPress.toStr();
}
}
if (!tutorialBloc.isTutorialDone()) {
if (tutorialBloc.isActive == false && tutorialBloc.canActivate) {
tutorialBloc.canActivate = true;
tutorialBloc.isActive = true;
tutorialBloc.menuBloc = menuBloc;
tutorialBloc.add(TutorialLoad());
tutorialBloc.init();
isFirst = true;
}
}
});
final bool canActivate = tutorialBloc.activateTutorial();
if (canActivate) {
if (!isFirst) {
TutorialWidget().tip(context);
}
}
}
@override
bool didUpdateWidget(MenuPageWidget oldWidget) {
super.didUpdateWidget(oldWidget);
@ -102,10 +73,68 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
return true;
}
Future runDelayedEvent() async {
await Future.delayed(Duration(milliseconds: 3000), () async {
if (Cache().userLoggedIn != null) {
await initDynamicLinks();
}
if (Cache().canTrial()) {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogTrialWidget(
title: "10 days Premium for free",
description: "Would you like to try all premium functions for 10 days, without any subscription or bank card data?",
widget: Column(children: [
Text(
"If you click to 'Yes', all premium functions will be available right now.",
style: GoogleFonts.inter(color: Colors.white),
),
Divider(),
Text(
"If you click to 'No', you can use all basic functions, and you will loose the oppurtunity to try the premium functions for free.",
style: GoogleFonts.inter(color: Colors.white),
),
]),
onCancel: () => {
Navigator.of(context).pop(),
menuBloc.add(MenuStartTrial(start: DateTime.parse("1900-01-01 00:00:00"))),
},
onTap: () => {Navigator.of(context).pop(), menuBloc.add(MenuStartTrial(start: DateTime.now()))},
);
});
}
});
}
Future<void> initDynamicLinks() async {
FirebaseDynamicLinks.instance.onLink(onSuccess: (PendingDynamicLinkData? dynamicLink) async {
final Uri? deepLink = dynamicLink?.link;
print("DeepLink: $deepLink");
if (deepLink != null) {
// ignore: unawaited_futures
final String deepLinkPath = deepLink.path.replaceFirst("/", "");
Navigator.pushNamed(context, deepLinkPath);
}
}, onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
});
final PendingDynamicLinkData? data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri? deepLink = data?.link;
print("Pending DeepLink: $deepLink");
if (deepLink != null) {
// ignore: unawaited_futures
final String deepLinkPath = deepLink.path.replaceFirst("/", "");
Navigator.pushNamed(context, deepLinkPath);
}
}
@override
Widget build(BuildContext context) {
menuBloc = BlocProvider.of<MenuBloc>(context);
tutorialBloc = BlocProvider.of<TutorialBloc>(context);
//tutorialBloc = BlocProvider.of<TutorialBloc>(context);
setContext(context);
double cWidth = MediaQuery.of(context).size.width;
double cHeight = MediaQuery.of(context).size.height;
@ -181,6 +210,10 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
});
}
_columnChildren.add(SizedBox(
height: 50,
));
SliverList sliverList = SliverList(
delegate: SliverChildListDelegate(_columnChildren),
);
@ -292,7 +325,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
}
},
),
Cache().myTrainingPlan != null
/* Cache().myTrainingPlan != null
? GestureDetector(
onTap: () => showDialog(
context: context,
@ -326,7 +359,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
),
);
}))
: Offstage(),
: Offstage(), */
/* activeExercisePlan
? SizedBox(
width: 10,
@ -376,24 +409,59 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
}
void menuClick(WorkoutMenuTree workoutTree, MenuBloc menuBloc) {
if (tutorialBloc.isActive) {
/* if (tutorialBloc.isActive) {
final String checkText = workoutTree.nameEnglish;
if (!tutorialBloc.checkAction(checkText)) {
return;
}
}
} */
print("ability: ${menuBloc.ability} tree: $workoutTree parent: ${workoutTree.parent}");
if (workoutTree.child == false) {
if (menuBloc.ability != null && ExerciseAbility.mini_test_set.equalsTo(menuBloc.ability!) && workoutTree.parent != 0) {
HashMap args = HashMap();
args['templateName'] = workoutTree.nameEnglish;
args['templateNameTranslation'] = workoutTree.name;
Navigator.of(context).pushNamed('testSetEdit', arguments: args);
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
} else if (menuBloc.ability != null && ExerciseAbility.training.equalsTo(menuBloc.ability!) && workoutTree.parent != 0) {
HashMap<String, dynamic> args = HashMap();
args['parentName'] = workoutTree.internalName;
Navigator.of(context).pushNamed("myTrainingPlanActivate", arguments: args);
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
} else if (workoutTree.internalName == "training_execute") {
/* Cache().myTrainingPlan = null;
Cache().deleteMyTrainingPlan(); */
if (Cache().myTrainingPlan != null) {
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
bloc.setMyPlan(Cache().myTrainingPlan);
Navigator.of(context).pushNamed("myTrainingPlanExecute");
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("No selected Training Plan"),
descriptions: t("Based on your initial data, we will generate the personalized training plan for you."),
text: "OK",
onTap: () {
TrainingPlanRepository trainingPlanRepository = TrainingPlanRepository();
trainingPlanRepository.generateTrainingPlan();
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
bloc.setMyPlan(Cache().myTrainingPlan);
Future.delayed(Duration(milliseconds: 1000), () async {
Navigator.of(context).pushNamed("myTrainingPlanExecute");
});
},
onCancel: () => {
Navigator.of(context).pop(),
},
);
});
}
} else {
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
}
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
} else {
menuBloc.add(MenuClickExercise(exerciseTypeId: workoutTree.id));

View File

@ -11,6 +11,9 @@ class NumberPickerWidget extends StatefulWidget {
final String unit;
final Color color;
double? fontSize;
double? diameterRatio;
double? itemExtent;
FontWeight? fontWeight;
NumberPickerWidget(
{Key? key,
@ -19,10 +22,16 @@ class NumberPickerWidget extends StatefulWidget {
required this.initalValue,
required this.unit,
this.fontSize,
this.diameterRatio,
this.itemExtent,
this.fontWeight,
required this.color,
required this.onChange})
: super(key: key) {
fontSize = fontSize ?? 20;
diameterRatio = diameterRatio ?? 0.85;
itemExtent = itemExtent ?? 30;
fontWeight = fontWeight ?? FontWeight.normal;
}
@override
_NumberPickerWidgetState createState() => _NumberPickerWidgetState();
@ -59,7 +68,7 @@ class _NumberPickerWidgetState extends State<NumberPickerWidget> with Trans {
scrollController: _scrollController,
useMagnifier: true,
magnification: 1.2,
diameterRatio: 0.85,
diameterRatio: widget.diameterRatio!,
backgroundColor: Colors.transparent,
selectionOverlay: Container(),
onSelectedItemChanged: (x) {
@ -72,8 +81,10 @@ class _NumberPickerWidgetState extends State<NumberPickerWidget> with Trans {
widget.onChange(value);
},
children: List.generate(
widget.maxValue, (index) => Text('$index ' + widget.unit, style: TextStyle(color: widget.color, fontSize: widget.fontSize))),
itemExtent: 30,
widget.maxValue,
(index) => Text('$index ' + widget.unit,
style: TextStyle(color: widget.color, fontSize: widget.fontSize, fontWeight: widget.fontWeight))),
itemExtent: widget.itemExtent!,
);
}

View File

@ -43,13 +43,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
awesome_notifications:
dependency: "direct main"
description:
name: awesome_notifications
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.6+9"
badges:
dependency: "direct main"
description:
@ -70,7 +63,7 @@ packages:
name: bloc_test
url: "https://pub.dartlang.org"
source: hosted
version: "8.0.0"
version: "8.1.0"
boolean_selector:
dependency: transitive
description:
@ -294,7 +287,7 @@ packages:
name: equatable
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.3"
extended_tabs:
dependency: "direct main"
description:
@ -343,7 +336,7 @@ packages:
name: firebase_analytics
url: "https://pub.dartlang.org"
source: hosted
version: "8.1.0"
version: "8.3.0"
firebase_analytics_platform_interface:
dependency: transitive
description:
@ -364,28 +357,28 @@ packages:
name: firebase_auth
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "3.0.2"
firebase_auth_platform_interface:
dependency: transitive
description:
name: firebase_auth_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.3"
version: "6.0.1"
firebase_auth_web:
dependency: transitive
description:
name: firebase_auth_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.3"
version: "3.0.1"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.5.0"
firebase_core_platform_interface:
dependency: transitive
description:
@ -400,41 +393,55 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
firebase_dynamic_links:
dependency: "direct main"
description:
name: firebase_dynamic_links
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
firebase_in_app_messaging:
dependency: "direct main"
description:
name: firebase_in_app_messaging
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.0+8"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
url: "https://pub.dartlang.org"
source: hosted
version: "10.0.0"
version: "10.0.5"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
version: "3.0.4"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.0.4"
firebase_remote_config:
dependency: "direct main"
description:
name: firebase_remote_config
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.0"
version: "0.10.0+4"
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"
version: "0.3.0+4"
fixnum:
dependency: transitive
description:
@ -474,28 +481,28 @@ packages:
name: flutter_bloc
url: "https://pub.dartlang.org"
source: hosted
version: "7.0.0"
version: "7.1.0"
flutter_facebook_auth:
dependency: "direct main"
description:
name: flutter_facebook_auth
url: "https://pub.dartlang.org"
source: hosted
version: "3.4.0"
version: "3.5.1"
flutter_facebook_auth_platform_interface:
dependency: transitive
description:
name: flutter_facebook_auth_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.0"
version: "2.7.0"
flutter_facebook_auth_web:
dependency: transitive
description:
name: flutter_facebook_auth_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.0"
version: "2.6.0+2"
flutter_fadein:
dependency: "direct main"
description:
@ -561,7 +568,7 @@ packages:
name: flutter_uxcam
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0-beta.1"
version: "2.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
@ -1285,7 +1292,7 @@ packages:
name: upgrader
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.0"
version: "3.5.1"
url_launcher:
dependency: transitive
description:
@ -1477,4 +1484,4 @@ packages:
version: "3.1.0"
sdks:
dart: ">=2.12.0 <3.0.0"
flutter: ">=2.0.4"
flutter: ">=2.0.0"

View File

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.1.21+92
version: 1.1.22+93
environment:
sdk: ">=2.12.0 <3.0.0"
@ -28,8 +28,8 @@ dependencies:
google_fonts: ^2.1.0
devicelocale: ^0.4.1
sentry_flutter: ^5.1.0-beta.1
flutter_bloc: ^7.0.0
equatable: ^2.0.2
flutter_bloc: ^7.1.0
equatable: ^2.0.3
spider_chart: ^0.1.5
rainbow_color: ^2.0.1
@ -49,33 +49,34 @@ dependencies:
purchases_flutter: ^3.2.2
package_info: ^2.0.0
ezanimation: ^0.5.0
flutter_fadein: ^2.0.0
confetti: ^0.6.0-nullsafety
crypto: ^3.0.0
carousel_slider: ^4.0.0-nullsafety.0
convex_bottom_bar: ^3.0.0
flutter_app_badger: ^1.2.0
extended_tabs: ^2.2.0
upgrader: ^3.3.0
upgrader: ^3.5.1
web_browser: ^0.5.0
flutter_fadein: ^2.0.0
firebase_core: ^1.2.0
firebase_core: ^1.5.0
firebase_analytics: ^8.1.0
firebase_messaging: ^10.0.0
firebase_auth: ^1.2.0
firebase_remote_config: ^0.10.0
awesome_notifications: ^0.0.6+9
firebase_auth: ^3.0.2
firebase_remote_config: ^0.10.0+4
firebase_dynamic_links: ^2.0.8
firebase_in_app_messaging: ^0.5.0+8
syncfusion_flutter_gauges: ^19.1.63
syncfusion_flutter_datagrid: ^19.1.63
flutter_facebook_auth: ^3.4.0
flutter_facebook_auth: ^3.5.1
google_sign_in: ^5.0.3
sign_in_with_apple: ^3.0.0
#smartlook: ^1.0.7
flurry_data: ^0.0.1
flutter_uxcam: ^2.0.0-beta.1
flutter_uxcam: ^2.0.0
animated_widgets: ^1.0.6
@ -94,7 +95,7 @@ dev_dependencies:
test: '>=1.0.0 <2.0.0'
flutter_test:
sdk: flutter
bloc_test: ^8.0.0
bloc_test: ^8.1.0
build_runner:
@ -154,6 +155,7 @@ flutter:
- asset/image/WT_Results_for_men.jpg
- asset/image/WT_results_background.jpg
- asset/image/WT_cup_victory400.png
- asset/image/WT_zold.jpg
- asset/image/button_fb.png
- asset/image/button_apple.png
@ -179,6 +181,7 @@ flutter:
- asset/image/gain_strength.jpg
- asset/image/muscle_endurance.jpg
- asset/image/shape_forming.jpg
- asset/image/woman_sizes.png
- asset/image/weight_loss.jpg
- asset/image/merleg.png
@ -368,6 +371,7 @@ flutter:
- asset/menu/situps.jpg
- asset/menu/sizes.jpg
- asset/menu/smith_machine_chest_press.jpg
- asset/menu/smith_machine_squats.jpg
- asset/menu/squats_with_kettlebell.jpg
- asset/menu/squat_jump_weight.jpg
- asset/menu/squat_jump.jpg
@ -403,6 +407,7 @@ flutter:
- asset/menu/training_plans_q_beginner.jpg
- asset/menu/training_plans_q_advanced.jpg
- asset/menu/training_plans_q_gain_strength.jpg
- asset/menu/training_start.jpg
- asset/menu/triceps_extension_on_cable_with_rope.jpg
- asset/menu/triceps_kickback.jpg
- asset/menu/triceps_pushdown.jpg