WT1.1.5 In-app-purchase
This commit is contained in:
parent
d44fefe9af
commit
71efd3f349
@ -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'
|
21
i18n/en.json
21
i18n/en.json
@ -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!"
|
||||||
}
|
}
|
21
i18n/hu.json
21
i18n/hu.json
@ -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."
|
||||||
|
|
||||||
}
|
}
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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";
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
@ -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});
|
||||||
|
@ -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';
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
} */
|
}
|
||||||
}
|
}
|
||||||
|
@ -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});
|
||||||
|
@ -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';
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,6 @@ class ExerciseType {
|
|||||||
this.parents.add(parent['exerciseTreeId']);
|
this.parents.add(parent['exerciseTreeId']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
|
@ -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'];
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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 }
|
||||||
|
|
||||||
|
@ -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;
|
||||||
Map<String, dynamic> userData = await FirebaseApi().signInWithGoogle();
|
|
||||||
if (userData == null || userData['email'] == null) {
|
|
||||||
throw new Exception("Google login was not successful");
|
|
||||||
}
|
|
||||||
modelUser.email = userData['email'];
|
|
||||||
try {
|
try {
|
||||||
|
Map<String, dynamic> userData = await FirebaseApi().signInWithGoogle();
|
||||||
|
if (userData == null || userData['email'] == null) {
|
||||||
|
throw new Exception("Google login was not successful");
|
||||||
|
}
|
||||||
|
modelUser.email = userData['email'];
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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');
|
||||||
|
@ -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;
|
||||||
|
@ -165,41 +165,37 @@ 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: [
|
'email',
|
||||||
'email',
|
'https://www.googleapis.com/auth/contacts.readonly',
|
||||||
'https://www.googleapis.com/auth/contacts.readonly',
|
],
|
||||||
],
|
);
|
||||||
);
|
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
|
||||||
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
|
|
||||||
|
|
||||||
if (googleUser == null) {
|
if (googleUser == null) {
|
||||||
throw Exception("Google Sign In failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain the auth details from the request
|
|
||||||
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
|
|
||||||
|
|
||||||
// Create a new credential
|
|
||||||
final GoogleAuthCredential credential = GoogleAuthProvider.credential(
|
|
||||||
accessToken: googleAuth.accessToken,
|
|
||||||
idToken: googleAuth.idToken,
|
|
||||||
);
|
|
||||||
|
|
||||||
await FirebaseAuth.instance.signInWithCredential(credential);
|
|
||||||
|
|
||||||
if (googleUser != null) {
|
|
||||||
log("GoogleUser: " + googleUser.toString());
|
|
||||||
userData['email'] = googleUser.email;
|
|
||||||
userData['id'] = googleUser.id;
|
|
||||||
userData['name'] = googleUser.displayName;
|
|
||||||
}
|
|
||||||
} on Exception catch (ex) {
|
|
||||||
log("Google exception: " + ex.toString());
|
|
||||||
throw Exception("Google Sign In failed");
|
throw Exception("Google Sign In failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Obtain the auth details from the request
|
||||||
|
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
|
||||||
|
|
||||||
|
// Create a new credential
|
||||||
|
final GoogleAuthCredential credential = GoogleAuthProvider.credential(
|
||||||
|
accessToken: googleAuth.accessToken,
|
||||||
|
idToken: googleAuth.idToken,
|
||||||
|
);
|
||||||
|
|
||||||
|
await FirebaseAuth.instance.signInWithCredential(credential);
|
||||||
|
|
||||||
|
if (googleUser != null) {
|
||||||
|
log("GoogleUser: " + googleUser.toString());
|
||||||
|
userData['email'] = googleUser.email;
|
||||||
|
userData['id'] = googleUser.id;
|
||||||
|
userData['name'] = googleUser.displayName;
|
||||||
|
}
|
||||||
|
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
await FlutterInappPurchase.instance.endConnection;
|
|
||||||
|
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());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void deliverProduct(PurchaseDetails purchaseDetails) async {
|
||||||
|
log("DeliverProduct");
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
_purchasePending = false;
|
||||||
|
//_consumables = consumables;
|
||||||
|
} else {
|
||||||
|
_purchases.add(purchaseDetails);
|
||||||
|
_purchasePending = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// prepare
|
Future<bool> _verifyPurchase(PurchaseDetails purchaseDetails) {
|
||||||
var result = await FlutterInappPurchase.instance.initConnection;
|
log("verifyPurchase");
|
||||||
log(' FlutterInappPurchase init result: $result');
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
_platformVersion = platformVersion;
|
void _handleInvalidPurchase(PurchaseDetails purchaseDetails) {
|
||||||
|
// handle invalid purchase here if _verifyPurchase` failed.
|
||||||
|
log("Invalid Purchase" + purchaseDetails.toString());
|
||||||
|
}
|
||||||
|
|
||||||
// refresh items for android
|
void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) {
|
||||||
try {
|
purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
|
||||||
String msg = await FlutterInappPurchase.instance.consumeAllItems;
|
if (purchaseDetails.status == PurchaseStatus.pending) {
|
||||||
log('consumeAllItems: $msg');
|
//showPendingUI();
|
||||||
} catch (err) {
|
log("Purchase pending");
|
||||||
log('consumeAllItems error: $err');
|
} else {
|
||||||
}
|
if (purchaseDetails.status == PurchaseStatus.error) {
|
||||||
|
//handleError(purchaseDetails.error);
|
||||||
_conectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) {
|
} else if (purchaseDetails.status == PurchaseStatus.purchased) {
|
||||||
log('connected: $connected');
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
_purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen((productItem) {
|
|
||||||
log('purchase-updated: $productItem');
|
|
||||||
});
|
|
||||||
|
|
||||||
_purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) {
|
|
||||||
log('purchase-error: $purchaseError');
|
|
||||||
});
|
|
||||||
|
|
||||||
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
120
lib/util/purchases.dart
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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`:
|
||||||
|
@ -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';
|
||||||
|
@ -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,
|
||||||
|
@ -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,19 +230,27 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void evaluation() {
|
void evaluation(ExerciseRepository exerciseRepository, Exercise exercise) {
|
||||||
showDialog(
|
if (!Cache().hasPurchased) {
|
||||||
context: context,
|
showDialog(
|
||||||
builder: (BuildContext context) {
|
context: context,
|
||||||
return DialogPremium(
|
builder: (BuildContext context) {
|
||||||
unlocked: true,
|
return DialogPremium(
|
||||||
unlockRound: 1,
|
unlocked: Cache().hasPurchased,
|
||||||
unlockedText: t("Enjoy also this premium fetaure to show all old evaluation data of your successful exercises."),
|
unlockRound: 1,
|
||||||
function: "My Exercise Logs",
|
unlockedText: t("Enjoy also this premium fetaure to show all old evaluation data of your successful exercises."),
|
||||||
onTap: () => {Navigator.of(context).pop()},
|
function: "My Exercise Logs",
|
||||||
onCancel: () => {Navigator.of(context).pop()},
|
onTap: () => {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) {
|
||||||
|
@ -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(),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -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()},
|
||||||
);
|
);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()},
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
@ -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(),
|
||||||
]),
|
]),
|
||||||
|
@ -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,
|
||||||
|
@ -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));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -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,18 +107,35 @@ 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(
|
||||||
style: GoogleFonts.archivoBlack(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
shadows: <Shadow>[
|
children: [
|
||||||
Shadow(
|
Text(widget.exerciseBloc.bmi.toStringAsFixed(1),
|
||||||
offset: Offset(5.0, 5.0),
|
style: GoogleFonts.archivoBlack(
|
||||||
blurRadius: 3.0,
|
shadows: <Shadow>[
|
||||||
color: Colors.black54,
|
Shadow(
|
||||||
),
|
offset: Offset(5.0, 5.0),
|
||||||
],
|
blurRadius: 3.0,
|
||||||
fontSize: 60,
|
color: Colors.black54,
|
||||||
color: Colors.orange[500],
|
),
|
||||||
)),
|
],
|
||||||
|
fontSize: 60,
|
||||||
|
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],
|
||||||
)),
|
)),
|
||||||
]))))));
|
]))))));
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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';
|
||||||
|
@ -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(
|
||||||
|
@ -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';
|
||||||
|
@ -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';
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
54
pubspec.lock
54
pubspec.lock
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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';
|
||||||
|
Loading…
Reference in New Issue
Block a user