WT1.1.5 In-app-purchase

This commit is contained in:
bossanyit 2021-01-24 14:34:13 +01:00
parent d44fefe9af
commit 71efd3f349
52 changed files with 847 additions and 367 deletions

View File

@ -78,7 +78,5 @@ dependencies {
implementation 'com.google.firebase:firebase-analytics:18.0.0' implementation 'com.google.firebase:firebase-analytics:18.0.0'
implementation 'com.facebook.android:facebook-login:5.15.3' implementation 'com.facebook.android:facebook-login:5.15.3'
implementation 'com.android.support:multidex:1.0.3' implementation 'com.android.support:multidex:1.0.3'
def billing_version = "3.0.0"
implementation "com.android.billingclient:billing:$billing_version"
} }
sourceCompatibility = '1.8' sourceCompatibility = '1.8'

View File

@ -172,10 +172,10 @@
"8. Calf": "8. Calf", "8. Calf": "8. Calf",
"Execute My Selected Training Plan": "Execute My Selected Training Plan", "Execute My Selected Training Plan": "Execute My Selected Training Plan",
"Edit My Custom Plan": "Edit My Custom Plan", "Edit My Custom Plan": "Create My Custom Plan",
"Suggested Training Plan": "Suggested Training Plan", "Suggested Training Plan": "Suggested Training Plan",
"My Special Plan": "My Special Plan", "My Special Plan": "My Special Plan",
"Star's Exercise Plan":"Celeb Exercise Plan", "Training Programs":"Training Programs",
"My Trainee's Plan": "My Trainee's Plan", "My Trainee's Plan": "My Trainee's Plan",
"Execute My Trainee's Training Plan": "Execute My Trainee's Training Plan", "Execute My Trainee's Training Plan": "Execute My Trainee's Training Plan",
@ -250,11 +250,15 @@
"Done": "Done", "Done": "Done",
"Height":"Height", "Height":"Height",
"Actual Height":"Height", "Actual Height":"Height",
"Actual Weight":"Weight", "Actual Weight":"Bodyweight",
"Based on your weight and height your goal for BMI and weight:":"Based on your weight and height your goal for BMI and weight:", "Bodyweight":"Bodyweight",
"Based on your weight and height your goal for BMI and weight:":"Based on your bodyweight and height your goal for BMI and weight:",
"Body Mass Index":"Body Mass Index", "Body Mass Index":"Body Mass Index",
"first step":"first step",
"goal":"goal",
"Basal Metabolic Rate":"Basal Metabolic Rate", "Basal Metabolic Rate":"Basal Metabolic Rate",
"Based on your weight, height and activity your BMR value":"Based on your weight, height and activity this is your daily calory demand.", "Resting Metabolic Rate":"Resting Metabolic Rate",
"Based on your weight, height and activity your BMR value":"Based on your bodyweight, height and activity this is your daily calory demand.",
"Your Sizes":"Your Sizes", "Your Sizes":"Your Sizes",
"Size Of Your":"Size Of Your", "Size Of Your":"Size Of Your",
"Please type the following data:":"Please type the following data:", "Please type the following data:":"Please type the following data:",
@ -303,7 +307,10 @@
"Please define your Exercise Plan":"Please define your Exercise Plan", "Please define your Exercise Plan":"Please define your Exercise Plan",
"Go to: 'Training Plan' - 'Edit My Custom Plan'":"Go to: 'Training Plan' - 'Edit My Custom Plan'", "Go to: 'Training Plan' - 'Edit My Custom Plan'":"Go to: 'Training Plan' - 'Edit My Custom Plan'",
"Jump there »":"Jump there »" "Jump there »":"Jump there »",
"Exception: Purchase was not successful":"Purchase was not successful",
"Exception: Purchase was cancelled":"Purchase was cancelled",
"Successful Purchase": "Successful Purchase",
"Now you can use the premium features of WorkoutTest!":"Now you can use the premium features of WorkoutTest!"
} }

View File

@ -169,10 +169,10 @@
"8. Calf": "8. Vádli", "8. Calf": "8. Vádli",
"Execute My Selected Training Plan": "Edzésterv végrehajtása", "Execute My Selected Training Plan": "Edzésterv végrehajtása",
"Edit My Custom Plan": "Egyéni edzésterv", "Edit My Custom Plan": "Egyéni edzésterv létrehozása",
"Suggested Training Plan": "Javasolt edzésterv", "Suggested Training Plan": "Javasolt edzésterv",
"My Special Plan": "Speciális edzésterv", "My Special Plan": "Speciális edzésterv",
"Star's Exercise Plan": "Sztárok edzésterve", "Training Programs":"Edzés programok",
"My Trainee's Plan" : "Kliensem edzésterve", "My Trainee's Plan" : "Kliensem edzésterve",
"Execute My Trainee's Training Plan": "Kliensem edzéstervének végrehajtása", "Execute My Trainee's Training Plan": "Kliensem edzéstervének végrehajtása",
@ -245,11 +245,15 @@
"Done": "Kész", "Done": "Kész",
"Height":"Magasság", "Height":"Magasság",
"Actual Height":"Magasság", "Actual Height":"Magasság",
"Actual Weight":"Tömeg", "Actual Weight":"Testtömeg",
"Based on your weight and height your goal for BMI and weight:":"A jelenlegi tömeged és magasságod alapján kiszámoltuk, hogy mennyi legyen a célod a BMI (testtömegindex) és tömeg elérésben:", "Bodyweight":"Testtömeg",
"Based on your weight and height your goal for BMI and weight:":"A jelenlegi testtömeged és magasságod alapján kiszámoltuk, hogy mennyi legyen a célod a BMI (testtömegindex) és tömeg elérésben:",
"Body Mass Index":"Testtömegindex", "Body Mass Index":"Testtömegindex",
"first step":"első lépés",
"goal":"cél",
"Basal Metabolic Rate":"Alapanyagcsere érték", "Basal Metabolic Rate":"Alapanyagcsere érték",
"Based on your weight, height and activity your BMR value":"A tömeged, magasságod és aktivitásod alapján megközelítőleg ennyi a napi kalóriaszükségleted.", "Resting Metabolic Rate":"Minimum energiaszükséglet",
"Based on your weight, height and activity your BMR value":"A testtömeged, magasságod és aktivitásod alapján megközelítőleg ennyi a napi kalóriaszükségleted.",
"Your Sizes":"Méreteid", "Your Sizes":"Méreteid",
"Size Of Your":"Testméret:", "Size Of Your":"Testméret:",
"Please type the following data:":"Kérlek írd be a következő adatot:", "Please type the following data:":"Kérlek írd be a következő adatot:",
@ -299,6 +303,11 @@
"Please define your Exercise Plan":"Kérlek készíts edzéstervet!", "Please define your Exercise Plan":"Kérlek készíts edzéstervet!",
"Go to: 'Training Plan' - 'Edit My Custom Plan'":"Menj a 'Edzéstervem' - 'Egyéni edzésterv' menübe", "Go to: 'Training Plan' - 'Edit My Custom Plan'":"Menj a 'Edzéstervem' - 'Egyéni edzésterv' menübe",
"Jump there »":"Vigyél oda »" "Jump there »":"Vigyél oda »",
"Exception: Purchase was not successful":"A vásárlás sikertelen volt",
"Exception: Purchase was cancelled":"A vásárlás megszakadt",
"Successful Purchase": "Sikeres vásárlás!",
"Now you can use the premium features of WorkoutTest!":"Most már eléred a WorkoutTest prémium tartalmait."
} }

View File

@ -21,6 +21,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>10.0</string> <string>12.0</string>
</dict> </dict>
</plist> </plist>

View File

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
# platform :ios, '9.0' platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'
@ -37,5 +37,8 @@ end
post_install do |installer| post_install do |installer|
installer.pods_project.targets.each do |target| installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target) flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
end
end end
end end

View File

@ -155,6 +155,14 @@ PODS:
- Flutter - Flutter
- PromisesObjC (1.2.11) - PromisesObjC (1.2.11)
- Protobuf (3.13.0) - Protobuf (3.13.0)
- Purchases (3.9.2):
- PurchasesCoreSwift (= 3.9.2)
- purchases_flutter (2.0.0):
- Flutter
- PurchasesHybridCommon (= 1.5.0)
- PurchasesCoreSwift (3.9.2)
- PurchasesHybridCommon (1.5.0):
- Purchases (= 3.9.2)
- shared_preferences (0.0.1): - shared_preferences (0.0.1):
- Flutter - Flutter
- sqflite (0.0.2): - sqflite (0.0.2):
@ -180,6 +188,7 @@ DEPENDENCIES:
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- google_sign_in (from `.symlinks/plugins/google_sign_in/ios`) - google_sign_in (from `.symlinks/plugins/google_sign_in/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`)
- purchases_flutter (from `.symlinks/plugins/purchases_flutter/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`)
- video_player (from `.symlinks/plugins/video_player/ios`) - video_player (from `.symlinks/plugins/video_player/ios`)
@ -210,6 +219,9 @@ SPEC REPOS:
- nanopb - nanopb
- PromisesObjC - PromisesObjC
- Protobuf - Protobuf
- Purchases
- PurchasesCoreSwift
- PurchasesHybridCommon
EXTERNAL SOURCES: EXTERNAL SOURCES:
apple_sign_in: apple_sign_in:
@ -236,6 +248,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/google_sign_in/ios" :path: ".symlinks/plugins/google_sign_in/ios"
path_provider: path_provider:
:path: ".symlinks/plugins/path_provider/ios" :path: ".symlinks/plugins/path_provider/ios"
purchases_flutter:
:path: ".symlinks/plugins/purchases_flutter/ios"
shared_preferences: shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios" :path: ".symlinks/plugins/shared_preferences/ios"
sqflite: sqflite:
@ -282,12 +296,16 @@ SPEC CHECKSUMS:
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f
Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
Purchases: d8a798c9c7552fe66b550bf314a143e94ffa70c8
purchases_flutter: 27f87080055c0fd2cd124c247b10cae75b46e7e1
PurchasesCoreSwift: ea4eabae180416e580ac60366f41aa1fefec0693
PurchasesHybridCommon: d9bfb34309db4c9ba82a6f7f3a6275c13befdca7
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e
wakelock: bfc7955c418d0db797614075aabbc58a39ab5107 wakelock: bfc7955c418d0db797614075aabbc58a39ab5107
webview_flutter: d2b4d6c66968ad042ad94cbb791f5b72b4678a96 webview_flutter: d2b4d6c66968ad042ad94cbb791f5b72b4678a96
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c PODFILE CHECKSUM: 28226b39c1afd238c6168e31e2bd3829c3d67530
COCOAPODS: 1.10.0 COCOAPODS: 1.10.0

View File

@ -16,6 +16,7 @@
BB69292B2521AF45001FBA4C /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BB69292A2521AF45001FBA4C /* Launch Screen.storyboard */; }; BB69292B2521AF45001FBA4C /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BB69292A2521AF45001FBA4C /* Launch Screen.storyboard */; };
BB81345024BB4BE10078D9A4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB81344F24BB4BE10078D9A4 /* GoogleService-Info.plist */; }; BB81345024BB4BE10078D9A4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB81344F24BB4BE10078D9A4 /* GoogleService-Info.plist */; };
BB8D3BFA25A8CBFE00BF29FE /* AuthenticationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB8D3BF925A8CBFE00BF29FE /* AuthenticationServices.framework */; }; BB8D3BFA25A8CBFE00BF29FE /* AuthenticationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB8D3BF925A8CBFE00BF29FE /* AuthenticationServices.framework */; };
BB98CEAF25B8867C000724FE /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB98CEAE25B8867C000724FE /* StoreKit.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@ -50,6 +51,7 @@
BB69292A2521AF45001FBA4C /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; }; BB69292A2521AF45001FBA4C /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
BB81344F24BB4BE10078D9A4 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; }; BB81344F24BB4BE10078D9A4 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
BB8D3BF925A8CBFE00BF29FE /* AuthenticationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AuthenticationServices.framework; path = System/Library/Frameworks/AuthenticationServices.framework; sourceTree = SDKROOT; }; BB8D3BF925A8CBFE00BF29FE /* AuthenticationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AuthenticationServices.framework; path = System/Library/Frameworks/AuthenticationServices.framework; sourceTree = SDKROOT; };
BB98CEAE25B8867C000724FE /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
D5EDDC52125075FB9E21AD35 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; }; D5EDDC52125075FB9E21AD35 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
F39E6E227EB942E5663A6086 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; }; F39E6E227EB942E5663A6086 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@ -59,6 +61,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
BB98CEAF25B8867C000724FE /* StoreKit.framework in Frameworks */,
BB8D3BFA25A8CBFE00BF29FE /* AuthenticationServices.framework in Frameworks */, BB8D3BFA25A8CBFE00BF29FE /* AuthenticationServices.framework in Frameworks */,
42B6B159AF35AFB6DE777DFB /* Pods_Runner.framework in Frameworks */, 42B6B159AF35AFB6DE777DFB /* Pods_Runner.framework in Frameworks */,
); );
@ -80,6 +83,7 @@
3ADC50290ED054951FAC1F56 /* Frameworks */ = { 3ADC50290ED054951FAC1F56 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
BB98CEAE25B8867C000724FE /* StoreKit.framework */,
BB8D3BF925A8CBFE00BF29FE /* AuthenticationServices.framework */, BB8D3BF925A8CBFE00BF29FE /* AuthenticationServices.framework */,
09BD889296C5C90D989820C8 /* Pods_Runner.framework */, 09BD889296C5C90D989820C8 /* Pods_Runner.framework */,
); );
@ -384,7 +388,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 2; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = SFJJBDCU6Z; DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -401,7 +405,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.1.3; MARKETING_VERSION = 1.1.5;
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app; PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -527,7 +531,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 2; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = SFJJBDCU6Z; DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -544,7 +548,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.1.3; MARKETING_VERSION = 1.1.5;
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app; PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -562,7 +566,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 2; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = SFJJBDCU6Z; DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -579,7 +583,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.1.3; MARKETING_VERSION = 1.1.5;
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app; PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

View File

@ -31,11 +31,15 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
double bmr = 0; double bmr = 0;
double goalBMI = 0; double goalBMI = 0;
double goalWeight = 0; double goalWeight = 0;
double goalMilestoneBMI = 0;
double goalMilestoneWeight = 0;
double bmiAngle = 0; double bmiAngle = 0;
double bmiTop = 0; double bmiTop = 0;
double bmiLeft = 0; double bmiLeft = 0;
double weight; double weight;
double height; double height;
double bmrEnergy = 0;
int birthYear;
String fitnessLevel; String fitnessLevel;
bool changedWeight = false; bool changedWeight = false;
bool changedSizes = false; bool changedSizes = false;
@ -66,6 +70,7 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
customerRepository.customer = Cache().userLoggedIn; customerRepository.customer = Cache().userLoggedIn;
weight = customerRepository.customer.getProperty("Weight"); weight = customerRepository.customer.getProperty("Weight");
height = customerRepository.customer.getProperty("Height"); height = customerRepository.customer.getProperty("Height");
birthYear = customerRepository.customer.birthYear;
fitnessLevel = customerRepository.customer.fitnessLevel; fitnessLevel = customerRepository.customer.fitnessLevel;
this.isMan = (customerRepository.customer.sex == "m"); this.isMan = (customerRepository.customer.sex == "m");
} }
@ -315,6 +320,7 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
changedWeight = true; changedWeight = true;
weight = event.value; weight = event.value;
getBMI(); getBMI();
getGoalBMI();
getBMR(); getBMR();
yield ExerciseNewReady(); yield ExerciseNewReady();
} else if (event is ExerciseNewFitnessLevelChange) { } else if (event is ExerciseNewFitnessLevelChange) {
@ -324,12 +330,20 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
changedWeight = true; changedWeight = true;
getBMR(); getBMR();
yield ExerciseNewReady(); yield ExerciseNewReady();
} else if (event is ExerciseNewBirthyearChange) {
yield ExerciseNewLoading();
changedWeight = true;
customerRepository.setBirthYear(event.value.toInt());
birthYear = event.value;
getBMR();
yield ExerciseNewReady();
} else if (event is ExerciseNewHeightChange) { } else if (event is ExerciseNewHeightChange) {
yield ExerciseNewLoading(); yield ExerciseNewLoading();
customerRepository.setHeight(event.value.toInt()); customerRepository.setHeight(event.value.toInt());
changedWeight = true; changedWeight = true;
height = event.value; height = event.value;
getBMI(); getBMI();
getGoalBMI();
getBMR(); getBMR();
yield ExerciseNewReady(); yield ExerciseNewReady();
} else if (event is ExerciseNewSaveWeight) { } else if (event is ExerciseNewSaveWeight) {
@ -390,6 +404,7 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
//BMR = 655.1 + ( 9.563 × ömeg kg-ban ) + ( 1.85 × magasság cm-ben) ( 4.676 × életkor évben kifejezve ) //BMR = 655.1 + ( 9.563 × ömeg kg-ban ) + ( 1.85 × magasság cm-ben) ( 4.676 × életkor évben kifejezve )
bmr = 655.1 + (9.563 * weight) + (1.85 * height) - (4.676 * (year - customerRepository.customer.birthYear)); bmr = 655.1 + (9.563 * weight) + (1.85 * height) - (4.676 * (year - customerRepository.customer.birthYear));
} }
bmrEnergy = bmr;
if (customerRepository.customer.fitnessLevel == FitnessState.beginner) { if (customerRepository.customer.fitnessLevel == FitnessState.beginner) {
bmr *= 1.2; bmr *= 1.2;
@ -424,32 +439,38 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
this.bmiAngle = (bmi * 90 / 25) - 90; this.bmiAngle = (bmi * 90 / 25) - 90;
if (bmi < 18.5) { if (bmi < 18.5) {
goalBMI = 19; goalMilestoneBMI = 19;
goalBMI = 21.75;
this.bmiTop = 99 * distortionHeight; this.bmiTop = 99 * distortionHeight;
this.bmiLeft = 77 * distortionWidth; this.bmiLeft = 77 * distortionWidth;
bmiAngle = -62; bmiAngle = -62;
} else if (bmi > 18.5 && bmi < 25) { } else if (bmi > 18.5 && bmi < 25) {
goalBMI = this.bmi; goalBMI = 21.75;
goalMilestoneBMI = 21.75;
this.bmiTop = 48 * distortionHeight; this.bmiTop = 48 * distortionHeight;
this.bmiLeft = 130 * distortionWidth; this.bmiLeft = 130 * distortionWidth;
bmiAngle = -23; bmiAngle = -23;
} else if (bmi < 30 && bmi > 24.9) { } else if (bmi < 30 && bmi > 24.9) {
goalBMI = 24; goalMilestoneBMI = 24;
goalBMI = 21.75;
this.bmiTop = 40.0 * distortionHeight; this.bmiTop = 40.0 * distortionHeight;
this.bmiLeft = 184.0 * distortionWidth; this.bmiLeft = 184.0 * distortionWidth;
bmiAngle = 7.2; bmiAngle = 7.2;
} else if (bmi < 34.9 && 29.9 < bmi) { } else if (bmi < 34.9 && 29.9 < bmi) {
goalBMI = 29; goalMilestoneBMI = 29;
goalBMI = 24;
bmiTop = 48 * distortionHeight; bmiTop = 48 * distortionHeight;
bmiLeft = 211 * distortionWidth; bmiLeft = 211 * distortionWidth;
} else if (bmi > 35) { } else if (bmi > 35) {
goalBMI = 34; goalMilestoneBMI = 34;
goalBMI = 24;
bmiTop = 94 * distortionHeight; bmiTop = 94 * distortionHeight;
bmiLeft = 260 * distortionWidth; bmiLeft = 260 * distortionWidth;
bmiAngle = 59; bmiAngle = 59;
} }
this.goalWeight = goalBMI * (height * height / 10000); this.goalWeight = goalBMI * (height * height / 10000);
this.goalMilestoneWeight = goalMilestoneBMI * (height * height / 10000);
//print("Angle: " + bmiAngle.toStringAsFixed(1)); //print("Angle: " + bmiAngle.toStringAsFixed(1));

View File

@ -28,6 +28,13 @@ class ExerciseNewQuantityUnitChange extends ExerciseNewEvent {
List<Object> get props => [quantity]; List<Object> get props => [quantity];
} }
class ExerciseNewBirthyearChange extends ExerciseNewEvent {
final int value;
const ExerciseNewBirthyearChange({this.value});
@override
List<Object> get props => [value];
}
class ExerciseNewWeightChange extends ExerciseNewEvent { class ExerciseNewWeightChange extends ExerciseNewEvent {
final double value; final double value;
const ExerciseNewWeightChange({this.value}); const ExerciseNewWeightChange({this.value});

View File

@ -7,7 +7,6 @@ import 'package:aitrainer_app/repository/workout_tree_repository.dart';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flurry/flurry.dart'; import 'package:flurry/flurry.dart';
import 'package:flurry/flurry.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
part 'exercise_plan_event.dart'; part 'exercise_plan_event.dart';

View File

@ -164,7 +164,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
ability = ExerciseAbility.endurance; ability = ExerciseAbility.endurance;
break; break;
case "Cardio": case "Cardio":
case "Body Compositions": case "My Body":
ability = ExerciseAbility.none; ability = ExerciseAbility.none;
break; break;
} }

View File

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/result.dart'; import 'package:aitrainer_app/model/result.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/repository/exercise_result_repository.dart'; import 'package:aitrainer_app/repository/exercise_result_repository.dart';
@ -38,6 +37,10 @@ class ResultBloc extends Bloc<ResultEvent, ResultState> with Logging, Trans {
ResultBloc({this.resultRepository, this.exerciseRepository, this.context}) : super(ResultInitial()) { ResultBloc({this.resultRepository, this.exerciseRepository, this.context}) : super(ResultInitial()) {
this.startTime = exerciseRepository.start; this.startTime = exerciseRepository.start;
this.endTime = exerciseRepository.end; this.endTime = exerciseRepository.end;
if (this.startTime == null) {
this.startTime = exerciseRepository.exercise.dateAdd;
exerciseRepository.start = exerciseRepository.exercise.dateAdd;
}
} }
@override @override

View File

@ -1,16 +1,19 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math' as math;
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/product.dart'; import 'package:aitrainer_app/model/product.dart';
import 'package:aitrainer_app/model/product_test.dart'; import 'package:aitrainer_app/model/product_test.dart';
import 'package:aitrainer_app/model/purchase.dart';
import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/service/product_test_service.dart'; import 'package:aitrainer_app/service/purchase.dart';
import 'package:aitrainer_app/util/platform_purchase.dart'; import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/purchases.dart';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flurry/flurry.dart'; import 'package:flurry/flurry.dart';
import 'package:purchases_flutter/offering_wrapper.dart';
part 'sales_event.dart'; part 'sales_event.dart';
part 'sales_state.dart'; part 'sales_state.dart';
@ -28,15 +31,34 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
try { try {
if (event is SalesLoad) { if (event is SalesLoad) {
yield SalesLoading(); yield SalesLoading();
//Flurry.logEvent("SalesPageOpen"); log("Load Sales");
// await PlatformPurchaseApi().initPurchasePlatformState(); Common.sendMessage("Salespage Load");
// this.getProductSet(); Flurry.logEvent("SalesPageOpen");
//await PlatformPurchaseApi().initPurchasePlatform();
await RevenueCatPurchases().getOfferings();
this.getProductSet();
yield SalesReady(); yield SalesReady();
} else if (event is SalesPurchase) { } else if (event is SalesPurchase) {
if (Cache().hasPurchased) {
throw Exception("You have already a successfull subscription");
}
yield SalesLoading();
final int productId = event.productId; final int productId = event.productId;
trace("Requesting purchase for" + productId.toString()); log("Requesting purchase for: " + productId.toString());
//Flurry.logEvent("PurchaseRequest"); Flurry.logEvent("PurchaseRequest");
// PlatformPurchaseApi().purchase(getSelectedProduct(productId)); final Product selectedProduct = this.getSelectedProduct(productId);
log("SelectedProduct for purchase " + selectedProduct.toString());
await RevenueCatPurchases().makePurchase(selectedProduct);
if (Cache().hasPurchased) {
Purchase purchase = Purchase(customerId: Cache().userLoggedIn.customerId, productId: productId);
purchase.dateAdd = DateTime.now();
purchase.purchaseSum = 0;
purchase.currency = "EUR";
await PurchaseApi().savePurchase(purchase);
Flurry.logEvent("PurchaseSuccessful");
Common.sendMessage("Purchase: " + purchase.toJson().toString());
}
yield SalesSuccessful();
} }
} on Exception catch (ex) { } on Exception catch (ex) {
yield SalesError(message: ex.toString()); yield SalesError(message: ex.toString());
@ -53,18 +75,24 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
return prod; return prod;
} }
/* String getLocalizedPrice(String productId) { String getLocalizedPrice(String productId) {
String price = ""; String price = "";
for (var product in PlatformPurchaseApi().getIAPItems()) { Offering offering = RevenueCatPurchases().offering;
if (Platform.isAndroid) { if (offering != null) {
print("PlatformProduct " + product.toString()); for (var package in offering.availablePackages) {
if (productId == product.productId) { log("PlatformProduct " + package.toString());
price = product.localizedPrice; if (productId == package.product.identifier) {
price = package.product.priceString;
if (price.contains(r'HUF')) {
price = price.replaceAll(RegExp(r'HUF'), 'Ft');
price = price.replaceAll(RegExp(r',00'), "");
}
break; break;
} }
} }
} else {
log(" !!! No Offering");
} }
return price; return price;
} }
@ -73,7 +101,7 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
this.tests = Cache().productTests; this.tests = Cache().productTests;
if (tests.isEmpty) { if (tests.isEmpty) {
var rand = Random.secure(); var rand = math.Random.secure();
productSet = rand.nextInt(5) + 1; productSet = rand.nextInt(5) + 1;
} else { } else {
trace("Previous ProductTest: " + tests[0].toJson().toString()); trace("Previous ProductTest: " + tests[0].toJson().toString());
@ -88,7 +116,9 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
} }
ProductTest productTest = ProductTest(); ProductTest productTest = ProductTest();
trace("ProductSet: " + productSet.toString());
productSet = 2;
log("ProductSet: " + productSet.toString());
for (var elem in Cache().products) { for (var elem in Cache().products) {
Product product = elem as Product; Product product = elem as Product;
@ -109,5 +139,5 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
productTest.dateView = DateTime.now(); productTest.dateView = DateTime.now();
//ProductTestApi().saveProductTest(productTest); //ProductTestApi().saveProductTest(productTest);
//Cache().productTests.add(productTest); //Cache().productTests.add(productTest);
} */ }
} }

View File

@ -19,6 +19,10 @@ class SalesReady extends SalesState {
const SalesReady(); const SalesReady();
} }
class SalesSuccessful extends SalesState {
const SalesSuccessful();
}
class SalesError extends SalesState { class SalesError extends SalesState {
final String message; final String message;
const SalesError({this.message}); const SalesError({this.message});

View File

@ -3,7 +3,6 @@ import 'dart:async';
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart'; import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart'; import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/platform_purchase.dart';
import 'package:aitrainer_app/util/session.dart'; import 'package:aitrainer_app/util/session.dart';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';

View File

@ -74,7 +74,7 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> with Logging {
HealthDataType.RESTING_HEART_RATE HealthDataType.RESTING_HEART_RATE
]; ];
final HealthFactory health = HealthFactory(); */ final HealthFactory health = HealthFactory(); */
DateTime now = DateTime.now(); //DateTime now = DateTime.now();
//List<HealthDataPoint> _healthDataList = await health.getHealthDataFromTypes(now.subtract(Duration(minutes: 5)), now, types); //List<HealthDataPoint> _healthDataList = await health.getHealthDataFromTypes(now.subtract(Duration(minutes: 5)), now, types);
//log(_healthDataList.toString()); //log(_healthDataList.toString());
} }

View File

@ -52,7 +52,7 @@ import 'bloc/menu/menu_bloc.dart';
import 'bloc/session/session_bloc.dart'; import 'bloc/session/session_bloc.dart';
import 'bloc/settings/settings_bloc.dart'; import 'bloc/settings/settings_bloc.dart';
final SentryClient _sentry = new SentryClient(dsn: 'https://5fac40cbfcfb4c15aa80c7a8638d7310@o418565.ingest.sentry.io/5322520'); const dsn = 'https://5fac40cbfcfb4c15aa80c7a8638d7310@o418565.ingest.sentry.io/5322520';
/// Whether the VM is running in debug mode. /// Whether the VM is running in debug mode.
/// ///
@ -80,16 +80,12 @@ Future<Null> _reportError(dynamic error, dynamic stackTrace) async {
print('Reporting to Sentry.io...'); print('Reporting to Sentry.io...');
final SentryResponse response = await _sentry.captureException( final sentryId = await Sentry.captureException(
exception: error, error,
stackTrace: stackTrace, stackTrace: stackTrace,
); );
if (response.isSuccessful) { print('Capture exception result : SentryId : $sentryId');
print('Success! Event ID: ${response.eventId}');
} else {
print('Failed to report to Sentry.io: ${response.error}');
}
} }
Future<Null> main() async { Future<Null> main() async {
@ -119,8 +115,10 @@ Future<Null> main() async {
runZonedGuarded<Future<Null>>(() async { runZonedGuarded<Future<Null>>(() async {
final WorkoutTreeRepository menuTreeRepository = WorkoutTreeRepository(); final WorkoutTreeRepository menuTreeRepository = WorkoutTreeRepository();
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
print(" -- FireBase init.."); print(" -- FireBase init..");
await FirebaseApi().initializeFlutterFire(); await FirebaseApi().initializeFlutterFire();
runApp(MultiBlocProvider( runApp(MultiBlocProvider(
providers: [ providers: [
BlocProvider<SessionBloc>( BlocProvider<SessionBloc>(
@ -157,8 +155,6 @@ Future<Null> main() async {
Future<void> initFlurry() async { Future<void> initFlurry() async {
await Flurry.initialize(androidKey: "JNYCTCWBT34FM3J8TV36", iosKey: "3QBG7BSMGPDH24S8TRQP", enableLog: true); await Flurry.initialize(androidKey: "JNYCTCWBT34FM3J8TV36", iosKey: "3QBG7BSMGPDH24S8TRQP", enableLog: true);
//await Flurry.setUserId("userId");
//await Flurry.logEvent("eventName");
} }
class WorkoutTestApp extends StatelessWidget { class WorkoutTestApp extends StatelessWidget {
@ -232,7 +228,7 @@ class WorkoutTestApp extends StatelessWidget {
//primarySwatch: Colors.transparent, //primarySwatch: Colors.transparent,
//fontFamily: 'Arial', //fontFamily: 'Arial',
textTheme: TextTheme( textTheme: TextTheme(
bodyText1: GoogleFonts.openSans(textStyle: TextStyle(fontSize: 14.0)), bodyText1: GoogleFonts.inter(textStyle: TextStyle(fontSize: 14.0)),
)), )),
navigatorObservers: [ navigatorObservers: [
FirebaseAnalyticsObserver(analytics: analytics), FirebaseAnalyticsObserver(analytics: analytics),

View File

@ -5,7 +5,7 @@ import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_tree.dart'; import 'package:aitrainer_app/model/exercise_tree.dart';
import 'package:aitrainer_app/model/exercise.dart'; import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/model_change.dart'; import 'package:aitrainer_app/model/model_change.dart';
import 'package:aitrainer_app/model/product.dart'; import 'package:aitrainer_app/model/product.dart' as wt_product;
import 'package:aitrainer_app/model/product_test.dart'; import 'package:aitrainer_app/model/product_test.dart';
import 'package:aitrainer_app/model/property.dart'; import 'package:aitrainer_app/model/property.dart';
import 'package:aitrainer_app/model/purchase.dart'; import 'package:aitrainer_app/model/purchase.dart';
@ -84,7 +84,7 @@ class Cache with Logging {
List<Exercise> _exercises; List<Exercise> _exercises;
ExercisePlan _myExercisePlan; ExercisePlan _myExercisePlan;
List<Property> _properties; List<Property> _properties;
List<Product> _products; List<wt_product.Product> _products;
List<Purchase> _purchases = List(); List<Purchase> _purchases = List();
List<ProductTest> _productTests; List<ProductTest> _productTests;
@ -405,18 +405,18 @@ class Cache with Logging {
setBadge("Sizes", true); setBadge("Sizes", true);
setBadge("BMI", true); setBadge("BMI", true);
setBadge("BMR", true); setBadge("BMR", true);
setBadgeNr("Body Compositions", 3); setBadgeNr("My Body", 3);
setBadgeNr("home", 3); setBadgeNr("home", 3);
} else if (customerRepository.getWeight() == 0) { } else if (customerRepository.getWeight() == 0) {
setBadge("BMI", true); setBadge("BMI", true);
setBadge("BMR", true); setBadge("BMR", true);
setBadge("Body Compositions", true); setBadge("My Body", true);
setBadgeNr("home", 1); setBadgeNr("home", 1);
} }
if (customerRepository.getHeight() == 0) { if (customerRepository.getHeight() == 0) {
setBadge("BMI", true); setBadge("BMI", true);
setBadge("BMR", true); setBadge("BMR", true);
setBadge("Body Compositions", true); setBadge("My Body", true);
setBadgeNr("home", 1); setBadgeNr("home", 1);
} }
} }
@ -450,7 +450,7 @@ class Cache with Logging {
await customerRepository.getPurchase(); await customerRepository.getPurchase();
await customerRepository.getProductTests(); await customerRepository.getProductTests();
this.hasPurchased = this._purchases.isNotEmpty; //this.hasPurchased = this._purchases.isNotEmpty;
Cache().startPage = "home"; Cache().startPage = "home";
} }

View File

@ -55,7 +55,6 @@ class ExerciseType {
this.parents.add(parent['exerciseTreeId']); this.parents.add(parent['exerciseTreeId']);
}); });
} }
;
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {

View File

@ -9,6 +9,8 @@ class Purchase {
double purchaseSum; double purchaseSum;
String currency; String currency;
Purchase({this.customerId, this.productId});
Purchase.fromJson(Map json) { Purchase.fromJson(Map json) {
this.purchaseId = json['purchaseId']; this.purchaseId = json['purchaseId'];
this.customerId = json['customerId']; this.customerId = json['customerId'];

View File

@ -270,7 +270,7 @@ class CustomerRepository with Logging {
try { try {
int customerId = Cache().userLoggedIn.customerId; int customerId = Cache().userLoggedIn.customerId;
tests = await ProductTestApi().getProductTestByCustomer(customerId); tests = await ProductTestApi().getProductTestByCustomer(customerId);
} on NotFoundException catch (ex) { } on NotFoundException catch (_) {
log("Product Tests not found"); log("Product Tests not found");
Cache().productTests = tests; Cache().productTests = tests;
} on Exception catch (ex) { } on Exception catch (ex) {

View File

@ -259,6 +259,17 @@ class ExerciseRepository {
return actualExerciseType; return actualExerciseType;
} }
void getSameExercise(int exerciseTypeId, String day) {
this.actualExerciseList = List();
for (int i = 0; i < this.exerciseList.length; i++) {
Exercise exercise = exerciseList[i];
String exerciseDate = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd);
if (exerciseTypeId == exercise.exerciseTypeId && exerciseDate == day) {
this.actualExerciseList.add(exercise);
}
}
}
void sortByDate() { void sortByDate() {
if (exerciseList.isEmpty) { if (exerciseList.isEmpty) {
return; return;

View File

@ -1,7 +1,6 @@
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_result.dart'; import 'package:aitrainer_app/model/exercise_result.dart';
import 'package:aitrainer_app/model/result.dart'; import 'package:aitrainer_app/model/result.dart';
import 'package:aitrainer_app/service/exercise_result_service.dart';
enum ResultType { running, man, woman, none } enum ResultType { running, man, woman, none }

View File

@ -59,6 +59,11 @@ class UserRepository with Logging {
if (e.code == 'email-already-in-use') { if (e.code == 'email-already-in-use') {
log('The account already exists for that email.'); log('The account already exists for that email.');
throw Exception("The email address has been registered already"); throw Exception("The email address has been registered already");
} else if (e.code == 'weak-password') {
log('The password provided is too weak.');
throw Exception("Password too short");
} else {
throw Exception(e);
} }
} on WorkoutTestException catch (ex) { } on WorkoutTestException catch (ex) {
if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) { if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) {
@ -66,8 +71,8 @@ class UserRepository with Logging {
throw Exception("The email address has been registered already"); throw Exception("The email address has been registered already");
} }
} on Exception catch (ex) { } on Exception catch (ex) {
log("Google exception: " + ex.toString()); log("FB exception: " + ex.toString());
throw Exception("Google Sign In failed"); throw Exception("Facebook Sign In failed");
} }
} }
@ -90,6 +95,8 @@ class UserRepository with Logging {
if (e.code == 'email-already-in-use') { if (e.code == 'email-already-in-use') {
log('The account already exists for that email.'); log('The account already exists for that email.');
throw Exception("The email address has been registered already"); throw Exception("The email address has been registered already");
} else {
throw Exception(e);
} }
} on WorkoutTestException catch (ex) { } on WorkoutTestException catch (ex) {
if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) { if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) {
@ -167,17 +174,18 @@ class UserRepository with Logging {
Future<void> getUserByGoogle() async { Future<void> getUserByGoogle() async {
final User modelUser = this.user; final User modelUser = this.user;
try {
Map<String, dynamic> userData = await FirebaseApi().signInWithGoogle(); Map<String, dynamic> userData = await FirebaseApi().signInWithGoogle();
if (userData == null || userData['email'] == null) { if (userData == null || userData['email'] == null) {
throw new Exception("Google login was not successful"); throw new Exception("Google login was not successful");
} }
modelUser.email = userData['email']; modelUser.email = userData['email'];
try {
await CustomerApi().getUserByEmail(modelUser.email); await CustomerApi().getUserByEmail(modelUser.email);
await Cache().afterFirebaseLogin(); await Cache().afterFirebaseLogin();
} on Exception catch (ex) { } on Exception catch (ex) {
log("Google exception: " + ex.toString()); log("Google exception: " + ex.toString());
throw Exception("Customer does not exist or the password is wrong"); throw Exception(ex);
} }
} }

View File

@ -10,7 +10,6 @@ import 'package:aitrainer_app/service/exercise_tree_service.dart';
import 'package:aitrainer_app/service/exercisetype_service.dart'; import 'package:aitrainer_app/service/exercisetype_service.dart';
import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/logging.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class Antagonist { class Antagonist {
static String chest = "Chest"; static String chest = "Chest";
@ -48,7 +47,7 @@ class WorkoutTreeRepository with Logging {
Antagonist.calf: Antagonist.calfNr Antagonist.calf: Antagonist.calfNr
}; };
Future<String> _buildImage(String imageUrl) async { /* Future<String> _buildImage(String imageUrl) async {
String assetImage = 'asset/menu/' + imageUrl.substring(7); String assetImage = 'asset/menu/' + imageUrl.substring(7);
//print("Loading image " + assetImage); //print("Loading image " + assetImage);
return rootBundle.load(assetImage).then((value) { return rootBundle.load(assetImage).then((value) {
@ -59,7 +58,7 @@ class WorkoutTreeRepository with Logging {
//print("Exception: " + assetImage + " will be loaded from the network " + url); //print("Exception: " + assetImage + " will be loaded from the network " + url);
return url; return url;
}); });
} } */
Future<void> createTree() async { Future<void> createTree() async {
isEnglish = AppLanguage().appLocal == Locale('en'); isEnglish = AppLanguage().appLocal == Locale('en');

View File

@ -15,7 +15,7 @@ class CustomerExerciseDeviceApi with Logging {
final body = await _client.get("customer_exercise_device/customer/" + customerId.toString(), ""); final body = await _client.get("customer_exercise_device/customer/" + customerId.toString(), "");
final Iterable json = jsonDecode(body); final Iterable json = jsonDecode(body);
devices = json.map((device) => CustomerExerciseDevice.fromJson(device)).toList(); devices = json.map((device) => CustomerExerciseDevice.fromJson(device)).toList();
} on NotFoundException catch (e) { } on NotFoundException catch (_) {
log("No devices found"); log("No devices found");
} }
return devices; return devices;

View File

@ -165,7 +165,6 @@ class FirebaseApi with logging.Logging {
Future<Map<String, dynamic>> signInWithGoogle() async { Future<Map<String, dynamic>> signInWithGoogle() async {
Map<String, dynamic> userData = Map(); Map<String, dynamic> userData = Map();
try {
// Trigger the authentication flow // Trigger the authentication flow
GoogleSignIn _googleSignIn = GoogleSignIn( GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [ scopes: [
@ -196,10 +195,7 @@ class FirebaseApi with logging.Logging {
userData['id'] = googleUser.id; userData['id'] = googleUser.id;
userData['name'] = googleUser.displayName; userData['name'] = googleUser.displayName;
} }
} on Exception catch (ex) {
log("Google exception: " + ex.toString());
throw Exception("Google Sign In failed");
}
return userData; return userData;
} }
@ -266,15 +262,16 @@ class FirebaseApi with logging.Logging {
Cache().accessTokenFacebook = accessToken; Cache().accessTokenFacebook = accessToken;
// get the user data // get the user data
userData = await FacebookAuth.instance.getUserData(); userData = await FacebookAuth.instance.getUserData();
log("FB user data: " + userData.toString());
// Create a credential from the access token // Create a credential from the access token
final FacebookAuthCredential facebookAuthCredential = FacebookAuthProvider.credential(accessToken.token); final FacebookAuthCredential facebookAuthCredential = FacebookAuthProvider.credential(accessToken.token);
// Once signed in, return the UserCredential // Once signed in, return the UserCredential
final userCredential = await FirebaseAuth.instance.signInWithCredential(facebookAuthCredential); final userCredential = await FirebaseAuth.instance.signInWithCredential(facebookAuthCredential);
log("Email by FB: " + userData['email'] + " FB credential: " + userCredential.toString());
Cache().firebaseUid = userCredential.user.uid; Cache().firebaseUid = userCredential.user.uid;
log(userData.toString());
} else { } else {
throw Exception("Facebook login was not successful"); throw Exception("Facebook login was not successful");
} }

View File

@ -15,7 +15,7 @@ class PurchaseApi with Logging {
final Iterable json = jsonDecode(body); final Iterable json = jsonDecode(body);
final List<Purchase> purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList(); final List<Purchase> purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList();
Cache().setPurchases(purchases); Cache().setPurchases(purchases);
} on NotFoundException catch (e) { } on NotFoundException catch (_) {
log("No purchases found"); log("No purchases found");
} }
return purchases; return purchases;

View File

@ -8,6 +8,7 @@ import 'package:badges/badges.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:sentry/sentry.dart';
class DateRate { class DateRate {
static String daily = "daily"; static String daily = "daily";
@ -130,4 +131,13 @@ mixin Common {
), ),
); );
} }
static Future<void> sendMessage(String message) async {
// Sends a full Sentry event payload to show the different parts of the UI.
await Sentry.captureMessage(
message,
level: SentryLevel.info,
template: 'Message: %s, customerId: ' + Cache().userLoggedIn.customerId.toString(),
);
}
} }

View File

@ -1,28 +1,29 @@
import 'dart:async';
import 'dart:io';
/* /*
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/product.dart'; import 'package:aitrainer_app/model/product.dart';
import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/logging.dart';
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart'; import 'package:in_app_purchase/in_app_purchase.dart';
class PlatformPurchaseApi with Logging { class PlatformPurchaseApi with Logging {
static final PlatformPurchaseApi _singleton = PlatformPurchaseApi._internal(); static final PlatformPurchaseApi _singleton = PlatformPurchaseApi._internal();
StreamSubscription _purchaseUpdatedSubscription; bool _kAutoConsume = true;
StreamSubscription _purchaseErrorSubscription; final String _kConsumableId = 'consumable';
StreamSubscription _conectionSubscription; final InAppPurchaseConnection _connection = InAppPurchaseConnection.instance;
String _platformVersion = 'Unknown'; bool _isAvailable = false;
List<IAPItem> _items = []; List<ProductDetails> _products = [];
List getIAPItems() => _items; List<PurchaseDetails> _purchases = [];
List<PurchasedItem> _purchases = []; List<String> _notFoundIds = [];
List<String> _consumables = [];
bool _purchasePending = false;
String _queryProductError;
StreamSubscription<List<PurchaseDetails>> _subscription;
final List<String> _productList = List(); final List<String> _productList = List();
List getProductList() => _productList; List getProductList() => _productList;
factory PlatformPurchaseApi() { factory PlatformPurchaseApi() {
return _singleton; return _singleton;
} }
@ -30,55 +31,152 @@ class PlatformPurchaseApi with Logging {
PlatformPurchaseApi._internal(); PlatformPurchaseApi._internal();
Future<void> close() async { Future<void> close() async {
if (_conectionSubscription != null) { _subscription.cancel();
_conectionSubscription.cancel();
_conectionSubscription = null;
} }
await FlutterInappPurchase.instance.endConnection;
Future<void> initStoreInfo() async {
final bool isAvailable = await _connection.isAvailable();
if (!isAvailable) {
_isAvailable = isAvailable;
_products = [];
_purchases = [];
_notFoundIds = [];
_consumables = [];
_purchasePending = false;
log("Payment processor not available");
return;
}
getSubscriptions();
ProductDetailsResponse productDetailResponse = await _connection.queryProductDetails(_productList.toSet());
log("ProductDetailsResponse " + productDetailResponse.toString());
if (productDetailResponse.error != null) {
_queryProductError = productDetailResponse.error.message;
_isAvailable = isAvailable;
_products = productDetailResponse.productDetails;
_purchases = [];
_notFoundIds = productDetailResponse.notFoundIDs;
_consumables = [];
_purchasePending = false;
log("Payment processor not available");
return;
}
if (productDetailResponse.productDetails.isEmpty) {
_queryProductError = null;
_isAvailable = isAvailable;
_products = productDetailResponse.productDetails;
_purchases = [];
_notFoundIds = productDetailResponse.notFoundIDs;
_consumables = [];
_purchasePending = false;
return;
}
_products = productDetailResponse.productDetails;
_products.forEach((element) {
ProductDetails product = element as ProductDetails;
log("Product " + product.id + " " + product.price + " " + product.skuDetail.toString());
});
final QueryPurchaseDetailsResponse purchaseResponse = await _connection.queryPastPurchases();
if (purchaseResponse.error != null) {
// handle query past purchase error..
}
final List<PurchaseDetails> verifiedPurchases = [];
for (PurchaseDetails purchase in purchaseResponse.pastPurchases) {
if (await _verifyPurchase(purchase)) {
verifiedPurchases.add(purchase);
}
}
//TODO List<String> consumables = await ConsumableStore.load();
_isAvailable = isAvailable;
_products = productDetailResponse.productDetails;
_purchases = verifiedPurchases;
_notFoundIds = productDetailResponse.notFoundIDs;
//_consumables = consumables;
_purchasePending = false;
} }
// Platform messages are asynchronous, so we initialize in an async method. // Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPurchasePlatformState() async { Future<void> initPurchasePlatform() async {
if (_productList.length > 0) { if (_productList.length > 0) {
return; return;
} }
log(' --- InappPurchase connection: $_connection');
log(" --- Init PurchasePlatform"); log(" --- Init PurchasePlatform");
String platformVersion; await this.initStoreInfo();
// Platform messages may fail, so we use a try/catch PlatformException.
try { Stream purchaseUpdated = InAppPurchaseConnection.instance.purchaseUpdatedStream;
platformVersion = await FlutterInappPurchase.instance.platformVersion; _subscription = purchaseUpdated.listen((purchaseDetailsList) {
} on Exception { _listenToPurchaseUpdated(purchaseDetailsList);
platformVersion = 'Failed to get platform version for InAppPurchase.'; }, onDone: () {
log("PlatformVersion" + platformVersion); _subscription.cancel();
}, onError: (error) {
// handle error here.
log("Error listen purchase updated " + error.toString());
});
} }
// prepare void deliverProduct(PurchaseDetails purchaseDetails) async {
var result = await FlutterInappPurchase.instance.initConnection; log("DeliverProduct");
log(' FlutterInappPurchase init result: $result'); // IMPORTANT!! Always verify a purchase purchase details before delivering the product.
if (purchaseDetails.productID == _kConsumableId) {
//TODO
//await ConsumableStore.save(purchaseDetails.purchaseID);
//List<String> consumables = await ConsumableStore.load();
_platformVersion = platformVersion; _purchasePending = false;
//_consumables = consumables;
// refresh items for android } else {
try { _purchases.add(purchaseDetails);
String msg = await FlutterInappPurchase.instance.consumeAllItems; _purchasePending = false;
log('consumeAllItems: $msg'); }
} catch (err) {
log('consumeAllItems error: $err');
} }
_conectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) { Future<bool> _verifyPurchase(PurchaseDetails purchaseDetails) {
log('connected: $connected'); log("verifyPurchase");
}); // IMPORTANT!! Always verify a purchase before delivering the product.
// For the purpose of an example, we directly return true.
log("Verifying Purchase" + purchaseDetails.toString());
return Future<bool>.value(true);
}
_purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen((productItem) { void _handleInvalidPurchase(PurchaseDetails purchaseDetails) {
log('purchase-updated: $productItem'); // handle invalid purchase here if _verifyPurchase` failed.
}); log("Invalid Purchase" + purchaseDetails.toString());
}
_purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) { void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) {
log('purchase-error: $purchaseError'); purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
if (purchaseDetails.status == PurchaseStatus.pending) {
//showPendingUI();
log("Purchase pending");
} else {
if (purchaseDetails.status == PurchaseStatus.error) {
//handleError(purchaseDetails.error);
} else if (purchaseDetails.status == PurchaseStatus.purchased) {
bool valid = await _verifyPurchase(purchaseDetails);
if (valid) {
deliverProduct(purchaseDetails);
} else {
_handleInvalidPurchase(purchaseDetails);
return;
}
}
if (Platform.isAndroid) {
if (!_kAutoConsume && purchaseDetails.productID == _kConsumableId) {
await InAppPurchaseConnection.instance.consumePurchase(purchaseDetails);
}
}
if (purchaseDetails.pendingCompletePurchase) {
await InAppPurchaseConnection.instance.completePurchase(purchaseDetails);
}
}
}); });
getSubscriptions();
} }
void getSubscriptions() { void getSubscriptions() {
@ -98,7 +196,6 @@ class PlatformPurchaseApi with Logging {
_productList.forEach((element) { _productList.forEach((element) {
print(element); print(element);
}); });
_getSubscription();
} }
void purchase(Product product) { void purchase(Product product) {
@ -106,57 +203,29 @@ class PlatformPurchaseApi with Logging {
throw Exception("No product to purchase"); throw Exception("No product to purchase");
} }
String productId = Platform.isAndroid ? product.productIdAndroid : product.productIdIos; String productId = Platform.isAndroid ? product.productIdAndroid : product.productIdIos;
IAPItem selected; ProductDetails productDetails;
for (var item in _items) { _products.forEach((element) {
if (item.productId == productId) { if (element.id == productId) {
selected = item; productDetails = element;
log("Item to purchase: " + item.toString()); log("product to purchase: " +
} productDetails.id +
" title " +
productDetails.title +
" price " +
productDetails.price +
" period " +
productDetails.skuDetail.subscriptionPeriod);
} }
});
if (selected != null) { final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);
requestPurchase(selected); /* if (_isConsumable(productDetails)) {
} else { InAppPurchaseConnection.instance.buyConsumable(purchaseParam: purchaseParam);
throw Exception("product " + productId + " not defined in the PlatformStore"); } else { */
} InAppPurchaseConnection.instance.buyNonConsumable(purchaseParam: purchaseParam);
} //}
// From here the purchase flow will be handled by the underlying storefront.
void requestPurchase(IAPItem item) { // Updates will be delivered to the `InAppPurchaseConnection.instance.purchaseUpdatedStream`.
//FlutterInappPurchase.instance.requestPurchase(item.productId);
FlutterInappPurchase.instance.requestPurchase(item.productId);
}
Future _getSubscription() async {
List<IAPItem> items = await FlutterInappPurchase.instance.getSubscriptions(_productList);
for (var item in items) {
log('${item.toString()}');
this._items.add(item);
}
this._items = items;
this._purchases = [];
}
Future _getPurchases() async {
List<PurchasedItem> items = await FlutterInappPurchase.instance.getAvailablePurchases();
for (var item in items) {
log('${item.toString()}');
this._purchases.add(item);
}
this._items = [];
this._purchases = items;
}
Future _getPurchaseHistory() async {
List<PurchasedItem> items = await FlutterInappPurchase.instance.getPurchaseHistory();
for (var item in items) {
log('${item.toString()}');
this._purchases.add(item);
}
this._items = [];
this._purchases = items;
} }
} }
*/ */

120
lib/util/purchases.dart Normal file
View File

@ -0,0 +1,120 @@
import 'dart:io';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:flutter/services.dart';
import 'package:purchases_flutter/purchases_flutter.dart';
import 'package:aitrainer_app/model/product.dart' as wtproduct;
class RevenueCatPurchases with Logging {
static final RevenueCatPurchases _singleton = RevenueCatPurchases._internal();
Offering _offering;
String appUserId;
factory RevenueCatPurchases() {
return _singleton;
}
RevenueCatPurchases._internal();
Offering get offering => _offering;
Future<void> initPlatform() async {
if (Cache().userLoggedIn != null) {
await Purchases.setDebugLogsEnabled(true);
await Purchases.setup("yLxGFWaeRtThLImqznvBnUEKjgArSsZE", appUserId: Cache().userLoggedIn.customerId.toString());
appUserId = await Purchases.appUserID;
log("AppUserId: " + appUserId);
await this.restore();
}
}
Future<void> restore() async {
if (appUserId != null) {
try {
PurchaserInfo purchaserInfo = await Purchases.restoreTransactions();
if (purchaserInfo != null &&
purchaserInfo.entitlements.all["wt_subscription"] != null &&
purchaserInfo.entitlements.all["wt_subscription"].isActive) {
Cache().hasPurchased = true;
log(" ******************************************** ");
log(" Purchase active ! ");
} else {
log(" ** No subscription active");
}
} on PlatformException catch (e) {
log("Purchaserinfo not reachable " + e.toString());
}
}
}
Future<Offering> getOfferings() async {
if (appUserId == null) {
await initPlatform();
}
log(" .. acessing offerings...");
try {
Offerings offerings = await Purchases.getOfferings();
if (offerings.current != null && offerings.current.availablePackages.isNotEmpty) {
// Display packages for sale
_offering = offerings.current;
} else {
log("No current offerings");
Common.sendMessage("No Current offerings");
}
} on PlatformException catch (e) {
// optional error handling
log("!!!! Getting offerings error " + e.toString());
}
return _offering;
}
Future<void> makePurchase(wtproduct.Product product) async {
try {
if (_offering == null) {
_offering = await getOfferings();
}
if (_offering != null) {
String productId = Platform.isAndroid ? product.productIdAndroid : product.productIdIos;
Package selectedPackage;
log("Nr of packages: " + _offering.availablePackages.length.toString() + " ProductId: " + productId);
for (var package in _offering.availablePackages) {
log("package to check " + package.product.identifier.toString());
if (package.product.identifier == productId) {
selectedPackage = package;
log("**** Selected package to purchase" + package.product.identifier);
break;
}
}
if (selectedPackage != null) {
PurchaserInfo purchaserInfo = await Purchases.purchasePackage(selectedPackage);
if (purchaserInfo.entitlements.all["wt_subscription"].isActive) {
Cache().hasPurchased = true;
}
} else {
log("!!!! No Selected package to purchase");
Common.sendMessage("No Selected package to purchase");
throw Exception("Purchase was not successful");
}
} else {
log("!!!! No active offering");
}
} on PlatformException catch (e) {
var errorCode = PurchasesErrorHelper.getErrorCode(e);
if (errorCode == PurchasesErrorCode.invalidReceiptError) {
log("iOS Sandbox invalid receipt");
Cache().hasPurchased = true;
return;
}
log(e.toString());
if (errorCode == PurchasesErrorCode.purchaseCancelledError) {
Common.sendMessage("Purchase was cancelled");
throw Exception("Purchase was cancelled");
} else {
Common.sendMessage("Purchase was not successful");
throw Exception("Purchase was not successful");
}
}
}
}

View File

@ -6,6 +6,7 @@ import 'package:aitrainer_app/service/api.dart';
import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/service/product_service.dart'; import 'package:aitrainer_app/service/product_service.dart';
import 'package:aitrainer_app/service/property_service.dart'; import 'package:aitrainer_app/service/property_service.dart';
import 'package:aitrainer_app/util/purchases.dart';
import 'package:devicelocale/devicelocale.dart'; import 'package:devicelocale/devicelocale.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -28,6 +29,7 @@ class Session with Logging {
Cache().setServerAddress(_sharedPreferences); Cache().setServerAddress(_sharedPreferences);
Cache().getHardware(_sharedPreferences); Cache().getHardware(_sharedPreferences);
await _fetchToken(_sharedPreferences); await _fetchToken(_sharedPreferences);
await RevenueCatPurchases().initPlatform();
//initDeviceLocale(); //initDeviceLocale();
// Create the initialization Future outside of `build`: // Create the initialization Future outside of `build`:

View File

@ -5,7 +5,6 @@ import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/util/common.dart'; import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart'; import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:badges/badges.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart'; import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View File

@ -4,7 +4,9 @@ import 'dart:ui';
import 'package:aitrainer_app/bloc/result/result_bloc.dart'; import 'package:aitrainer_app/bloc/result/result_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart'; import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_ability.dart'; import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/repository/exercise_result_repository.dart'; import 'package:aitrainer_app/repository/exercise_result_repository.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
@ -15,6 +17,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart'; import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:aitrainer_app/model/result.dart'; import 'package:aitrainer_app/model/result.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
// ignore: must_be_immutable // ignore: must_be_immutable
class EvaluationPage extends StatelessWidget with Trans { class EvaluationPage extends StatelessWidget with Trans {
@ -22,7 +25,7 @@ class EvaluationPage extends StatelessWidget with Trans {
Widget build(BuildContext context) { Widget build(BuildContext context) {
LinkedHashMap arguments = ModalRoute.of(context).settings.arguments; LinkedHashMap arguments = ModalRoute.of(context).settings.arguments;
ExerciseRepository exerciseRepository; ExerciseRepository exerciseRepository;
// ignore: close_sinks
if (arguments != null) { if (arguments != null) {
exerciseRepository = arguments['exerciseRepository']; exerciseRepository = arguments['exerciseRepository'];
} else { } else {
@ -37,10 +40,22 @@ class EvaluationPage extends StatelessWidget with Trans {
resultType = ResultType.man; resultType = ResultType.man;
imageUrl = 'asset/image/WT_Results_for_female.png'; imageUrl = 'asset/image/WT_Results_for_female.png';
} }
if (arguments['past'] != null && arguments['past'] == true) {
Exercise exercise = arguments['exercise'];
if (exercise != null) {
ExerciseType exerciseType = exerciseRepository.getExerciseTypeById(exercise.exerciseTypeId);
exerciseRepository.exerciseType = exerciseType;
exerciseRepository.exercise = exercise;
String exerciseDate = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd);
exerciseRepository.getSameExercise(exercise.exerciseTypeId, exerciseDate);
}
}
if (exerciseRepository.exerciseType.getAbility().equalsTo(ExerciseAbility.running)) { if (exerciseRepository.exerciseType.getAbility().equalsTo(ExerciseAbility.running)) {
resultType = ResultType.running; resultType = ResultType.running;
imageUrl = 'asset/image/WT_Results_for_runners.png'; imageUrl = 'asset/image/WT_Results_for_runners.png';
} }
setContext(context); setContext(context);
return Scaffold( return Scaffold(
appBar: AppBarMin( appBar: AppBarMin(
@ -61,7 +76,7 @@ class EvaluationPage extends StatelessWidget with Trans {
create: (context) => ResultBloc( create: (context) => ResultBloc(
resultRepository: ExerciseResultRepository(resultType: resultType), resultRepository: ExerciseResultRepository(resultType: resultType),
exerciseRepository: exerciseRepository, exerciseRepository: exerciseRepository,
context: context), //..add(ResultLoad()) context: context),
child: BlocConsumer<ResultBloc, ResultState>(listener: (context, state) { child: BlocConsumer<ResultBloc, ResultState>(listener: (context, state) {
if (state is ResultError) { if (state is ResultError) {
Scaffold.of(context).showSnackBar( Scaffold.of(context).showSnackBar(
@ -74,7 +89,13 @@ class EvaluationPage extends StatelessWidget with Trans {
} }
}, builder: (context, state) { }, builder: (context, state) {
final resultBloc = BlocProvider.of<ResultBloc>(context); final resultBloc = BlocProvider.of<ResultBloc>(context);
return getEvaluationWidgets(resultBloc); return ModalProgressHUD(
child: getEvaluationWidgets(resultBloc),
inAsyncCall: state is ResultLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}))), }))),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 0)); bottomNavigationBar: BottomNavigator(bottomNavIndex: 0));
} }
@ -89,13 +110,15 @@ class EvaluationPage extends StatelessWidget with Trans {
SliverAppBar( SliverAppBar(
pinned: true, pinned: true,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
expandedHeight: 50.0, expandedHeight: 120.0,
collapsedHeight: 80,
toolbarHeight: 30,
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
flexibleSpace: FlexibleSpaceBar( flexibleSpace: FlexibleSpaceBar(
title: Text(exerciseName, title: Text(exerciseName,
textAlign: TextAlign.center, textAlign: TextAlign.center,
maxLines: 3, maxLines: 3,
softWrap: true, //softWrap: true,
style: GoogleFonts.archivoBlack( style: GoogleFonts.archivoBlack(
fontSize: 24, fontSize: 24,
color: Colors.white, color: Colors.white,
@ -382,14 +405,12 @@ class EvaluationPage extends StatelessWidget with Trans {
Widget getSummary(ResultBloc bloc) { Widget getSummary(ResultBloc bloc) {
int index = 0; int index = 0;
List<Text> resultList = List(); List<Text> resultList = List();
/* for (int i = 0; i < bloc.exerciseRepository.actualExerciseList.length; i++) {
print("Q " +
bloc.exerciseRepository.actualExerciseList[i].quantity.toString() +
" Qu: " +
bloc.exerciseRepository.actualExerciseList[i].unitQuantity.toString());
} */
bloc.exerciseRepository.actualExerciseList.forEach((actual) { bloc.exerciseRepository.actualExerciseList.forEach((actual) {
final String unit = t(bloc.exerciseRepository.exerciseType.unit); //final String unit = t(bloc.exerciseRepository.exerciseType.unit);
final String unit = bloc.exerciseRepository.exerciseType.unitQuantityUnit != null
? bloc.exerciseRepository.exerciseType.unitQuantityUnit
: bloc.exerciseRepository.exerciseType.unit;
String exerciseElement = ""; String exerciseElement = "";
String exerciseRepeats = actual.quantity.toStringAsFixed(0); String exerciseRepeats = actual.quantity.toStringAsFixed(0);
if (bloc.exerciseRepository.exerciseType.unit == "second") { if (bloc.exerciseRepository.exerciseType.unit == "second") {
@ -407,7 +428,7 @@ class EvaluationPage extends StatelessWidget with Trans {
} }
index++; index++;
resultList.add( resultList.add(
Text(exerciseElement + exerciseRepeats + exerciseUnitQuantity + " " + unit, Text(exerciseElement + exerciseRepeats + exerciseUnitQuantity + " " + t(unit),
textAlign: TextAlign.center, textAlign: TextAlign.center,
maxLines: 2, maxLines: 2,
softWrap: true, softWrap: true,

View File

@ -200,7 +200,7 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
iconSize: 36, iconSize: 36,
icon: Icon(CustomIcon.heart_1, color: Colors.blue[800]), icon: Icon(CustomIcon.heart_1, color: Colors.blue[800]),
onPressed: () { onPressed: () {
evaluation(); evaluation(exerciseRepository, exercise);
}, },
), ),
Cache().hasPurchased Cache().hasPurchased
@ -212,7 +212,7 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
width: 25, width: 25,
), ),
onTap: () { onTap: () {
evaluation(); evaluation(exerciseRepository, exercise);
}), }),
], ],
), ),
@ -230,12 +230,13 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
return list; return list;
} }
void evaluation() { void evaluation(ExerciseRepository exerciseRepository, Exercise exercise) {
if (!Cache().hasPurchased) {
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return DialogPremium( return DialogPremium(
unlocked: true, unlocked: Cache().hasPurchased,
unlockRound: 1, unlockRound: 1,
unlockedText: t("Enjoy also this premium fetaure to show all old evaluation data of your successful exercises."), unlockedText: t("Enjoy also this premium fetaure to show all old evaluation data of your successful exercises."),
function: "My Exercise Logs", function: "My Exercise Logs",
@ -243,6 +244,13 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
onCancel: () => {Navigator.of(context).pop()}, onCancel: () => {Navigator.of(context).pop()},
); );
}); });
} else {
LinkedHashMap args = LinkedHashMap();
args['exerciseRepository'] = exerciseRepository;
args['exercise'] = exercise;
args['past'] = true;
Navigator.of(context).pushNamed('evaluationPage', arguments: args);
}
} }
void confirmationDialog(ExerciseLogBloc bloc, Exercise exercise) { void confirmationDialog(ExerciseLogBloc bloc, Exercise exercise) {

View File

@ -22,6 +22,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart'; import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:keyboard_actions/keyboard_actions.dart'; import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:stop_watch_timer/stop_watch_timer.dart'; import 'package:stop_watch_timer/stop_watch_timer.dart';
import 'package:wakelock/wakelock.dart'; import 'package:wakelock/wakelock.dart';
@ -101,11 +102,14 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
} }
}, },
builder: (context, state) { builder: (context, state) {
if (state is ExerciseNewReady) {
//LoadingDialog.hide(context);
}
final exerciseBloc = BlocProvider.of<ExerciseNewBloc>(context); final exerciseBloc = BlocProvider.of<ExerciseNewBloc>(context);
return getExerciseWidget(exerciseBloc, exerciseType, menuBloc); return ModalProgressHUD(
child: getExerciseWidget(exerciseBloc, exerciseType, menuBloc),
inAsyncCall: state is ExerciseNewLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}, },
)); ));
} }

View File

@ -28,7 +28,7 @@ class _MyDevelopmentBodyPage extends State<MyDevelopmentBodyPage> with Trans, Co
void initState() { void initState() {
super.initState(); super.initState();
Flurry.logEvent("myDevelopmentBody"); Flurry.logEvent("myDevelopmentBody");
if (!Cache().hasPurchased) { if (!Cache().hasPurchased || true) {
Timer( Timer(
Duration(milliseconds: 2000), Duration(milliseconds: 2000),
() => { () => {
@ -38,10 +38,10 @@ class _MyDevelopmentBodyPage extends State<MyDevelopmentBodyPage> with Trans, Co
builder: (BuildContext context) { builder: (BuildContext context) {
setContext(context); setContext(context);
return DialogPremium( return DialogPremium(
unlocked: false, unlocked: Cache().hasPurchased,
unlockRound: 2, unlockRound: 2,
function: "My Whole Body Development", function: "My Whole Body Development",
unlockedText: "", unlockedText: null,
onTap: () => {Navigator.of(context).pop(), Navigator.of(context).pop()}, onTap: () => {Navigator.of(context).pop(), Navigator.of(context).pop()},
onCancel: () => {Navigator.of(context).pop(), Navigator.of(context).pop()}, onCancel: () => {Navigator.of(context).pop(), Navigator.of(context).pop()},
); );

View File

@ -217,27 +217,37 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
))); )));
exerciseTypes.add(explanation); exerciseTypes.add(explanation);
LinkedHashMap<String, dynamic> rc = LinkedHashMap();
tree.forEach((name, list) { tree.forEach((name, list) {
rc = _getChildList(list, bloc);
final List<Widget> children = rc['list'];
final bool hasNoData = rc['hasNoData'];
exerciseTypes.add(Container( exerciseTypes.add(Container(
margin: const EdgeInsets.only(left: 4.0), margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild( child: TreeViewChild(
startExpanded: false, startExpanded: false,
parent: _getExerciseWidget(exerciseTypeName: name), parent: _getExerciseWidget(exerciseTypeName: name, noData: hasNoData),
children: _getChildList(list, bloc), children: children,
))); )));
}); });
return exerciseTypes; return exerciseTypes;
} }
Widget _getExerciseWidget({@required String exerciseTypeName, List<WorkoutMenuTree> list}) { Widget _getExerciseWidget({@required String exerciseTypeName, bool noData = false}) {
return TreeviewParentWidget(text: exerciseTypeName); return TreeviewParentWidget(
text: exerciseTypeName,
backgroundColor: !noData ? Colors.white38 : Colors.white12,
color: !noData ? Colors.blue[800] : Colors.grey[400]);
} }
List<Widget> _getChildList(List<WorkoutMenuTree> listWorkoutTree, DevelopmentByMuscleBloc bloc) { LinkedHashMap<String, dynamic> _getChildList(List<WorkoutMenuTree> listWorkoutTree, DevelopmentByMuscleBloc bloc) {
LinkedHashMap<String, dynamic> rc = LinkedHashMap();
List<Widget> list = List(); List<Widget> list = List();
bool hasSummaryNoData = true;
listWorkoutTree.forEach((element) { listWorkoutTree.forEach((element) {
bool hasNoData = (bloc.listChartData[element.exerciseTypeId] == null); final bool hasNoData = (bloc.listChartData[element.exerciseTypeId] == null);
hasSummaryNoData = hasSummaryNoData && hasNoData;
String unit = " kg"; String unit = " kg";
if (bloc.diagramType == DiagramType.percent) { if (bloc.diagramType == DiagramType.percent) {
unit = " %"; unit = " %";
@ -320,7 +330,8 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
), ),
)); ));
}); });
rc['list'] = list;
return list; rc['hasNoData'] = hasSummaryNoData;
return rc;
} }
} }

View File

@ -106,10 +106,10 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return DialogPremium( return DialogPremium(
unlocked: false, unlocked: Cache().hasPurchased,
unlockRound: 2, unlockRound: 3,
function: "Predictions", function: "Predictions",
unlockedText: "", unlockedText: null,
onTap: () => {Navigator.of(context).pop()}, onTap: () => {Navigator.of(context).pop()},
); );
}) })

View File

@ -97,10 +97,10 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return DialogPremium( return DialogPremium(
unlocked: false, unlocked: Cache().hasPurchased,
unlockRound: 1, unlockRound: 1,
function: "Suggested Training Plan", function: "Suggested Training Plan",
unlockedText: "", unlockedText: null,
onTap: () => {Navigator.of(context).pop()}, onTap: () => {Navigator.of(context).pop()},
onCancel: () => {Navigator.of(context).pop()}, onCancel: () => {Navigator.of(context).pop()},
); );
@ -111,25 +111,25 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
ImageButton( ImageButton(
width: imageWidth, width: imageWidth,
textAlignment: Alignment.topLeft, textAlignment: Alignment.topLeft,
text: t("My Special Plan"), text: t("Training Programs"),
style: GoogleFonts.robotoMono( style: GoogleFonts.robotoMono(
textStyle: TextStyle( textStyle: TextStyle(
fontSize: 14, fontSize: 14,
color: Colors.white, color: Colors.white,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
backgroundColor: Colors.black54.withOpacity(0.4))), backgroundColor: Colors.black54.withOpacity(0.4))),
image: "asset/image/exercise_plan_special.jpg", image: "asset/image/exercise_plan_stars.jpg",
left: 5, left: 5,
onTap: () => { onTap: () => {
Flurry.logEvent("SpecialTrainingPlan"), Flurry.logEvent("SpecialTraining Programs"),
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return DialogPremium( return DialogPremium(
unlocked: false, unlocked: Cache().hasPurchased,
unlockRound: 1, unlockRound: 1,
function: "My Special Plan", function: "Training Programs",
unlockedText: "", unlockedText: null,
onTap: () => {Navigator.of(context).pop()}, onTap: () => {Navigator.of(context).pop()},
onCancel: () => {Navigator.of(context).pop()}, onCancel: () => {Navigator.of(context).pop()},
); );
@ -137,7 +137,7 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
}, },
isLocked: true, isLocked: true,
), ),
ImageButton( /* ImageButton(
width: imageWidth, width: imageWidth,
textAlignment: Alignment.topLeft, textAlignment: Alignment.topLeft,
text: t("Star's Exercise Plan"), text: t("Star's Exercise Plan"),
@ -165,7 +165,7 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
}) })
}, },
isLocked: true, isLocked: true,
), ), */
hiddenPlanWidget(exerciseRepository), hiddenPlanWidget(exerciseRepository),
hiddenTrainingWidget(), hiddenTrainingWidget(),
]), ]),

View File

@ -2,6 +2,7 @@ import 'package:aitrainer_app/bloc/sales/sales_bloc.dart';
import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart'; import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/sales_button.dart'; import 'package:aitrainer_app/widgets/sales_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -23,7 +24,25 @@ class SalesPage extends StatelessWidget with Trans, Logging {
if (state is SalesError) { if (state is SalesError) {
log("Error: " + state.message); log("Error: " + state.message);
Scaffold.of(context).showSnackBar( Scaffold.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white)))); SnackBar(backgroundColor: Colors.orange, content: Text(t(state.message), style: TextStyle(color: Colors.white))));
} else if (state is SalesSuccessful) {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("Successful Purchase"),
descriptions: t("Now you can use the premium features of WorkoutTest!"),
text: "OK",
onTap: () => {
Navigator.of(context).pop(),
Navigator.of(context).pushNamed("home"),
},
onCancel: () => {
Navigator.of(context).pop(),
Navigator.of(context).pushNamed("home"),
},
);
});
} }
}, builder: (context, state) { }, builder: (context, state) {
final salesBloc = BlocProvider.of<SalesBloc>(context); final salesBloc = BlocProvider.of<SalesBloc>(context);
@ -38,8 +57,6 @@ class SalesPage extends StatelessWidget with Trans, Logging {
} }
Widget salesWidget(SalesBloc bloc) { Widget salesWidget(SalesBloc bloc) {
final double mediaWidth = MediaQuery.of(context).size.width;
final double imageWidth = (mediaWidth - 5) / 2;
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
image: DecorationImage( image: DecorationImage(
@ -54,7 +71,7 @@ class SalesPage extends StatelessWidget with Trans, Logging {
Divider(), Divider(),
Container( Container(
padding: EdgeInsets.only(left: 65, right: 65), padding: EdgeInsets.only(left: 65, right: 65),
child: Text("Unleash Your Development Now!", child: Text(t("Unleash Your Development Now!"),
textAlign: TextAlign.center, textAlign: TextAlign.center,
maxLines: 4, maxLines: 4,
softWrap: true, softWrap: true,
@ -77,7 +94,7 @@ class SalesPage extends StatelessWidget with Trans, Logging {
Divider(), Divider(),
Container( Container(
padding: EdgeInsets.only(left: 45, right: 45), padding: EdgeInsets.only(left: 45, right: 45),
child: Text("Learn about your development, enjoy AI-driven predictions of all of your skills and bodyparts.", child: Text(t("Learn about your development, enjoy AI-driven predictions of all of your skills and bodyparts."),
textAlign: TextAlign.left, textAlign: TextAlign.left,
maxLines: 4, maxLines: 4,
softWrap: true, softWrap: true,
@ -106,47 +123,45 @@ class SalesPage extends StatelessWidget with Trans, Logging {
Container( Container(
padding: EdgeInsets.only(left: 55, right: 55), padding: EdgeInsets.only(left: 55, right: 55),
child: Text( child: Text(
"Subscription Conditions", t("Subscription Conditions"),
style: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white), style: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white),
)), )),
Divider(), Divider(),
Container( Container(
padding: EdgeInsets.only(left: 55, right: 55), padding: EdgeInsets.only(left: 55, right: 55),
child: Text( child: Text(
"Payment will be charged to your account. Subscription automatically renews unless auto-renew is turned off at least 24 hourse before the end of the current period", t("Payment will be charged to your account. Subscription automatically renews unless auto-renew is turned off at least 24 hours before the end of the current period"),
style: GoogleFonts.inter(fontSize: 12, color: Colors.white), style: GoogleFonts.inter(fontSize: 12, color: Colors.white),
)), )),
Divider(), Divider(),
Container( Container(
padding: EdgeInsets.only(left: 55, right: 55), padding: EdgeInsets.only(left: 55, right: 55),
child: Text( child: Text(
"Account will be charged for renewal within 24 hours prior to the end of the current period", t("Account will be charged for renewal within 24 hours prior to the end of the current period"),
style: GoogleFonts.inter(fontSize: 12, color: Colors.white), style: GoogleFonts.inter(fontSize: 12, color: Colors.white),
)), )),
])), ])),
])); ]));
;
} }
List<Widget> getButtons(SalesBloc bloc) { List<Widget> getButtons(SalesBloc bloc) {
List<Widget> buttons = List(); List<Widget> buttons = List();
bloc.product2Display.forEach((element) { bloc.product2Display.forEach((element) {
final String title = element.sort == 3 ? "Montly" : "Annual"; final String title = element.sort == 3 ? t("Montly") : t("Annual");
final String interval = element.sort == 3 ? " / month" : " / year"; final String desc4 = element.sort == 1 ? "" : t("AI driven predictions");
final String desc4 = element.sort == 1 ? "" : "AI driven predictions";
String badge; String badge;
if (element.sort == 2) { if (element.sort == 2) {
badge = "14% discount"; badge = t("14% discount");
} else if (element.sort == 1) { } else if (element.sort == 1) {
badge = "2 months free"; badge = t("2 months free");
} }
Widget button = SalesButton( Widget button = SalesButton(
title: title, title: title,
price: element.localizedPrice, price: element.localizedPrice,
desc1: "Development programs", desc1: t("Development programs"),
desc2: "Suggestions based on your actual status", desc2: t("Suggestions based on your actual status"),
desc3: "Special customized training plans", desc3: t("Special customized training plans"),
desc4: desc4, desc4: desc4,
descStyle: GoogleFonts.inter(fontSize: 10, color: Colors.blue[800]), descStyle: GoogleFonts.inter(fontSize: 10, color: Colors.blue[800]),
badgeText: badge, badgeText: badge,

View File

@ -10,6 +10,7 @@ import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:toggle_switch/toggle_switch.dart'; import 'package:toggle_switch/toggle_switch.dart';
// ignore: must_be_immutable // ignore: must_be_immutable
@ -40,16 +41,15 @@ class SettingsPage extends StatelessWidget with Trans {
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white)))); SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is SettingsReady) { } else if (state is SettingsReady) {
menuBloc.add(MenuRecreateTree()); menuBloc.add(MenuRecreateTree());
} else if (state is SettingsLoading) {
Scaffold.of(context).showSnackBar(SnackBar(
duration: Duration(milliseconds: 100),
backgroundColor: Colors.transparent,
content: Container(child: Center(child: CircularProgressIndicator()))));
} }
}, }, builder: (context, state) {
// ignore: missing_return return ModalProgressHUD(
builder: (context, state) { child: settingsUI(context, settingsBloc, menuBloc),
return settingsUI(context, settingsBloc, menuBloc); inAsyncCall: state is SettingsLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}), }),
), ),
), ),
@ -101,7 +101,6 @@ class SettingsPage extends StatelessWidget with Trans {
inactiveFgColor: Colors.grey[900], inactiveFgColor: Colors.grey[900],
labels: [t('Live-Server'), t('Test-Server')], labels: [t('Live-Server'), t('Test-Server')],
onToggle: (index) { onToggle: (index) {
//Cache().setServer(index == 0);
settingsBloc.add(SettingsSetServer(live: index == 0)); settingsBloc.add(SettingsSetServer(live: index == 0));
}, },
), ),

View File

@ -2,7 +2,6 @@ import 'package:aitrainer_app/bloc/exercise_new/exercise_new_bloc.dart';
import 'package:aitrainer_app/localization/app_localization.dart'; import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:animated_widgets/widgets/rotation_animated.dart'; import 'package:animated_widgets/widgets/rotation_animated.dart';
import 'package:flurry/flurry.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@ -71,7 +70,6 @@ class _BMIState extends State<BMI> with Trans {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
setContext(context); setContext(context);
Flurry.logEvent("BMI");
double mediaWidth = MediaQuery.of(context).size.width * .8; double mediaWidth = MediaQuery.of(context).size.width * .8;
double mediaHeight = MediaQuery.of(context).size.height * .8; double mediaHeight = MediaQuery.of(context).size.height * .8;
//print("w " + mediaWidth.toString() + "h " + mediaHeight.toString()); //print("w " + mediaWidth.toString() + "h " + mediaHeight.toString());
@ -109,7 +107,10 @@ class _BMIState extends State<BMI> with Trans {
fontSize: 30, fontSize: 30,
color: Colors.orange[500], color: Colors.orange[500],
)), )),
Text(widget.exerciseBloc.bmi.toStringAsFixed(1) + "%", Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(widget.exerciseBloc.bmi.toStringAsFixed(1),
style: GoogleFonts.archivoBlack( style: GoogleFonts.archivoBlack(
shadows: <Shadow>[ shadows: <Shadow>[
Shadow( Shadow(
@ -121,6 +122,20 @@ class _BMIState extends State<BMI> with Trans {
fontSize: 60, fontSize: 60,
color: Colors.orange[500], color: Colors.orange[500],
)), )),
Text(" kg/m2",
style: GoogleFonts.archivoBlack(
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 3.0,
color: Colors.black54,
),
],
fontSize: 30,
color: Colors.orange[500],
)),
],
),
Divider(color: Colors.transparent), Divider(color: Colors.transparent),
Stack(alignment: Alignment.center, children: [ Stack(alignment: Alignment.center, children: [
Container( Container(
@ -153,15 +168,31 @@ class _BMIState extends State<BMI> with Trans {
color: Colors.yellow[200], color: Colors.yellow[200],
)), )),
), ),
Text("BMI" + ": " + widget.exerciseBloc.goalBMI.toStringAsFixed(0), Text("BMI" + " " + t("first step") + ": " + widget.exerciseBloc.goalMilestoneBMI.toStringAsFixed(1),
style: GoogleFonts.archivoBlack( style: GoogleFonts.archivoBlack(
fontSize: 40, fontSize: 20,
color: Colors.orange[200],
)),
Text(
t("Bodyweight") +
" " +
t("first step") +
": " +
widget.exerciseBloc.goalMilestoneWeight.toStringAsFixed(0) +
" kg",
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.orange[200],
)),
Text("BMI" + " " + t("goal") + ": " + widget.exerciseBloc.goalBMI.toStringAsFixed(1),
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.orange[500], color: Colors.orange[500],
)), )),
Text(t("Weight") + ": " + widget.exerciseBloc.goalWeight.toStringAsFixed(0) + " kg", Text(t("Bodyweight") + " " + t("goal") + ": " + widget.exerciseBloc.goalWeight.toStringAsFixed(0) + " kg",
style: GoogleFonts.archivoBlack( style: GoogleFonts.archivoBlack(
fontSize: 30, fontSize: 20,
color: Colors.orange[200], color: Colors.orange[500],
)), )),
])))))); ]))))));
} }

View File

@ -2,7 +2,6 @@ import 'package:aitrainer_app/bloc/exercise_new/exercise_new_bloc.dart';
import 'package:aitrainer_app/localization/app_localization.dart'; import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/fitness_state.dart'; import 'package:aitrainer_app/model/fitness_state.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:flurry/flurry.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@ -26,6 +25,7 @@ class _BMRState extends State<BMR> with Trans {
final FocusNode _nodeText1 = FocusNode(); final FocusNode _nodeText1 = FocusNode();
final FocusNode _nodeText2 = FocusNode(); final FocusNode _nodeText2 = FocusNode();
final FocusNode _nodeText3 = FocusNode();
KeyboardActionsConfig _buildConfig(BuildContext context) { KeyboardActionsConfig _buildConfig(BuildContext context) {
return KeyboardActionsConfig( return KeyboardActionsConfig(
@ -34,6 +34,21 @@ class _BMRState extends State<BMR> with Trans {
keyboardSeparatorColor: Colors.black26, keyboardSeparatorColor: Colors.black26,
nextFocus: true, nextFocus: true,
actions: [ actions: [
KeyboardActionsItem(focusNode: _nodeText3, toolbarButtons: [
(node) {
return GestureDetector(
onTap: () => node.unfocus(),
child: Container(
padding: EdgeInsets.all(8.0),
color: Colors.orange[500],
child: Text(
AppLocalizations.of(context).translate("Done"),
style: TextStyle(color: Colors.white),
),
),
);
}
]),
KeyboardActionsItem(focusNode: _nodeText2, toolbarButtons: [ KeyboardActionsItem(focusNode: _nodeText2, toolbarButtons: [
(node) { (node) {
return GestureDetector( return GestureDetector(
@ -75,7 +90,6 @@ class _BMRState extends State<BMR> with Trans {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
setContext(context); setContext(context);
Flurry.logEvent("BMR");
return Form( return Form(
child: Scaffold( child: Scaffold(
resizeToAvoidBottomInset: true, resizeToAvoidBottomInset: true,
@ -99,6 +113,35 @@ class _BMRState extends State<BMR> with Trans {
getWeightInput(), getWeightInput(),
getFitnessLevel(), getFitnessLevel(),
Divider(), Divider(),
Container(
padding: EdgeInsets.only(left: 35, right: 35),
child: Text(t("Resting Metabolic Rate"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 3.0,
color: Colors.black54,
),
],
fontSize: 24,
color: Colors.orange[300],
)),
),
Text(widget.exerciseBloc.bmrEnergy.toStringAsFixed(0) + " kCal",
style: GoogleFonts.archivoBlack(
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 3.0,
color: Colors.black54,
),
],
fontSize: 30,
color: Colors.orange[300],
)),
SizedBox(height: 20),
Container( Container(
padding: EdgeInsets.only(left: 35, right: 35), padding: EdgeInsets.only(left: 35, right: 35),
child: Text(t("Basal Metabolic Rate"), child: Text(t("Basal Metabolic Rate"),
@ -111,7 +154,7 @@ class _BMRState extends State<BMR> with Trans {
color: Colors.black54, color: Colors.black54,
), ),
], ],
fontSize: 30, fontSize: 24,
color: Colors.orange[500], color: Colors.orange[500],
)), )),
), ),
@ -124,7 +167,7 @@ class _BMRState extends State<BMR> with Trans {
color: Colors.black54, color: Colors.black54,
), ),
], ],
fontSize: 50, fontSize: 30,
color: Colors.orange[500], color: Colors.orange[500],
)), )),
Container( Container(
@ -168,6 +211,30 @@ class _BMRState extends State<BMR> with Trans {
} }
} }
Widget getBirthyearInput() {
return Flexible(
child: TextFormField(
focusNode: _nodeText3,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 15, top: 5, bottom: 5),
labelText: AppLocalizations.of(context).translate("Birth Year"),
labelStyle: GoogleFonts.inter(fontSize: 16, color: Colors.yellow[50]),
fillColor: Colors.black38,
filled: true,
border: OutlineInputBorder(
gapPadding: 4.0,
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide(color: Colors.white12, width: 0.4),
),
),
initialValue: widget.exerciseBloc.birthYear.toStringAsFixed(0),
keyboardType: TextInputType.numberWithOptions(decimal: false),
textInputAction: TextInputAction.done,
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
onChanged: (value) => {widget.exerciseBloc.add(ExerciseNewBirthyearChange(value: int.parse(value)))}),
);
}
Widget getFitnessLevel() { Widget getFitnessLevel() {
String fitnessLevel = widget.exerciseBloc.fitnessLevel; String fitnessLevel = widget.exerciseBloc.fitnessLevel;
return Container( return Container(
@ -254,14 +321,18 @@ class _BMRState extends State<BMR> with Trans {
Widget getWeightInput() { Widget getWeightInput() {
return Container( return Container(
padding: EdgeInsets.only(top: 15, left: 65, right: 65, bottom: 10), padding: EdgeInsets.only(top: 15, left: 35, right: 35, bottom: 10),
alignment: Alignment.center, alignment: Alignment.center,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
getBirthyearInput(),
SizedBox(
width: 5,
),
getHeightInput(), getHeightInput(),
SizedBox( SizedBox(
width: 10, width: 5,
), ),
Flexible( Flexible(
child: TextFormField( child: TextFormField(

View File

@ -1,9 +1,7 @@
import 'package:aitrainer_app/localization/app_localization.dart'; import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/common.dart'; import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:badges/badges.dart';
import 'package:flurry/flurry.dart'; import 'package:flurry/flurry.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gradient_bottom_navigation_bar/gradient_bottom_navigation_bar.dart'; import 'package:gradient_bottom_navigation_bar/gradient_bottom_navigation_bar.dart';

View File

@ -26,9 +26,6 @@ class DialogPremium extends StatefulWidget {
: super(key: key) { : super(key: key) {
description = description ?? ""; description = description ?? "";
function = function ?? ""; function = function ?? "";
unlockedText = unlockedText ?? "";
unlocked = true;
} }
@override @override
@ -92,7 +89,7 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
Text( Text(
widget.unlocked ? t("Keep testing") : t("Go Premium") + " ", widget.unlocked ? t("Keep testing") : t("Go Premium") + " ",
style: GoogleFonts.archivoBlack( style: GoogleFonts.archivoBlack(
fontSize: widget.unlocked ? 18 : 24, fontSize: widget.unlocked ? 20 : 24,
color: Colors.yellow[400], color: Colors.yellow[400],
shadows: <Shadow>[ shadows: <Shadow>[
Shadow( Shadow(
@ -226,9 +223,10 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
List<TextSpan> getDescriptionText() { List<TextSpan> getDescriptionText() {
List<TextSpan> list = List(); List<TextSpan> list = List();
/* if (widget.unlocked) { if (widget.unlockedText != null) {
list.add(TextSpan(text: widget.unlockedText)); list.add(TextSpan(text: widget.unlockedText));
} */ return list;
}
list.add(TextSpan(text: t("The"))); list.add(TextSpan(text: t("The")));
list.add(TextSpan(text: t(" "))); list.add(TextSpan(text: t(" ")));
list.add( list.add(

View File

@ -2,14 +2,12 @@ import 'package:aitrainer_app/bloc/session/session_bloc.dart';
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart'; import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/platform_purchase.dart';
import 'package:aitrainer_app/view/login.dart'; import 'package:aitrainer_app/view/login.dart';
import 'package:aitrainer_app/view/menu_page.dart'; import 'package:aitrainer_app/view/menu_page.dart';
import 'package:aitrainer_app/view/registration.dart'; import 'package:aitrainer_app/view/registration.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/semantics.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'loading.dart'; import 'loading.dart';

View File

@ -8,14 +8,12 @@ import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart'; import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/not_found_exception.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart'; import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:badges/badges.dart'; import 'package:badges/badges.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';

View File

@ -4,21 +4,23 @@ import 'package:google_fonts/google_fonts.dart';
class TreeviewParentWidget extends StatelessWidget { class TreeviewParentWidget extends StatelessWidget {
final String text; final String text;
final Color backgroundColor;
final Color color;
//final DateTime lastModified; //final DateTime lastModified;
TreeviewParentWidget({@required this.text}); TreeviewParentWidget({@required this.text, this.backgroundColor = Colors.white38, this.color});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget parentWidget = Text( Widget parentWidget = Text(
this.text, this.text,
style: GoogleFonts.archivoBlack(fontSize: 24, color: Colors.blue[800], backgroundColor: Colors.transparent), style: GoogleFonts.archivoBlack(fontSize: 24, color: color ?? Colors.blue[800], backgroundColor: Colors.transparent),
); );
Icon icon = Icon(Icons.person); Icon icon = Icon(Icons.person);
return Card( return Card(
color: Colors.white38, color: backgroundColor,
shadowColor: Colors.black54, shadowColor: Colors.black54,
elevation: 0.0, elevation: 0.0,
child: ListTile( child: ListTile(

View File

@ -84,7 +84,7 @@ packages:
name: build name: build
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.0" version: "1.6.1"
build_config: build_config:
dependency: transitive dependency: transitive
description: description:
@ -98,28 +98,28 @@ packages:
name: build_daemon name: build_daemon
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.4" version: "2.1.6"
build_resolvers: build_resolvers:
dependency: transitive dependency: transitive
description: description:
name: build_resolvers name: build_resolvers
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.5.1" version: "1.5.2"
build_runner: build_runner:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.10.11" version: "1.10.13"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
name: build_runner_core name: build_runner_core
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.1.5" version: "6.1.6"
built_collection: built_collection:
dependency: transitive dependency: transitive
description: description:
@ -189,7 +189,7 @@ packages:
name: code_builder name: code_builder
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.5.0" version: "3.6.0"
collection: collection:
dependency: transitive dependency: transitive
description: description:
@ -432,7 +432,7 @@ packages:
name: flutter_html name: flutter_html
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.1" version: "1.2.0"
flutter_keyboard_visibility: flutter_keyboard_visibility:
dependency: transitive dependency: transitive
description: description:
@ -447,6 +447,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.8.1" version: "0.8.1"
flutter_layout_grid:
dependency: transitive
description:
name: flutter_layout_grid
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.3"
flutter_localizations: flutter_localizations:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -713,7 +720,7 @@ packages:
name: path_provider name: path_provider
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.24" version: "1.6.27"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@ -727,7 +734,7 @@ packages:
name: path_provider_macos name: path_provider_macos
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.4+6" version: "0.0.4+8"
path_provider_platform_interface: path_provider_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -797,7 +804,7 @@ packages:
name: provider name: provider
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.3.2+3" version: "4.3.2+4"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
@ -812,6 +819,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.7" version: "0.1.7"
purchases_flutter:
dependency: "direct main"
description:
name: purchases_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
quiver: quiver:
dependency: transitive dependency: transitive
description: description:
@ -846,7 +860,7 @@ packages:
name: sentry name: sentry
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.1" version: "4.0.3"
shared_preferences: shared_preferences:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -963,14 +977,14 @@ packages:
name: sqflite name: sqflite
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.2+1" version: "1.3.2+2"
sqflite_common: sqflite_common:
dependency: transitive dependency: transitive
description: description:
name: sqflite_common name: sqflite_common
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.2+1" version: "1.0.3"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -1041,6 +1055,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.12-nullsafety.5" version: "0.3.12-nullsafety.5"
timeline_tile:
dependency: "direct main"
description:
name: timeline_tile
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -1062,13 +1083,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.0-nullsafety.3" version: "1.3.0-nullsafety.3"
usage:
dependency: transitive
description:
name: usage
url: "https://pub.dartlang.org"
source: hosted
version: "3.4.2"
uuid: uuid:
dependency: transitive dependency: transitive
description: description:

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. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.1.4+46 version: 1.1.5+48
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.7.0 <3.0.0"
@ -27,7 +27,7 @@ dependencies:
cupertino_icons: ^1.0.0 cupertino_icons: ^1.0.0
google_fonts: ^1.1.1 google_fonts: ^1.1.1
devicelocale: ^0.3.3 devicelocale: ^0.3.3
sentry: ^3.0.1 sentry: ^4.0.3
flutter_bloc: ^6.1.1 flutter_bloc: ^6.1.1
equatable: ^1.2.5 equatable: ^1.2.5
#freezed: ^0.12.2 #freezed: ^0.12.2
@ -45,10 +45,11 @@ dependencies:
#health: ^3.0.0 #health: ^3.0.0
stop_watch_timer: ^0.6.0+1 stop_watch_timer: ^0.6.0+1
#geolocator: ^6.1.13 #geolocator: ^6.1.13
#flutter_inapp_purchase: ^3.0.1
modal_progress_hud: ^0.1.3 modal_progress_hud: ^0.1.3
flutter_html: ^1.1.1 flutter_html: ^1.1.1
wakelock: ^0.2.1+1 wakelock: ^0.2.1+1
timeline_tile: ^1.0.0
purchases_flutter: ^2.0.0
firebase_core: ^0.5.0 firebase_core: ^0.5.0

View File

@ -1,5 +1,3 @@
import 'dart:html';
import 'package:aitrainer_app/model/customer.dart'; import 'package:aitrainer_app/model/customer.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../lib/helper/database.dart'; import '../../lib/helper/database.dart';