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.facebook.android:facebook-login:5.15.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'
|
21
i18n/en.json
21
i18n/en.json
@ -172,10 +172,10 @@
|
||||
"8. Calf": "8. Calf",
|
||||
|
||||
"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",
|
||||
"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",
|
||||
"Execute My Trainee's Training Plan": "Execute My Trainee's Training Plan",
|
||||
|
||||
@ -250,11 +250,15 @@
|
||||
"Done": "Done",
|
||||
"Height":"Height",
|
||||
"Actual Height":"Height",
|
||||
"Actual Weight":"Weight",
|
||||
"Based on your weight and height your goal for BMI and weight:":"Based on your weight and height your goal for BMI and weight:",
|
||||
"Actual Weight":"Bodyweight",
|
||||
"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",
|
||||
"first step":"first step",
|
||||
"goal":"goal",
|
||||
"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",
|
||||
"Size Of Your":"Size Of Your",
|
||||
"Please type the following data:":"Please type the following data:",
|
||||
@ -303,7 +307,10 @@
|
||||
|
||||
"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'",
|
||||
"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",
|
||||
|
||||
"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",
|
||||
"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",
|
||||
"Execute My Trainee's Training Plan": "Kliensem edzéstervének végrehajtása",
|
||||
|
||||
@ -245,11 +245,15 @@
|
||||
"Done": "Kész",
|
||||
"Height":"Magasság",
|
||||
"Actual Height":"Magasság",
|
||||
"Actual Weight":"Tö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:",
|
||||
"Actual Weight":"Testtömeg",
|
||||
"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",
|
||||
"first step":"első lépés",
|
||||
"goal":"cél",
|
||||
"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",
|
||||
"Size Of Your":"Testméret:",
|
||||
"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!",
|
||||
"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>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>10.0</string>
|
||||
<string>12.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -1,5 +1,5 @@
|
||||
# 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.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
@ -37,5 +37,8 @@ end
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -155,6 +155,14 @@ PODS:
|
||||
- Flutter
|
||||
- PromisesObjC (1.2.11)
|
||||
- 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):
|
||||
- Flutter
|
||||
- sqflite (0.0.2):
|
||||
@ -180,6 +188,7 @@ DEPENDENCIES:
|
||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||
- google_sign_in (from `.symlinks/plugins/google_sign_in/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`)
|
||||
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
||||
- video_player (from `.symlinks/plugins/video_player/ios`)
|
||||
@ -210,6 +219,9 @@ SPEC REPOS:
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
- Protobuf
|
||||
- Purchases
|
||||
- PurchasesCoreSwift
|
||||
- PurchasesHybridCommon
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
apple_sign_in:
|
||||
@ -236,6 +248,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/google_sign_in/ios"
|
||||
path_provider:
|
||||
:path: ".symlinks/plugins/path_provider/ios"
|
||||
purchases_flutter:
|
||||
:path: ".symlinks/plugins/purchases_flutter/ios"
|
||||
shared_preferences:
|
||||
:path: ".symlinks/plugins/shared_preferences/ios"
|
||||
sqflite:
|
||||
@ -282,12 +296,16 @@ SPEC CHECKSUMS:
|
||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||
PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f
|
||||
Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
|
||||
Purchases: d8a798c9c7552fe66b550bf314a143e94ffa70c8
|
||||
purchases_flutter: 27f87080055c0fd2cd124c247b10cae75b46e7e1
|
||||
PurchasesCoreSwift: ea4eabae180416e580ac60366f41aa1fefec0693
|
||||
PurchasesHybridCommon: d9bfb34309db4c9ba82a6f7f3a6275c13befdca7
|
||||
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
|
||||
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
|
||||
video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e
|
||||
wakelock: bfc7955c418d0db797614075aabbc58a39ab5107
|
||||
webview_flutter: d2b4d6c66968ad042ad94cbb791f5b72b4678a96
|
||||
|
||||
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
|
||||
PODFILE CHECKSUM: 28226b39c1afd238c6168e31e2bd3829c3d67530
|
||||
|
||||
COCOAPODS: 1.10.0
|
||||
|
@ -16,6 +16,7 @@
|
||||
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 */; };
|
||||
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 */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@ -50,6 +51,7 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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 */
|
||||
@ -59,6 +61,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
BB98CEAF25B8867C000724FE /* StoreKit.framework in Frameworks */,
|
||||
BB8D3BFA25A8CBFE00BF29FE /* AuthenticationServices.framework in Frameworks */,
|
||||
42B6B159AF35AFB6DE777DFB /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
@ -80,6 +83,7 @@
|
||||
3ADC50290ED054951FAC1F56 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BB98CEAE25B8867C000724FE /* StoreKit.framework */,
|
||||
BB8D3BF925A8CBFE00BF29FE /* AuthenticationServices.framework */,
|
||||
09BD889296C5C90D989820C8 /* Pods_Runner.framework */,
|
||||
);
|
||||
@ -384,7 +388,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@ -401,7 +405,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.3;
|
||||
MARKETING_VERSION = 1.1.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@ -527,7 +531,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@ -544,7 +548,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.3;
|
||||
MARKETING_VERSION = 1.1.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@ -562,7 +566,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@ -579,7 +583,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.3;
|
||||
MARKETING_VERSION = 1.1.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
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 goalBMI = 0;
|
||||
double goalWeight = 0;
|
||||
double goalMilestoneBMI = 0;
|
||||
double goalMilestoneWeight = 0;
|
||||
double bmiAngle = 0;
|
||||
double bmiTop = 0;
|
||||
double bmiLeft = 0;
|
||||
double weight;
|
||||
double height;
|
||||
double bmrEnergy = 0;
|
||||
int birthYear;
|
||||
String fitnessLevel;
|
||||
bool changedWeight = false;
|
||||
bool changedSizes = false;
|
||||
@ -66,6 +70,7 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
|
||||
customerRepository.customer = Cache().userLoggedIn;
|
||||
weight = customerRepository.customer.getProperty("Weight");
|
||||
height = customerRepository.customer.getProperty("Height");
|
||||
birthYear = customerRepository.customer.birthYear;
|
||||
fitnessLevel = customerRepository.customer.fitnessLevel;
|
||||
this.isMan = (customerRepository.customer.sex == "m");
|
||||
}
|
||||
@ -315,6 +320,7 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
|
||||
changedWeight = true;
|
||||
weight = event.value;
|
||||
getBMI();
|
||||
getGoalBMI();
|
||||
getBMR();
|
||||
yield ExerciseNewReady();
|
||||
} else if (event is ExerciseNewFitnessLevelChange) {
|
||||
@ -324,12 +330,20 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
|
||||
changedWeight = true;
|
||||
getBMR();
|
||||
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) {
|
||||
yield ExerciseNewLoading();
|
||||
customerRepository.setHeight(event.value.toInt());
|
||||
changedWeight = true;
|
||||
height = event.value;
|
||||
getBMI();
|
||||
getGoalBMI();
|
||||
getBMR();
|
||||
yield ExerciseNewReady();
|
||||
} 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 * weight) + (1.85 * height) - (4.676 * (year - customerRepository.customer.birthYear));
|
||||
}
|
||||
bmrEnergy = bmr;
|
||||
|
||||
if (customerRepository.customer.fitnessLevel == FitnessState.beginner) {
|
||||
bmr *= 1.2;
|
||||
@ -424,32 +439,38 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
|
||||
|
||||
this.bmiAngle = (bmi * 90 / 25) - 90;
|
||||
if (bmi < 18.5) {
|
||||
goalBMI = 19;
|
||||
goalMilestoneBMI = 19;
|
||||
goalBMI = 21.75;
|
||||
this.bmiTop = 99 * distortionHeight;
|
||||
this.bmiLeft = 77 * distortionWidth;
|
||||
bmiAngle = -62;
|
||||
} else if (bmi > 18.5 && bmi < 25) {
|
||||
goalBMI = this.bmi;
|
||||
goalBMI = 21.75;
|
||||
goalMilestoneBMI = 21.75;
|
||||
this.bmiTop = 48 * distortionHeight;
|
||||
this.bmiLeft = 130 * distortionWidth;
|
||||
bmiAngle = -23;
|
||||
} else if (bmi < 30 && bmi > 24.9) {
|
||||
goalBMI = 24;
|
||||
goalMilestoneBMI = 24;
|
||||
goalBMI = 21.75;
|
||||
this.bmiTop = 40.0 * distortionHeight;
|
||||
this.bmiLeft = 184.0 * distortionWidth;
|
||||
bmiAngle = 7.2;
|
||||
} else if (bmi < 34.9 && 29.9 < bmi) {
|
||||
goalBMI = 29;
|
||||
goalMilestoneBMI = 29;
|
||||
goalBMI = 24;
|
||||
bmiTop = 48 * distortionHeight;
|
||||
bmiLeft = 211 * distortionWidth;
|
||||
} else if (bmi > 35) {
|
||||
goalBMI = 34;
|
||||
goalMilestoneBMI = 34;
|
||||
goalBMI = 24;
|
||||
bmiTop = 94 * distortionHeight;
|
||||
bmiLeft = 260 * distortionWidth;
|
||||
bmiAngle = 59;
|
||||
}
|
||||
|
||||
this.goalWeight = goalBMI * (height * height / 10000);
|
||||
this.goalMilestoneWeight = goalMilestoneBMI * (height * height / 10000);
|
||||
|
||||
//print("Angle: " + bmiAngle.toStringAsFixed(1));
|
||||
|
||||
|
@ -28,6 +28,13 @@ class ExerciseNewQuantityUnitChange extends ExerciseNewEvent {
|
||||
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 {
|
||||
final double 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:equatable/equatable.dart';
|
||||
import 'package:flurry/flurry.dart';
|
||||
import 'package:flurry/flurry.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
part 'exercise_plan_event.dart';
|
||||
|
@ -164,7 +164,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
|
||||
ability = ExerciseAbility.endurance;
|
||||
break;
|
||||
case "Cardio":
|
||||
case "Body Compositions":
|
||||
case "My Body":
|
||||
ability = ExerciseAbility.none;
|
||||
break;
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/result.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_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()) {
|
||||
this.startTime = exerciseRepository.start;
|
||||
this.endTime = exerciseRepository.end;
|
||||
if (this.startTime == null) {
|
||||
this.startTime = exerciseRepository.exercise.dateAdd;
|
||||
exerciseRepository.start = exerciseRepository.exercise.dateAdd;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1,16 +1,19 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/product.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/product_test_service.dart';
|
||||
import 'package:aitrainer_app/util/platform_purchase.dart';
|
||||
import 'package:aitrainer_app/service/purchase.dart';
|
||||
import 'package:aitrainer_app/util/common.dart';
|
||||
import 'package:aitrainer_app/util/purchases.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flurry/flurry.dart';
|
||||
import 'package:purchases_flutter/offering_wrapper.dart';
|
||||
|
||||
part 'sales_event.dart';
|
||||
part 'sales_state.dart';
|
||||
@ -28,15 +31,34 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
||||
try {
|
||||
if (event is SalesLoad) {
|
||||
yield SalesLoading();
|
||||
//Flurry.logEvent("SalesPageOpen");
|
||||
// await PlatformPurchaseApi().initPurchasePlatformState();
|
||||
// this.getProductSet();
|
||||
log("Load Sales");
|
||||
Common.sendMessage("Salespage Load");
|
||||
Flurry.logEvent("SalesPageOpen");
|
||||
//await PlatformPurchaseApi().initPurchasePlatform();
|
||||
await RevenueCatPurchases().getOfferings();
|
||||
this.getProductSet();
|
||||
yield SalesReady();
|
||||
} else if (event is SalesPurchase) {
|
||||
if (Cache().hasPurchased) {
|
||||
throw Exception("You have already a successfull subscription");
|
||||
}
|
||||
yield SalesLoading();
|
||||
final int productId = event.productId;
|
||||
trace("Requesting purchase for" + productId.toString());
|
||||
//Flurry.logEvent("PurchaseRequest");
|
||||
// PlatformPurchaseApi().purchase(getSelectedProduct(productId));
|
||||
log("Requesting purchase for: " + productId.toString());
|
||||
Flurry.logEvent("PurchaseRequest");
|
||||
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) {
|
||||
yield SalesError(message: ex.toString());
|
||||
@ -53,18 +75,24 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
||||
return prod;
|
||||
}
|
||||
|
||||
/* String getLocalizedPrice(String productId) {
|
||||
String getLocalizedPrice(String productId) {
|
||||
String price = "";
|
||||
for (var product in PlatformPurchaseApi().getIAPItems()) {
|
||||
if (Platform.isAndroid) {
|
||||
print("PlatformProduct " + product.toString());
|
||||
if (productId == product.productId) {
|
||||
price = product.localizedPrice;
|
||||
Offering offering = RevenueCatPurchases().offering;
|
||||
if (offering != null) {
|
||||
for (var package in offering.availablePackages) {
|
||||
log("PlatformProduct " + package.toString());
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log(" !!! No Offering");
|
||||
}
|
||||
|
||||
return price;
|
||||
}
|
||||
|
||||
@ -73,7 +101,7 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
||||
this.tests = Cache().productTests;
|
||||
|
||||
if (tests.isEmpty) {
|
||||
var rand = Random.secure();
|
||||
var rand = math.Random.secure();
|
||||
productSet = rand.nextInt(5) + 1;
|
||||
} else {
|
||||
trace("Previous ProductTest: " + tests[0].toJson().toString());
|
||||
@ -88,7 +116,9 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
||||
}
|
||||
|
||||
ProductTest productTest = ProductTest();
|
||||
trace("ProductSet: " + productSet.toString());
|
||||
|
||||
productSet = 2;
|
||||
log("ProductSet: " + productSet.toString());
|
||||
for (var elem in Cache().products) {
|
||||
Product product = elem as Product;
|
||||
|
||||
@ -109,5 +139,5 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
||||
productTest.dateView = DateTime.now();
|
||||
//ProductTestApi().saveProductTest(productTest);
|
||||
//Cache().productTests.add(productTest);
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,10 @@ class SalesReady extends SalesState {
|
||||
const SalesReady();
|
||||
}
|
||||
|
||||
class SalesSuccessful extends SalesState {
|
||||
const SalesSuccessful();
|
||||
}
|
||||
|
||||
class SalesError extends SalesState {
|
||||
final String 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/localization/app_language.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:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
@ -74,7 +74,7 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> with Logging {
|
||||
HealthDataType.RESTING_HEART_RATE
|
||||
];
|
||||
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);
|
||||
//log(_healthDataList.toString());
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ import 'bloc/menu/menu_bloc.dart';
|
||||
import 'bloc/session/session_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.
|
||||
///
|
||||
@ -80,16 +80,12 @@ Future<Null> _reportError(dynamic error, dynamic stackTrace) async {
|
||||
|
||||
print('Reporting to Sentry.io...');
|
||||
|
||||
final SentryResponse response = await _sentry.captureException(
|
||||
exception: error,
|
||||
final sentryId = await Sentry.captureException(
|
||||
error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
|
||||
if (response.isSuccessful) {
|
||||
print('Success! Event ID: ${response.eventId}');
|
||||
} else {
|
||||
print('Failed to report to Sentry.io: ${response.error}');
|
||||
}
|
||||
print('Capture exception result : SentryId : $sentryId');
|
||||
}
|
||||
|
||||
Future<Null> main() async {
|
||||
@ -119,8 +115,10 @@ Future<Null> main() async {
|
||||
runZonedGuarded<Future<Null>>(() async {
|
||||
final WorkoutTreeRepository menuTreeRepository = WorkoutTreeRepository();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
print(" -- FireBase init..");
|
||||
await FirebaseApi().initializeFlutterFire();
|
||||
|
||||
runApp(MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<SessionBloc>(
|
||||
@ -157,8 +155,6 @@ Future<Null> main() async {
|
||||
|
||||
Future<void> initFlurry() async {
|
||||
await Flurry.initialize(androidKey: "JNYCTCWBT34FM3J8TV36", iosKey: "3QBG7BSMGPDH24S8TRQP", enableLog: true);
|
||||
//await Flurry.setUserId("userId");
|
||||
//await Flurry.logEvent("eventName");
|
||||
}
|
||||
|
||||
class WorkoutTestApp extends StatelessWidget {
|
||||
@ -232,7 +228,7 @@ class WorkoutTestApp extends StatelessWidget {
|
||||
//primarySwatch: Colors.transparent,
|
||||
//fontFamily: 'Arial',
|
||||
textTheme: TextTheme(
|
||||
bodyText1: GoogleFonts.openSans(textStyle: TextStyle(fontSize: 14.0)),
|
||||
bodyText1: GoogleFonts.inter(textStyle: TextStyle(fontSize: 14.0)),
|
||||
)),
|
||||
navigatorObservers: [
|
||||
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.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/property.dart';
|
||||
import 'package:aitrainer_app/model/purchase.dart';
|
||||
@ -84,7 +84,7 @@ class Cache with Logging {
|
||||
List<Exercise> _exercises;
|
||||
ExercisePlan _myExercisePlan;
|
||||
List<Property> _properties;
|
||||
List<Product> _products;
|
||||
List<wt_product.Product> _products;
|
||||
List<Purchase> _purchases = List();
|
||||
List<ProductTest> _productTests;
|
||||
|
||||
@ -405,18 +405,18 @@ class Cache with Logging {
|
||||
setBadge("Sizes", true);
|
||||
setBadge("BMI", true);
|
||||
setBadge("BMR", true);
|
||||
setBadgeNr("Body Compositions", 3);
|
||||
setBadgeNr("My Body", 3);
|
||||
setBadgeNr("home", 3);
|
||||
} else if (customerRepository.getWeight() == 0) {
|
||||
setBadge("BMI", true);
|
||||
setBadge("BMR", true);
|
||||
setBadge("Body Compositions", true);
|
||||
setBadge("My Body", true);
|
||||
setBadgeNr("home", 1);
|
||||
}
|
||||
if (customerRepository.getHeight() == 0) {
|
||||
setBadge("BMI", true);
|
||||
setBadge("BMR", true);
|
||||
setBadge("Body Compositions", true);
|
||||
setBadge("My Body", true);
|
||||
setBadgeNr("home", 1);
|
||||
}
|
||||
}
|
||||
@ -450,7 +450,7 @@ class Cache with Logging {
|
||||
await customerRepository.getPurchase();
|
||||
await customerRepository.getProductTests();
|
||||
|
||||
this.hasPurchased = this._purchases.isNotEmpty;
|
||||
//this.hasPurchased = this._purchases.isNotEmpty;
|
||||
Cache().startPage = "home";
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,6 @@ class ExerciseType {
|
||||
this.parents.add(parent['exerciseTreeId']);
|
||||
});
|
||||
}
|
||||
;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
|
@ -9,6 +9,8 @@ class Purchase {
|
||||
double purchaseSum;
|
||||
String currency;
|
||||
|
||||
Purchase({this.customerId, this.productId});
|
||||
|
||||
Purchase.fromJson(Map json) {
|
||||
this.purchaseId = json['purchaseId'];
|
||||
this.customerId = json['customerId'];
|
||||
|
@ -270,7 +270,7 @@ class CustomerRepository with Logging {
|
||||
try {
|
||||
int customerId = Cache().userLoggedIn.customerId;
|
||||
tests = await ProductTestApi().getProductTestByCustomer(customerId);
|
||||
} on NotFoundException catch (ex) {
|
||||
} on NotFoundException catch (_) {
|
||||
log("Product Tests not found");
|
||||
Cache().productTests = tests;
|
||||
} on Exception catch (ex) {
|
||||
|
@ -259,6 +259,17 @@ class ExerciseRepository {
|
||||
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() {
|
||||
if (exerciseList.isEmpty) {
|
||||
return;
|
||||
|
@ -1,7 +1,6 @@
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/exercise_result.dart';
|
||||
import 'package:aitrainer_app/model/result.dart';
|
||||
import 'package:aitrainer_app/service/exercise_result_service.dart';
|
||||
|
||||
enum ResultType { running, man, woman, none }
|
||||
|
||||
|
@ -59,6 +59,11 @@ class UserRepository with Logging {
|
||||
if (e.code == 'email-already-in-use') {
|
||||
log('The account already exists for that email.');
|
||||
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) {
|
||||
if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) {
|
||||
@ -66,8 +71,8 @@ class UserRepository with Logging {
|
||||
throw Exception("The email address has been registered already");
|
||||
}
|
||||
} on Exception catch (ex) {
|
||||
log("Google exception: " + ex.toString());
|
||||
throw Exception("Google Sign In failed");
|
||||
log("FB exception: " + ex.toString());
|
||||
throw Exception("Facebook Sign In failed");
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +95,8 @@ class UserRepository with Logging {
|
||||
if (e.code == 'email-already-in-use') {
|
||||
log('The account already exists for that email.');
|
||||
throw Exception("The email address has been registered already");
|
||||
} else {
|
||||
throw Exception(e);
|
||||
}
|
||||
} on WorkoutTestException catch (ex) {
|
||||
if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) {
|
||||
@ -167,17 +174,18 @@ class UserRepository with Logging {
|
||||
|
||||
Future<void> getUserByGoogle() async {
|
||||
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 {
|
||||
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 Cache().afterFirebaseLogin();
|
||||
} on Exception catch (ex) {
|
||||
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/logging.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class Antagonist {
|
||||
static String chest = "Chest";
|
||||
@ -48,7 +47,7 @@ class WorkoutTreeRepository with Logging {
|
||||
Antagonist.calf: Antagonist.calfNr
|
||||
};
|
||||
|
||||
Future<String> _buildImage(String imageUrl) async {
|
||||
/* Future<String> _buildImage(String imageUrl) async {
|
||||
String assetImage = 'asset/menu/' + imageUrl.substring(7);
|
||||
//print("Loading image " + assetImage);
|
||||
return rootBundle.load(assetImage).then((value) {
|
||||
@ -59,7 +58,7 @@ class WorkoutTreeRepository with Logging {
|
||||
//print("Exception: " + assetImage + " will be loaded from the network " + url);
|
||||
return url;
|
||||
});
|
||||
}
|
||||
} */
|
||||
|
||||
Future<void> createTree() async {
|
||||
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 Iterable json = jsonDecode(body);
|
||||
devices = json.map((device) => CustomerExerciseDevice.fromJson(device)).toList();
|
||||
} on NotFoundException catch (e) {
|
||||
} on NotFoundException catch (_) {
|
||||
log("No devices found");
|
||||
}
|
||||
return devices;
|
||||
|
@ -165,41 +165,37 @@ class FirebaseApi with logging.Logging {
|
||||
Future<Map<String, dynamic>> signInWithGoogle() async {
|
||||
Map<String, dynamic> userData = Map();
|
||||
|
||||
try {
|
||||
// Trigger the authentication flow
|
||||
GoogleSignIn _googleSignIn = GoogleSignIn(
|
||||
scopes: [
|
||||
'email',
|
||||
'https://www.googleapis.com/auth/contacts.readonly',
|
||||
],
|
||||
);
|
||||
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
|
||||
// Trigger the authentication flow
|
||||
GoogleSignIn _googleSignIn = GoogleSignIn(
|
||||
scopes: [
|
||||
'email',
|
||||
'https://www.googleapis.com/auth/contacts.readonly',
|
||||
],
|
||||
);
|
||||
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
|
||||
|
||||
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());
|
||||
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;
|
||||
}
|
||||
|
||||
return userData;
|
||||
}
|
||||
|
||||
@ -266,15 +262,16 @@ class FirebaseApi with logging.Logging {
|
||||
Cache().accessTokenFacebook = accessToken;
|
||||
// get the user data
|
||||
userData = await FacebookAuth.instance.getUserData();
|
||||
log("FB user data: " + userData.toString());
|
||||
|
||||
// Create a credential from the access token
|
||||
final FacebookAuthCredential facebookAuthCredential = FacebookAuthProvider.credential(accessToken.token);
|
||||
|
||||
// Once signed in, return the UserCredential
|
||||
final userCredential = await FirebaseAuth.instance.signInWithCredential(facebookAuthCredential);
|
||||
log("Email by FB: " + userData['email'] + " FB credential: " + userCredential.toString());
|
||||
|
||||
Cache().firebaseUid = userCredential.user.uid;
|
||||
log(userData.toString());
|
||||
} else {
|
||||
throw Exception("Facebook login was not successful");
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ class PurchaseApi with Logging {
|
||||
final Iterable json = jsonDecode(body);
|
||||
final List<Purchase> purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList();
|
||||
Cache().setPurchases(purchases);
|
||||
} on NotFoundException catch (e) {
|
||||
} on NotFoundException catch (_) {
|
||||
log("No purchases found");
|
||||
}
|
||||
return purchases;
|
||||
|
@ -8,6 +8,7 @@ import 'package:badges/badges.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:sentry/sentry.dart';
|
||||
|
||||
class DateRate {
|
||||
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/product.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 {
|
||||
static final PlatformPurchaseApi _singleton = PlatformPurchaseApi._internal();
|
||||
|
||||
StreamSubscription _purchaseUpdatedSubscription;
|
||||
StreamSubscription _purchaseErrorSubscription;
|
||||
StreamSubscription _conectionSubscription;
|
||||
String _platformVersion = 'Unknown';
|
||||
List<IAPItem> _items = [];
|
||||
List getIAPItems() => _items;
|
||||
List<PurchasedItem> _purchases = [];
|
||||
bool _kAutoConsume = true;
|
||||
final String _kConsumableId = 'consumable';
|
||||
final InAppPurchaseConnection _connection = InAppPurchaseConnection.instance;
|
||||
bool _isAvailable = false;
|
||||
List<ProductDetails> _products = [];
|
||||
List<PurchaseDetails> _purchases = [];
|
||||
List<String> _notFoundIds = [];
|
||||
List<String> _consumables = [];
|
||||
bool _purchasePending = false;
|
||||
String _queryProductError;
|
||||
|
||||
StreamSubscription<List<PurchaseDetails>> _subscription;
|
||||
|
||||
final List<String> _productList = List();
|
||||
|
||||
List getProductList() => _productList;
|
||||
|
||||
|
||||
|
||||
factory PlatformPurchaseApi() {
|
||||
return _singleton;
|
||||
}
|
||||
@ -30,55 +31,152 @@ class PlatformPurchaseApi with Logging {
|
||||
PlatformPurchaseApi._internal();
|
||||
|
||||
Future<void> close() async {
|
||||
if (_conectionSubscription != null) {
|
||||
_conectionSubscription.cancel();
|
||||
_conectionSubscription = null;
|
||||
_subscription.cancel();
|
||||
}
|
||||
|
||||
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.
|
||||
Future<void> initPurchasePlatformState() async {
|
||||
Future<void> initPurchasePlatform() async {
|
||||
if (_productList.length > 0) {
|
||||
return;
|
||||
}
|
||||
log(' --- InappPurchase connection: $_connection');
|
||||
log(" --- Init PurchasePlatform");
|
||||
String platformVersion;
|
||||
// Platform messages may fail, so we use a try/catch PlatformException.
|
||||
try {
|
||||
platformVersion = await FlutterInappPurchase.instance.platformVersion;
|
||||
} on Exception {
|
||||
platformVersion = 'Failed to get platform version for InAppPurchase.';
|
||||
log("PlatformVersion" + platformVersion);
|
||||
await this.initStoreInfo();
|
||||
|
||||
Stream purchaseUpdated = InAppPurchaseConnection.instance.purchaseUpdatedStream;
|
||||
_subscription = purchaseUpdated.listen((purchaseDetailsList) {
|
||||
_listenToPurchaseUpdated(purchaseDetailsList);
|
||||
}, onDone: () {
|
||||
_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
|
||||
var result = await FlutterInappPurchase.instance.initConnection;
|
||||
log(' FlutterInappPurchase init result: $result');
|
||||
Future<bool> _verifyPurchase(PurchaseDetails purchaseDetails) {
|
||||
log("verifyPurchase");
|
||||
// IMPORTANT!! Always verify a purchase before delivering the product.
|
||||
// For the purpose of an example, we directly return true.
|
||||
log("Verifying Purchase" + purchaseDetails.toString());
|
||||
return Future<bool>.value(true);
|
||||
}
|
||||
|
||||
_platformVersion = platformVersion;
|
||||
void _handleInvalidPurchase(PurchaseDetails purchaseDetails) {
|
||||
// handle invalid purchase here if _verifyPurchase` failed.
|
||||
log("Invalid Purchase" + purchaseDetails.toString());
|
||||
}
|
||||
|
||||
// refresh items for android
|
||||
try {
|
||||
String msg = await FlutterInappPurchase.instance.consumeAllItems;
|
||||
log('consumeAllItems: $msg');
|
||||
} catch (err) {
|
||||
log('consumeAllItems error: $err');
|
||||
}
|
||||
|
||||
_conectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) {
|
||||
log('connected: $connected');
|
||||
void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) {
|
||||
purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
|
||||
if (purchaseDetails.status == PurchaseStatus.pending) {
|
||||
//showPendingUI();
|
||||
log("Purchase pending");
|
||||
} else {
|
||||
if (purchaseDetails.status == PurchaseStatus.error) {
|
||||
//handleError(purchaseDetails.error);
|
||||
} else if (purchaseDetails.status == PurchaseStatus.purchased) {
|
||||
bool valid = await _verifyPurchase(purchaseDetails);
|
||||
if (valid) {
|
||||
deliverProduct(purchaseDetails);
|
||||
} else {
|
||||
_handleInvalidPurchase(purchaseDetails);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (Platform.isAndroid) {
|
||||
if (!_kAutoConsume && purchaseDetails.productID == _kConsumableId) {
|
||||
await InAppPurchaseConnection.instance.consumePurchase(purchaseDetails);
|
||||
}
|
||||
}
|
||||
if (purchaseDetails.pendingCompletePurchase) {
|
||||
await InAppPurchaseConnection.instance.completePurchase(purchaseDetails);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen((productItem) {
|
||||
log('purchase-updated: $productItem');
|
||||
});
|
||||
|
||||
_purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) {
|
||||
log('purchase-error: $purchaseError');
|
||||
});
|
||||
|
||||
getSubscriptions();
|
||||
}
|
||||
|
||||
void getSubscriptions() {
|
||||
@ -98,7 +196,6 @@ class PlatformPurchaseApi with Logging {
|
||||
_productList.forEach((element) {
|
||||
print(element);
|
||||
});
|
||||
_getSubscription();
|
||||
}
|
||||
|
||||
void purchase(Product product) {
|
||||
@ -106,57 +203,29 @@ class PlatformPurchaseApi with Logging {
|
||||
throw Exception("No product to purchase");
|
||||
}
|
||||
String productId = Platform.isAndroid ? product.productIdAndroid : product.productIdIos;
|
||||
IAPItem selected;
|
||||
for (var item in _items) {
|
||||
if (item.productId == productId) {
|
||||
selected = item;
|
||||
log("Item to purchase: " + item.toString());
|
||||
ProductDetails productDetails;
|
||||
_products.forEach((element) {
|
||||
if (element.id == productId) {
|
||||
productDetails = element;
|
||||
log("product to purchase: " +
|
||||
productDetails.id +
|
||||
" title " +
|
||||
productDetails.title +
|
||||
" price " +
|
||||
productDetails.price +
|
||||
" period " +
|
||||
productDetails.skuDetail.subscriptionPeriod);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (selected != null) {
|
||||
requestPurchase(selected);
|
||||
} else {
|
||||
throw Exception("product " + productId + " not defined in the PlatformStore");
|
||||
}
|
||||
}
|
||||
|
||||
void requestPurchase(IAPItem item) {
|
||||
//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;
|
||||
final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);
|
||||
/* if (_isConsumable(productDetails)) {
|
||||
InAppPurchaseConnection.instance.buyConsumable(purchaseParam: purchaseParam);
|
||||
} else { */
|
||||
InAppPurchaseConnection.instance.buyNonConsumable(purchaseParam: purchaseParam);
|
||||
//}
|
||||
// From here the purchase flow will be handled by the underlying storefront.
|
||||
// Updates will be delivered to the `InAppPurchaseConnection.instance.purchaseUpdatedStream`.
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
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/product_service.dart';
|
||||
import 'package:aitrainer_app/service/property_service.dart';
|
||||
import 'package:aitrainer_app/util/purchases.dart';
|
||||
import 'package:devicelocale/devicelocale.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
@ -28,6 +29,7 @@ class Session with Logging {
|
||||
Cache().setServerAddress(_sharedPreferences);
|
||||
Cache().getHardware(_sharedPreferences);
|
||||
await _fetchToken(_sharedPreferences);
|
||||
await RevenueCatPurchases().initPlatform();
|
||||
//initDeviceLocale();
|
||||
|
||||
// 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/trans.dart';
|
||||
import 'package:aitrainer_app/widgets/app_bar_min.dart';
|
||||
import 'package:badges/badges.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:aitrainer_app/widgets/bottom_nav.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/localization/app_language.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_type.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_result_repository.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:google_fonts/google_fonts.dart';
|
||||
import 'package:aitrainer_app/model/result.dart';
|
||||
import 'package:modal_progress_hud/modal_progress_hud.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class EvaluationPage extends StatelessWidget with Trans {
|
||||
@ -22,7 +25,7 @@ class EvaluationPage extends StatelessWidget with Trans {
|
||||
Widget build(BuildContext context) {
|
||||
LinkedHashMap arguments = ModalRoute.of(context).settings.arguments;
|
||||
ExerciseRepository exerciseRepository;
|
||||
// ignore: close_sinks
|
||||
|
||||
if (arguments != null) {
|
||||
exerciseRepository = arguments['exerciseRepository'];
|
||||
} else {
|
||||
@ -37,10 +40,22 @@ class EvaluationPage extends StatelessWidget with Trans {
|
||||
resultType = ResultType.man;
|
||||
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)) {
|
||||
resultType = ResultType.running;
|
||||
imageUrl = 'asset/image/WT_Results_for_runners.png';
|
||||
}
|
||||
|
||||
setContext(context);
|
||||
return Scaffold(
|
||||
appBar: AppBarMin(
|
||||
@ -61,7 +76,7 @@ class EvaluationPage extends StatelessWidget with Trans {
|
||||
create: (context) => ResultBloc(
|
||||
resultRepository: ExerciseResultRepository(resultType: resultType),
|
||||
exerciseRepository: exerciseRepository,
|
||||
context: context), //..add(ResultLoad())
|
||||
context: context),
|
||||
child: BlocConsumer<ResultBloc, ResultState>(listener: (context, state) {
|
||||
if (state is ResultError) {
|
||||
Scaffold.of(context).showSnackBar(
|
||||
@ -74,7 +89,13 @@ class EvaluationPage extends StatelessWidget with Trans {
|
||||
}
|
||||
}, builder: (context, state) {
|
||||
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));
|
||||
}
|
||||
@ -89,13 +110,15 @@ class EvaluationPage extends StatelessWidget with Trans {
|
||||
SliverAppBar(
|
||||
pinned: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
expandedHeight: 50.0,
|
||||
expandedHeight: 120.0,
|
||||
collapsedHeight: 80,
|
||||
toolbarHeight: 30,
|
||||
automaticallyImplyLeading: false,
|
||||
flexibleSpace: FlexibleSpaceBar(
|
||||
title: Text(exerciseName,
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 3,
|
||||
softWrap: true,
|
||||
//softWrap: true,
|
||||
style: GoogleFonts.archivoBlack(
|
||||
fontSize: 24,
|
||||
color: Colors.white,
|
||||
@ -382,14 +405,12 @@ class EvaluationPage extends StatelessWidget with Trans {
|
||||
Widget getSummary(ResultBloc bloc) {
|
||||
int index = 0;
|
||||
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) {
|
||||
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 exerciseRepeats = actual.quantity.toStringAsFixed(0);
|
||||
if (bloc.exerciseRepository.exerciseType.unit == "second") {
|
||||
@ -407,7 +428,7 @@ class EvaluationPage extends StatelessWidget with Trans {
|
||||
}
|
||||
index++;
|
||||
resultList.add(
|
||||
Text(exerciseElement + exerciseRepeats + exerciseUnitQuantity + " " + unit,
|
||||
Text(exerciseElement + exerciseRepeats + exerciseUnitQuantity + " " + t(unit),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
softWrap: true,
|
||||
|
@ -200,7 +200,7 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
|
||||
iconSize: 36,
|
||||
icon: Icon(CustomIcon.heart_1, color: Colors.blue[800]),
|
||||
onPressed: () {
|
||||
evaluation();
|
||||
evaluation(exerciseRepository, exercise);
|
||||
},
|
||||
),
|
||||
Cache().hasPurchased
|
||||
@ -212,7 +212,7 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
|
||||
width: 25,
|
||||
),
|
||||
onTap: () {
|
||||
evaluation();
|
||||
evaluation(exerciseRepository, exercise);
|
||||
}),
|
||||
],
|
||||
),
|
||||
@ -230,19 +230,27 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
|
||||
return list;
|
||||
}
|
||||
|
||||
void evaluation() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogPremium(
|
||||
unlocked: true,
|
||||
unlockRound: 1,
|
||||
unlockedText: t("Enjoy also this premium fetaure to show all old evaluation data of your successful exercises."),
|
||||
function: "My Exercise Logs",
|
||||
onTap: () => {Navigator.of(context).pop()},
|
||||
onCancel: () => {Navigator.of(context).pop()},
|
||||
);
|
||||
});
|
||||
void evaluation(ExerciseRepository exerciseRepository, Exercise exercise) {
|
||||
if (!Cache().hasPurchased) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogPremium(
|
||||
unlocked: Cache().hasPurchased,
|
||||
unlockRound: 1,
|
||||
unlockedText: t("Enjoy also this premium fetaure to show all old evaluation data of your successful exercises."),
|
||||
function: "My Exercise Logs",
|
||||
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) {
|
||||
|
@ -22,6 +22,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
|
||||
import 'package:google_fonts/google_fonts.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:wakelock/wakelock.dart';
|
||||
|
||||
@ -101,11 +102,14 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
if (state is ExerciseNewReady) {
|
||||
//LoadingDialog.hide(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() {
|
||||
super.initState();
|
||||
Flurry.logEvent("myDevelopmentBody");
|
||||
if (!Cache().hasPurchased) {
|
||||
if (!Cache().hasPurchased || true) {
|
||||
Timer(
|
||||
Duration(milliseconds: 2000),
|
||||
() => {
|
||||
@ -38,10 +38,10 @@ class _MyDevelopmentBodyPage extends State<MyDevelopmentBodyPage> with Trans, Co
|
||||
builder: (BuildContext context) {
|
||||
setContext(context);
|
||||
return DialogPremium(
|
||||
unlocked: false,
|
||||
unlocked: Cache().hasPurchased,
|
||||
unlockRound: 2,
|
||||
function: "My Whole Body Development",
|
||||
unlockedText: "",
|
||||
unlockedText: null,
|
||||
onTap: () => {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);
|
||||
|
||||
LinkedHashMap<String, dynamic> rc = LinkedHashMap();
|
||||
tree.forEach((name, list) {
|
||||
rc = _getChildList(list, bloc);
|
||||
final List<Widget> children = rc['list'];
|
||||
final bool hasNoData = rc['hasNoData'];
|
||||
exerciseTypes.add(Container(
|
||||
margin: const EdgeInsets.only(left: 4.0),
|
||||
child: TreeViewChild(
|
||||
startExpanded: false,
|
||||
parent: _getExerciseWidget(exerciseTypeName: name),
|
||||
children: _getChildList(list, bloc),
|
||||
parent: _getExerciseWidget(exerciseTypeName: name, noData: hasNoData),
|
||||
children: children,
|
||||
)));
|
||||
});
|
||||
|
||||
return exerciseTypes;
|
||||
}
|
||||
|
||||
Widget _getExerciseWidget({@required String exerciseTypeName, List<WorkoutMenuTree> list}) {
|
||||
return TreeviewParentWidget(text: exerciseTypeName);
|
||||
Widget _getExerciseWidget({@required String exerciseTypeName, bool noData = false}) {
|
||||
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();
|
||||
bool hasSummaryNoData = true;
|
||||
listWorkoutTree.forEach((element) {
|
||||
bool hasNoData = (bloc.listChartData[element.exerciseTypeId] == null);
|
||||
final bool hasNoData = (bloc.listChartData[element.exerciseTypeId] == null);
|
||||
hasSummaryNoData = hasSummaryNoData && hasNoData;
|
||||
String unit = " kg";
|
||||
if (bloc.diagramType == DiagramType.percent) {
|
||||
unit = " %";
|
||||
@ -320,7 +330,8 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
|
||||
),
|
||||
));
|
||||
});
|
||||
|
||||
return list;
|
||||
rc['list'] = list;
|
||||
rc['hasNoData'] = hasSummaryNoData;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
@ -106,10 +106,10 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogPremium(
|
||||
unlocked: false,
|
||||
unlockRound: 2,
|
||||
unlocked: Cache().hasPurchased,
|
||||
unlockRound: 3,
|
||||
function: "Predictions",
|
||||
unlockedText: "",
|
||||
unlockedText: null,
|
||||
onTap: () => {Navigator.of(context).pop()},
|
||||
);
|
||||
})
|
||||
|
@ -97,10 +97,10 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogPremium(
|
||||
unlocked: false,
|
||||
unlocked: Cache().hasPurchased,
|
||||
unlockRound: 1,
|
||||
function: "Suggested Training Plan",
|
||||
unlockedText: "",
|
||||
unlockedText: null,
|
||||
onTap: () => {Navigator.of(context).pop()},
|
||||
onCancel: () => {Navigator.of(context).pop()},
|
||||
);
|
||||
@ -111,25 +111,25 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
|
||||
ImageButton(
|
||||
width: imageWidth,
|
||||
textAlignment: Alignment.topLeft,
|
||||
text: t("My Special Plan"),
|
||||
text: t("Training Programs"),
|
||||
style: GoogleFonts.robotoMono(
|
||||
textStyle: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
backgroundColor: Colors.black54.withOpacity(0.4))),
|
||||
image: "asset/image/exercise_plan_special.jpg",
|
||||
image: "asset/image/exercise_plan_stars.jpg",
|
||||
left: 5,
|
||||
onTap: () => {
|
||||
Flurry.logEvent("SpecialTrainingPlan"),
|
||||
Flurry.logEvent("SpecialTraining Programs"),
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogPremium(
|
||||
unlocked: false,
|
||||
unlocked: Cache().hasPurchased,
|
||||
unlockRound: 1,
|
||||
function: "My Special Plan",
|
||||
unlockedText: "",
|
||||
function: "Training Programs",
|
||||
unlockedText: null,
|
||||
onTap: () => {Navigator.of(context).pop()},
|
||||
onCancel: () => {Navigator.of(context).pop()},
|
||||
);
|
||||
@ -137,7 +137,7 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
|
||||
},
|
||||
isLocked: true,
|
||||
),
|
||||
ImageButton(
|
||||
/* ImageButton(
|
||||
width: imageWidth,
|
||||
textAlignment: Alignment.topLeft,
|
||||
text: t("Star's Exercise Plan"),
|
||||
@ -165,7 +165,7 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
|
||||
})
|
||||
},
|
||||
isLocked: true,
|
||||
),
|
||||
), */
|
||||
hiddenPlanWidget(exerciseRepository),
|
||||
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/util/trans.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:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@ -23,7 +24,25 @@ class SalesPage extends StatelessWidget with Trans, Logging {
|
||||
if (state is SalesError) {
|
||||
log("Error: " + state.message);
|
||||
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) {
|
||||
final salesBloc = BlocProvider.of<SalesBloc>(context);
|
||||
@ -38,8 +57,6 @@ class SalesPage extends StatelessWidget with Trans, Logging {
|
||||
}
|
||||
|
||||
Widget salesWidget(SalesBloc bloc) {
|
||||
final double mediaWidth = MediaQuery.of(context).size.width;
|
||||
final double imageWidth = (mediaWidth - 5) / 2;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
@ -54,7 +71,7 @@ class SalesPage extends StatelessWidget with Trans, Logging {
|
||||
Divider(),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 65, right: 65),
|
||||
child: Text("Unleash Your Development Now!",
|
||||
child: Text(t("Unleash Your Development Now!"),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 4,
|
||||
softWrap: true,
|
||||
@ -77,7 +94,7 @@ class SalesPage extends StatelessWidget with Trans, Logging {
|
||||
Divider(),
|
||||
Container(
|
||||
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,
|
||||
maxLines: 4,
|
||||
softWrap: true,
|
||||
@ -106,47 +123,45 @@ class SalesPage extends StatelessWidget with Trans, Logging {
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 55, right: 55),
|
||||
child: Text(
|
||||
"Subscription Conditions",
|
||||
t("Subscription Conditions"),
|
||||
style: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white),
|
||||
)),
|
||||
Divider(),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 55, right: 55),
|
||||
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),
|
||||
)),
|
||||
Divider(),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 55, right: 55),
|
||||
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),
|
||||
)),
|
||||
])),
|
||||
]));
|
||||
;
|
||||
}
|
||||
|
||||
List<Widget> getButtons(SalesBloc bloc) {
|
||||
List<Widget> buttons = List();
|
||||
|
||||
bloc.product2Display.forEach((element) {
|
||||
final String title = element.sort == 3 ? "Montly" : "Annual";
|
||||
final String interval = element.sort == 3 ? " / month" : " / year";
|
||||
final String desc4 = element.sort == 1 ? "" : "AI driven predictions";
|
||||
final String title = element.sort == 3 ? t("Montly") : t("Annual");
|
||||
final String desc4 = element.sort == 1 ? "" : t("AI driven predictions");
|
||||
String badge;
|
||||
if (element.sort == 2) {
|
||||
badge = "14% discount";
|
||||
badge = t("14% discount");
|
||||
} else if (element.sort == 1) {
|
||||
badge = "2 months free";
|
||||
badge = t("2 months free");
|
||||
}
|
||||
Widget button = SalesButton(
|
||||
title: title,
|
||||
price: element.localizedPrice,
|
||||
desc1: "Development programs",
|
||||
desc2: "Suggestions based on your actual status",
|
||||
desc3: "Special customized training plans",
|
||||
desc1: t("Development programs"),
|
||||
desc2: t("Suggestions based on your actual status"),
|
||||
desc3: t("Special customized training plans"),
|
||||
desc4: desc4,
|
||||
descStyle: GoogleFonts.inter(fontSize: 10, color: Colors.blue[800]),
|
||||
badgeText: badge,
|
||||
|
@ -10,6 +10,7 @@ import 'package:aitrainer_app/widgets/bottom_nav.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:modal_progress_hud/modal_progress_hud.dart';
|
||||
import 'package:toggle_switch/toggle_switch.dart';
|
||||
|
||||
// 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))));
|
||||
} else if (state is SettingsReady) {
|
||||
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()))));
|
||||
}
|
||||
},
|
||||
// ignore: missing_return
|
||||
builder: (context, state) {
|
||||
return settingsUI(context, settingsBloc, menuBloc);
|
||||
}, builder: (context, state) {
|
||||
return ModalProgressHUD(
|
||||
child: 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],
|
||||
labels: [t('Live-Server'), t('Test-Server')],
|
||||
onToggle: (index) {
|
||||
//Cache().setServer(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/util/trans.dart';
|
||||
import 'package:animated_widgets/widgets/rotation_animated.dart';
|
||||
import 'package:flurry/flurry.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -71,7 +70,6 @@ class _BMIState extends State<BMI> with Trans {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
setContext(context);
|
||||
Flurry.logEvent("BMI");
|
||||
double mediaWidth = MediaQuery.of(context).size.width * .8;
|
||||
double mediaHeight = MediaQuery.of(context).size.height * .8;
|
||||
//print("w " + mediaWidth.toString() + "h " + mediaHeight.toString());
|
||||
@ -109,18 +107,35 @@ class _BMIState extends State<BMI> with Trans {
|
||||
fontSize: 30,
|
||||
color: Colors.orange[500],
|
||||
)),
|
||||
Text(widget.exerciseBloc.bmi.toStringAsFixed(1) + "%",
|
||||
style: GoogleFonts.archivoBlack(
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(5.0, 5.0),
|
||||
blurRadius: 3.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
fontSize: 60,
|
||||
color: Colors.orange[500],
|
||||
)),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(widget.exerciseBloc.bmi.toStringAsFixed(1),
|
||||
style: GoogleFonts.archivoBlack(
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(5.0, 5.0),
|
||||
blurRadius: 3.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
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),
|
||||
Stack(alignment: Alignment.center, children: [
|
||||
Container(
|
||||
@ -153,15 +168,31 @@ class _BMIState extends State<BMI> with Trans {
|
||||
color: Colors.yellow[200],
|
||||
)),
|
||||
),
|
||||
Text("BMI" + ": " + widget.exerciseBloc.goalBMI.toStringAsFixed(0),
|
||||
Text("BMI" + " " + t("first step") + ": " + widget.exerciseBloc.goalMilestoneBMI.toStringAsFixed(1),
|
||||
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],
|
||||
)),
|
||||
Text(t("Weight") + ": " + widget.exerciseBloc.goalWeight.toStringAsFixed(0) + " kg",
|
||||
Text(t("Bodyweight") + " " + t("goal") + ": " + widget.exerciseBloc.goalWeight.toStringAsFixed(0) + " kg",
|
||||
style: GoogleFonts.archivoBlack(
|
||||
fontSize: 30,
|
||||
color: Colors.orange[200],
|
||||
fontSize: 20,
|
||||
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/model/fitness_state.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:flurry/flurry.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -26,6 +25,7 @@ class _BMRState extends State<BMR> with Trans {
|
||||
|
||||
final FocusNode _nodeText1 = FocusNode();
|
||||
final FocusNode _nodeText2 = FocusNode();
|
||||
final FocusNode _nodeText3 = FocusNode();
|
||||
|
||||
KeyboardActionsConfig _buildConfig(BuildContext context) {
|
||||
return KeyboardActionsConfig(
|
||||
@ -34,6 +34,21 @@ class _BMRState extends State<BMR> with Trans {
|
||||
keyboardSeparatorColor: Colors.black26,
|
||||
nextFocus: true,
|
||||
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: [
|
||||
(node) {
|
||||
return GestureDetector(
|
||||
@ -75,7 +90,6 @@ class _BMRState extends State<BMR> with Trans {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
setContext(context);
|
||||
Flurry.logEvent("BMR");
|
||||
return Form(
|
||||
child: Scaffold(
|
||||
resizeToAvoidBottomInset: true,
|
||||
@ -99,6 +113,35 @@ class _BMRState extends State<BMR> with Trans {
|
||||
getWeightInput(),
|
||||
getFitnessLevel(),
|
||||
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(
|
||||
padding: EdgeInsets.only(left: 35, right: 35),
|
||||
child: Text(t("Basal Metabolic Rate"),
|
||||
@ -111,7 +154,7 @@ class _BMRState extends State<BMR> with Trans {
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
fontSize: 30,
|
||||
fontSize: 24,
|
||||
color: Colors.orange[500],
|
||||
)),
|
||||
),
|
||||
@ -124,7 +167,7 @@ class _BMRState extends State<BMR> with Trans {
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
fontSize: 50,
|
||||
fontSize: 30,
|
||||
color: Colors.orange[500],
|
||||
)),
|
||||
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() {
|
||||
String fitnessLevel = widget.exerciseBloc.fitnessLevel;
|
||||
return Container(
|
||||
@ -254,14 +321,18 @@ class _BMRState extends State<BMR> with Trans {
|
||||
|
||||
Widget getWeightInput() {
|
||||
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,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
getBirthyearInput(),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
getHeightInput(),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
width: 5,
|
||||
),
|
||||
Flexible(
|
||||
child: TextFormField(
|
||||
|
@ -1,9 +1,7 @@
|
||||
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/util/common.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:badges/badges.dart';
|
||||
import 'package:flurry/flurry.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gradient_bottom_navigation_bar/gradient_bottom_navigation_bar.dart';
|
||||
|
@ -26,9 +26,6 @@ class DialogPremium extends StatefulWidget {
|
||||
: super(key: key) {
|
||||
description = description ?? "";
|
||||
function = function ?? "";
|
||||
unlockedText = unlockedText ?? "";
|
||||
|
||||
unlocked = true;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -92,7 +89,7 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
|
||||
Text(
|
||||
widget.unlocked ? t("Keep testing") : t("Go Premium") + " ",
|
||||
style: GoogleFonts.archivoBlack(
|
||||
fontSize: widget.unlocked ? 18 : 24,
|
||||
fontSize: widget.unlocked ? 20 : 24,
|
||||
color: Colors.yellow[400],
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
@ -226,9 +223,10 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
|
||||
List<TextSpan> getDescriptionText() {
|
||||
List<TextSpan> list = List();
|
||||
|
||||
/* if (widget.unlocked) {
|
||||
if (widget.unlockedText != null) {
|
||||
list.add(TextSpan(text: widget.unlockedText));
|
||||
} */
|
||||
return list;
|
||||
}
|
||||
list.add(TextSpan(text: t("The")));
|
||||
list.add(TextSpan(text: t(" ")));
|
||||
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/model/cache.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/menu_page.dart';
|
||||
import 'package:aitrainer_app/view/registration.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/semantics.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.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/workout_menu_tree.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/widgets/dialog_common.dart';
|
||||
import 'package:badges/badges.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
|
@ -4,21 +4,23 @@ import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
class TreeviewParentWidget extends StatelessWidget {
|
||||
final String text;
|
||||
final Color backgroundColor;
|
||||
final Color color;
|
||||
//final DateTime lastModified;
|
||||
|
||||
TreeviewParentWidget({@required this.text});
|
||||
TreeviewParentWidget({@required this.text, this.backgroundColor = Colors.white38, this.color});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget parentWidget = 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);
|
||||
|
||||
return Card(
|
||||
color: Colors.white38,
|
||||
color: backgroundColor,
|
||||
shadowColor: Colors.black54,
|
||||
elevation: 0.0,
|
||||
child: ListTile(
|
||||
|
54
pubspec.lock
54
pubspec.lock
@ -84,7 +84,7 @@ packages:
|
||||
name: build
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
version: "1.6.1"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -98,28 +98,28 @@ packages:
|
||||
name: build_daemon
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.1.6"
|
||||
build_resolvers:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_resolvers
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
version: "1.5.2"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.10.11"
|
||||
version: "1.10.13"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.5"
|
||||
version: "6.1.6"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -189,7 +189,7 @@ packages:
|
||||
name: code_builder
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.5.0"
|
||||
version: "3.6.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -432,7 +432,7 @@ packages:
|
||||
name: flutter_html
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.2.0"
|
||||
flutter_keyboard_visibility:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -447,6 +447,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -713,7 +720,7 @@ packages:
|
||||
name: path_provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.24"
|
||||
version: "1.6.27"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -727,7 +734,7 @@ packages:
|
||||
name: path_provider_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.4+6"
|
||||
version: "0.0.4+8"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -797,7 +804,7 @@ packages:
|
||||
name: provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.3.2+3"
|
||||
version: "4.3.2+4"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -812,6 +819,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -846,7 +860,7 @@ packages:
|
||||
name: sentry
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "4.0.3"
|
||||
shared_preferences:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -963,14 +977,14 @@ packages:
|
||||
name: sqflite
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.2+1"
|
||||
version: "1.3.2+2"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_common
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2+1"
|
||||
version: "1.0.3"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1041,6 +1055,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1062,13 +1083,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0-nullsafety.3"
|
||||
usage:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: usage
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.4.2"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
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.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 1.1.4+46
|
||||
version: 1.1.5+48
|
||||
|
||||
environment:
|
||||
sdk: ">=2.7.0 <3.0.0"
|
||||
@ -27,7 +27,7 @@ dependencies:
|
||||
cupertino_icons: ^1.0.0
|
||||
google_fonts: ^1.1.1
|
||||
devicelocale: ^0.3.3
|
||||
sentry: ^3.0.1
|
||||
sentry: ^4.0.3
|
||||
flutter_bloc: ^6.1.1
|
||||
equatable: ^1.2.5
|
||||
#freezed: ^0.12.2
|
||||
@ -45,10 +45,11 @@ dependencies:
|
||||
#health: ^3.0.0
|
||||
stop_watch_timer: ^0.6.0+1
|
||||
#geolocator: ^6.1.13
|
||||
#flutter_inapp_purchase: ^3.0.1
|
||||
modal_progress_hud: ^0.1.3
|
||||
flutter_html: ^1.1.1
|
||||
wakelock: ^0.2.1+1
|
||||
timeline_tile: ^1.0.0
|
||||
purchases_flutter: ^2.0.0
|
||||
|
||||
|
||||
firebase_core: ^0.5.0
|
||||
|
@ -1,5 +1,3 @@
|
||||
import 'dart:html';
|
||||
|
||||
import 'package:aitrainer_app/model/customer.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../lib/helper/database.dart';
|
||||
|
Loading…
Reference in New Issue
Block a user