WT 1.1.7+2 SearchBar, Timer for ExerciseControl
1
android/.gitignore
vendored
@ -4,4 +4,5 @@ gradle-wrapper.jar
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
key.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 54 KiB |
BIN
asset/menu/2.1.4.squats.jpg
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
asset/menu/bent_over_rows.jpg
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
asset/menu/close_grip_bench_press.jpg
Normal file
After Width: | Height: | Size: 138 KiB |
BIN
asset/menu/hyperextension_floor.jpg
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
asset/menu/pulldown_machine.jpg
Normal file
After Width: | Height: | Size: 113 KiB |
BIN
asset/menu/row_machine.jpg
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
asset/wine-glass.mp3
Normal file
53
i18n/en.json
@ -361,33 +361,36 @@
|
||||
|
||||
"Body Type Analyser":"Body Type Analyser",
|
||||
"How likely is it true about you?":"How likely is it true about you?",
|
||||
"Very unlikely":"Very unlikely",
|
||||
"Very unlikely":"Not True",
|
||||
"Maybe":"Maybe",
|
||||
"Very likely":"Very likely",
|
||||
"Very likely":"True",
|
||||
"« Back":"« Back",
|
||||
"1. Basicly I am skinny and bonny":"1. Basicly I am skinny and bonny",
|
||||
"2. question":"2. question",
|
||||
"3. question":"3. question",
|
||||
"4. question":"4. question",
|
||||
"5. question":"5. question",
|
||||
"6. question":"6. question",
|
||||
"7. question":"7. question",
|
||||
"8. question":"8. question",
|
||||
"9. question":"9. question",
|
||||
"10. question":"10. question",
|
||||
"11. question":"11. question",
|
||||
"12. question":"12. question",
|
||||
"13. question":"13. question",
|
||||
"14. question":"14. question",
|
||||
"15. question":"15. question",
|
||||
"16. question":"16. question",
|
||||
"17. question":"17. question",
|
||||
"18. question":"18. question",
|
||||
"19. question":"19. question",
|
||||
"20. question":"20. question",
|
||||
"21. question":"21. question",
|
||||
"22. question":"22. question",
|
||||
"1. Basicly I am skinny and bonny":"1. I have basically a thin and bony physique",
|
||||
"2. question":"2. Long limbs and narrow shoulders are typical of me",
|
||||
"3. question":"3. It is difficult for me to build muscle",
|
||||
"4. question":"4. My chest and waist are nearly the same width",
|
||||
"5. question":"5. ’Chopstick’ was my nickname in the kindergarten",
|
||||
"6. question":"6. I easily lose the muscle I built up",
|
||||
"7. question":"7. To my knowledge, my body fat percentage is low",
|
||||
"8. question":"8. Basically, I have a sporty and athletic physique",
|
||||
"9. question":"9. I have a wide collarbone and shoulders",
|
||||
"10. question":"10. My hips are narrow and my waist is sporty",
|
||||
"11. question":"11. I get muscular quickly",
|
||||
"12. question":"12. My chest is wider than my waist",
|
||||
"13. question":"13. I could be the statue of David",
|
||||
"14. question":"14. I have a strong calf and forearm",
|
||||
"15. question":"15. I have a wide rib cage",
|
||||
"16. question":"16. I have thick and wide joints",
|
||||
"17. question":"17. My bones are strong",
|
||||
"18. question":"18. My body is muscular but a little fatter",
|
||||
"19. question":"19. My hips are wider than my chest",
|
||||
"20. question":"20. Tun’ could be my nickname too",
|
||||
"21. question":"21. I lose weight hard and gain weight more easily",
|
||||
"22. question":"22. I have a strong and chunky physique",
|
||||
"Your Bodytype result":"Your Bodytype result",
|
||||
"Change the weight to":"Change the weight to"
|
||||
"Change the weight to":"Change the weight to",
|
||||
|
||||
"Search Exercises...":"Search Exercises...",
|
||||
"No exercise found":"No exercise found"
|
||||
|
||||
}
|
13
i18n/hu.json
@ -361,7 +361,7 @@
|
||||
"Maybe":"Talán",
|
||||
"Very likely":"Biztosan",
|
||||
"« Back":"« Vissza",
|
||||
"1. Basicly I am skinny and bonny":"1. Alapvetően vékony csontos testalkat vagyok",
|
||||
"1. Basicly I am skinny and bonny":"1. Alapvetően vékony, csontos testalkat vagyok",
|
||||
"2. question":"2. Hosszú végtagok, keskeny vállak jellemzőek rám",
|
||||
"3. question":"3. Nehezen tudok izmot növelni",
|
||||
"4. question":"4. Mellkasom, derekam közel egyforma szélességű",
|
||||
@ -374,16 +374,19 @@
|
||||
"11. question":"11. Gyorsan izmosodok",
|
||||
"12. question":"12. Szélesebb a mellkasom a derekamnál",
|
||||
"13. question":"13. Akár lehetnék én a Dávid szobor",
|
||||
"14. question":"14. Erős vádli és alkar",
|
||||
"14. question":"14. Erős vádli és alkar jellemez",
|
||||
"15. question":"15. Széles bordakosaram van",
|
||||
"16. question":"16. Vastag széles ízületeim vannak",
|
||||
"16. question":"16. Vastag, széles ízületeim vannak",
|
||||
"17. question":"17. Erős a csontozatom",
|
||||
"18. question":"18. Zsírosabb, de izmos vagyok",
|
||||
"19. question":"19. Szélesebb a csípőm a mellkasomnál",
|
||||
"20. question":"20. Hordó is lehetne a becenevem",
|
||||
"21. question":"21. Nehezen fogyok, könnyebben hízok",
|
||||
"22. question":"22. Erős vaskos testalkat vagyok",
|
||||
"22. question":"22. Erős, vaskos testalkat vagyok",
|
||||
"Your Bodytype result":"Testtípus eredményed",
|
||||
"Change the weight to":"Súly változtatása"
|
||||
"Change the weight to":"Súly változtatása",
|
||||
|
||||
"Search Exercises...":"Gyakorlat keresése...",
|
||||
"No exercise found":"Nincs ilyen gyakorlat"
|
||||
|
||||
}
|
@ -6,6 +6,8 @@ PODS:
|
||||
- AppAuth/ExternalUserAgent (1.4.0)
|
||||
- apple_sign_in (0.0.1):
|
||||
- Flutter
|
||||
- audioplayer (0.0.1):
|
||||
- Flutter
|
||||
- devicelocale (0.0.1):
|
||||
- Flutter
|
||||
- FBSDKCoreKit (9.0.0):
|
||||
@ -181,6 +183,7 @@ PODS:
|
||||
|
||||
DEPENDENCIES:
|
||||
- apple_sign_in (from `.symlinks/plugins/apple_sign_in/ios`)
|
||||
- audioplayer (from `.symlinks/plugins/audioplayer/ios`)
|
||||
- devicelocale (from `.symlinks/plugins/devicelocale/ios`)
|
||||
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
|
||||
- firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
|
||||
@ -232,6 +235,8 @@ SPEC REPOS:
|
||||
EXTERNAL SOURCES:
|
||||
apple_sign_in:
|
||||
:path: ".symlinks/plugins/apple_sign_in/ios"
|
||||
audioplayer:
|
||||
:path: ".symlinks/plugins/audioplayer/ios"
|
||||
devicelocale:
|
||||
:path: ".symlinks/plugins/devicelocale/ios"
|
||||
firebase_analytics:
|
||||
@ -274,6 +279,7 @@ EXTERNAL SOURCES:
|
||||
SPEC CHECKSUMS:
|
||||
AppAuth: 31bcec809a638d7bd2f86ea8a52bd45f6e81e7c7
|
||||
apple_sign_in: 7716c7ddfa195aeab7dec0dc374ef4ff45d1adb4
|
||||
audioplayer: 0584f31a697e4b0bbad405ae7903d7a93585e784
|
||||
devicelocale: feebbe5e7a30adb8c4f83185de1b50ff19b44f00
|
||||
FBSDKCoreKit: ac6cc500b8e104bb9a4dd20b1527b5d199123c2e
|
||||
FBSDKLoginKit: e9b6542fdee322333502ab497f628b011dce7d78
|
||||
|
@ -388,7 +388,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 3;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@ -405,7 +405,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.6;
|
||||
MARKETING_VERSION = 1.1.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@ -531,7 +531,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 3;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@ -548,7 +548,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.6;
|
||||
MARKETING_VERSION = 1.1.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@ -566,7 +566,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 3;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@ -583,7 +583,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.6;
|
||||
MARKETING_VERSION = 1.1.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
@ -47,8 +47,14 @@
|
||||
<string>10.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>audio</string>
|
||||
<string>fetch</string>
|
||||
<string>remote-notification</string>
|
||||
</array>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/exercise.dart';
|
||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
||||
|
32
lib/bloc/development_sizes/development_sizes_bloc.dart
Normal file
@ -0,0 +1,32 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/repository/customer_repository.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
part 'development_sizes_event.dart';
|
||||
part 'development_sizes_state.dart';
|
||||
|
||||
class DevelopmentSizesBloc extends Bloc<DevelopmentSizesEvent, DevelopmentSizesState> {
|
||||
final CustomerRepository customerRepository;
|
||||
DevelopmentSizesBloc({this.customerRepository}) : super(DevelopmentSizesInitial()) {
|
||||
isMan = Cache().userLoggedIn.sex == "m";
|
||||
}
|
||||
|
||||
bool isMan;
|
||||
|
||||
@override
|
||||
Stream<DevelopmentSizesState> mapEventToState(
|
||||
DevelopmentSizesEvent event,
|
||||
) async* {
|
||||
try {
|
||||
if (state is DevelopmentSizesLoad) {
|
||||
yield DevelopmentSizesLoading();
|
||||
yield DevelopmentSizesReady();
|
||||
}
|
||||
} on Exception catch (e) {
|
||||
yield DevelopmentSizesError(message: e.toString());
|
||||
}
|
||||
}
|
||||
}
|
12
lib/bloc/development_sizes/development_sizes_event.dart
Normal file
@ -0,0 +1,12 @@
|
||||
part of 'development_sizes_bloc.dart';
|
||||
|
||||
abstract class DevelopmentSizesEvent extends Equatable {
|
||||
const DevelopmentSizesEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class DevelopmentSizesLoad extends DevelopmentSizesEvent {
|
||||
const DevelopmentSizesLoad();
|
||||
}
|
28
lib/bloc/development_sizes/development_sizes_state.dart
Normal file
@ -0,0 +1,28 @@
|
||||
part of 'development_sizes_bloc.dart';
|
||||
|
||||
abstract class DevelopmentSizesState extends Equatable {
|
||||
const DevelopmentSizesState();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class DevelopmentSizesInitial extends DevelopmentSizesState {
|
||||
const DevelopmentSizesInitial();
|
||||
}
|
||||
|
||||
class DevelopmentSizesLoading extends DevelopmentSizesState {
|
||||
const DevelopmentSizesLoading();
|
||||
}
|
||||
|
||||
class DevelopmentSizesReady extends DevelopmentSizesState {
|
||||
const DevelopmentSizesReady();
|
||||
}
|
||||
|
||||
class DevelopmentSizesError extends DevelopmentSizesState {
|
||||
final String message;
|
||||
const DevelopmentSizesError({this.message});
|
||||
|
||||
@override
|
||||
List<Object> get props => [this.message];
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
@ -9,6 +10,7 @@ part 'exercise_control_event.dart';
|
||||
part 'exercise_control_state.dart';
|
||||
|
||||
class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlState> {
|
||||
final TimerBloc timerBloc;
|
||||
final ExerciseRepository exerciseRepository;
|
||||
final bool readonly;
|
||||
final double percentToCalculate;
|
||||
@ -25,7 +27,8 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
|
||||
double scrollOffset = 0;
|
||||
|
||||
@override
|
||||
ExerciseControlBloc({this.exerciseRepository, this.readonly, this.percentToCalculate}) : super(ExerciseControlInitial()) {
|
||||
ExerciseControlBloc({this.exerciseRepository, this.readonly, this.percentToCalculate, @required this.timerBloc})
|
||||
: super(ExerciseControlInitial()) {
|
||||
initialRM = this.calculate1RM(percent75: false);
|
||||
unitQuantity = this.calculate1RM(percent75: true).roundToDouble();
|
||||
quantity = percentToCalculate == 0.75 ? 12 : 30;
|
||||
@ -34,6 +37,7 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
|
||||
exerciseRepository.setUnitQuantity(unitQuantity);
|
||||
exerciseRepository.setQuantity(quantity);
|
||||
print("init quantity: " + quantity.toString());
|
||||
timerBloc.add(TimerStart(duration: 300));
|
||||
}
|
||||
|
||||
@override
|
||||
@ -78,6 +82,7 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
|
||||
|
||||
exerciseRepository.setQuantity(quantity);
|
||||
exerciseRepository.exercise.exerciseId = null;
|
||||
step <= 3 ? timerBloc.add(TimerStart(duration: 300)) : timerBloc.add(TimerEnd());
|
||||
}
|
||||
yield ExerciseControlReady();
|
||||
}
|
||||
@ -109,12 +114,7 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
|
||||
final double weight = exerciseRepository.exercise.unitQuantity;
|
||||
final double repeatWendler = (rmWendler - weight) / 0.0333 / weight;
|
||||
final double repeatOconner = (rmOconner / weight - 1) * 40;
|
||||
print("Weight: " +
|
||||
weight.toString() +
|
||||
" repeatWendler: " +
|
||||
repeatWendler.toStringAsFixed(0) +
|
||||
" repeat Oconner: " +
|
||||
repeatOconner.toStringAsFixed(0));
|
||||
return repeatWendler;
|
||||
print("Weight: $weight repeatWendler: $repeatWendler repeat Oconner: $repeatOconner");
|
||||
return unitQuantity > 100 ? (repeatOconner + repeatWendler) / 2 : repeatWendler;
|
||||
}
|
||||
}
|
||||
|
@ -44,14 +44,12 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
|
||||
String fitnessLevel;
|
||||
bool changedWeight = false;
|
||||
bool changedSizes = false;
|
||||
final List<Property> womanSizes = List();
|
||||
final List<Property> manSizes = List();
|
||||
|
||||
final double baseWidth = 312;
|
||||
final double baseHeight = 675.2;
|
||||
double mediaWidth = 0;
|
||||
double mediaHeight = 0;
|
||||
bool isMan = true;
|
||||
|
||||
String exerciseTask = "";
|
||||
|
||||
final StopWatchTimer stopWatchTimer = StopWatchTimer(
|
||||
@ -73,7 +71,7 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
|
||||
height = customerRepository.customer.getProperty("Height");
|
||||
birthYear = customerRepository.customer.birthYear;
|
||||
fitnessLevel = customerRepository.customer.fitnessLevel;
|
||||
this.isMan = (customerRepository.customer.sex == "m");
|
||||
|
||||
}
|
||||
if (exerciseType.unit == "second") {
|
||||
stopWatchTimer.rawTime.listen((value) => {timerValue = value, this.setQuantity((value / 1000).toDouble())});
|
||||
@ -109,196 +107,6 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
|
||||
exerciseRepository.setQuantity(quantity);
|
||||
}
|
||||
|
||||
void setMediaDimensions(double width, double height) {
|
||||
this.mediaHeight = height;
|
||||
this.mediaWidth = width;
|
||||
this.addSizes(customerRepository.sex);
|
||||
}
|
||||
|
||||
void addSizes(String sex) {
|
||||
List<Property> properties = Cache().getProperties();
|
||||
if (properties == null) {
|
||||
return;
|
||||
}
|
||||
final double distortionWidth = mediaWidth / baseWidth;
|
||||
final double distortionHeight = mediaHeight / baseHeight;
|
||||
if (isMan) {
|
||||
properties.forEach((element) {
|
||||
if (element.propertyName == "Shoulder") {
|
||||
element.top = (122 * distortionHeight).toInt();
|
||||
element.left = (130 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Shoulder");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Neck") {
|
||||
element.top = (68 * distortionHeight).toInt();
|
||||
element.left = (130 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Neck");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Biceps") {
|
||||
element.top = (178 * distortionHeight).toInt();
|
||||
element.left = (208 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Biceps");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Chest") {
|
||||
element.top = (154 * distortionHeight).toInt();
|
||||
element.left = (130 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Chest");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Belly") {
|
||||
element.top = (244 * distortionHeight).toInt();
|
||||
element.left = (130 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Belly");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Hip") {
|
||||
element.top = (308 * distortionHeight).toInt();
|
||||
element.left = (130 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Hip");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Thigh Top") {
|
||||
element.top = (332 * distortionHeight).toInt();
|
||||
element.left = (165 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Thigh Top");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Thigh Middle") {
|
||||
element.top = (382 * distortionHeight).toInt();
|
||||
element.left = (100 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Thigh Middle");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Knee") {
|
||||
element.top = (464 * distortionHeight).toInt();
|
||||
element.left = (97 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Knee");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Calf") {
|
||||
element.top = (520 * distortionHeight).toInt();
|
||||
element.left = (97 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Calf");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Ankle") {
|
||||
element.top = (620 * distortionHeight).toInt();
|
||||
element.left = (150 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Ankle");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Weight") {
|
||||
element.top = (402 * distortionHeight).toInt();
|
||||
element.left = (240 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Weight");
|
||||
manSizes.add(element);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
properties.forEach((element) {
|
||||
if (element.propertyName == "Shoulder") {
|
||||
element.top = (122 * distortionHeight).toInt();
|
||||
element.left = (151 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Shoulder");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Neck") {
|
||||
element.top = (78 * distortionHeight).toInt();
|
||||
element.left = (151 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Neck");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Biceps") {
|
||||
element.top = (178 * distortionHeight).toInt();
|
||||
element.left = (212 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Biceps");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Chest") {
|
||||
element.top = (154 * distortionHeight).toInt();
|
||||
element.left = (151 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Chest");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Belly") {
|
||||
element.top = (230 * distortionHeight).toInt();
|
||||
element.left = (151 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Belly");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Hip") {
|
||||
element.top = (294 * distortionHeight).toInt();
|
||||
element.left = (151 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Hip");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Thigh Top") {
|
||||
element.top = (335 * distortionHeight).toInt();
|
||||
element.left = (185 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Thigh Top");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Thigh Middle") {
|
||||
element.top = (377 * distortionHeight).toInt();
|
||||
element.left = (125 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Thigh Middle");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Knee") {
|
||||
element.top = (468 * distortionHeight).toInt();
|
||||
element.left = (129 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Knee");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Calf") {
|
||||
element.top = (525 * distortionHeight).toInt();
|
||||
element.left = (129 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Calf");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Ankle") {
|
||||
element.top = (620 * distortionHeight).toInt();
|
||||
element.left = (162 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Ankle");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Weight") {
|
||||
element.top = (402 * distortionHeight).toInt();
|
||||
element.left = (240 * distortionWidth).toInt();
|
||||
element.value = customerRepository.customer.getProperty("Weight");
|
||||
manSizes.add(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int getWeightCoordinate(isMan, {isTop = false, isLeft = false}) {
|
||||
int value = 0;
|
||||
this.manSizes.forEach((element) {
|
||||
if (element.propertyName == "Weight") {
|
||||
if (isTop == true) {
|
||||
value = element.top;
|
||||
} else if (isLeft == true) {
|
||||
value = element.left;
|
||||
}
|
||||
}
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
Property getPropertyByName(String propertyName) {
|
||||
Property property;
|
||||
List<Property> sizes;
|
||||
if (customerRepository.sex == "Man") {
|
||||
sizes = this.manSizes;
|
||||
} else {
|
||||
sizes = this.womanSizes;
|
||||
}
|
||||
|
||||
sizes.forEach((element) {
|
||||
if (element.propertyName == propertyName) {
|
||||
property = element;
|
||||
}
|
||||
});
|
||||
return property;
|
||||
}
|
||||
|
||||
void updateSizes(String propertyName, double value) {
|
||||
List<Property> sizes;
|
||||
if (customerRepository.sex == "Man") {
|
||||
sizes = this.manSizes;
|
||||
} else {
|
||||
sizes = this.womanSizes;
|
||||
}
|
||||
|
||||
sizes.forEach((element) {
|
||||
if (element.propertyName == propertyName) {
|
||||
element.value = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<ExerciseNewState> mapEventToState(ExerciseNewEvent event) async* {
|
||||
try {
|
||||
@ -358,7 +166,7 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
|
||||
} else if (event is ExerciseNewSizeChange) {
|
||||
yield ExerciseNewLoading();
|
||||
this.changedSizes = true;
|
||||
this.updateSizes(event.propertyName, event.value);
|
||||
this.customerRepository.updateSizes(event.propertyName, event.value);
|
||||
customerRepository.setCustomerProperty(event.propertyName, event.value);
|
||||
yield ExerciseNewReady();
|
||||
} else if (event is ExerciseNewSubmit) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
import 'package:aitrainer_app/util/session.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
import 'package:aitrainer_app/util/enums.dart';
|
||||
|
106
lib/bloc/timer/timer_bloc.dart
Normal file
@ -0,0 +1,106 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:audioplayer/audioplayer.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
part 'timer_event.dart';
|
||||
part 'timer_state.dart';
|
||||
|
||||
class Ticker {
|
||||
Stream<int> tick({int ticks}) {
|
||||
return Stream.periodic(Duration(seconds: 1), (x) => compute(ticks, x)).take(ticks);
|
||||
}
|
||||
|
||||
int compute(int ticks, int x) {
|
||||
//print("tcik: " + (ticks - x - 1).toString());
|
||||
return ticks - x - 1;
|
||||
}
|
||||
}
|
||||
|
||||
class TimerBloc extends Bloc<TimerEvent, TimerState> {
|
||||
final Ticker _ticker = Ticker();
|
||||
int _duration = 0;
|
||||
|
||||
final AudioPlayer audioPlayer = AudioPlayer();
|
||||
int minutes = 0;
|
||||
int seconds = 0;
|
||||
|
||||
StreamSubscription<int> _tickerSubscription;
|
||||
|
||||
TimerBloc() : super(TimerReady(300));
|
||||
|
||||
@override
|
||||
void onTransition(Transition<TimerEvent, TimerState> transition) {
|
||||
super.onTransition(transition);
|
||||
//print(transition);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<TimerState> mapEventToState(
|
||||
TimerEvent event,
|
||||
) async* {
|
||||
if (event is TimerStart) {
|
||||
yield* _mapStartToState(event);
|
||||
} else if (event is TimerPause) {
|
||||
yield* _mapPauseToState(event);
|
||||
} else if (event is TimerResume) {
|
||||
yield* _mapResumeToState(event);
|
||||
} else if (event is TimerReset) {
|
||||
yield* _mapResetToState(event);
|
||||
} else if (event is TimerTick) {
|
||||
yield* _mapTickToState(event);
|
||||
} else if (event is TimerEnd) {
|
||||
print("$event");
|
||||
_tickerSubscription?.cancel();
|
||||
yield TimerFinished(state.duration);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_tickerSubscription?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
Stream<TimerState> _mapStartToState(TimerStart start) async* {
|
||||
//print("$start");
|
||||
yield TimerRunning(start.duration);
|
||||
_tickerSubscription?.cancel();
|
||||
_tickerSubscription = _ticker.tick(ticks: start.duration).listen(
|
||||
(localDuration) {
|
||||
//print("local: $localDuration");
|
||||
add(TimerTick(duration: localDuration));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Stream<TimerState> _mapPauseToState(TimerPause pause) async* {
|
||||
if (state is TimerRunning) {
|
||||
_tickerSubscription?.pause();
|
||||
yield TimerPaused(state.duration);
|
||||
}
|
||||
}
|
||||
|
||||
Stream<TimerState> _mapResumeToState(TimerResume pause) async* {
|
||||
if (state is TimerPaused) {
|
||||
_tickerSubscription?.resume();
|
||||
yield TimerRunning(state.duration);
|
||||
}
|
||||
}
|
||||
|
||||
Stream<TimerState> _mapResetToState(TimerReset reset) async* {
|
||||
this._duration = 0;
|
||||
yield TimerReady(_duration);
|
||||
}
|
||||
|
||||
Stream<TimerState> _mapTickToState(TimerTick tick) async* {
|
||||
//print("tick $tick");
|
||||
yield TickStart(tick.duration);
|
||||
yield tick.duration >= 0 ? TimerRunning(tick.duration) : TimerFinished(tick.duration);
|
||||
}
|
||||
|
||||
Future _play() async {
|
||||
await audioPlayer.play('asset/wine-glass.mp3', isLocal: true);
|
||||
}
|
||||
}
|
41
lib/bloc/timer/timer_event.dart
Normal file
@ -0,0 +1,41 @@
|
||||
part of 'timer_bloc.dart';
|
||||
|
||||
abstract class TimerEvent extends Equatable {
|
||||
const TimerEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class TimerStart extends TimerEvent {
|
||||
final int duration;
|
||||
const TimerStart({this.duration});
|
||||
|
||||
@override
|
||||
String toString() => "TimerStart { duration: $duration }";
|
||||
}
|
||||
|
||||
class TimerEnd extends TimerEvent {
|
||||
final int duration;
|
||||
const TimerEnd({this.duration});
|
||||
}
|
||||
|
||||
class TimerTick extends TimerEvent {
|
||||
final int duration;
|
||||
const TimerTick({this.duration});
|
||||
|
||||
@override
|
||||
String toString() => "Tick { duration: $duration }";
|
||||
}
|
||||
|
||||
class TimerPause extends TimerEvent {
|
||||
const TimerPause();
|
||||
}
|
||||
|
||||
class TimerResume extends TimerEvent {
|
||||
const TimerResume();
|
||||
}
|
||||
|
||||
class TimerReset extends TimerEvent {
|
||||
const TimerReset();
|
||||
}
|
49
lib/bloc/timer/timer_state.dart
Normal file
@ -0,0 +1,49 @@
|
||||
part of 'timer_bloc.dart';
|
||||
|
||||
abstract class TimerState extends Equatable {
|
||||
final int duration;
|
||||
|
||||
TimerState(this.duration, [List props = const []]);
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class TickStart extends TimerState {
|
||||
TickStart(int duration) : super(duration);
|
||||
@override
|
||||
String toString() => 'Start { duration: $duration }';
|
||||
}
|
||||
|
||||
class TimerRunning extends TimerState {
|
||||
TimerRunning(int duration) : super(duration);
|
||||
|
||||
@override
|
||||
String toString() => 'Running { duration: $duration }';
|
||||
}
|
||||
|
||||
class TimerReady extends TimerState {
|
||||
TimerReady(int duration) : super(duration);
|
||||
|
||||
@override
|
||||
String toString() => 'Ready { duration: $duration }';
|
||||
}
|
||||
|
||||
class TimerPaused extends TimerState {
|
||||
TimerPaused(int duration) : super(duration);
|
||||
|
||||
@override
|
||||
String toString() => 'Paused { duration: $duration }';
|
||||
}
|
||||
|
||||
class TimerFinished extends TimerState {
|
||||
TimerFinished(int duration) : super(duration);
|
||||
|
||||
@override
|
||||
String toString() => 'Finished { duration: $duration }';
|
||||
}
|
||||
|
||||
class TimerError extends TimerState {
|
||||
final String message;
|
||||
TimerError(int duration, {this.message}) : super(duration);
|
||||
}
|
161
lib/library/clock.dart
Normal file
@ -0,0 +1,161 @@
|
||||
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'dart:math';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
final temperatureColors = [
|
||||
const Color(0xFFB50DE2), // -20 Celsius , friggin cold
|
||||
const Color(0xFFAE0DE2),
|
||||
const Color(0xFF980DE2),
|
||||
const Color(0xFF8E0DE2),
|
||||
const Color(0xFF810DE2),
|
||||
const Color(0xFF7B0DE2),
|
||||
const Color(0xFF670DE2),
|
||||
const Color(0xFF570DE2),
|
||||
const Color(0xFF4A0DE2),
|
||||
const Color(0xFF410DE2),
|
||||
const Color(0xFF1D0DE2),
|
||||
const Color(0xFF0D4AE2),
|
||||
const Color(0xFF0D57E2),
|
||||
const Color(0xFF0D74E2),
|
||||
const Color(0xFF0DB8E2),
|
||||
const Color(0xFF0DD8E2),
|
||||
const Color(0xFF0DE2BB),
|
||||
const Color(0xFF0DE2A1),
|
||||
const Color(0xFF0DE284),
|
||||
const Color(0xFF0DE25E),
|
||||
const Color(0xFF0DE244),
|
||||
const Color(0xFF84E20D),
|
||||
const Color(0xFFC2E20D),
|
||||
const Color(0xFFE2DF0D),
|
||||
const Color(0xFFE2A10D),
|
||||
const Color(0xFFE2740D),
|
||||
const Color(0xFFE2510D),
|
||||
const Color(0xFFE22D0D),
|
||||
const Color(0xFFE2100D),
|
||||
const Color(0xFFE20D17), // 40 Celsius, rather be dead
|
||||
];
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class Clock extends StatelessWidget {
|
||||
final TimerBloc bloc;
|
||||
final List<Color> colors = temperatureColors;
|
||||
|
||||
Clock({this.bloc});
|
||||
|
||||
// ignore: close_sinks
|
||||
|
||||
final Paint paintSeconds = Paint()
|
||||
..strokeCap = StrokeCap.butt
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 4
|
||||
..isAntiAlias = true;
|
||||
|
||||
final Paint paintMinutes = Paint()
|
||||
..strokeCap = StrokeCap.butt
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 4
|
||||
..isAntiAlias = true;
|
||||
|
||||
final Paint paintHours = Paint()
|
||||
..strokeCap = StrokeCap.butt
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 4
|
||||
..isAntiAlias = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<TimerBloc, TimerState>(builder: (context, state) {
|
||||
if (state is TimerRunning) {
|
||||
return getLayout(bloc.state);
|
||||
} else {
|
||||
return Offstage();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Widget getLayout(TimerState state) {
|
||||
int duration = 300 - state.duration;
|
||||
int seconds = (duration % 60).floor();
|
||||
int minutes = ((duration / 60) % 60).floor();
|
||||
String secondStr = seconds.toString().padLeft(2, '0');
|
||||
String time = minutes == 0 ? "$secondStr" : "$minutes:$secondStr";
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
fit: StackFit.expand,
|
||||
children: <Widget>[
|
||||
Positioned(
|
||||
top: 37,
|
||||
left: (45 - time.length / 2 * 9).toDouble(), //seconds < 10 ? 37 : 30,
|
||||
child: Text(
|
||||
"$time",
|
||||
style: GoogleFonts.kosugi(color: colors[(seconds ~/ 2)], fontSize: 16),
|
||||
)),
|
||||
CustomPaint(painter: ArcPainter(minutes, paintMinutes, 5, constraints.maxHeight * 0.40, 0.15, colors)),
|
||||
CustomPaint(painter: ArcPainter(seconds, paintSeconds, 60, constraints.maxHeight * 0.34, 0.2, colors)),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ArcPainter extends CustomPainter {
|
||||
int _progress;
|
||||
Paint _paint;
|
||||
int _units;
|
||||
double _gap;
|
||||
|
||||
List<Color> _gradient;
|
||||
|
||||
Offset center;
|
||||
double _radius;
|
||||
|
||||
Paint paintMarkerEmpty;
|
||||
|
||||
ArcPainter(
|
||||
this._progress,
|
||||
this._paint,
|
||||
this._units,
|
||||
this._radius,
|
||||
this._gap,
|
||||
this._gradient,
|
||||
) {
|
||||
this.paintMarkerEmpty = Paint()
|
||||
..strokeCap = StrokeCap.butt
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = this._paint.strokeWidth
|
||||
..isAntiAlias = true;
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
center = Offset(size.width / 2, size.height / 2);
|
||||
var rect = Rect.fromCircle(center: center, radius: this._radius);
|
||||
|
||||
final gradient2 = new SweepGradient(
|
||||
startAngle: -pi / 2,
|
||||
endAngle: (-pi / 2) + (pi * 2),
|
||||
tileMode: TileMode.repeated,
|
||||
colors: this._gradient,
|
||||
);
|
||||
|
||||
this._paint.shader = gradient2.createShader(rect);
|
||||
|
||||
this.paintMarkerEmpty.color = this._gradient[0].withOpacity(0.2);
|
||||
|
||||
for (var i = 0; i < this._units; i++) {
|
||||
final double unit = 2 * pi / this._units;
|
||||
double start = unit * i;
|
||||
double to = (((2 * pi) / this._units) + unit);
|
||||
|
||||
canvas.drawArc(rect, (-pi / 2 + start), to * 2 * this._gap, false, i < this._progress ? this._paint : this.paintMarkerEmpty);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ import 'package:aitrainer_app/view/menu_page.dart';
|
||||
import 'package:aitrainer_app/view/mydevelopment_body_page.dart';
|
||||
import 'package:aitrainer_app/view/mydevelopment_muscle_page.dart';
|
||||
import 'package:aitrainer_app/view/mydevelopment_page.dart';
|
||||
import 'package:aitrainer_app/view/mydevelopment_sizes_page.dart';
|
||||
import 'package:aitrainer_app/view/myexcercise_plan_page.dart';
|
||||
import 'package:aitrainer_app/view/registration.dart';
|
||||
import 'package:aitrainer_app/view/reset_password.dart';
|
||||
@ -40,7 +41,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:sentry/sentry.dart';
|
||||
import 'bloc/account/account_bloc.dart';
|
||||
@ -51,6 +52,7 @@ import 'bloc/exercise_plan/exercise_plan_bloc.dart';
|
||||
import 'bloc/menu/menu_bloc.dart';
|
||||
import 'bloc/session/session_bloc.dart';
|
||||
import 'bloc/settings/settings_bloc.dart';
|
||||
import 'bloc/timer/timer_bloc.dart';
|
||||
|
||||
const dsn = 'https://5fac40cbfcfb4c15aa80c7a8638d7310@o418565.ingest.sentry.io/5322520';
|
||||
|
||||
@ -145,6 +147,9 @@ Future<Null> main() async {
|
||||
BlocProvider<BodyDevelopmentBloc>(
|
||||
create: (BuildContext context) => BodyDevelopmentBloc(workoutTreeRepository: menuTreeRepository),
|
||||
),
|
||||
BlocProvider<TimerBloc>(
|
||||
create: (BuildContext context) => TimerBloc(),
|
||||
),
|
||||
],
|
||||
child: WorkoutTestApp(),
|
||||
));
|
||||
@ -218,6 +223,7 @@ class WorkoutTestApp extends StatelessWidget {
|
||||
'exerciseExecuteAddPage': (context) => ExerciseExecutePlanAddPage(),
|
||||
'mydevelopmentMusclePage': (context) => MyDevelopmentMusclePage(),
|
||||
'mydevelopmentBodyPage': (context) => MyDevelopmentBodyPage(),
|
||||
'mydevelopmentSizesPage': (context) => SizesDevelopmentPage(),
|
||||
'evaluationPage': (context) => EvaluationPage(),
|
||||
'salesPage': (context) => SalesPage(),
|
||||
},
|
||||
|
@ -62,6 +62,7 @@ class Cache with Logging {
|
||||
static final String serverKey = 'live';
|
||||
static final String hardwareKey = 'hardware';
|
||||
static final String loginTypeKey = 'login_type';
|
||||
static final String timerDisplayKey = 'timer_display';
|
||||
|
||||
static String baseUrl = 'http://aitrainer.info:8888/api/';
|
||||
static final String mediaUrl = 'https://aitrainer.info:4343/media/';
|
||||
@ -421,7 +422,7 @@ class Cache with Logging {
|
||||
int _ecto = customerRepository.getCustomerPropertyValue(PropertyEnum.Ectomorph.toStr()).toInt();
|
||||
int _mezo = customerRepository.getCustomerPropertyValue(PropertyEnum.Mesomorph.toStr()).toInt();
|
||||
int _endo = customerRepository.getCustomerPropertyValue(PropertyEnum.Endomorph.toStr()).toInt();
|
||||
print("endo " + _endo.toString() + " mezo " + _mezo.toString());
|
||||
//print("endo " + _endo.toString() + " mezo " + _mezo.toString());
|
||||
if (this.userLoggedIn != null) {
|
||||
if (this.userLoggedIn.birthYear == null || this.userLoggedIn.birthYear == 0) {
|
||||
setBadge("personalData", true);
|
||||
|
@ -38,9 +38,26 @@ class WorkoutMenuTree {
|
||||
bool executed = false;
|
||||
String exerciseDetail;
|
||||
String nameEnglish;
|
||||
String parentName;
|
||||
String parentNameEnglish;
|
||||
|
||||
WorkoutMenuTree(this.id, this.parent, this.name, this.imageName, this.color, this.fontSize, this.child, this.exerciseTypeId,
|
||||
this.exerciseType, this.base, this.is1RM, this.isEndurance, this.isRunning, this.nameEnglish);
|
||||
WorkoutMenuTree(
|
||||
this.id,
|
||||
this.parent,
|
||||
this.name,
|
||||
this.imageName,
|
||||
this.color,
|
||||
this.fontSize,
|
||||
this.child,
|
||||
this.exerciseTypeId,
|
||||
this.exerciseType,
|
||||
this.base,
|
||||
this.is1RM,
|
||||
this.isEndurance,
|
||||
this.isRunning,
|
||||
this.nameEnglish,
|
||||
this.parentName,
|
||||
this.parentNameEnglish);
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
|
@ -11,6 +11,7 @@ import 'package:aitrainer_app/service/customer_service.dart';
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
import 'package:aitrainer_app/service/product_test_service.dart';
|
||||
import 'package:aitrainer_app/service/purchase_service.dart';
|
||||
import 'package:aitrainer_app/util/enums.dart';
|
||||
import 'package:aitrainer_app/util/not_found_exception.dart';
|
||||
|
||||
class GenderItem {
|
||||
@ -25,6 +26,14 @@ class CustomerRepository with Logging {
|
||||
List<Customer> _trainees;
|
||||
List<CustomerProperty> _allProperties;
|
||||
final PropertyRepository propertyRepository = PropertyRepository();
|
||||
final List<Property> womanSizes = List();
|
||||
final List<Property> manSizes = List();
|
||||
|
||||
final double baseWidth = 312;
|
||||
final double baseHeight = 675.2;
|
||||
double mediaWidth = 0;
|
||||
double mediaHeight = 0;
|
||||
bool isMan = true;
|
||||
|
||||
//List<CustomerRepository> customerList = List<CustomerRepository>();
|
||||
bool visibleDetails = false;
|
||||
@ -32,10 +41,10 @@ class CustomerRepository with Logging {
|
||||
|
||||
CustomerRepository({this.customer}) {
|
||||
customer = Customer();
|
||||
genders = [
|
||||
GenderItem("m", "Man"),
|
||||
GenderItem("w", "Woman"),
|
||||
];
|
||||
|
||||
if (Cache().userLoggedIn != null) {
|
||||
isMan = (Cache().userLoggedIn.sex == "m");
|
||||
}
|
||||
}
|
||||
|
||||
String getGenderByName(String name) {
|
||||
@ -297,4 +306,194 @@ class CustomerRepository with Logging {
|
||||
Future<void> addProductTest(ProductTest productTest) async {
|
||||
await ProductTestApi().saveProductTest(productTest);
|
||||
}
|
||||
|
||||
void setMediaDimensions(double width, double height) {
|
||||
this.mediaHeight = height;
|
||||
this.mediaWidth = width;
|
||||
this.addSizes(this.sex);
|
||||
}
|
||||
|
||||
void addSizes(String sex) {
|
||||
List<Property> properties = Cache().getProperties();
|
||||
if (properties == null) {
|
||||
return;
|
||||
}
|
||||
final double distortionWidth = mediaWidth / baseWidth;
|
||||
final double distortionHeight = mediaHeight / baseHeight;
|
||||
if (isMan) {
|
||||
properties.forEach((element) {
|
||||
if (element.propertyName == "Shoulder") {
|
||||
element.top = (122 * distortionHeight).toInt();
|
||||
element.left = (130 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Shoulder");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Neck") {
|
||||
element.top = (68 * distortionHeight).toInt();
|
||||
element.left = (130 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Neck");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Biceps") {
|
||||
element.top = (178 * distortionHeight).toInt();
|
||||
element.left = (208 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Biceps");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Chest") {
|
||||
element.top = (154 * distortionHeight).toInt();
|
||||
element.left = (130 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Chest");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Belly") {
|
||||
element.top = (244 * distortionHeight).toInt();
|
||||
element.left = (130 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Belly");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Hip") {
|
||||
element.top = (308 * distortionHeight).toInt();
|
||||
element.left = (130 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Hip");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Thigh Top") {
|
||||
element.top = (332 * distortionHeight).toInt();
|
||||
element.left = (165 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Thigh Top");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Thigh Middle") {
|
||||
element.top = (382 * distortionHeight).toInt();
|
||||
element.left = (100 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Thigh Middle");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Knee") {
|
||||
element.top = (464 * distortionHeight).toInt();
|
||||
element.left = (97 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Knee");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Calf") {
|
||||
element.top = (520 * distortionHeight).toInt();
|
||||
element.left = (97 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Calf");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Ankle") {
|
||||
element.top = (620 * distortionHeight).toInt();
|
||||
element.left = (150 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Ankle");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Weight") {
|
||||
element.top = (402 * distortionHeight).toInt();
|
||||
element.left = (240 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Weight");
|
||||
manSizes.add(element);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
properties.forEach((element) {
|
||||
if (element.propertyName == "Shoulder") {
|
||||
element.top = (122 * distortionHeight).toInt();
|
||||
element.left = (151 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Shoulder");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Neck") {
|
||||
element.top = (78 * distortionHeight).toInt();
|
||||
element.left = (151 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Neck");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Biceps") {
|
||||
element.top = (178 * distortionHeight).toInt();
|
||||
element.left = (212 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Biceps");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Chest") {
|
||||
element.top = (154 * distortionHeight).toInt();
|
||||
element.left = (151 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Chest");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Belly") {
|
||||
element.top = (230 * distortionHeight).toInt();
|
||||
element.left = (151 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Belly");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Hip") {
|
||||
element.top = (294 * distortionHeight).toInt();
|
||||
element.left = (151 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Hip");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Thigh Top") {
|
||||
element.top = (335 * distortionHeight).toInt();
|
||||
element.left = (185 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Thigh Top");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Thigh Middle") {
|
||||
element.top = (377 * distortionHeight).toInt();
|
||||
element.left = (125 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Thigh Middle");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Knee") {
|
||||
element.top = (468 * distortionHeight).toInt();
|
||||
element.left = (129 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Knee");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Calf") {
|
||||
element.top = (525 * distortionHeight).toInt();
|
||||
element.left = (129 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Calf");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Ankle") {
|
||||
element.top = (620 * distortionHeight).toInt();
|
||||
element.left = (162 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Ankle");
|
||||
manSizes.add(element);
|
||||
} else if (element.propertyName == "Weight") {
|
||||
element.top = (402 * distortionHeight).toInt();
|
||||
element.left = (240 * distortionWidth).toInt();
|
||||
element.value = this.customer.getProperty("Weight");
|
||||
manSizes.add(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int getWeightCoordinate(isMan, {isTop = false, isLeft = false}) {
|
||||
int value = 0;
|
||||
this.manSizes.forEach((element) {
|
||||
if (element.propertyName == SizesEnum.Weight.toStr()) {
|
||||
if (isTop == true) {
|
||||
value = element.top;
|
||||
} else if (isLeft == true) {
|
||||
value = element.left;
|
||||
}
|
||||
}
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
Property getPropertyByName(String propertyName) {
|
||||
Property property;
|
||||
List<Property> sizes;
|
||||
if (this.sex == "m") {
|
||||
sizes = this.manSizes;
|
||||
} else {
|
||||
sizes = this.womanSizes;
|
||||
}
|
||||
|
||||
sizes.forEach((element) {
|
||||
if (element.propertyName == propertyName) {
|
||||
property = element;
|
||||
}
|
||||
});
|
||||
return property;
|
||||
}
|
||||
|
||||
void updateSizes(String propertyName, double value) {
|
||||
List<Property> sizes;
|
||||
if (this.sex == "m") {
|
||||
sizes = this.manSizes;
|
||||
} else {
|
||||
sizes = this.womanSizes;
|
||||
}
|
||||
|
||||
sizes.forEach((element) {
|
||||
if (element.propertyName == propertyName) {
|
||||
element.value = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/customer.dart';
|
||||
import 'package:aitrainer_app/model/exercise.dart';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'dart:collection';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/exercise_ability.dart';
|
||||
import 'package:aitrainer_app/model/exercise_tree.dart';
|
||||
@ -35,6 +35,7 @@ class WorkoutTreeRepository with Logging {
|
||||
SplayTreeMap sortedTree = SplayTreeMap<String, List<WorkoutMenuTree>>();
|
||||
bool isEnglish;
|
||||
WorkoutType workoutType;
|
||||
final List<WorkoutMenuTree> menuAsExercise = List();
|
||||
|
||||
final Map<String, int> _antagonist = {
|
||||
Antagonist.chest: Antagonist.chestNr,
|
||||
@ -85,23 +86,24 @@ class WorkoutTreeRepository with Logging {
|
||||
if (isRunning == false && treeItem.parentId != 0) {
|
||||
isRunning = isParentRunning(treeItem.parentId);
|
||||
}
|
||||
|
||||
WorkoutMenuTree parent = getParentItem(treeItem.parentId);
|
||||
WorkoutMenuTree menuItem = WorkoutMenuTree(
|
||||
treeItem.treeId,
|
||||
treeItem.parentId,
|
||||
treeName,
|
||||
treeItem.imageUrl,
|
||||
Colors.white,
|
||||
30,
|
||||
false,
|
||||
0,
|
||||
null,
|
||||
false,
|
||||
is1RM,
|
||||
isEndurance,
|
||||
isRunning,
|
||||
treeItem.name,
|
||||
);
|
||||
treeItem.treeId,
|
||||
treeItem.parentId,
|
||||
treeName,
|
||||
treeItem.imageUrl,
|
||||
Colors.white,
|
||||
30,
|
||||
false,
|
||||
0,
|
||||
null,
|
||||
false,
|
||||
is1RM,
|
||||
isEndurance,
|
||||
isRunning,
|
||||
treeItem.name,
|
||||
parent != null ? parent.name : "",
|
||||
parent != null ? parent.nameEnglish : "");
|
||||
menuItem = this.setWorkoutTypes(menuItem, treeItem);
|
||||
this.tree[treeItem.name + "_" + treeItem.parentId.toString()] = menuItem;
|
||||
//log("WorkoutMenuTree item " + menuItem.toJson().toString());
|
||||
@ -113,6 +115,7 @@ class WorkoutTreeRepository with Logging {
|
||||
exerciseType.active == true) {
|
||||
String exerciseTypeName = isEnglish ? exerciseType.name : exerciseType.nameTranslation;
|
||||
//String assetImage = await _buildImage(exerciseType.imageUrl); //'asset/menu/' + exerciseType.imageUrl.substring(7);
|
||||
|
||||
if (exerciseType.parents.isNotEmpty) {
|
||||
exerciseType.parents.forEach((parentId) {
|
||||
bool is1RM = this.isParent1RM(parentId);
|
||||
@ -121,6 +124,7 @@ class WorkoutTreeRepository with Logging {
|
||||
if (isEndurance) exerciseType.setAbility(ExerciseAbility.endurance);
|
||||
bool isRunning = this.isParentRunning(parentId);
|
||||
if (isRunning) exerciseType.setAbility(ExerciseAbility.running);
|
||||
WorkoutMenuTree parent = getParentItem(parentId);
|
||||
WorkoutMenuTree menuItem = WorkoutMenuTree(
|
||||
exerciseType.exerciseTypeId,
|
||||
parentId,
|
||||
@ -135,8 +139,11 @@ class WorkoutTreeRepository with Logging {
|
||||
is1RM,
|
||||
isEndurance,
|
||||
isRunning,
|
||||
exerciseType.name);
|
||||
exerciseType.name,
|
||||
parent != null ? parent.name : "",
|
||||
parent != null ? parent.nameEnglish : "");
|
||||
this.tree[exerciseType.name] = menuItem;
|
||||
menuAsExercise.add(menuItem);
|
||||
//log("WorkoutMenuTree item " + menuItem.toJson().toString());
|
||||
/* log("ExerciseType in Menu item " +
|
||||
exerciseType.toJson().toString() +
|
||||
@ -156,6 +163,7 @@ class WorkoutTreeRepository with Logging {
|
||||
Cache().setWorkoutMenuTree(tree);
|
||||
ExerciseRepository exerciseRepository = ExerciseRepository();
|
||||
exerciseRepository.getBaseExerciseFinishedPercent();
|
||||
menuAsExercise.sort((a, b) => a.name.compareTo(b.name));
|
||||
}
|
||||
|
||||
WorkoutMenuTree setWorkoutTypes(WorkoutMenuTree menu, ExerciseTree treeItem) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||
import 'package:aitrainer_app/repository/user_repository.dart';
|
||||
|
@ -36,7 +36,7 @@ enum TrackingEvent {
|
||||
my_special_plan,
|
||||
my_suggested_plan,
|
||||
prediction,
|
||||
|
||||
search,
|
||||
exercise_device,
|
||||
customer_change,
|
||||
settings_lang,
|
||||
@ -62,3 +62,11 @@ extension PropertyExt on PropertyEnum {
|
||||
bool equalsTo(PropertyEnum event) => this.toString() == event.toString();
|
||||
bool equalsStringTo(String event) => this.toString() == event;
|
||||
}
|
||||
|
||||
enum SizesEnum { Weight, Height, Shoulder, Neck, Biceps, Chest, Belly, Hip, ThighTop, ThighMiddle, Knee, Calf, Ankle, Underarm, Lowerarm }
|
||||
|
||||
extension SizesExt on SizesEnum {
|
||||
String toStr() => this.toString().split(".").last;
|
||||
bool equalsTo(SizesEnum event) => this.toString() == event.toString();
|
||||
bool equalsStringTo(String event) => this.toString() == event;
|
||||
}
|
||||
|
@ -1,231 +0,0 @@
|
||||
/*
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/product.dart';
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
import 'package:in_app_purchase/in_app_purchase.dart';
|
||||
|
||||
class PlatformPurchaseApi with Logging {
|
||||
static final PlatformPurchaseApi _singleton = PlatformPurchaseApi._internal();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
PlatformPurchaseApi._internal();
|
||||
|
||||
Future<void> close() async {
|
||||
_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;
|
||||
}
|
||||
|
||||
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> initPurchasePlatform() async {
|
||||
if (_productList.length > 0) {
|
||||
return;
|
||||
}
|
||||
log(' --- InappPurchase connection: $_connection');
|
||||
log(" --- Init PurchasePlatform");
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void _handleInvalidPurchase(PurchaseDetails purchaseDetails) {
|
||||
// handle invalid purchase here if _verifyPurchase` failed.
|
||||
log("Invalid Purchase" + purchaseDetails.toString());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void getSubscriptions() {
|
||||
Cache().products.forEach((element) {
|
||||
Product product = element as Product;
|
||||
if (Platform.isAndroid) {
|
||||
if (product.productIdAndroid != null && product.productIdAndroid.isNotEmpty) {
|
||||
_productList.add(product.productIdAndroid);
|
||||
}
|
||||
} else {
|
||||
if (product.productIdIos != null && product.productIdIos.isNotEmpty) {
|
||||
_productList.add(product.productIdIos);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_productList.forEach((element) {
|
||||
print(element);
|
||||
});
|
||||
}
|
||||
|
||||
void purchase(Product product) {
|
||||
if (product == null) {
|
||||
throw Exception("No product to purchase");
|
||||
}
|
||||
String productId = Platform.isAndroid ? product.productIdAndroid : product.productIdIos;
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
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`.
|
||||
}
|
||||
}
|
||||
*/
|
@ -34,7 +34,8 @@ class RevenueCatPurchases with Logging {
|
||||
Future<void> restore() async {
|
||||
if (appUserId != null) {
|
||||
try {
|
||||
PurchaserInfo purchaserInfo = await Purchases.restoreTransactions();
|
||||
//PurchaserInfo purchaserInfo = await Purchases.restoreTransactions();
|
||||
PurchaserInfo purchaserInfo = await Purchases.getPurchaserInfo();
|
||||
if (purchaserInfo != null &&
|
||||
purchaserInfo.entitlements.all["wt_subscription"] != null &&
|
||||
purchaserInfo.entitlements.all["wt_subscription"].isActive) {
|
||||
|
@ -1,15 +1,11 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/main.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/service/api.dart';
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
import 'package:aitrainer_app/service/package_service.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:aitrainer_app/util/track.dart';
|
||||
import 'package:devicelocale/devicelocale.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
mixin Trans {
|
||||
|
@ -2,12 +2,10 @@ import 'dart:collection';
|
||||
|
||||
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
|
||||
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/customer.dart';
|
||||
import 'package:aitrainer_app/repository/customer_repository.dart';
|
||||
import 'package:aitrainer_app/util/common.dart';
|
||||
import 'package:aitrainer_app/util/enums.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:aitrainer_app/widgets/app_bar_min.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:aitrainer_app/bloc/custom_exercise_form_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
|
@ -2,7 +2,7 @@ import 'dart:collection';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:aitrainer_app/bloc/body_type/bodytype_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/repository/customer_repository.dart';
|
||||
import 'package:aitrainer_app/util/enums.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
@ -44,7 +44,7 @@ class _CustomerBodyTypeAnimationPageState extends State<CustomerBodyTypeAnimatio
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('asset/image/WT_black_G_background.jpg'),
|
||||
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
|
||||
fit: BoxFit.cover,
|
||||
alignment: Alignment.topCenter,
|
||||
),
|
||||
@ -445,8 +445,8 @@ class _QuestionState extends State<Question> with TickerProviderStateMixin {
|
||||
}
|
||||
|
||||
void buildAnimation() {
|
||||
_controller = AnimationController(duration: const Duration(milliseconds: 1000), vsync: this);
|
||||
_animation = CurvedAnimation(parent: _controller, curve: Curves.slowMiddle);
|
||||
_controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
|
||||
_animation = CurvedAnimation(parent: _controller, curve: Curves.fastOutSlowIn);
|
||||
|
||||
_controller.forward();
|
||||
}
|
||||
|
@ -1,220 +0,0 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
|
||||
import 'package:aitrainer_app/repository/customer_repository.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:aitrainer_app/widgets/app_bar_min.dart';
|
||||
import 'package:aitrainer_app/widgets/app_bar_progress.dart';
|
||||
import 'package:aitrainer_app/widgets/dialog_html.dart';
|
||||
import 'package:badges/badges.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class CustomerBodyTypePage extends StatefulWidget {
|
||||
_CustomerBodyTypePageState _state;
|
||||
|
||||
_CustomerBodyTypePageState createState() {
|
||||
_state = _CustomerBodyTypePageState();
|
||||
return _state;
|
||||
}
|
||||
}
|
||||
|
||||
class BodyTypeItem {
|
||||
static String endomorph = "endomorph";
|
||||
static String ectomorph = "ectomorph";
|
||||
static String mesomorph = "mesomorph";
|
||||
}
|
||||
|
||||
class _CustomerBodyTypePageState extends State<CustomerBodyTypePage> with Trans {
|
||||
String selected;
|
||||
bool fulldata = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
CustomerRepository customerRepository;
|
||||
dynamic args = ModalRoute.of(context).settings.arguments;
|
||||
if (args is HashMap && args['personal_data'] != null) {
|
||||
fulldata = args['personal_data'];
|
||||
customerRepository = args['bloc'];
|
||||
} else {
|
||||
customerRepository = ModalRoute.of(context).settings.arguments;
|
||||
}
|
||||
final double cWidth = MediaQuery.of(context).size.width * 0.75;
|
||||
setContext(context);
|
||||
|
||||
return Scaffold(
|
||||
appBar: fulldata
|
||||
? AppBarMin(
|
||||
back: true,
|
||||
)
|
||||
: AppBarProgress(min: 76, max: 100),
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('asset/image/WT_light_background.jpg'),
|
||||
fit: BoxFit.cover,
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
),
|
||||
child: BlocProvider(
|
||||
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
|
||||
child: Builder(builder: (context) {
|
||||
// ignore: close_sinks
|
||||
CustomerChangeBloc changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Divider(),
|
||||
Wrap(
|
||||
//runAlignment: WrapAlignment.center,
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
t("Your Body Type"),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Colors.orange, fontSize: 42, fontFamily: 'Arial', fontWeight: FontWeight.w900),
|
||||
)
|
||||
]),
|
||||
Divider(),
|
||||
Badge(
|
||||
badgeColor: customerRepository.bodyType == BodyTypeItem.ectomorph ? Colors.orange[200] : Colors.blue[50],
|
||||
badgeContent: GestureDetector(
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogHTML(
|
||||
title: t("Ectomorph"),
|
||||
htmlData: t("Ectomorph_desc"),
|
||||
);
|
||||
})
|
||||
},
|
||||
child: Icon(Icons.info_outline_rounded),
|
||||
),
|
||||
child: FlatButton(
|
||||
child: Container(
|
||||
width: cWidth,
|
||||
child: Column(
|
||||
children: [
|
||||
InkWell(
|
||||
child: Text(
|
||||
t("Ectomorph"),
|
||||
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
|
||||
),
|
||||
highlightColor: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.all(10.0),
|
||||
shape: getShape(customerRepository, BodyTypeItem.ectomorph),
|
||||
onPressed: () => {
|
||||
setState(() {
|
||||
selected = BodyTypeItem.ectomorph;
|
||||
changeBloc.add(CustomerBodyTypeChange(bodyType: selected));
|
||||
}),
|
||||
})),
|
||||
Divider(),
|
||||
Badge(
|
||||
badgeColor: customerRepository.bodyType == BodyTypeItem.endomorph ? Colors.orange : Colors.blue[50],
|
||||
badgeContent: GestureDetector(
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogHTML(
|
||||
title: t("Endomorph"),
|
||||
htmlData: t("Endomorph_desc"),
|
||||
);
|
||||
})
|
||||
},
|
||||
child: Icon(Icons.info_outline_rounded)),
|
||||
child: FlatButton(
|
||||
child: Container(
|
||||
width: cWidth,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(t("Endomorph"),
|
||||
textWidthBasis: TextWidthBasis.longestLine,
|
||||
style:
|
||||
TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900)),
|
||||
],
|
||||
)),
|
||||
padding: EdgeInsets.all(10.0),
|
||||
shape: getShape(customerRepository, BodyTypeItem.endomorph),
|
||||
onPressed: () => {
|
||||
setState(() {
|
||||
selected = BodyTypeItem.endomorph;
|
||||
changeBloc.add(CustomerBodyTypeChange(bodyType: selected));
|
||||
}),
|
||||
})),
|
||||
Divider(),
|
||||
Badge(
|
||||
badgeColor: customerRepository.bodyType == BodyTypeItem.mesomorph ? Colors.orange[200] : Colors.blue[50],
|
||||
badgeContent: GestureDetector(
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogHTML(
|
||||
title: t("Mesomorph"),
|
||||
htmlData: t("Mesomorph_desc"),
|
||||
);
|
||||
})
|
||||
},
|
||||
child: Icon(Icons.info_outline_rounded),
|
||||
),
|
||||
child: FlatButton(
|
||||
child: Container(
|
||||
width: cWidth,
|
||||
child: Column(
|
||||
children: [
|
||||
InkWell(
|
||||
child: Text(
|
||||
t("Mesomorph"),
|
||||
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
|
||||
),
|
||||
highlightColor: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.all(10.0),
|
||||
shape: getShape(customerRepository, BodyTypeItem.mesomorph),
|
||||
onPressed: () => {
|
||||
setState(() {
|
||||
selected = BodyTypeItem.mesomorph;
|
||||
changeBloc.add(CustomerBodyTypeChange(bodyType: selected));
|
||||
}),
|
||||
})),
|
||||
Divider(),
|
||||
RaisedButton(
|
||||
color: Colors.orange,
|
||||
textColor: Colors.white,
|
||||
child: Text(fulldata ? t("Save") : t("Next")),
|
||||
onPressed: () => {
|
||||
changeBloc.add(CustomerSave()),
|
||||
Navigator.of(context).pop(),
|
||||
if (fulldata == false) {Navigator.of(context).pushNamed("customerWelcomePage", arguments: customerRepository)}
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
})),
|
||||
));
|
||||
}
|
||||
|
||||
dynamic getShape(CustomerRepository customerRepository, String fitnessLevel) {
|
||||
String selected = customerRepository.bodyType;
|
||||
dynamic returnCode = (selected == fitnessLevel)
|
||||
? RoundedRectangleBorder(
|
||||
side: BorderSide(width: 4, color: Colors.orange),
|
||||
)
|
||||
: RoundedRectangleBorder(
|
||||
side: BorderSide(width: 1, color: Colors.blue),
|
||||
);
|
||||
//return
|
||||
return returnCode;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import 'package:aitrainer_app/bloc/customer_exercise_device/customer_exercise_device_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/exercise_device.dart';
|
||||
import 'package:aitrainer_app/repository/customer_exercise_device_repository.dart';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/repository/customer_repository.dart';
|
||||
import 'package:aitrainer_app/model/fitness_state.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/repository/customer_repository.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:aitrainer_app/widgets/app_bar_min.dart';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/widgets/app_bar_min.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
@ -2,7 +2,7 @@ import 'dart:collection';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:aitrainer_app/bloc/result/result_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/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';
|
||||
|
@ -1,15 +1,16 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:aitrainer_app/bloc/exercise_control/exercise_control_bloc.dart';
|
||||
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
|
||||
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:aitrainer_app/widgets/app_bar.dart';
|
||||
import 'package:aitrainer_app/widgets/bottom_nav.dart';
|
||||
import 'package:aitrainer_app/widgets/dialog_html.dart';
|
||||
import 'package:aitrainer_app/widgets/number_picker.dart';
|
||||
import 'package:aitrainer_app/widgets/timer_widget.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -38,9 +39,12 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
|
||||
final double percent = arguments['percent'];
|
||||
final bool readonly = arguments['readonly'];
|
||||
setContext(context);
|
||||
// ignore: close_sinks
|
||||
TimerBloc timerBloc = BlocProvider.of<TimerBloc>(context);
|
||||
|
||||
return BlocProvider(
|
||||
create: (context) => ExerciseControlBloc(exerciseRepository: exerciseRepository, percentToCalculate: percent, readonly: readonly)
|
||||
create: (context) => ExerciseControlBloc(
|
||||
exerciseRepository: exerciseRepository, percentToCalculate: percent, readonly: readonly, timerBloc: timerBloc)
|
||||
..add(ExerciseControlLoad()),
|
||||
child: BlocConsumer<ExerciseControlBloc, ExerciseControlState>(listener: (context, state) {
|
||||
if (state is ExerciseControlError) {
|
||||
@ -53,7 +57,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
|
||||
_controller.animateTo(exerciseBloc.scrollOffset, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
|
||||
}
|
||||
return ModalProgressHUD(
|
||||
child: getControlForm(exerciseBloc),
|
||||
child: getControlForm(exerciseBloc, timerBloc),
|
||||
inAsyncCall: state is ExerciseControlLoading,
|
||||
opacity: 0.5,
|
||||
color: Colors.black54,
|
||||
@ -62,7 +66,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
|
||||
}));
|
||||
}
|
||||
|
||||
Form getControlForm(ExerciseControlBloc exerciseBloc) {
|
||||
Form getControlForm(ExerciseControlBloc exerciseBloc, TimerBloc timerBloc) {
|
||||
this.offset = exerciseBloc.scrollOffset;
|
||||
String exerciseName = AppLanguage().appLocal == Locale("en")
|
||||
? exerciseBloc.exerciseRepository.exerciseType.name
|
||||
@ -84,120 +88,63 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
|
||||
alignment: Alignment.topCenter,
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(top: 10, left: 25, right: 25),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
controller: _controller,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
exerciseName,
|
||||
style: GoogleFonts.archivoBlack(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 24,
|
||||
color: Colors.white,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(2.0, 2.0),
|
||||
blurRadius: 6.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(-3.0, 3.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
),
|
||||
overflow: TextOverflow.fade,
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
softWrap: true,
|
||||
),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(t("Your 1RM:"),
|
||||
style: GoogleFonts.inter(
|
||||
color: Colors.yellow[300],
|
||||
fontSize: 18,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(-2.0, -2.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(-3.0, 3.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
)),
|
||||
Text(
|
||||
" " +
|
||||
exerciseBloc.initialRM.toStringAsFixed(0) +
|
||||
" " +
|
||||
exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit,
|
||||
style: GoogleFonts.inter(
|
||||
color: Colors.yellow[300],
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(-2.0, -2.0),
|
||||
blurRadius: 6.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(-3.0, 3.0),
|
||||
blurRadius: 6.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Stack(children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(top: 10, left: 25, right: 25),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
controller: _controller,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
exerciseName,
|
||||
style: GoogleFonts.archivoBlack(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 24,
|
||||
color: Colors.white,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(2.0, 2.0),
|
||||
blurRadius: 6.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(-3.0, 3.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogHTML(
|
||||
title: t("OneRepMax"),
|
||||
htmlData: t("OneRepMax_desc"),
|
||||
);
|
||||
})
|
||||
},
|
||||
child: Icon(CustomIcon.question, color: Colors.yellow[300]))
|
||||
],
|
||||
),
|
||||
Divider(),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.start, children: [
|
||||
Flexible(
|
||||
child: Text(t("Why do you need Exercise Control?"),
|
||||
overflow: TextOverflow.fade,
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
softWrap: true,
|
||||
),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(t("Your 1RM:"),
|
||||
style: GoogleFonts.inter(
|
||||
color: Colors.yellow[300],
|
||||
fontSize: 18,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(2.0, 2.0),
|
||||
blurRadius: 6.0,
|
||||
offset: Offset(-2.0, -2.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Shadow(
|
||||
@ -206,29 +153,91 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
))),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogHTML(
|
||||
title: t("Control Exercise:"),
|
||||
htmlData: t("controlexercise_desc"),
|
||||
);
|
||||
})
|
||||
},
|
||||
child: Icon(CustomIcon.question, color: Colors.yellow[300]))
|
||||
)),
|
||||
Text(
|
||||
" " +
|
||||
exerciseBloc.initialRM.toStringAsFixed(0) +
|
||||
" " +
|
||||
exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit,
|
||||
style: GoogleFonts.inter(
|
||||
color: Colors.yellow[300],
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(-2.0, -2.0),
|
||||
blurRadius: 6.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(-3.0, 3.0),
|
||||
blurRadius: 6.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogHTML(
|
||||
title: t("OneRepMax"),
|
||||
htmlData: t("OneRepMax_desc"),
|
||||
);
|
||||
})
|
||||
},
|
||||
child: Icon(CustomIcon.question, color: Colors.yellow[300]))
|
||||
],
|
||||
),
|
||||
Divider(),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.start, children: [
|
||||
Flexible(
|
||||
child: Text(t("Why do you need Exercise Control?"),
|
||||
style: GoogleFonts.inter(
|
||||
color: Colors.yellow[300],
|
||||
fontSize: 18,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(2.0, 2.0),
|
||||
blurRadius: 6.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(-3.0, 3.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
))),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogHTML(
|
||||
title: t("Control Exercise:"),
|
||||
htmlData: t("controlexercise_desc"),
|
||||
);
|
||||
})
|
||||
},
|
||||
child: Icon(CustomIcon.question, color: Colors.yellow[300]))
|
||||
]),
|
||||
Divider(),
|
||||
numberPickForm(exerciseBloc, 1),
|
||||
Divider(),
|
||||
numberPickForm(exerciseBloc, 2),
|
||||
Divider(),
|
||||
numberPickForm(exerciseBloc, 3),
|
||||
]),
|
||||
Divider(),
|
||||
numberPickForm(exerciseBloc, 1),
|
||||
Divider(),
|
||||
numberPickForm(exerciseBloc, 2),
|
||||
Divider(),
|
||||
numberPickForm(exerciseBloc, 3),
|
||||
]),
|
||||
))),
|
||||
)),
|
||||
TimerWidget(
|
||||
bloc: timerBloc,
|
||||
),
|
||||
])),
|
||||
//bottomNavigationBar: BottomNavigator(bottomNavIndex: 1),
|
||||
),
|
||||
);
|
||||
|
@ -3,7 +3,7 @@ import 'dart:collection';
|
||||
import 'package:aitrainer_app/bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart';
|
||||
import 'package:aitrainer_app/bloc/exercise_execute_plan_add/exercise_execute_plan_add_bloc.dart';
|
||||
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
|
@ -7,7 +7,7 @@ import 'package:aitrainer_app/widgets/dialog_premium.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/exercise.dart';
|
||||
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||
|
@ -3,7 +3,7 @@ import 'dart:collection';
|
||||
import 'package:aitrainer_app/bloc/exercise_new/exercise_new_bloc.dart';
|
||||
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/exercise_ability.dart';
|
||||
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||
|
@ -2,7 +2,7 @@ import 'dart:collection';
|
||||
|
||||
import 'package:aitrainer_app/bloc/exercise_plan/exercise_plan_bloc.dart';
|
||||
import 'package:aitrainer_app/bloc/exercise_plan_custom_add/exercise_plan_custom_add_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
||||
import 'package:aitrainer_app/widgets/app_bar_min.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -2,7 +2,6 @@ import 'dart:io';
|
||||
|
||||
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
|
||||
import 'package:aitrainer_app/bloc/login/login_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/repository/user_repository.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:aitrainer_app/widgets/app_bar_min.dart';
|
||||
@ -183,17 +182,17 @@ class LoginPage extends StatelessWidget with Trans {
|
||||
),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
|
||||
InkWell(
|
||||
child: Text(AppLocalizations.of(context).translate('SignUpLink')),
|
||||
child: Text(t('SignUpLink')),
|
||||
onTap: () => Navigator.of(context).pushNamed('registration'),
|
||||
),
|
||||
Spacer(flex: 2),
|
||||
InkWell(
|
||||
child: Text(AppLocalizations.of(context).translate('I forgot the password')),
|
||||
child: Text(t('I forgot the password')),
|
||||
onTap: () => Navigator.of(context).pushNamed('resetPassword'),
|
||||
),
|
||||
Spacer(flex: 2),
|
||||
InkWell(
|
||||
child: Text(AppLocalizations.of(context).translate('Privacy')),
|
||||
child: Text(t('Privacy')),
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
|
@ -83,15 +83,12 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
|
||||
),
|
||||
backgroundColor: Colors.orange,
|
||||
));
|
||||
} else if (state is DevelopmentByMuscleLoadingState) {
|
||||
//LoadingDialog.show(context);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
if (state is DevelopmentByMuscleStateInitial) {
|
||||
return Container();
|
||||
} else {
|
||||
//LoadingDialog.hide(context);
|
||||
return TreeView(
|
||||
startExpanded: false,
|
||||
children: _getTreeChildren(bloc.workoutTreeRepository.sortedTree, bloc),
|
||||
|
@ -77,6 +77,25 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
|
||||
},
|
||||
isLocked: true,
|
||||
),
|
||||
/* ImageButton(
|
||||
width: imageWidth,
|
||||
textAlignment: Alignment.topLeft,
|
||||
text: t("My Sizes Development"),
|
||||
style: GoogleFonts.robotoMono(
|
||||
textStyle: TextStyle(
|
||||
fontSize: 14, color: Colors.white, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4)),
|
||||
),
|
||||
image: "asset/image/testemfejl400x400.jpg",
|
||||
left: 5,
|
||||
onTap: () => {
|
||||
if (Cache().userLoggedIn != null)
|
||||
{
|
||||
args['customerId'] = Cache().userLoggedIn.customerId,
|
||||
Navigator.of(context).pushNamed('mydevelopmentSizesPage', arguments: args)
|
||||
}
|
||||
},
|
||||
isLocked: true,
|
||||
), */
|
||||
ImageButton(
|
||||
width: imageWidth,
|
||||
textAlignment: Alignment.topLeft,
|
||||
|
196
lib/view/mydevelopment_sizes_page.dart
Normal file
@ -0,0 +1,196 @@
|
||||
import 'package:aitrainer_app/bloc/development_sizes/development_sizes_bloc.dart';
|
||||
import 'package:aitrainer_app/model/property.dart';
|
||||
import 'package:aitrainer_app/repository/customer_repository.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:modal_progress_hud/modal_progress_hud.dart';
|
||||
import '../widgets/app_bar.dart';
|
||||
import '../widgets/input_dialog_widget.dart';
|
||||
|
||||
class SizesDevelopmentPage extends StatefulWidget {
|
||||
const SizesDevelopmentPage();
|
||||
|
||||
@override
|
||||
_SizeState createState() => _SizeState();
|
||||
}
|
||||
|
||||
class _SizeState extends State<SizesDevelopmentPage> with Trans {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
setContext(context);
|
||||
return BlocProvider(
|
||||
create: (context) => DevelopmentSizesBloc(customerRepository: CustomerRepository())..add(DevelopmentSizesLoad()),
|
||||
child: BlocConsumer<DevelopmentSizesBloc, DevelopmentSizesState>(listener: (context, state) {
|
||||
if (state is DevelopmentSizesError) {
|
||||
Scaffold.of(context)
|
||||
.showSnackBar(SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
|
||||
}
|
||||
}, builder: (context, state) {
|
||||
final bloc = BlocProvider.of<DevelopmentSizesBloc>(context);
|
||||
return ModalProgressHUD(
|
||||
child: getForm(bloc),
|
||||
inAsyncCall: state is DevelopmentSizesLoad,
|
||||
opacity: 0.5,
|
||||
color: Colors.black54,
|
||||
progressIndicator: CircularProgressIndicator(),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Widget getForm(DevelopmentSizesBloc bloc) {
|
||||
return Form(
|
||||
child: Scaffold(
|
||||
resizeToAvoidBottomInset: true,
|
||||
appBar: AppBarNav(depth: 1),
|
||||
body: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height,
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('asset/image/WT_black_background.jpg'),
|
||||
fit: BoxFit.fill,
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: getSizeFigure(bloc),
|
||||
)
|
||||
]))),
|
||||
)));
|
||||
}
|
||||
|
||||
List<Widget> getSizeFigure(DevelopmentSizesBloc bloc) {
|
||||
double mediaWidth = MediaQuery.of(context).size.width * .8;
|
||||
double mediaHeight = MediaQuery.of(context).size.height * .8;
|
||||
|
||||
bloc.customerRepository.setMediaDimensions(mediaWidth, mediaHeight);
|
||||
List<Widget> list = List();
|
||||
|
||||
list.add(
|
||||
bloc.isMan
|
||||
? Image.asset(
|
||||
"asset/image/man_sizes.png",
|
||||
height: mediaHeight,
|
||||
width: mediaWidth,
|
||||
)
|
||||
: Image.asset(
|
||||
"asset/image/woman_sizes.png",
|
||||
height: mediaHeight,
|
||||
width: mediaWidth,
|
||||
),
|
||||
);
|
||||
list.add(Positioned(
|
||||
top: bloc.customerRepository.getWeightCoordinate(bloc.isMan, isTop: true).toDouble(),
|
||||
left: bloc.customerRepository.getWeightCoordinate(bloc.isMan, isTop: false, isLeft: true).toDouble() - 45,
|
||||
child: GestureDetector(
|
||||
//onTap: () => onPressed(bloc.customerRepository.getPropertyByName("Weight")),
|
||||
child: Image.asset(
|
||||
"asset/image/merleg.png",
|
||||
height: 120,
|
||||
width: 120,
|
||||
color: Colors.blue,
|
||||
)),
|
||||
));
|
||||
|
||||
list.addAll(getSizeElements(bloc));
|
||||
list.add(
|
||||
Positioned(
|
||||
top: mediaHeight * .07,
|
||||
left: bloc.isMan ? mediaWidth * .62 : mediaWidth * .65,
|
||||
child: Stack(
|
||||
alignment: Alignment.topLeft,
|
||||
children: [
|
||||
SizedBox(height: 80, width: 100),
|
||||
Text(t("Your Size Diagrams"),
|
||||
maxLines: 2,
|
||||
style: GoogleFonts.archivoBlack(
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(5.0, 5.0),
|
||||
blurRadius: 3.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
fontSize: 20,
|
||||
color: Colors.orange[500],
|
||||
)),
|
||||
],
|
||||
)),
|
||||
);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
List<Widget> getSizeElements(DevelopmentSizesBloc bloc) {
|
||||
List<Widget> list = List();
|
||||
|
||||
bloc.customerRepository.manSizes.forEach((element) {
|
||||
list.add(
|
||||
Positioned(
|
||||
top: element.top.toDouble(),
|
||||
left: element.left.toDouble(),
|
||||
child: element.value != 0
|
||||
? Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: bloc.isMan ? Colors.green[800] : Color(0xFFEA776C),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(20),
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.zero,
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.trending_up, color: Colors.green),
|
||||
padding: EdgeInsets.zero,
|
||||
color: Colors.red[800],
|
||||
splashColor: Colors.amber,
|
||||
onPressed: () => onPressed(element),
|
||||
))
|
||||
: Container(
|
||||
width: 23,
|
||||
height: 23,
|
||||
padding: EdgeInsets.zero,
|
||||
decoration: BoxDecoration(
|
||||
color: bloc.isMan ? Colors.white10 : Color(0xFFEA776C),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(23),
|
||||
),
|
||||
),
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.trending_up, color: Colors.red),
|
||||
padding: EdgeInsets.zero,
|
||||
color: Colors.red[800],
|
||||
splashColor: Colors.amber,
|
||||
onPressed: () => onPressed(element),
|
||||
))),
|
||||
);
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void onPressed(Property element) {
|
||||
print(element.propertyName);
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => InputDialog(
|
||||
title: t("Size Of Your"),
|
||||
subtitle: element.propertyNameTranslation,
|
||||
initialValue: element.value,
|
||||
onChanged: (value) {
|
||||
//widget.exerciseBloc.add(ExerciseNewSizeChange(propertyName: element.propertyName, value: value));
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ import 'dart:io';
|
||||
|
||||
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
|
||||
import 'package:aitrainer_app/bloc/login/login_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/repository/user_repository.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:aitrainer_app/widgets/app_bar_min.dart';
|
||||
@ -208,12 +207,12 @@ class RegistrationPage extends StatelessWidget with Trans {
|
||||
),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
|
||||
InkWell(
|
||||
child: Text(AppLocalizations.of(context).translate('Login')),
|
||||
child: Text(t('Login')),
|
||||
onTap: () => Navigator.of(context).pushNamed('login'),
|
||||
),
|
||||
Spacer(flex: 2),
|
||||
InkWell(
|
||||
child: Text(AppLocalizations.of(context).translate('Privacy')),
|
||||
child: Text(t('Privacy')),
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'package:aitrainer_app/bloc/reset_password_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/repository/user_repository.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:aitrainer_app/widgets/app_bar_min.dart';
|
||||
@ -77,8 +76,7 @@ class ResetPasswordPage extends StatelessWidget with Trans {
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
new InkWell(
|
||||
child: new Text(AppLocalizations.of(context).translate('I forgot the password'),
|
||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24)),
|
||||
child: new Text(t('I forgot the password'), style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24)),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -119,7 +117,7 @@ class ResetPasswordPage extends StatelessWidget with Trans {
|
||||
),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
|
||||
new InkWell(
|
||||
child: new Text(AppLocalizations.of(context).translate('Login')),
|
||||
child: new Text(t('Login')),
|
||||
onTap: () => Navigator.of(context).pushNamed('login'),
|
||||
),
|
||||
Spacer(flex: 1),
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
|
||||
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/util/common.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
|
@ -1,7 +1,8 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
||||
import 'package:aitrainer_app/util/common.dart';
|
||||
@ -69,6 +70,8 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin, C
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
menuBloc = BlocProvider.of<MenuBloc>(context);
|
||||
// ignore: close_sinks
|
||||
final TimerBloc timerBloc = BlocProvider.of<TimerBloc>(context);
|
||||
|
||||
return AppBar(
|
||||
backgroundColor: Colors.black,
|
||||
@ -91,6 +94,7 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin, C
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.arrow_back, color: Colors.white),
|
||||
onPressed: () => {
|
||||
timerBloc.add(TimerEnd()),
|
||||
if (widget.isMenu != null)
|
||||
{
|
||||
if (menuBloc.workoutItem != null)
|
||||
|
@ -1,7 +1,9 @@
|
||||
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/util/common.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
@ -24,6 +26,8 @@ class _AppBarNav extends State<AppBarMin> with Common {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// ignore: close_sinks
|
||||
final TimerBloc timerBloc = BlocProvider.of<TimerBloc>(context);
|
||||
return AppBar(
|
||||
backgroundColor: Colors.black,
|
||||
title: Row(
|
||||
@ -44,6 +48,7 @@ class _AppBarNav extends State<AppBarMin> with Common {
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.arrow_back, color: widget.back ? Colors.white : Colors.black),
|
||||
onPressed: () => {
|
||||
timerBloc.add(TimerEnd()),
|
||||
if (widget.back) {Navigator.of(context).pop()}
|
||||
},
|
||||
));
|
||||
|
@ -1,6 +1,8 @@
|
||||
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
|
||||
import 'package:aitrainer_app/util/common.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:liquid_progress_indicator/liquid_progress_indicator.dart';
|
||||
|
||||
class AppBarProgress extends StatefulWidget implements PreferredSizeWidget {
|
||||
@ -23,14 +25,12 @@ class _AppBarNav extends State<AppBarProgress> with SingleTickerProviderStateMix
|
||||
_animationController = AnimationController(
|
||||
lowerBound: (widget.min).toDouble(),
|
||||
upperBound: (widget.max).toDouble(),
|
||||
//upperBound: (widget.value / 100).toDouble(),
|
||||
vsync: this,
|
||||
duration: Duration(seconds: 3),
|
||||
);
|
||||
|
||||
_animationController.addListener(() => setState(() {}));
|
||||
_animationController.forward();
|
||||
//Future.delayed(Duration(seconds: 3)).then((value) => _animationController.repeat());
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@ -42,12 +42,15 @@ class _AppBarNav extends State<AppBarProgress> with SingleTickerProviderStateMix
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// ignore: close_sinks
|
||||
final TimerBloc timerBloc = BlocProvider.of<TimerBloc>(context);
|
||||
|
||||
return AppBar(
|
||||
backgroundColor: Colors.black,
|
||||
title: getAnimatedWidget(),
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.arrow_back, color: Colors.white),
|
||||
onPressed: () => {Navigator.of(context).pop()},
|
||||
onPressed: () => {timerBloc.add(TimerEnd()), Navigator.of(context).pop()},
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:aitrainer_app/bloc/exercise_new/exercise_new_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:animated_widgets/widgets/rotation_animated.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
@ -73,7 +73,7 @@ class _BMIState extends State<BMI> with Trans {
|
||||
double mediaWidth = MediaQuery.of(context).size.width * .8;
|
||||
double mediaHeight = MediaQuery.of(context).size.height * .8;
|
||||
//print("w " + mediaWidth.toString() + "h " + mediaHeight.toString());
|
||||
widget.exerciseBloc.setMediaDimensions(mediaWidth, mediaHeight);
|
||||
widget.exerciseBloc.customerRepository.setMediaDimensions(mediaWidth, mediaHeight);
|
||||
widget.exerciseBloc.getBMI();
|
||||
return Form(
|
||||
child: Scaffold(
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:aitrainer_app/bloc/exercise_new/exercise_new_bloc.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/model/fitness_state.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
import 'package:aitrainer_app/util/common.dart';
|
||||
@ -94,7 +94,12 @@ class _NawDrawerWidget extends State<BottomNavigator> with Trans, Logging {
|
||||
backgroundColor: bgrColor,
|
||||
icon: Icon(Icons.settings, color: inactive),
|
||||
activeIcon: Icon(Icons.settings, color: active),
|
||||
title: Text(t("Settings"), style: TextStyle(fontSize: 12)))
|
||||
title: Text(t("Settings"), style: TextStyle(fontSize: 12))),
|
||||
/* BottomNavigationBarItem(
|
||||
backgroundColor: bgrColor,
|
||||
icon: Icon(Icons.multiple_stop, color: inactive),
|
||||
activeIcon: Icon(Icons.multiple_stop, color: active),
|
||||
title: Text(t("Multi test"), style: TextStyle(fontSize: 12))) */
|
||||
],
|
||||
onTap: (index) {
|
||||
setState(() {
|
||||
|
@ -3,8 +3,11 @@ import 'dart:ui';
|
||||
|
||||
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/enums.dart';
|
||||
import 'package:aitrainer_app/util/track.dart';
|
||||
import 'package:aitrainer_app/widgets/menu_search_bar.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/util/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';
|
||||
@ -233,86 +236,50 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||
return sliverList;
|
||||
}
|
||||
|
||||
SliverList getInfoWidget(BuildContext context, MenuBloc menuBloc) {
|
||||
List<Widget> widgets = List();
|
||||
SliverAppBar getInfoWidget(BuildContext context, MenuBloc menuBloc) {
|
||||
menuBloc.setContext(context);
|
||||
menuBloc.setMenuInfo();
|
||||
|
||||
if (context != null) {
|
||||
menuBloc.setContext(context);
|
||||
menuBloc.setMenuInfo();
|
||||
widgets.add(SizedBox(
|
||||
height: 10,
|
||||
));
|
||||
|
||||
widgets.add(
|
||||
GestureDetector(
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return DialogCommon(
|
||||
title: menuBloc.infoTitle,
|
||||
descriptions: menuBloc.infoText,
|
||||
description2: menuBloc.infoText2,
|
||||
description3: menuBloc.infoText3,
|
||||
text: "OK",
|
||||
onTap: () => {Navigator.of(context).pop()},
|
||||
onCancel: () => {Navigator.of(context).pop()},
|
||||
);
|
||||
})
|
||||
},
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: SizedBox(
|
||||
height: 35,
|
||||
child: AnimatedSwitcher(
|
||||
duration: Duration(milliseconds: 800),
|
||||
transitionBuilder: (Widget child, Animation<double> animation) {
|
||||
return ScaleTransition(child: child, scale: animation);
|
||||
},
|
||||
child: isFirst && !wait
|
||||
? Icon(
|
||||
CustomIcon.question_circle,
|
||||
color: Colors.yellow[300],
|
||||
size: 40,
|
||||
)
|
||||
: Offstage())))),
|
||||
);
|
||||
}
|
||||
SliverList sliverList = SliverList(delegate: SliverChildListDelegate(widgets));
|
||||
return sliverList;
|
||||
}
|
||||
|
||||
SliverGrid getInfoWidget2(BuildContext context, MenuBloc menuBloc) {
|
||||
final List<Widget> _columnChildren = List();
|
||||
if (context != null) {
|
||||
menuBloc.setContext(context);
|
||||
menuBloc.setMenuInfo();
|
||||
|
||||
Widget info = MenuInfoWidget(
|
||||
title: menuBloc.infoTitle,
|
||||
titleSize: 18,
|
||||
titleWeight: FontWeight.bold,
|
||||
titleColor: Colors.orangeAccent,
|
||||
text: menuBloc.infoText,
|
||||
textSize: 13,
|
||||
textColor: Colors.yellowAccent,
|
||||
text2: menuBloc.infoText2,
|
||||
text3: menuBloc.infoText3,
|
||||
link: menuBloc.infoLink,
|
||||
bloc: menuBloc,
|
||||
);
|
||||
_columnChildren.add(info);
|
||||
}
|
||||
SliverGrid sliverList = SliverGrid(
|
||||
delegate: SliverChildListDelegate(_columnChildren),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 1,
|
||||
mainAxisSpacing: 5.0,
|
||||
crossAxisSpacing: 5.0,
|
||||
childAspectRatio: 2,
|
||||
));
|
||||
return sliverList;
|
||||
SliverAppBar sliverAppBar = SliverAppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
title: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return DialogCommon(
|
||||
title: menuBloc.infoTitle,
|
||||
descriptions: menuBloc.infoText,
|
||||
description2: menuBloc.infoText2,
|
||||
description3: menuBloc.infoText3,
|
||||
text: "OK",
|
||||
onTap: () => {Navigator.of(context).pop()},
|
||||
onCancel: () => {Navigator.of(context).pop()},
|
||||
);
|
||||
})
|
||||
},
|
||||
child: Icon(
|
||||
CustomIcon.question_circle,
|
||||
color: Colors.orange[400],
|
||||
size: 40,
|
||||
)),
|
||||
MenuSearchBar(
|
||||
listItems: menuBloc.menuTreeRepository.menuAsExercise,
|
||||
onFind: (value) => {
|
||||
Track().track(TrackingEvent.search, eventValue: value.exerciseType.name),
|
||||
Navigator.of(context).pushNamed('exerciseNewPage', arguments: value.exerciseType)
|
||||
},
|
||||
),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
]));
|
||||
return sliverAppBar;
|
||||
}
|
||||
|
||||
void menuClick(WorkoutMenuTree workoutTree, MenuBloc menuBloc, BuildContext context) {
|
||||
|
277
lib/widgets/menu_search_bar.dart
Normal file
@ -0,0 +1,277 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:dropdown_search/dropdown_search.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
class SearchBarStream {
|
||||
static final SearchBarStream _singleton = SearchBarStream._internal();
|
||||
final StreamController<bool> streamController = StreamController<bool>.broadcast();
|
||||
bool searching = false;
|
||||
|
||||
Stream get stream => streamController.stream;
|
||||
StreamController getStreamController() => streamController;
|
||||
|
||||
factory SearchBarStream() => _singleton;
|
||||
|
||||
SearchBarStream._internal();
|
||||
|
||||
void dispose() {
|
||||
streamController.close();
|
||||
}
|
||||
}
|
||||
|
||||
class MenuSearchBar extends StatelessWidget {
|
||||
final List listItems;
|
||||
final Function(WorkoutMenuTree) onFind;
|
||||
|
||||
const MenuSearchBar({@required this.listItems, this.onFind});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedSearch(
|
||||
listItems: listItems,
|
||||
onFind: onFind,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AnimatedSearch extends StatefulWidget {
|
||||
final List listItems;
|
||||
final Function(WorkoutMenuTree) onFind;
|
||||
|
||||
AnimatedSearch({this.listItems, this.onFind});
|
||||
@override
|
||||
_AnimatedSearch createState() => _AnimatedSearch();
|
||||
}
|
||||
|
||||
class _AnimatedSearch extends State<AnimatedSearch> {
|
||||
bool isSearching = false;
|
||||
final Stream stream = SearchBarStream().stream;
|
||||
var subscription;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
subscription = stream.listen((value) {
|
||||
setState(() {
|
||||
isSearching = SearchBarStream().searching;
|
||||
});
|
||||
});
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
subscription.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
AnimateExpansion(
|
||||
animate: !isSearching,
|
||||
axisAlignment: 1.0,
|
||||
child: IconButton(
|
||||
onPressed: () => {
|
||||
setState(() {
|
||||
isSearching = !isSearching;
|
||||
SearchBarStream().searching = isSearching;
|
||||
SearchBarStream().getStreamController().add(true);
|
||||
})
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xffb4f500),
|
||||
size: 40,
|
||||
),
|
||||
)),
|
||||
AnimateExpansion(
|
||||
animate: isSearching,
|
||||
axisAlignment: -1.0,
|
||||
child: Search(
|
||||
listItems: widget.listItems,
|
||||
onFind: widget.onFind,
|
||||
),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class Search extends StatelessWidget with Trans {
|
||||
final List listItems;
|
||||
final Function(WorkoutMenuTree) onFind;
|
||||
|
||||
Search({this.listItems, this.onFind});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
setContext(context);
|
||||
return SizedBox(
|
||||
width: MediaQuery.of(context).size.width * .6,
|
||||
child: DropdownSearch<WorkoutMenuTree>(
|
||||
onPopupDismissed: () => {SearchBarStream().searching = false, SearchBarStream().getStreamController().add(false)},
|
||||
showAsSuffixIcons: false,
|
||||
showSearchBox: true,
|
||||
mode: Mode.DIALOG,
|
||||
showSelectedItem: false,
|
||||
items: listItems,
|
||||
onChanged: (value) => onFind(value),
|
||||
dropdownSearchDecoration: InputDecoration(
|
||||
contentPadding: EdgeInsets.only(left: 15, top: 0, bottom: 5),
|
||||
labelStyle: GoogleFonts.inter(fontSize: 12, color: Colors.yellow[50]),
|
||||
fillColor: Colors.black38,
|
||||
filled: true,
|
||||
border: OutlineInputBorder(
|
||||
gapPadding: 8.0,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
borderSide: BorderSide(color: Colors.white12, width: 0.4),
|
||||
),
|
||||
),
|
||||
searchBoxController: TextEditingController(),
|
||||
searchBoxDecoration: InputDecoration(
|
||||
contentPadding: EdgeInsets.only(left: 15, top: 5, bottom: 5),
|
||||
labelText: t("Search Exercises..."),
|
||||
labelStyle: GoogleFonts.inter(fontSize: 14, color: Colors.grey[400]),
|
||||
fillColor: Colors.white24,
|
||||
filled: true,
|
||||
border: OutlineInputBorder(
|
||||
gapPadding: 8.0,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
borderSide: BorderSide(color: Colors.white12, width: 0.4),
|
||||
),
|
||||
),
|
||||
popupBackgroundColor: Colors.grey[700],
|
||||
popupItemBuilder: (context, item, isSelected) {
|
||||
return Container(
|
||||
margin: EdgeInsets.all(3),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('asset/image/WT_black_G_background.jpg'),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
child: ListTile(
|
||||
selected: isSelected,
|
||||
title: Text(
|
||||
item.name,
|
||||
style: GoogleFonts.inter(color: Colors.yellow[300], fontSize: 16),
|
||||
),
|
||||
subtitle: Text(
|
||||
item.parentName,
|
||||
maxLines: 1,
|
||||
style: GoogleFonts.inter(color: Colors.grey[400]),
|
||||
),
|
||||
leading: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
child: Image.asset(item.imageName),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
emptyBuilder: (context, searchEntry) => Center(
|
||||
child: Text(
|
||||
t("No exercise found"),
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.inter(color: Colors.yellow[200], fontSize: 16),
|
||||
)),
|
||||
dropdownBuilder: (context, WorkoutMenuTree item, itemDesignation) => Container(
|
||||
child: ListView(scrollDirection: Axis.vertical, shrinkWrap: true, children: [
|
||||
(item == null)
|
||||
? Container(
|
||||
height: 15,
|
||||
padding: EdgeInsets.all(0),
|
||||
child: Text(
|
||||
t("Search Exercises..."),
|
||||
style: GoogleFonts.inter(color: Colors.grey[400], fontSize: 14),
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
height: 15,
|
||||
padding: EdgeInsets.all(0),
|
||||
child: Text(
|
||||
item.name,
|
||||
maxLines: 3,
|
||||
style: GoogleFonts.inter(color: Colors.yellow[400], fontSize: 14),
|
||||
),
|
||||
),
|
||||
]))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AnimateExpansion extends StatefulWidget {
|
||||
final Widget child;
|
||||
final bool animate;
|
||||
final double axisAlignment;
|
||||
AnimateExpansion({
|
||||
this.animate = false,
|
||||
this.axisAlignment,
|
||||
this.child,
|
||||
});
|
||||
|
||||
@override
|
||||
_AnimateExpansionState createState() => _AnimateExpansionState();
|
||||
}
|
||||
|
||||
class _AnimateExpansionState extends State<AnimateExpansion> with SingleTickerProviderStateMixin {
|
||||
AnimationController _animationController;
|
||||
Animation<double> _animation;
|
||||
|
||||
void prepareAnimations() {
|
||||
_animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: Duration(milliseconds: 350),
|
||||
);
|
||||
_animation = CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: Curves.easeInCubic,
|
||||
reverseCurve: Curves.easeOutCubic,
|
||||
);
|
||||
}
|
||||
|
||||
void _toggle() {
|
||||
if (widget.animate) {
|
||||
_animationController.forward();
|
||||
} else {
|
||||
_animationController.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
prepareAnimations();
|
||||
_toggle();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(AnimateExpansion oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
_toggle();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizeTransition(axis: Axis.horizontal, axisAlignment: -1.0, sizeFactor: _animation, child: widget.child);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
@ -53,7 +53,7 @@ class _SizeState extends State<SizeWidget> with Trans {
|
||||
double mediaWidth = MediaQuery.of(context).size.width * .8;
|
||||
double mediaHeight = MediaQuery.of(context).size.height * .8;
|
||||
//print("w " + mediaWidth.toString() + "h " + mediaHeight.toString());
|
||||
widget.exerciseBloc.setMediaDimensions(mediaWidth, mediaHeight);
|
||||
widget.exerciseBloc.customerRepository.setMediaDimensions(mediaWidth, mediaHeight);
|
||||
List<Widget> list = List();
|
||||
list.add(GestureDetector(
|
||||
onTap: () => {print("Save"), widget.exerciseBloc.add(ExerciseNewSaveWeight())},
|
||||
@ -63,7 +63,7 @@ class _SizeState extends State<SizeWidget> with Trans {
|
||||
)));
|
||||
|
||||
list.add(
|
||||
widget.exerciseBloc.isMan
|
||||
widget.exerciseBloc.customerRepository.isMan
|
||||
? Image.asset(
|
||||
"asset/image/man_sizes.png",
|
||||
height: mediaHeight,
|
||||
@ -76,10 +76,13 @@ class _SizeState extends State<SizeWidget> with Trans {
|
||||
),
|
||||
);
|
||||
list.add(Positioned(
|
||||
top: widget.exerciseBloc.getWeightCoordinate(widget.exerciseBloc.isMan, isTop: true).toDouble(),
|
||||
left: widget.exerciseBloc.getWeightCoordinate(widget.exerciseBloc.isMan, isTop: false, isLeft: true).toDouble() - 45,
|
||||
top: widget.exerciseBloc.customerRepository.getWeightCoordinate(widget.exerciseBloc.customerRepository.isMan, isTop: true).toDouble(),
|
||||
left: widget.exerciseBloc.customerRepository
|
||||
.getWeightCoordinate(widget.exerciseBloc.customerRepository.isMan, isTop: false, isLeft: true)
|
||||
.toDouble() -
|
||||
45,
|
||||
child: GestureDetector(
|
||||
onTap: () => onPressed(widget.exerciseBloc.getPropertyByName("Weight")),
|
||||
onTap: () => onPressed(widget.exerciseBloc.customerRepository.getPropertyByName("Weight")),
|
||||
child: Image.asset(
|
||||
"asset/image/merleg.png",
|
||||
height: 120,
|
||||
@ -92,7 +95,7 @@ class _SizeState extends State<SizeWidget> with Trans {
|
||||
list.add(
|
||||
Positioned(
|
||||
top: mediaHeight * .07,
|
||||
left: widget.exerciseBloc.isMan ? mediaWidth * .62 : mediaWidth * .65,
|
||||
left: widget.exerciseBloc.customerRepository.isMan ? mediaWidth * .62 : mediaWidth * .65,
|
||||
child: Stack(
|
||||
alignment: Alignment.topLeft,
|
||||
children: [
|
||||
@ -129,7 +132,7 @@ class _SizeState extends State<SizeWidget> with Trans {
|
||||
List<Widget> getSizeElements() {
|
||||
List<Widget> list = List();
|
||||
|
||||
widget.exerciseBloc.manSizes.forEach((element) {
|
||||
widget.exerciseBloc.customerRepository.manSizes.forEach((element) {
|
||||
list.add(
|
||||
Positioned(
|
||||
top: element.top.toDouble(),
|
||||
@ -139,7 +142,7 @@ class _SizeState extends State<SizeWidget> with Trans {
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.exerciseBloc.isMan ? Colors.green[800] : Color(0xFFEA776C),
|
||||
color: widget.exerciseBloc.customerRepository.isMan ? Colors.green[800] : Color(0xFFEA776C),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(20),
|
||||
),
|
||||
@ -156,7 +159,7 @@ class _SizeState extends State<SizeWidget> with Trans {
|
||||
height: 20,
|
||||
padding: EdgeInsets.zero,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.exerciseBloc.isMan ? Color(0xFF369fb9) : Color(0xFFEA776C),
|
||||
color: widget.exerciseBloc.customerRepository.isMan ? Color(0xFF369fb9) : Color(0xFFEA776C),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(20),
|
||||
),
|
||||
|
34
lib/widgets/timer_widget.dart
Normal file
@ -0,0 +1,34 @@
|
||||
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
|
||||
import 'package:aitrainer_app/library/clock.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TimerWidget extends StatelessWidget {
|
||||
final TimerBloc bloc;
|
||||
const TimerWidget({this.bloc});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Positioned(
|
||||
left: MediaQuery.of(context).size.width - 95,
|
||||
top: 28,
|
||||
child: Stack(alignment: AlignmentDirectional.topEnd, children: [
|
||||
digitalClock(),
|
||||
]));
|
||||
}
|
||||
|
||||
Widget digitalClock() {
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(45.0),
|
||||
child: Container(
|
||||
width: 90,
|
||||
height: 90,
|
||||
color: Colors.transparent,
|
||||
child: Overlay(initialEntries: <OverlayEntry>[
|
||||
OverlayEntry(
|
||||
opaque: true,
|
||||
builder: (BuildContext context) {
|
||||
return Container(color: Colors.transparent, child: Clock(bloc: bloc));
|
||||
})
|
||||
])));
|
||||
}
|
||||
}
|
13
pubspec.lock
@ -50,6 +50,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.5.0-nullsafety.1"
|
||||
audioplayer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: audioplayer
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.8.1"
|
||||
badges:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -259,7 +266,7 @@ packages:
|
||||
name: dropdown_search
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.8"
|
||||
version: "0.4.9"
|
||||
equatable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -397,7 +404,7 @@ packages:
|
||||
name: flutter_bloc
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.1"
|
||||
version: "6.1.2"
|
||||
flutter_facebook_auth:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1005,7 +1012,7 @@ packages:
|
||||
name: sqflite
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.2+2"
|
||||
version: "1.3.2+3"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
22
pubspec.yaml
@ -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.6+55
|
||||
version: 1.1.7+56
|
||||
|
||||
environment:
|
||||
sdk: ">=2.7.0 <3.0.0"
|
||||
@ -28,7 +28,7 @@ dependencies:
|
||||
google_fonts: ^1.1.1
|
||||
devicelocale: ^0.3.3
|
||||
sentry: ^4.0.3
|
||||
flutter_bloc: ^6.1.1
|
||||
flutter_bloc: ^6.1.2
|
||||
equatable: ^1.2.5
|
||||
#freezed: ^0.12.2
|
||||
flutter_form_bloc: ^0.19.0
|
||||
@ -40,7 +40,6 @@ dependencies:
|
||||
infinite_listview: ^1.0.1+1
|
||||
toggle_switch: ^0.1.8
|
||||
keyboard_actions: ^3.3.1+1
|
||||
dropdown_search: ^0.4.8
|
||||
badges: ^1.1.4
|
||||
#health: ^3.0.0
|
||||
stop_watch_timer: ^0.6.0+1
|
||||
@ -53,6 +52,8 @@ dependencies:
|
||||
network_image_to_byte: ^0.0.1
|
||||
package_info: ^0.4.3+4
|
||||
liquid_progress_indicator: ^0.3.2
|
||||
dropdown_search: ^0.4.9
|
||||
audioplayer: ^0.8.1
|
||||
|
||||
|
||||
firebase_core: ^0.5.0
|
||||
@ -71,7 +72,7 @@ dependencies:
|
||||
animated_widgets: ^1.0.6
|
||||
|
||||
mockito: ^4.1.3
|
||||
sqflite: ^1.3.2+2
|
||||
sqflite: ^1.3.2+3
|
||||
flutter_secure_storage: ^3.3.5
|
||||
|
||||
flutter_localizations:
|
||||
@ -212,6 +213,7 @@ flutter:
|
||||
- asset/menu/1.2.anaerob.jpg
|
||||
- asset/menu/2.strength.jpg
|
||||
- asset/menu/2.1.endurance.jpg
|
||||
- asset/menu/2.1.4.squats.jpg
|
||||
- asset/menu/2.1.6.core.jpg
|
||||
- asset/menu/2.1.1.1RM.jpg
|
||||
- asset/menu/2.2.1.1.chest.jpg
|
||||
@ -234,6 +236,7 @@ flutter:
|
||||
- asset/menu/bent_arm_barbell_pullovers.jpg
|
||||
- asset/menu/bent_knee_situps.jpg
|
||||
- asset/menu/bent_over_lateral_raises_with_dumbbells.jpg
|
||||
- asset/menu/bent_over_rows.jpg
|
||||
- asset/menu/biceps_machine.jpg
|
||||
- asset/menu/bmi.jpg
|
||||
- asset/menu/bmr.jpg
|
||||
@ -244,14 +247,18 @@ flutter:
|
||||
- asset/menu/chest_press_machine.jpg
|
||||
- asset/menu/chest_press.jpg
|
||||
- asset/menu/chins.jpg
|
||||
- asset/menu/close_grip_bench_press.jpg
|
||||
- asset/menu/close_grip_front_lat_pulldown.jpg
|
||||
- asset/menu/close_grip_pull_ups.jpg
|
||||
- asset/menu/close_reverse_grip_lat_pulldown.jpg
|
||||
- asset/menu/concentration.jpg
|
||||
- asset/menu/cooper.jpg
|
||||
- asset/menu/crisscross.jpg
|
||||
- asset/menu/cross_bench_dumbbell_pullover.jpg
|
||||
- asset/menu/deadlift.jpg
|
||||
- asset/menu/decline_bench_press.jpg
|
||||
- asset/menu/decline_dumbbell_bench_press.jpg
|
||||
- asset/menu/decline_flyes.jpg
|
||||
- asset/menu/decline_cable_flyes.jpg
|
||||
- asset/menu/donkey_calf_raises.jpg
|
||||
- asset/menu/dumbbell_alternate_bicep_curl.jpg
|
||||
@ -266,6 +273,7 @@ flutter:
|
||||
- asset/menu/hanging_leg_raises.jpg
|
||||
- asset/menu/head-on-bench_dumbbell_rear_delt_raise.jpg
|
||||
- asset/menu/hyperextension.jpg
|
||||
- asset/menu/hyperextension_floor.jpg
|
||||
- asset/menu/incline_cable_flyes.jpg
|
||||
- asset/menu/incline_curl_with_dumbbels.jpg
|
||||
- asset/menu/incline_dumbbell_press.jpg
|
||||
@ -292,10 +300,13 @@ flutter:
|
||||
- asset/menu/peck_deck_flyes.jpg
|
||||
- asset/menu/plank.jpg
|
||||
- asset/menu/pull_up.jpg
|
||||
- asset/menu/pulldown_machine.jpg
|
||||
- asset/menu/pullups.jpg
|
||||
- asset/menu/pushups.jpg
|
||||
- asset/menu/pushups_dip.jpg
|
||||
- asset/menu/reverse_crunches.jpg
|
||||
- asset/menu/roman_chair_situps.jpg
|
||||
- asset/menu/row_machine.jpg
|
||||
- asset/menu/russian_twist.jpg
|
||||
- asset/menu/seated_bar_twist.jpg
|
||||
- asset/menu/seated_dumbbell_curl.jpg
|
||||
@ -307,7 +318,7 @@ flutter:
|
||||
- asset/menu/single_arm_bent_over_cable_reverse_fly.jpg
|
||||
- asset/menu/single_arm_t-bar_rows.jpg
|
||||
- asset/menu/single_hand_lateral_raises.jpg
|
||||
- asset/menu/single_hand_lying_triceps_Extension.jpg
|
||||
- asset/menu/single_hand_lying_triceps_extension.jpg
|
||||
- asset/menu/sitting_knee_ups.jpg
|
||||
- asset/menu/sitting_machine_calf_raises.jpg
|
||||
- asset/menu/situps.jpg
|
||||
@ -340,6 +351,7 @@ flutter:
|
||||
- asset/menu/weighted_bench_dip.jpg
|
||||
- asset/menu/wide_grip_behind_the_neck_pull_ups.jpg
|
||||
- asset/menu/wide_grip_front_lat_pulldown.jpg
|
||||
- asset/wine-glass.mp3
|
||||
|
||||
|
||||
- i18n/en.json
|
||||
|
@ -8,7 +8,7 @@
|
||||
//import 'package:aitrainer_app/bloc/login_form_bloc.dart';
|
||||
import 'package:aitrainer_app/helper/database.dart';
|
||||
import 'package:aitrainer_app/library_keys.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/model/user.dart';
|
||||
import 'package:aitrainer_app/repository/user_repository.dart';
|
||||
import 'package:aitrainer_app/util/common.dart';
|
||||
|
@ -9,7 +9,7 @@
|
||||
import 'package:aitrainer_app/bloc/login/login_bloc.dart';
|
||||
import 'package:aitrainer_app/helper/database.dart';
|
||||
import 'package:aitrainer_app/library_keys.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/model/user.dart';
|
||||
import 'package:aitrainer_app/repository/user_repository.dart';
|
||||
import 'package:aitrainer_app/util/common.dart';
|
||||
|