WT1.1.6+3 bodyType animation, bug fixes

This commit is contained in:
bossanyit
2021-02-20 16:48:01 +01:00
parent 3c5360f224
commit cf348cebb0
293 changed files with 2966 additions and 1673 deletions
+40 -4
View File
@@ -4,6 +4,7 @@ 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/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
@@ -16,12 +17,47 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
bool loggedIn = false;
int traineeId = 0;
AccountBloc({this.customerRepository}) : super(AccountInitial()) {
if ( Cache().userLoggedIn != null ) {
if (Cache().userLoggedIn != null) {
customerRepository.customer = Cache().userLoggedIn;
loggedIn = true;
}
}
String getAccurateBodyType() {
String bodyType = ("Set your body type");
int _ecto = 0;
int _mezo = 0;
int _endo = 0;
_ecto = customerRepository.getCustomerPropertyValue(PropertyEnum.Ectomorph.toStr()).toInt();
_mezo = customerRepository.getCustomerPropertyValue(PropertyEnum.Mesomorph.toStr()).toInt();
_endo = customerRepository.getCustomerPropertyValue(PropertyEnum.Endomorph.toStr()).toInt();
if (_ecto == 0 && _mezo == 0 && _endo == 0) {
return bodyType;
}
int bodyTypeValue;
if (_ecto < 50) {
bodyTypeValue = (50 + ((50 / (_mezo + _endo)) * _endo)).toInt();
} else if (_endo < 50) {
bodyTypeValue = (0 + ((50 / (_mezo + _ecto)) * _mezo)).toInt();
} else {
// random answers probably
bodyTypeValue = (0 + ((100 / (_endo + _ecto))) * _endo).toInt();
}
print("BodyType value " + bodyTypeValue.toString());
if (bodyTypeValue < 20) {
bodyType = ("Ectomorph");
} else if (bodyTypeValue >= 25 && bodyTypeValue < 40) {
bodyType = ("Ecto") + "-" + ("Mesomorph");
} else if (bodyTypeValue >= 40 && bodyTypeValue < 60) {
bodyType = ("Mesomorph");
} else if (bodyTypeValue >= 60 && bodyTypeValue < 80) {
bodyType = ("Meso") + "-" + ("Endomorph");
} else {
bodyType = ("Endomorph");
}
return bodyType;
}
@override
Stream<AccountState> mapEventToState(
AccountEvent event,
@@ -42,11 +78,11 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
customerRepository.emptyTrainees();
loggedIn = false;
yield AccountLoggedOut();
} else if ( event is AccountGetTrainees) {
} else if (event is AccountGetTrainees) {
yield AccountLoading();
await customerRepository.getTrainees();
yield AccountReady();
} else if ( event is AccountSelectTrainee ) {
} else if (event is AccountSelectTrainee) {
yield AccountLoading();
customerRepository.setTrainee(event.traineeId);
Cache().setTrainee(customerRepository.getTraineeById(event.traineeId));
@@ -55,7 +91,7 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
this.traineeId = event.traineeId;
yield AccountReady();
}
} on Exception catch(e) {
} on Exception catch (e) {
yield AccountError(message: e.toString());
}
}
+239
View File
@@ -0,0 +1,239 @@
import 'dart:async';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer_property.dart';
import 'package:aitrainer_app/model/property.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/service/customer_service.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
part 'bodytype_event.dart';
part 'bodytype_state.dart';
class BodytypeBloc extends Bloc<BodytypeEvent, BodytypeState> {
static const int numberQuestions = 22;
final CustomerRepository repository;
final List<String> questions = List();
final List<int> answers = List();
final weights = List.generate(numberQuestions, (i) => List(3), growable: false);
BodytypeBloc({this.repository}) : super(BodytypeInitial()) {
questions.add("1. Basicly I am skinny and bonny");
questions.add("2. question");
questions.add("3. question");
questions.add("4. question");
questions.add("5. question");
questions.add("6. question");
questions.add("7. question");
questions.add("8. question");
questions.add("9. question");
questions.add("10. question");
questions.add("11. question");
questions.add("12. question");
questions.add("13. question");
questions.add("14. question");
questions.add("15. question");
questions.add("16. question");
questions.add("17. question");
questions.add("18. question");
questions.add("19. question");
questions.add("20. question");
questions.add("21. question");
questions.add("22. question");
for (int i = 0; i < numberQuestions; i++) {
answers.add(0);
}
weights[0] = [0, 3, 7];
weights[1] = [0, 3, 7];
weights[2] = [0, 3, 7];
weights[3] = [0, 3, 7];
weights[4] = [0, 3, 7];
weights[5] = [0, 3, 7];
weights[6] = [0, 3, 7];
weights[7] = [3, 7, 0];
weights[8] = [5, 7, 0];
weights[9] = [0, 7, 3];
weights[10] = [5, 5, 0];
weights[11] = [7, 5, 0];
weights[12] = [7, 5, 0];
weights[13] = [5, 5, 0];
weights[14] = [7, 3, 0];
weights[15] = [7, 3, 0];
weights[16] = [7, 3, 0];
weights[17] = [7, 3, 0];
weights[18] = [7, 0, 0];
weights[19] = [7, 0, 0];
weights[20] = [7, 3, 0];
weights[21] = [7, 3, 0];
final double value = repository.getCustomerPropertyValue(PropertyEnum.Ectomorph.toStr());
if (value != null) {
_ecto = value.toInt();
_mezo = repository.getCustomerPropertyValue(PropertyEnum.Mesomorph.toStr()).toInt();
_endo = repository.getCustomerPropertyValue(PropertyEnum.Endomorph.toStr()).toInt();
print("** Init ecto: " + _ecto.toString() + " mezo: " + _mezo.toString() + " endo: " + _endo.toString());
if (_ecto > 0 && _mezo > 0 && _endo > 0) {
calculateBodyType(init: true);
origBodyTypeValue = bodyTypeValue;
}
}
}
int value = 0;
int step = 1;
int bodyTypeValue = 0;
int origBodyTypeValue = 0;
int _ecto = 0;
int _mezo = 0;
int _endo = 0;
@override
Stream<BodytypeState> mapEventToState(
BodytypeEvent event,
) async* {
try {
if (event is BodytypeClick) {
yield BodytypeLoading();
this.value = event.value;
answers[step - 1] = value;
calculateBodyType();
await saveToDB();
if (step >= questions.length) {
yield BodytypeFinished();
return;
}
step++;
yield BodytypeReady();
} else if (event is BodytypeBack) {
yield BodytypeLoading();
if (step == 1) {
yield BodytypeReady();
return;
}
step--;
this.value = answers[step - 1];
yield BodytypeReady();
}
} on Exception catch (e) {
yield BodytypeError(error: e.toString());
}
}
bool showResults() {
return this.state == BodytypeFinished() || origBodyTypeValue > 0;
}
Future<void> saveToDB() async {
await savePropertyDB(PropertyEnum.Ectomorph.toStr(), _ecto.toDouble());
await savePropertyDB(PropertyEnum.Mesomorph.toStr(), _mezo.toDouble());
await savePropertyDB(PropertyEnum.Endomorph.toStr(), _endo.toDouble());
}
Future<void> savePropertyDB(String name, double value) async {
final now = DateTime.now();
Property property = repository.propertyRepository.getPropertyByName(name);
if (property != null) {
int propertyId = property.propertyId;
CustomerProperty customerProperty = repository.getCustomerProperty(name);
if (customerProperty == null || customerProperty.customerPropertyId == null) {
customerProperty =
CustomerProperty(customerId: Cache().userLoggedIn.customerId, propertyId: propertyId, propertyValue: value, dateAdd: now);
CustomerProperty newProperty = await CustomerApi().addProperty(customerProperty);
repository.setCustomerProperty(name, value, id: newProperty.customerPropertyId);
} else {
customerProperty.propertyValue = value;
customerProperty.dateAdd = now;
await CustomerApi().updateProperty(customerProperty);
repository.setCustomerProperty(name, value);
}
}
}
String getQuestion() {
return questions[step - 1];
}
int getValue() {
return answers[this.step - 1];
}
int getPrevValue() {
return step < 2 ? 0 : answers[this.step - 2];
}
int getBodyTypeValue() {
return bodyTypeValue;
}
void calculateBodyType({bool init = false}) {
if (!init) {
_endo = 0;
_mezo = 0;
_ecto = 0;
for (int index = 0; index < step; index++) {
_endo += getValueByWeight(weights[index][0], answers[index]);
_mezo += getValueByWeight(weights[index][1], answers[index]);
_ecto += getValueByWeight(weights[index][2], answers[index]);
}
print("ecto: " + _ecto.toString() + " mezo: " + _mezo.toString() + " endo: " + _endo.toString());
}
if (_ecto < 50) {
bodyTypeValue = (50 + ((50 / (_mezo + _endo)) * _endo)).toInt();
} else if (_endo < 50) {
bodyTypeValue = (0 + ((50 / (_mezo + _ecto)) * _mezo)).toInt();
} else {
// random answers probably
bodyTypeValue = (0 + ((100 / (_endo + _ecto))) * _endo).toInt();
}
origBodyTypeValue = 0;
print("bodyTypeValue: " + bodyTypeValue.toString());
}
int getValueByWeight(int weight, int answer) {
if (answer == 4) {
if (weight > 3 && weight < 7) {
return ((weight - (5 - answer) * 1.25)).round();
} else if (weight >= 7) {
return ((weight - (5 - answer) * 2)).round();
} else {
return (weight + (5 - answer) * 1.25).round();
}
} else if (answer == 3) {
if (weight > 3 && weight < 7) {
return ((weight - (5 - answer))).round();
} else if (weight >= 7) {
return ((weight - (5 - answer) * 2)).round();
} else {
return ((weight + (5 - answer) * 1.5)).round();
}
} else if (answer == 2) {
if (weight > 3 && weight < 7) {
return ((weight - (5 - answer))).round();
} else if (weight >= 7) {
return ((weight - (5 - answer) * 2)).round();
} else if (weight == 3) {
return ((weight + (5 - answer) * 0.25)).round();
} else {
return ((weight + (5 - answer) * 1.75)).round();
}
} else if (answer == 1) {
if (weight > 3 && weight < 7) {
return ((weight - (5 - answer))).round();
} else if (weight >= 7) {
return ((weight - (5 - answer) * 1.85)).round();
} else if (weight == 3) {
return weight;
} else {
return ((weight + (5 - answer) * 1.85)).round();
}
} else {
return weight;
}
}
}
+28
View File
@@ -0,0 +1,28 @@
part of 'bodytype_bloc.dart';
abstract class BodytypeEvent extends Equatable {
const BodytypeEvent();
@override
List<Object> get props => [];
}
class BodytypeLoad extends BodytypeEvent {
const BodytypeLoad();
}
class BodytypeSave extends BodytypeEvent {
const BodytypeSave();
}
class BodytypeClick extends BodytypeEvent {
final int value;
const BodytypeClick({this.value});
@override
List<Object> get props => [value];
}
class BodytypeBack extends BodytypeEvent {
const BodytypeBack();
}
+32
View File
@@ -0,0 +1,32 @@
part of 'bodytype_bloc.dart';
abstract class BodytypeState extends Equatable {
const BodytypeState();
@override
List<Object> get props => [];
}
class BodytypeInitial extends BodytypeState {
const BodytypeInitial();
}
class BodytypeLoading extends BodytypeState {
const BodytypeLoading();
}
class BodytypeReady extends BodytypeState {
const BodytypeReady();
}
class BodytypeFinished extends BodytypeState {
const BodytypeFinished();
}
class BodytypeError extends BodytypeState {
final String error;
const BodytypeError({this.error});
@override
List<Object> get props => [error];
}
-129
View File
@@ -1,129 +0,0 @@
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
class CustomerChangeFormBloc extends FormBloc<String, String> {
final CustomerRepository customerRepository;
int weight = 60;
int birthYear = 1990;
final emailField = TextFieldBloc(
validators: [
FieldBlocValidators.required,
],
);
final firstNameField = TextFieldBloc(
validators: [
FieldBlocValidators.required,
],
);
final nameField = TextFieldBloc();
final passwordField = TextFieldBloc(
validators: [
//FieldBlocValidators.confirmPassword(passwordField),
],
);
final birthYearField = InputFieldBloc<int, Object>(initialValue: 1990);
final weightField = InputFieldBloc<int, Object>(initialValue: 60);
final genderField = InputFieldBloc<int, Object>(initialValue: 0);
final goalField = TextFieldBloc();
CustomerChangeFormBloc({this.customerRepository}) {
addFieldBlocs(fieldBlocs: [
emailField,
firstNameField,
nameField,
passwordField,
birthYearField,
weightField,
genderField,
goalField,
]);
emailField.updateInitialValue(customerRepository.customer.email);
firstNameField.updateInitialValue(customerRepository.customer.firstname);
nameField.updateInitialValue(customerRepository.customer.name);
birthYearField.updateInitialValue(customerRepository.customer.birthYear);
weightField.updateInitialValue(customerRepository.customer.getProperty("weight").toInt());
int initialGender = customerRepository.getGenderByDBValue(customerRepository.sex) == "m" ? 0 : 1;
genderField.updateInitialValue(initialGender);
firstNameField.onValueChanges(onData: (previous, current) async* {
customerRepository.setFirstName(current.value);
});
nameField.onValueChanges(onData: (previous, current) async* {
customerRepository.setName(current.value);
});
/*birthYearField.onValueChanges(onData: (previous, current) async* {
customerRepository.setBirthYear(current.valueToInt);
});
weightField.onValueChanges(onData: (previous, current) async* {
customerRepository.setWeight(current.valueToInt);
});
customerRepository.genders.forEach((element) {
genderField.addItem(element.name);
});*/
genderField.onValueChanges(onData: (previous, current) async* {
String dbValue = customerRepository.getGenderByName(current.value.toString());
customerRepository.setSex(dbValue);
});
}
int getGender() {
return customerRepository.customer.sex == "M" ? 0 : 1;
}
void switchGender(int index) {
String dbValue;
if (index == 0) {
dbValue = customerRepository.getGenderByName("Man");
} else if (index == 1) {
dbValue = customerRepository.getGenderByName("Woman");
}
customerRepository.setSex(dbValue);
genderField.add(UpdateFieldBlocValue(dbValue));
}
void changeWeight(int value) {
customerRepository.setWeight(value);
weight = value;
weightField.updateValue(value);
}
changeBirthYear(int value) {
customerRepository.setBirthYear(value);
birthYear = value;
birthYearField.updateValue(value);
}
@override
void onSubmitting() async {
try {
emitLoading(progress: 30);
// Emit either Loaded or Error
await customerRepository.saveCustomer();
emitSuccess(canSubmitAgain: true);
} on Exception catch (ex) {
emitFailure(failureResponse: ex.toString());
}
}
@override
Future<void> close() {
emailField.close();
firstNameField.close();
nameField.close();
passwordField.close();
birthYearField.close();
weightField.close();
genderField.close();
goalField.close();
return super.close();
}
}
@@ -3,6 +3,8 @@ import 'dart:async';
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';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
@@ -17,6 +19,7 @@ class CustomerExerciseDeviceBloc extends Bloc<CustomerExerciseDeviceEvent, Custo
if (repository.getDevices().isEmpty) {
repository.setDevices(Cache().getCustomerDevices());
}
Track().track(TrackingEvent.exercise_device);
}
@override
@@ -29,7 +32,6 @@ class CustomerExerciseDeviceBloc extends Bloc<CustomerExerciseDeviceEvent, Custo
yield CustomerExerciseDeviceReady();
} else if (event is CustomerExerciseDeviceAdd) {
yield CustomerExerciseDeviceLoading();
//await Future.delayed(const Duration(seconds: 2), () => "2");
await repository.addDevice(event.device);
Cache().initBadges();
yield CustomerExerciseDeviceReady();
@@ -9,7 +9,9 @@ import 'package:aitrainer_app/repository/workout_tree_repository.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/calculate.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/group_data.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
@@ -282,7 +284,9 @@ class DevelopmentByMuscleBloc extends Bloc<DevelopmentByMuscleEvent, Development
double basePercent = 0;
@override
DevelopmentByMuscleBloc({this.workoutTreeRepository}) : super(DevelopmentByMuscleStateInitial());
DevelopmentByMuscleBloc({this.workoutTreeRepository}) : super(DevelopmentByMuscleStateInitial()) {
Track().track(TrackingEvent.my_muscle_development);
}
Future<void> getData() async {
workoutTreeRepository.sortedTree = null;
@@ -33,6 +33,7 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
exerciseRepository.setUnitQuantity(unitQuantity);
exerciseRepository.setQuantity(quantity);
print("init quantity: " + quantity.toString());
}
@override
@@ -40,6 +41,7 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
try {
if (event is ExerciseControlLoad) {
yield ExerciseControlLoading();
print("init quantity: " + quantity.toString());
step = 1;
yield ExerciseControlReady();
} else if (event is ExerciseControlQuantityChange) {
@@ -49,6 +51,18 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
quantity = event.quantity;
}
//yield ExerciseControlReady();
} else if (event is ExerciseControlUnitQuantityChange) {
yield ExerciseControlLoading();
if (event.step == step) {
this.unitQuantity = event.quantity;
exerciseRepository.setUnitQuantity(event.quantity);
unitQuantity = event.quantity;
quantity = calculateQuantityByUnitQuantity();
exerciseRepository.setQuantity(quantity);
origQuantity = quantity;
}
yield ExerciseControlReady();
} else if (event is ExerciseControlSubmit) {
yield ExerciseControlLoading();
if (event.step == step) {
@@ -57,7 +71,7 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
quantity = origQuantity;
if (exerciseRepository.exercise.quantity == null) {
exerciseRepository.setQuantity(12);
exerciseRepository.setQuantity(quantity);
}
exerciseRepository.end = DateTime.now();
await exerciseRepository.addExercise();
@@ -88,4 +102,19 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
return percent75 ? average * this.percentToCalculate : average;
}
double calculateQuantityByUnitQuantity() {
final double rmWendler = initialRM;
final double rmOconner = initialRM;
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;
}
}
@@ -18,6 +18,12 @@ class ExerciseControlQuantityChange extends ExerciseControlEvent {
const ExerciseControlQuantityChange({this.quantity, this.step});
}
class ExerciseControlUnitQuantityChange extends ExerciseControlEvent {
final double quantity;
final int step;
const ExerciseControlUnitQuantityChange({this.quantity, this.step});
}
class ExerciseControlSubmit extends ExerciseControlEvent {
final int step;
const ExerciseControlSubmit({this.step});
@@ -5,9 +5,10 @@ import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flurry/flurry.dart';
import 'package:meta/meta.dart';
part 'exercise_execute_plan_add_event.dart';
@@ -55,7 +56,7 @@ class ExerciseExecutePlanAddBloc extends Bloc<ExerciseExecutePlanAddEvent, Exerc
try {
if (event is ExerciseExecutePlanAddLoad) {
yield ExerciseExecutePlanAddLoading();
Flurry.logEvent("ExecuteExercisePlanOpen");
Track().track(TrackingEvent.my_exercise_plan_execute_open);
yield ExerciseExecutePlanAddReady();
} else if (event is ExerciseExecutePlanAddChangeQuantity) {
yield ExerciseExecutePlanAddLoading();
@@ -73,7 +74,7 @@ class ExerciseExecutePlanAddBloc extends Bloc<ExerciseExecutePlanAddEvent, Exerc
exerciseRepository.exercise.unit = workoutTree.exerciseType.unit;
workoutTree.executed = true;
await exerciseRepository.addExercise();
Flurry.logEvent("ExecuteExercisePlanSave");
Track().track(TrackingEvent.my_exercise_plan_execute_save);
step++;
scrollOffset = step * 200.0;
planBloc.add(ExerciseByPlanLoad());
+5 -4
View File
@@ -1,9 +1,10 @@
import 'dart:async';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flurry/flurry.dart';
import 'package:meta/meta.dart';
part 'exercise_log_event.dart';
@@ -20,17 +21,17 @@ class ExerciseLogBloc extends Bloc<ExerciseLogEvent, ExerciseLogState> {
try {
if (event is ExerciseLogLoad) {
yield ExerciseLogLoading();
Flurry.logEvent("exerciseLog");
Track().track(TrackingEvent.exercise_log_open);
yield ExerciseLogReady();
} else if (event is ExerciseLogDelete) {
yield ExerciseLogLoading();
exerciseRepository.exerciseList.remove(event.exercise);
await exerciseRepository.deleteExercise(event.exercise);
Flurry.logEvent("exerciseDelete");
Track().track(TrackingEvent.exercise_log_delete);
yield ExerciseLogReady();
} else if (event is ExerciseResult) {
yield ExerciseLogLoading();
Flurry.logEvent("exerciseResult");
Track().track(TrackingEvent.exercise_log_result);
yield ExerciseLogReady();
}
} on Exception catch (e) {
+4 -4
View File
@@ -8,9 +8,10 @@ import 'package:aitrainer_app/model/fitness_state.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flurry/flurry.dart';
import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
@@ -352,7 +353,7 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
changedWeight = false;
this.changedSizes = false;
Cache().initBadges();
Flurry.logEvent("Sizes");
Track().track(TrackingEvent.sizes);
yield ExerciseNewReady();
} else if (event is ExerciseNewSizeChange) {
yield ExerciseNewLoading();
@@ -366,8 +367,7 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
await exerciseRepository.addExercise();
menuBloc.add(MenuTreeDown(parent: 0));
Cache().initBadges();
Flurry.logEvent("newExercise");
Flurry.logEvent("newExercise " + exerciseRepository.exerciseType.name);
Track().track(TrackingEvent.exercise_new, eventValue: exerciseRepository.exerciseType.name);
yield ExerciseNewReady();
} else if (event is ExerciseNewBMIAnimate) {
yield ExerciseNewLoading();
@@ -4,9 +4,10 @@ import 'package:aitrainer_app/model/model_change.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
import 'package:aitrainer_app/repository/workout_tree_repository.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flurry/flurry.dart';
import 'package:meta/meta.dart';
part 'exercise_plan_event.dart';
@@ -48,7 +49,7 @@ class ExercisePlanBloc extends Bloc<ExercisePlanEvent, ExercisePlanState> {
try {
if (event is ExercisePlanLoad) {
yield ExercisePlanLoading();
Flurry.logEvent("exercisePlan");
Track().track(TrackingEvent.my_custom_exercise_plan);
await this.getData();
yield ExercisePlanReady();
}
@@ -98,7 +99,7 @@ class ExercisePlanBloc extends Bloc<ExercisePlanEvent, ExercisePlanState> {
if (exercisePlanRepository.getExercisePlanDetailSize() != 0) {
exercisePlanRepository.saveExercisePlan();
Flurry.logEvent("SaveExercisePlan");
Track().track(TrackingEvent.my_custom_exercise_plan_save);
}
yield ExercisePlanReady();
+13 -17
View File
@@ -5,13 +5,13 @@ import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/user_repository.dart';
import 'package:aitrainer_app/service/exercise_tree_service.dart';
import 'package:aitrainer_app/service/exercisetype_service.dart';
import 'package:aitrainer_app/service/exercise_type_service.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flurry/flurry.dart';
import 'package:flutter/material.dart';
part 'login_event.dart';
@@ -51,7 +51,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
yield LoginLoading();
await userRepository.getUser();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
Flurry.logEvent("Login");
Track().track(TrackingEvent.login, eventValue: "email");
Cache().setLoginType(LoginType.email);
yield LoginSuccess();
} else if (event is LoginFB) {
@@ -59,24 +59,21 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
Cache().setLoginType(LoginType.fb);
await userRepository.getUserByFB();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
Flurry.logEvent("Login");
Flurry.logEvent("LoginFB");
Track().track(TrackingEvent.login, eventValue: "FB");
yield LoginSuccess();
} else if (event is LoginGoogle) {
yield LoginLoading();
Cache().setLoginType(LoginType.google);
await userRepository.getUserByGoogle();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
Flurry.logEvent("Login");
Flurry.logEvent("LoginGoogle");
Track().track(TrackingEvent.login, eventValue: "Google");
yield LoginSuccess();
} else if (event is LoginApple) {
yield LoginLoading();
Cache().setLoginType(LoginType.apple);
await userRepository.getUserByApple();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
Flurry.logEvent("Login");
Flurry.logEvent("LoginApple");
Track().track(TrackingEvent.login, eventValue: "Apple");
yield LoginSuccess();
} else if (event is RegistrationSubmit) {
yield LoginLoading();
@@ -87,7 +84,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
await userRepository.addUser();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
await saveCustomer();
Flurry.logEvent("Registration");
Track().track(TrackingEvent.registration, eventValue: "email");
Cache().setLoginType(LoginType.email);
yield LoginSuccess();
} else if (event is RegistrationFB) {
@@ -100,8 +97,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
await userRepository.addUserFB();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
await saveCustomer();
Flurry.logEvent("RegistrationFB");
Flurry.logEvent("Registration");
Track().track(TrackingEvent.registration, eventValue: "FB");
yield LoginSuccess();
} else if (event is RegistrationGoogle) {
yield LoginLoading();
@@ -113,8 +109,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
await userRepository.addUserGoogle();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
await saveCustomer();
Flurry.logEvent("RegistrationGoogle");
Flurry.logEvent("Registration");
Track().track(TrackingEvent.registration, eventValue: "Google");
yield LoginSuccess();
} else if (event is RegistrationApple) {
yield LoginLoading();
@@ -124,10 +119,11 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
}
Cache().setLoginType(LoginType.apple);
await userRepository.addUserApple();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
await saveCustomer();
Flurry.logEvent("RegistrationApple");
Flurry.logEvent("Registration");
Track().track(TrackingEvent.registration);
Track().track(TrackingEvent.registration, eventValue: "Apple");
yield LoginSuccess();
} else if (event is DataProtectionClicked) {
yield LoginLoading();
+6 -5
View File
@@ -7,9 +7,11 @@ import 'package:aitrainer_app/model/product.dart';
import 'package:aitrainer_app/model/product_test.dart';
import 'package:aitrainer_app/model/purchase.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/service/purchase.dart';
import 'package:aitrainer_app/service/purchase_service.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/purchases.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flurry/flurry.dart';
@@ -32,8 +34,7 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
if (event is SalesLoad) {
yield SalesLoading();
log("Load Sales");
Common.sendMessage("Salespage Load");
Flurry.logEvent("SalesPageOpen");
Track().track(TrackingEvent.sales_page);
//await PlatformPurchaseApi().initPurchasePlatform();
await RevenueCatPurchases().getOfferings();
this.getProductSet();
@@ -45,7 +46,7 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
yield SalesLoading();
final int productId = event.productId;
log("Requesting purchase for: " + productId.toString());
Flurry.logEvent("PurchaseRequest");
Track().track(TrackingEvent.purchase_request);
final Product selectedProduct = this.getSelectedProduct(productId);
log("SelectedProduct for purchase " + selectedProduct.toString());
await RevenueCatPurchases().makePurchase(selectedProduct);
@@ -55,7 +56,7 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
purchase.purchaseSum = 0;
purchase.currency = "EUR";
await PurchaseApi().savePurchase(purchase);
Flurry.logEvent("PurchaseSuccessful");
Track().track(TrackingEvent.purchase_successful, eventValue: selectedProduct.localizedPrice.toString());
Common.sendMessage("Purchase: " + purchase.toJson().toString());
}
yield SalesSuccessful();
-4
View File
@@ -2,13 +2,10 @@ import 'dart:async';
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/service/exercise_tree_service.dart';
import 'package:aitrainer_app/service/exercisetype_service.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/session.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flurry/flurry.dart';
part 'session_event.dart';
part 'session_state.dart';
@@ -32,7 +29,6 @@ class SessionBloc extends Bloc<SessionEvent, SessionState> with Logging {
String lang = AppLanguage().appLocal.languageCode;
log("Change lang to $lang");
settingsBloc.add(SettingsChangeLanguage(language: lang));
Flurry.logEvent("Enter");
yield SessionReady();
}
} on Exception catch (ex) {
+4
View File
@@ -4,6 +4,8 @@ import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
@@ -35,6 +37,7 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> with Logging {
if (event is SettingsChangeLanguage) {
yield SettingsLoading();
await _changeLang(event.language);
Track().track(TrackingEvent.settings_lang);
yield SettingsReady(_locale);
} else if (event is SettingsGetLanguage) {
await AppLanguage().fetchLocale();
@@ -44,6 +47,7 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> with Logging {
yield SettingsLoading();
final bool live = event.live;
Cache().setServer(live);
Track().track(TrackingEvent.settings_server);
yield SettingsReady(_locale);
} else if (event is SettingsSetHardware) {
yield SettingsLoading();
+148
View File
@@ -0,0 +1,148 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
class FadeIn extends StatefulWidget {
/// Fade-in controller
final FadeInController controller;
/// Child widget to fade-in
final Widget child;
/// Duration of fade-in. Defaults to 250ms
final Duration duration;
/// Fade-in curve. Defaults to [Curves.easeIn]
final Curve curve;
const FadeIn({
Key key,
this.controller,
this.child,
this.duration = const Duration(milliseconds: 250),
this.curve = Curves.easeIn,
}) : super(key: key);
@override
_FadeInState createState() => _FadeInState();
}
enum FadeInAction {
fadeIn,
fadeOut,
}
/// Fade-in controller which dispatches fade-in/fade-out actions
class FadeInController {
final _streamController = StreamController<FadeInAction>();
/// Automatically starts the initial fade-in. Defaults to true
final bool autoStart;
FadeInController({this.autoStart = true});
void dispose() => _streamController.close();
/// Fades-in child
void fadeIn() => run(FadeInAction.fadeIn);
/// Fades-out child
void fadeOut() => run(FadeInAction.fadeOut);
/// Dispatches a [FadeInAction]
void run(FadeInAction action) => _streamController.add(action);
/// Stream of [FadeInAction]s dispatched by this controller
Stream<FadeInAction> get stream => _streamController.stream;
}
class _FadeInState extends State<FadeIn> with TickerProviderStateMixin {
AnimationController _controller;
StreamSubscription<FadeInAction> _listener;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: widget.duration,
);
_setupCurve();
if (widget.controller?.autoStart != false) {
fadeIn();
}
_listen();
}
void _setupCurve() {
final curve = CurvedAnimation(parent: _controller, curve: widget.curve);
Tween(
begin: 0.0,
end: 1.0,
).animate(curve);
}
void _listen() {
if (_listener != null) {
_listener.cancel();
_listener = null;
}
if (widget.controller != null) {
_listener = widget.controller.stream.listen(_onAction);
}
}
void _onAction(FadeInAction action) {
switch (action) {
case FadeInAction.fadeIn:
fadeIn();
break;
case FadeInAction.fadeOut:
fadeOut();
break;
}
}
@override
void didUpdateWidget(FadeIn oldWidget) {
if (oldWidget.controller != widget.controller) {
_listen();
}
if (oldWidget.duration != widget.duration) {
_controller.duration = widget.duration;
}
if (oldWidget.curve != widget.curve) {
_setupCurve();
}
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: _controller,
child: widget.child,
);
}
/// Fades-in child
void fadeIn() => _controller.forward();
/// Fades-out child
void fadeOut() => _controller.reverse();
}
-807
View File
@@ -1,807 +0,0 @@
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:infinite_listview/infinite_listview.dart';
/// Created by Marcin Szałek
///Define a text mapper to transform the text displayed by the picker
typedef String TextMapper(String numberText);
///NumberPicker is a widget designed to pick a number between #minValue and #maxValue
class NumberPicker extends StatelessWidget {
///height of every list element for normal number picker
///width of every list element for horizontal number picker
static const double kDefaultItemExtent = 60.0;
///width of list view for normal number picker
///height of list view for horizontal number picker
static const double kDefaultListViewCrossAxisSize = 120.0;
///constructor for horizontal number picker
NumberPicker.horizontal({
Key key,
@required int initialValue,
@required this.minValue,
@required this.maxValue,
@required this.onChanged,
this.textMapper,
this.itemExtent = kDefaultItemExtent,
this.listViewHeight = kDefaultListViewCrossAxisSize,
this.step = 1,
this.zeroPad = false,
this.highlightSelectedValue = true,
this.decoration,
this.haptics = false,
this.textStyle,
this.textStyleHighlighted
}) : assert(initialValue != null),
assert(minValue != null),
assert(maxValue != null),
assert(maxValue > minValue),
assert(initialValue >= minValue && initialValue <= maxValue),
assert(step > 0),
selectedIntValue = initialValue,
selectedDecimalValue = -1,
decimalPlaces = 0,
intScrollController = ScrollController(
initialScrollOffset: (initialValue - minValue) ~/ step * itemExtent,
),
scrollDirection = Axis.horizontal,
decimalScrollController = null,
listViewWidth = 3 * itemExtent,
infiniteLoop = false,
integerItemCount = (maxValue - minValue) ~/ step + 1,
super(key: key);
///constructor for integer number picker
NumberPicker.integer({
Key key,
@required int initialValue,
@required this.minValue,
@required this.maxValue,
@required this.onChanged,
this.textMapper,
this.itemExtent = kDefaultItemExtent,
this.listViewWidth = kDefaultListViewCrossAxisSize,
this.step = 1,
this.scrollDirection = Axis.vertical,
this.infiniteLoop = false,
this.zeroPad = false,
this.highlightSelectedValue = true,
this.decoration,
this.haptics = false,
this.textStyle,
this.textStyleHighlighted
}) : assert(initialValue != null),
assert(minValue != null),
assert(maxValue != null),
assert(maxValue > minValue),
assert(initialValue >= minValue && initialValue <= maxValue),
assert(step > 0),
assert(scrollDirection != null),
selectedIntValue = initialValue,
selectedDecimalValue = -1,
decimalPlaces = 0,
intScrollController = infiniteLoop
? InfiniteScrollController(
initialScrollOffset:
(initialValue - minValue) ~/ step * itemExtent,
)
: ScrollController(
initialScrollOffset:
(initialValue - minValue) ~/ step * itemExtent,
),
decimalScrollController = null,
listViewHeight = 3 * itemExtent,
integerItemCount = (maxValue - minValue) ~/ step + 1,
super(key: key);
///constructor for decimal number picker
NumberPicker.decimal({
Key key,
@required double initialValue,
@required this.minValue,
@required this.maxValue,
@required this.onChanged,
this.textMapper,
this.decimalPlaces = 1,
this.itemExtent = kDefaultItemExtent,
this.listViewWidth = kDefaultListViewCrossAxisSize,
this.highlightSelectedValue = true,
this.decoration,
this.haptics = false,
this.textStyle,
this.textStyleHighlighted
}) : assert(initialValue != null),
assert(minValue != null),
assert(maxValue != null),
assert(decimalPlaces != null && decimalPlaces > 0),
assert(maxValue > minValue),
assert(initialValue >= minValue && initialValue <= maxValue),
selectedIntValue = initialValue.floor(),
selectedDecimalValue = ((initialValue - initialValue.floorToDouble()) *
math.pow(10, decimalPlaces))
.round(),
intScrollController = ScrollController(
initialScrollOffset: (initialValue.floor() - minValue) * itemExtent,
),
decimalScrollController = ScrollController(
initialScrollOffset: ((initialValue - initialValue.floorToDouble()) *
math.pow(10, decimalPlaces))
.roundToDouble() *
itemExtent,
),
listViewHeight = 3 * itemExtent,
step = 1,
scrollDirection = Axis.vertical,
integerItemCount = maxValue.floor() - minValue.floor() + 1,
infiniteLoop = false,
zeroPad = false,
super(key: key);
///called when selected value changes
final ValueChanged<num> onChanged;
///min value user can pick
final int minValue;
///max value user can pick
final int maxValue;
///build the text of each item on the picker
final TextMapper textMapper;
///inidcates how many decimal places to show
/// e.g. 0=>[1,2,3...], 1=>[1.0, 1.1, 1.2...] 2=>[1.00, 1.01, 1.02...]
final int decimalPlaces;
///height of every list element in pixels
final double itemExtent;
///height of list view in pixels
final double listViewHeight;
///width of list view in pixels
final double listViewWidth;
///ScrollController used for integer list
final ScrollController intScrollController;
///ScrollController used for decimal list
final ScrollController decimalScrollController;
///Currently selected integer value
final int selectedIntValue;
///Currently selected decimal value
final int selectedDecimalValue;
///If currently selected value should be highlighted
final bool highlightSelectedValue;
///Decoration to apply to central box where the selected value is placed
final Decoration decoration;
///Step between elements. Only for integer datePicker
///Examples:
/// if step is 100 the following elements may be 100, 200, 300...
/// if min=0, max=6, step=3, then items will be 0, 3 and 6
/// if min=0, max=5, step=3, then items will be 0 and 3.
final int step;
/// Direction of scrolling
final Axis scrollDirection;
///Repeat values infinitely
final bool infiniteLoop;
///Pads displayed integer values up to the length of maxValue
final bool zeroPad;
///Amount of items
final int integerItemCount;
///Whether to trigger haptic pulses or not
final bool haptics;
///TextStyle of the non-highlighted numbers
final TextStyle textStyle;
///TextStyle of the highlighted numbers
final TextStyle textStyleHighlighted;
//
//----------------------------- PUBLIC ------------------------------
//
/// Used to animate integer number picker to new selected value
void animateInt(int valueToSelect) {
int diff = valueToSelect - minValue;
int index = diff ~/ step;
animateIntToIndex(index);
}
/// Used to animate integer number picker to new selected index
void animateIntToIndex(int index) {
_animate(intScrollController, index * itemExtent);
}
/// Used to animate decimal part of double value to new selected value
void animateDecimal(int decimalValue) {
_animate(decimalScrollController, decimalValue * itemExtent);
}
/// Used to animate decimal number picker to selected value
void animateDecimalAndInteger(double valueToSelect) {
animateInt(valueToSelect.floor());
animateDecimal(((valueToSelect - valueToSelect.floorToDouble()) *
math.pow(10, decimalPlaces))
.round());
}
//
//----------------------------- VIEWS -----------------------------
//
///main widget
@override
Widget build(BuildContext context) {
final ThemeData themeData = Theme.of(context);
if (infiniteLoop) {
return _integerInfiniteListView(themeData);
}
if (decimalPlaces == 0) {
return _integerListView(themeData);
} else {
return Row(
children: <Widget>[
_integerListView(themeData),
_decimalListView(themeData),
],
mainAxisAlignment: MainAxisAlignment.center,
);
}
}
Widget _integerListView(ThemeData themeData) {
TextStyle defaultStyle = textStyle == null ?
themeData.textTheme.body1 : textStyle;
TextStyle selectedStyle = textStyleHighlighted == null ?
themeData.textTheme.headline.copyWith(color: themeData.accentColor)
: textStyleHighlighted;
var listItemCount = integerItemCount + 2;
return Listener(
onPointerUp: (ev) {
///used to detect that user stopped scrolling
if (intScrollController.position.activity is HoldScrollActivity) {
animateInt(selectedIntValue);
}
},
child: NotificationListener(
child: Container(
height: listViewHeight,
width: listViewWidth,
child: Stack(
children: <Widget>[
ListView.builder(
scrollDirection: scrollDirection,
controller: intScrollController,
itemExtent: itemExtent,
itemCount: listItemCount,
cacheExtent: _calculateCacheExtent(listItemCount),
itemBuilder: (BuildContext context, int index) {
final int value = _intValueFromIndex(index);
//define special style for selected (middle) element
final TextStyle itemStyle =
value == selectedIntValue && highlightSelectedValue
? selectedStyle
: defaultStyle;
double top = defaultStyle != null && defaultStyle.fontSize != null
? listViewHeight / 2 - defaultStyle.fontSize / 2 - 15
: listViewHeight / 2 - 22;
double left = defaultStyle != null && defaultStyle.fontSize != null
? listViewWidth / 6 - defaultStyle.fontSize / 2 - 10
: listViewHeight / 2 - 27;
bool isExtra = index == 0 || index == listItemCount - 1;
return isExtra
? Container() //empty first and last element
: Center(
child: value != selectedIntValue ?
Container(
padding: EdgeInsets.only(top: 15, left: 10, right: 5, bottom: 10),
child: Stack(
children: [
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: value < selectedIntValue ? Alignment.centerRight : Alignment.centerLeft,
end: value < selectedIntValue ? Alignment.centerLeft : Alignment.centerRight,
colors: [Colors.white12, Colors.black12]),
borderRadius: BorderRadius.circular(8.0),
),
),
Positioned(
top: top,
left: left,
child:
Text(
getDisplayedValue(value),
style: itemStyle,
),
),
],
)
) :
Text(
getDisplayedValue(value),
style: itemStyle,
),
);
},
),
_NumberPickerSelectedItemDecoration(
axis: scrollDirection,
itemExtent: itemExtent,
decoration: decoration,
),
],
),
),
onNotification: _onIntegerNotification,
),
);
}
Widget _decimalListView(ThemeData themeData) {
TextStyle defaultStyle = textStyle == null ?
themeData.textTheme.body1 : textStyle;
TextStyle selectedStyle = textStyleHighlighted == null ?
themeData.textTheme.headline.copyWith(color: themeData.accentColor)
: textStyleHighlighted;
int decimalItemCount =
selectedIntValue == maxValue ? 3 : math.pow(10, decimalPlaces) + 2;
return Listener(
onPointerUp: (ev) {
///used to detect that user stopped scrolling
if (decimalScrollController.position.activity is HoldScrollActivity) {
animateDecimal(selectedDecimalValue);
}
},
child: NotificationListener(
child: Container(
height: listViewHeight,
width: listViewWidth,
child: Stack(
children: <Widget>[
ListView.builder(
controller: decimalScrollController,
itemExtent: itemExtent,
itemCount: decimalItemCount,
itemBuilder: (BuildContext context, int index) {
final int value = index - 1;
//define special style for selected (middle) element
final TextStyle itemStyle =
value == selectedDecimalValue && highlightSelectedValue
? selectedStyle
: defaultStyle;
bool isExtra = index == 0 || index == decimalItemCount - 1;
return isExtra
? Container() //empty first and last element
: Center(
child: Text(
value.toString().padLeft(decimalPlaces, '0'),
style: itemStyle,
),
);
},
),
_NumberPickerSelectedItemDecoration(
axis: scrollDirection,
itemExtent: itemExtent,
decoration: decoration,
),
],
),
),
onNotification: _onDecimalNotification,
),
);
}
Widget _integerInfiniteListView(ThemeData themeData) {
TextStyle defaultStyle = textStyle == null ?
themeData.textTheme.body1 : textStyle;
TextStyle selectedStyle = textStyleHighlighted == null ?
themeData.textTheme.headline.copyWith(color: themeData.accentColor)
: textStyleHighlighted;
return Listener(
onPointerUp: (ev) {
///used to detect that user stopped scrolling
if (intScrollController.position.activity is HoldScrollActivity) {
_animateIntWhenUserStoppedScrolling(selectedIntValue);
}
},
child: NotificationListener(
child: Container(
height: listViewHeight,
width: listViewWidth,
child: Stack(
children: <Widget>[
InfiniteListView.builder(
controller: intScrollController,
itemExtent: itemExtent,
itemBuilder: (BuildContext context, int index) {
final int value = _intValueFromIndex(index);
//define special style for selected (middle) element
final TextStyle itemStyle =
value == selectedIntValue && highlightSelectedValue
? selectedStyle
: defaultStyle;
return Center(
child: Text(
getDisplayedValue(value),
style: itemStyle,
),
);
},
),
_NumberPickerSelectedItemDecoration(
axis: scrollDirection,
itemExtent: itemExtent,
decoration: decoration,
),
],
),
),
onNotification: _onIntegerNotification,
),
);
}
String getDisplayedValue(int value) {
final text = zeroPad
? value.toString().padLeft(maxValue.toString().length, '0')
: value.toString();
return textMapper != null ? textMapper(text) : text;
}
//
// ----------------------------- LOGIC -----------------------------
//
int _intValueFromIndex(int index) {
index--;
index %= integerItemCount;
return minValue + index * step;
}
bool _onIntegerNotification(Notification notification) {
if (notification is ScrollNotification) {
//calculate
int intIndexOfMiddleElement =
(notification.metrics.pixels / itemExtent).round();
if (!infiniteLoop) {
intIndexOfMiddleElement =
intIndexOfMiddleElement.clamp(0, integerItemCount - 1);
}
int intValueInTheMiddle = _intValueFromIndex(intIndexOfMiddleElement + 1);
intValueInTheMiddle = _normalizeIntegerMiddleValue(intValueInTheMiddle);
if (_userStoppedScrolling(notification, intScrollController)) {
//center selected value
animateIntToIndex(intIndexOfMiddleElement);
}
//update selection
if (intValueInTheMiddle != selectedIntValue) {
num newValue;
if (decimalPlaces == 0) {
//return integer value
newValue = (intValueInTheMiddle);
} else {
if (intValueInTheMiddle == maxValue) {
//if new value is maxValue, then return that value and ignore decimal
newValue = (intValueInTheMiddle.toDouble());
animateDecimal(0);
} else {
//return integer+decimal
double decimalPart = _toDecimal(selectedDecimalValue);
newValue = ((intValueInTheMiddle + decimalPart).toDouble());
}
}
if (haptics) {
HapticFeedback.selectionClick();
}
onChanged(newValue);
}
}
return true;
}
bool _onDecimalNotification(Notification notification) {
if (notification is ScrollNotification) {
//calculate middle value
int indexOfMiddleElement =
(notification.metrics.pixels + listViewHeight / 2) ~/ itemExtent;
int decimalValueInTheMiddle = indexOfMiddleElement - 1;
decimalValueInTheMiddle =
_normalizeDecimalMiddleValue(decimalValueInTheMiddle);
if (_userStoppedScrolling(notification, decimalScrollController)) {
//center selected value
animateDecimal(decimalValueInTheMiddle);
}
//update selection
if (selectedIntValue != maxValue &&
decimalValueInTheMiddle != selectedDecimalValue) {
double decimalPart = _toDecimal(decimalValueInTheMiddle);
double newValue = ((selectedIntValue + decimalPart).toDouble());
if (haptics) {
HapticFeedback.selectionClick();
}
onChanged(newValue);
}
}
return true;
}
///There was a bug, when if there was small integer range, e.g. from 1 to 5,
///When user scrolled to the top, whole listview got displayed.
///To prevent this we are calculating cacheExtent by our own so it gets smaller if number of items is smaller
double _calculateCacheExtent(int itemCount) {
double cacheExtent = 250.0; //default cache extent
if ((itemCount - 2) * kDefaultItemExtent <= cacheExtent) {
cacheExtent = ((itemCount - 3) * kDefaultItemExtent);
}
return cacheExtent;
}
///When overscroll occurs on iOS,
///we can end up with value not in the range between [minValue] and [maxValue]
///To avoid going out of range, we change values out of range to border values.
int _normalizeMiddleValue(int valueInTheMiddle, int min, int max) {
return math.max(math.min(valueInTheMiddle, max), min);
}
int _normalizeIntegerMiddleValue(int integerValueInTheMiddle) {
//make sure that max is a multiple of step
int max = (maxValue ~/ step) * step;
return _normalizeMiddleValue(integerValueInTheMiddle, minValue, max);
}
int _normalizeDecimalMiddleValue(int decimalValueInTheMiddle) {
return _normalizeMiddleValue(
decimalValueInTheMiddle, 0, math.pow(10, decimalPlaces) - 1);
}
///indicates if user has stopped scrolling so we can center value in the middle
bool _userStoppedScrolling(
Notification notification,
ScrollController scrollController,
) {
return notification is UserScrollNotification &&
notification.direction == ScrollDirection.idle &&
scrollController.position.activity is! HoldScrollActivity;
}
/// Allows to find currently selected element index and animate this element
/// Use it only when user manually stops scrolling in infinite loop
void _animateIntWhenUserStoppedScrolling(int valueToSelect) {
// estimated index of currently selected element based on offset and item extent
int currentlySelectedElementIndex =
intScrollController.offset ~/ itemExtent;
// when more(less) than half of the top(bottom) element is hidden
// then we should increment(decrement) index in case of positive(negative) offset
if (intScrollController.offset > 0 &&
intScrollController.offset % itemExtent > itemExtent / 2) {
currentlySelectedElementIndex++;
} else if (intScrollController.offset < 0 &&
intScrollController.offset % itemExtent < itemExtent / 2) {
currentlySelectedElementIndex--;
}
animateIntToIndex(currentlySelectedElementIndex);
}
///converts integer indicator of decimal value to double
///e.g. decimalPlaces = 1, value = 4 >>> result = 0.4
/// decimalPlaces = 2, value = 12 >>> result = 0.12
double _toDecimal(int decimalValueAsInteger) {
return double.parse((decimalValueAsInteger * math.pow(10, -decimalPlaces))
.toStringAsFixed(decimalPlaces));
}
///scroll to selected value
_animate(ScrollController scrollController, double value) {
scrollController.animateTo(
value,
duration: Duration(seconds: 1),
curve: ElasticOutCurve(),
);
}
}
class _NumberPickerSelectedItemDecoration extends StatelessWidget {
final Axis axis;
final double itemExtent;
final Decoration decoration;
const _NumberPickerSelectedItemDecoration(
{Key key,
@required this.axis,
@required this.itemExtent,
@required this.decoration})
: super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: IgnorePointer(
child: Container(
width: isVertical ? double.infinity : itemExtent,
height: isVertical ? itemExtent : double.infinity,
decoration: decoration,
),
),
);
}
bool get isVertical => axis == Axis.vertical;
}
///Returns AlertDialog as a Widget so it is designed to be used in showDialog method
class NumberPickerDialog extends StatefulWidget {
final int minValue;
final int maxValue;
final int initialIntegerValue;
final double initialDoubleValue;
final int decimalPlaces;
final Widget title;
final EdgeInsets titlePadding;
final Widget confirmWidget;
final Widget cancelWidget;
final int step;
final bool infiniteLoop;
final bool zeroPad;
final bool highlightSelectedValue;
final Decoration decoration;
final TextMapper textMapper;
final bool haptics;
///constructor for integer values
NumberPickerDialog.integer({
@required this.minValue,
@required this.maxValue,
@required this.initialIntegerValue,
this.title,
this.titlePadding,
this.step = 1,
this.infiniteLoop = false,
this.zeroPad = false,
this.highlightSelectedValue = true,
this.decoration,
this.textMapper,
this.haptics = false,
Widget confirmWidget,
Widget cancelWidget,
}) : confirmWidget = confirmWidget ?? Text("OK"),
cancelWidget = cancelWidget ?? Text("CANCEL"),
decimalPlaces = 0,
initialDoubleValue = -1.0;
///constructor for decimal values
NumberPickerDialog.decimal({
@required this.minValue,
@required this.maxValue,
@required this.initialDoubleValue,
this.decimalPlaces = 1,
this.title,
this.titlePadding,
this.highlightSelectedValue = true,
this.decoration,
this.textMapper,
this.haptics = false,
Widget confirmWidget,
Widget cancelWidget,
}) : confirmWidget = confirmWidget ?? Text("OK"),
cancelWidget = cancelWidget ?? Text("CANCEL"),
initialIntegerValue = -1,
step = 1,
infiniteLoop = false,
zeroPad = false;
@override
State<NumberPickerDialog> createState() => _NumberPickerDialogControllerState(
initialIntegerValue, initialDoubleValue);
}
class _NumberPickerDialogControllerState extends State<NumberPickerDialog> {
int selectedIntValue;
double selectedDoubleValue;
_NumberPickerDialogControllerState(
this.selectedIntValue, this.selectedDoubleValue);
void _handleValueChanged(num value) {
if (value is int) {
setState(() => selectedIntValue = value);
} else {
setState(() => selectedDoubleValue = value);
}
}
NumberPicker _buildNumberPicker() {
if (widget.decimalPlaces > 0) {
return NumberPicker.decimal(
initialValue: selectedDoubleValue,
minValue: widget.minValue,
maxValue: widget.maxValue,
decimalPlaces: widget.decimalPlaces,
highlightSelectedValue: widget.highlightSelectedValue,
decoration: widget.decoration,
onChanged: _handleValueChanged,
textMapper: widget.textMapper,
haptics: widget.haptics,
);
} else {
return NumberPicker.integer(
initialValue: selectedIntValue,
minValue: widget.minValue,
maxValue: widget.maxValue,
step: widget.step,
infiniteLoop: widget.infiniteLoop,
zeroPad: widget.zeroPad,
highlightSelectedValue: widget.highlightSelectedValue,
decoration: widget.decoration,
onChanged: _handleValueChanged,
textMapper: widget.textMapper,
haptics: widget.haptics,
);
}
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: widget.title,
titlePadding: widget.titlePadding,
content: _buildNumberPicker(),
actions: [
FlatButton(
onPressed: () => Navigator.of(context).pop(),
child: widget.cancelWidget,
),
FlatButton(
onPressed: () => Navigator.of(context).pop(widget.decimalPlaces > 0
? selectedDoubleValue
: selectedIntValue),
child: widget.confirmWidget),
],
);
}
}
+3 -3
View File
@@ -81,17 +81,17 @@ class __TreeViewDataState extends State<_TreeViewData> {
subscription = stream.listen((value) {
if (value) {
final double positionY = TreeViewStream().positionY;
print("pos " +
/* print("pos " +
positionY.toString() +
" height: " +
cHeight.toString() +
" controller offset " +
_controller.offset.toString() +
" controller initial " +
_controller.initialScrollOffset.toString());
_controller.initialScrollOffset.toString()); */
if (positionY > cHeight - 190) {
final double offset = positionY + 40;
print("antimateTo " + offset.toString());
//print("antimateTo " + offset.toString());
_controller.animateTo(offset, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
}
}
+2 -2
View File
@@ -6,7 +6,7 @@ import 'package:aitrainer_app/service/firebase_api.dart';
import 'package:aitrainer_app/util/session.dart';
import 'package:aitrainer_app/view/account.dart';
import 'package:aitrainer_app/view/custom_exercise_page.dart';
import 'package:aitrainer_app/view/customer_bodytype_page.dart';
import 'package:aitrainer_app/view/customer_bodytype_animation.dart';
import 'package:aitrainer_app/view/customer_exercise_device.dart';
import 'package:aitrainer_app/view/customer_fitness_page.dart';
import 'package:aitrainer_app/view/customer_goal_page.dart';
@@ -196,7 +196,7 @@ class WorkoutTestApp extends StatelessWidget {
'customerModifyPage': (context) => CustomerModifyPage(),
'customerGoalPage': (context) => CustomerGoalPage(),
'customerFitnessPage': (context) => CustomerFitnessPage(),
'customerBodyTypePage': (context) => CustomerBodyTypePage(),
'customerBodyTypePage': (context) => CustomerBodyTypeAnimationPage(),
'customerWelcomePage': (context) => CustomerWelcomePage(),
'customerExerciseDevicePage': (context) => CustomerExerciseDevicePage(),
'exerciseNewPage': (context) => ExerciseNewPage(),
+30 -28
View File
@@ -11,18 +11,15 @@ import 'package:aitrainer_app/model/property.dart';
import 'package:aitrainer_app/model/purchase.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/service/customer_exercise_device_service.dart';
import 'package:aitrainer_app/service/customer_service.dart';
import 'package:aitrainer_app/service/exercise_device_service.dart';
import 'package:aitrainer_app/service/exercise_tree_service.dart';
import 'package:aitrainer_app/service/exercisetype_service.dart';
import 'package:aitrainer_app/service/firebase_api.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/service/package_service.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/env.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:flurry/flurry.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:package_info/package_info.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
@@ -76,6 +73,7 @@ class Cache with Logging {
Customer userLoggedIn;
String firebaseUid;
LoginType loginType;
PackageInfo packageInfo;
bool hasPurchased = false;
@@ -201,7 +199,7 @@ class Cache with Logging {
} else if (loginType == LoginType.email.toString()) {
type = LoginType.email;
}
print("LoginType: " + loginType == null ? "NULL" : loginType);
//print("LoginType: " + loginType == null ? "NULL" : loginType);
Cache().setLoginType(type);
}
@@ -316,7 +314,7 @@ class Cache with Logging {
List<ExerciseType> getExerciseTypes() => this._exerciseTypes;
ExerciseType getExercise(int exerciseTypeId) {
ExerciseType getExerciseTypeById(int exerciseTypeId) {
ExerciseType exerciseType;
this._exerciseTypes.forEach((element) {
if (element.exerciseTypeId == exerciseTypeId) {
@@ -420,6 +418,10 @@ class Cache with Logging {
CustomerRepository customerRepository = CustomerRepository();
_badges = LinkedHashMap();
customerRepository.setCustomer(userLoggedIn);
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());
if (this.userLoggedIn != null) {
if (this.userLoggedIn.birthYear == null || this.userLoggedIn.birthYear == 0) {
setBadge("personalData", true);
@@ -431,6 +433,7 @@ class Cache with Logging {
}
if (userLoggedIn.properties == null || userLoggedIn.properties.isEmpty) {
setBadge("personalData", true);
setBadge("bodyType", true);
setBadge("Sizes", true);
setBadge("BMI", true);
setBadge("BMR", true);
@@ -442,12 +445,29 @@ class Cache with Logging {
setBadge("My Body", true);
setBadgeNr("home", 1);
}
if (_ecto == 0 && _mezo == 0 && _endo == 0) {
setBadge("account", true);
setBadge("bodyType", true);
}
if (this._exercises == null || this._exercises.length == 0) {
setBadge("home", true);
setBadge("Strength", true);
setBadge("Cardio", true);
}
if (customerRepository.getHeight() == 0) {
setBadge("BMI", true);
setBadge("BMR", true);
setBadge("My Body", true);
setBadgeNr("home", 1);
}
if (userLoggedIn.goal == null) {
setBadge("Goal", true);
setBadge("account", true);
}
if (userLoggedIn.fitnessLevel == null) {
setBadge("FitnessLevel", true);
setBadge("account", true);
}
}
log("Badges: " + _badges.toString());
}
@@ -463,31 +483,13 @@ class Cache with Logging {
Future<void> initCustomer(int customerId) async {
log(" *** initCustomer");
await CustomerApi().getCustomer(customerId);
await PackageApi().getCustomerPackage(customerId);
Flurry.setUserId(customerId.toString());
final customerDevices = await CustomerExerciseDeviceApi().getDevices(customerId);
Cache().setCustomerDevices(customerDevices);
if (this._exerciseTree == null) {
await ExerciseTreeApi().getExerciseTree();
}
if (this._exerciseTypes == null) {
await ExerciseTypeApi().getExerciseTypes();
}
await ExerciseDeviceApi().getDevices();
ExerciseRepository exerciseRepository = ExerciseRepository();
await exerciseRepository.getExercisesByCustomer(customerId);
CustomerRepository customerRepository = CustomerRepository(customer: this.userLoggedIn);
await customerRepository.getPurchase();
await customerRepository.getProductTests();
//this.hasPurchased = this._purchases.isNotEmpty;
await setLoginTypeFromPrefs();
Cache().startPage = "home";
Track().track(TrackingEvent.enter);
}
AccessToken get getAccessTokenFacebook => accessTokenFacebook;
+29 -22
View File
@@ -1,4 +1,6 @@
import 'dart:collection';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'customer_property.dart';
class Customer {
@@ -11,7 +13,6 @@ class Customer {
int customerId;
String password;
int birthYear;
//int weight;
String goal;
String fitnessLevel;
String bodyType;
@@ -19,28 +20,30 @@ class Customer {
int trainer;
int dataPolicyAllowed;
String firebaseUid;
DateTime dateAdd;
DateTime dateChange;
LinkedHashMap<String, CustomerProperty> properties = LinkedHashMap();
Customer({
this.customerId,
this.name,
this.firstname,
this.email,
this.sex,
this.age,
this.active,
this.password,
this.birthYear,
this.bodyType,
this.fitnessLevel,
this.goal,
//this.weight,
this.admin,
this.trainer,
this.dataPolicyAllowed,
this.firebaseUid,
});
Customer(
{this.customerId,
this.name,
this.firstname,
this.email,
this.sex,
this.age,
this.active,
this.password,
this.birthYear,
this.bodyType,
this.fitnessLevel,
this.goal,
this.admin,
this.trainer,
this.dataPolicyAllowed,
this.firebaseUid,
this.dateAdd,
this.dateChange});
Customer.fromJson(Map json) {
this.customerId = json['customerId'];
@@ -54,10 +57,13 @@ class Customer {
this.bodyType = json['bodyType'];
this.fitnessLevel = json['fitnessLevel'];
this.goal = json['goal'];
//this.weight = json['weight'];
this.admin = json['admin'];
this.trainer = json['trainer'];
this.firebaseUid = json['firebaseUid'];
this.dateAdd = json['dateAdd'] == null ? DateTime.parse("0000-00-00") : DateTime.parse(json['dateAdd']);
this.dateChange = json['dateChange'] == null ? DateTime.parse("0000-00-00") : DateTime.parse(json['dateChange']);
}
Map<String, dynamic> toJson() => {
@@ -72,10 +78,11 @@ class Customer {
"bodyType": bodyType,
"fitnessLevel": fitnessLevel,
"goal": goal,
//"weight": weight,
"admin": admin,
"trainer": trainer,
"dataPolicyAllowed": dataPolicyAllowed,
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd),
"dateChange": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateChange),
};
double getProperty(String propertyName) {
+15 -1
View File
@@ -1,6 +1,7 @@
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
class CustomerProperty {
int customerPropertyId;
int propertyId;
int customerId;
DateTime dateAdd;
@@ -10,16 +11,29 @@ class CustomerProperty {
CustomerProperty({this.propertyId, this.customerId, this.dateAdd, this.propertyValue});
CustomerProperty.fromJson(Map json) {
this.customerPropertyId = json['customerPropertyId'];
this.propertyId = json['propertyId'];
this.customerId = json['customerId'];
this.dateAdd = json['propertyName'];
this.propertyValue = json['propertyValue'];
}
Map<String, dynamic> toJson() => {
Map<String, dynamic> toJson() {
if (customerPropertyId != null) {
return {
"customerPropertyId": this.customerPropertyId,
"propertyId": this.propertyId,
"customerId": this.customerId,
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd),
"propertyValue": this.propertyValue
};
} else {
return {
"propertyId": this.propertyId,
"customerId": this.customerId,
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd),
"propertyValue": this.propertyValue
};
}
}
}
+24
View File
@@ -0,0 +1,24 @@
import 'dart:io';
import 'package:aitrainer_app/model/cache.dart';
import 'package:intl/intl.dart';
class Tracking {
int customerId;
DateTime dateAdd;
String event;
String eventValue;
String area;
String platform;
String version;
Map<String, dynamic> toJson() => {
"customerId": customerId,
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd),
"event": event,
"eventValue": eventValue,
"area": Platform.localeName,
"platform": Platform.isAndroid ? "Android" : "iOS",
"version": Cache().packageInfo.version + "+" + Cache().packageInfo.buildNumber
};
}
+17 -3
View File
@@ -4,12 +4,13 @@ import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/model/customer_property.dart';
import 'package:aitrainer_app/model/product_test.dart';
import 'package:aitrainer_app/model/property.dart';
import 'package:aitrainer_app/model/purchase.dart';
import 'package:aitrainer_app/repository/property_repository.dart';
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.dart';
import 'package:aitrainer_app/service/purchase_service.dart';
import 'package:aitrainer_app/util/not_found_exception.dart';
class GenderItem {
@@ -115,7 +116,7 @@ class CustomerRepository with Logging {
this.setCustomerProperty(propertyName, height.toDouble());
}
setCustomerProperty(String propertyName, double value) {
setCustomerProperty(String propertyName, double value, {id = 0}) {
if (this.customer.properties[propertyName] == null) {
this.customer.properties[propertyName] = CustomerProperty(
propertyId: propertyRepository.getPropertyByName("Height").propertyId,
@@ -126,6 +127,9 @@ class CustomerRepository with Logging {
}
this.customer.properties[propertyName].dateAdd = DateTime.now();
this.customer.properties[propertyName].newData = true;
if (id > 0) {
this.customer.properties[propertyName].customerPropertyId = id;
}
}
double getWeight() {
@@ -137,7 +141,7 @@ class CustomerRepository with Logging {
}
double getCustomerPropertyValue(String propertyName) {
if (this.customer.properties[propertyName] == null) {
if (this.customer == null || this.customer.properties == null || this.customer.properties[propertyName] == null) {
return 0.0;
} else {
return this.customer.properties[propertyName].propertyValue;
@@ -196,6 +200,16 @@ class CustomerRepository with Logging {
});
}
Future<void> savePropertyByName(String name) async {
await Future.forEach(this._allProperties, (element) async {
final CustomerProperty customerProperty = element;
final Property property = propertyRepository.getPropertyByName(name);
if (property.propertyId == customerProperty.propertyId) {
await CustomerApi().updateProperty(customerProperty);
}
});
}
Future<Customer> getTraineeAsCustomer() async {
this._trainee = await CustomerApi().getTrainee(Cache().userLoggedIn.customerId);
return _trainee;
+3 -2
View File
@@ -290,7 +290,7 @@ class ExerciseRepository {
String exerciseDate = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd);
//print(" -- $prevExerciseTypeId - $prevDate");
if (!(exerciseTypeId == prevExerciseTypeId && prevDate == exerciseDate)) {
ExerciseType exerciseType = Cache().getExercise(prevExercise.exerciseTypeId);
ExerciseType exerciseType = Cache().getExerciseTypeById(prevExercise.exerciseTypeId);
String unit = exerciseType.unitQuantityUnit != null ? exerciseType.unitQuantityUnit : prevExercise.unit;
prevExercise.summary = summary + " " + unit;
exerciseLogList.add(prevExercise);
@@ -302,7 +302,8 @@ class ExerciseRepository {
if (prevCount > 0) delimiter = ", ";
double quantity = exercise.quantity == null ? 0 : exercise.quantity;
summary += delimiter + quantity.toStringAsFixed(0);
ExerciseType exerciseType = Cache().getExercise(exercise.exerciseTypeId);
ExerciseType exerciseType = Cache().getExerciseTypeById(exercise.exerciseTypeId);
//print("exerciseType " + (exerciseType == null ? "NULL" : exerciseType.name) + " ID " + exercise.exerciseTypeId.toString());
if (exerciseType.unitQuantity == "1") {
summary += "x" + exercise.unitQuantity.toStringAsFixed(0);
}
+3 -2
View File
@@ -7,7 +7,7 @@ import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/service/exercise_tree_service.dart';
import 'package:aitrainer_app/service/exercisetype_service.dart';
import 'package:aitrainer_app/service/exercise_type_service.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:flutter/material.dart';
@@ -22,7 +22,7 @@ class Antagonist {
static int backNr = 4;
static String shoulder = "Shoulders";
static int shoulderNr = 5;
static String core = "Core";
static String core = "Core & ABS";
static int coreNr = 6;
static String thigh = "Thigh";
static int thighNr = 7;
@@ -48,6 +48,7 @@ class WorkoutTreeRepository with Logging {
};
Future<void> createTree() async {
//if (Cache().getExerciseTree().length > 0 || Cache().getWorkoutMenuTree().length > 0) return;
isEnglish = AppLanguage().appLocal == Locale('en');
log("** Start creating tree on lang: " +
AppLanguage().appLocal.languageCode +
+40 -6
View File
@@ -21,6 +21,7 @@ class CustomerApi with Logging {
}
Future<void> saveCustomer(Customer customer) async {
customer.dateChange = DateTime.now();
String body = JsonEncoder().convert(customer.toJson());
log(" ===== saving customer id: " + customer.customerId.toString() + ":" + body);
await _client.post("customers/" + customer.customerId.toString(), body);
@@ -32,6 +33,8 @@ class CustomerApi with Logging {
}
Future<void> addCustomer(Customer customer) async {
customer.dateAdd = DateTime.now();
customer.dateChange = DateTime.now();
String body = JsonEncoder().convert(customer.toJson());
log(" ===== add new customer: " + body);
await _client.post("customers", body);
@@ -84,7 +87,7 @@ class CustomerApi with Logging {
Cache().userLoggedIn = customer;
final List properties = await this.getActualProperties(customer.customerId);
if (properties != null) {
this._initProperties(properties);
this.initProperties(properties);
}
} on FormatException {
throw new Exception(responseBody);
@@ -103,7 +106,7 @@ class CustomerApi with Logging {
//log(" ---- Props: " + properties.toJson().toString());
//await Cache().initCustomer(customerId);
if (properties != null) {
this._initProperties(properties);
this.initProperties(properties);
}
} on Exception catch (exception) {
log("Exception: " + exception.toString());
@@ -113,7 +116,7 @@ class CustomerApi with Logging {
}
}
void _initProperties(List<CustomerProperty> customerProperties) {
void initProperties(final List<CustomerProperty> customerProperties) {
List<Property> properties = Cache().getProperties();
Customer customer = Cache().userLoggedIn;
customer.properties = LinkedHashMap<String, CustomerProperty>();
@@ -190,22 +193,53 @@ class CustomerApi with Logging {
return properties;
}
Future<void> addProperty(CustomerProperty property) async {
Future<CustomerProperty> addProperty(CustomerProperty property) async {
String body = JsonEncoder().convert(property.toJson());
log(" ===== add new customer property: " + body);
final String responseBody = await _client.post("customer_property", body);
CustomerProperty customerProperty;
String responseBody;
try {
responseBody = await _client.post("customer_property", body);
log(" responseBody: " + responseBody);
int status = jsonDecode(responseBody)['status'];
if (status != null) {
throw new Exception(jsonDecode(responseBody)['error']);
} else {
CustomerProperty customerProperty = CustomerProperty.fromJson(jsonDecode(responseBody));
customerProperty = CustomerProperty.fromJson(jsonDecode(responseBody));
if (customerProperty == null) {
throw new Exception("Property Insert was not successful");
}
}
} on FormatException {
throw new Exception(responseBody);
} on Exception catch (e) {
throw new Exception(e);
}
return customerProperty;
}
Future<CustomerProperty> updateProperty(CustomerProperty property) async {
String body = JsonEncoder().convert(property.toJson());
CustomerProperty customerProperty;
log(" ===== update customer property: " + body);
String responseBody;
try {
responseBody = await _client.post("customer_property/update/" + property.customerPropertyId.toString(), body);
log(" responseBody: " + responseBody);
int status = jsonDecode(responseBody)['status'];
if (status != null) {
throw new Exception(jsonDecode(responseBody)['error']);
} else {
customerProperty = CustomerProperty.fromJson(jsonDecode(responseBody));
if (customerProperty == null) {
throw new Exception("Property Update was not successful");
}
}
} on FormatException {
throw new Exception(responseBody);
} on Exception catch (e) {
throw new Exception(e);
}
return customerProperty;
}
}
-8
View File
@@ -6,14 +6,6 @@ import 'package:aitrainer_app/service/logging.dart';
class ExerciseApi with Logging {
final APIClient _client = new APIClient();
Future<List<Exercise>> getExerciseTypes(String param) async {
final body = await _client.get("exercises", param);
final Iterable json = jsonDecode(body);
final List<Exercise> exerciseTypes = json.map((exerciseType) => Exercise.fromJson(exerciseType)).toList();
return exerciseTypes;
}
Future<void> saveExercise(Exercise exercise) async {
String body = JsonEncoder().convert(exercise.toJson());
log(" ===== saving exercise id: " + exercise.exerciseId.toString() + ":" + body);
+4 -4
View File
@@ -20,7 +20,7 @@ class ExerciseTreeApi with Logging {
if (exerciseTree != null) {
await Future.forEach(exerciseTree, (element) async {
//exerciseTree.forEach((element) async {
element.imageUrl = await _buildImage(element.imageUrl, element.treeId);
element.imageUrl = await buildImage(element.imageUrl, element.treeId);
});
log("ExerciseTree downloaded");
Cache().setExerciseTree(exerciseTree);
@@ -29,7 +29,7 @@ class ExerciseTreeApi with Logging {
return exerciseTree;
}
Future<String> _buildImage(String imageUrl, int treeId) async {
Future<String> buildImage(String imageUrl, int treeId) async {
String assetImage = 'asset/menu/' + imageUrl.substring(7);
return await rootBundle.load(assetImage).then((value) {
return assetImage;
@@ -41,7 +41,7 @@ class ExerciseTreeApi with Logging {
}
Future<List<ExerciseTree>> getExerciseTreeParents(List<ExerciseTree> exerciseTree) async {
List<ExerciseTree> copyList = this._copyList(exerciseTree);
List<ExerciseTree> copyList = this.copyList(exerciseTree);
final String body = await _client.get("exercise_tree_parents", "");
Iterable json = jsonDecode(body);
@@ -71,7 +71,7 @@ class ExerciseTreeApi with Logging {
return exerciseTree;
}
List<ExerciseTree> _copyList(List<ExerciseTree> tree) {
List<ExerciseTree> copyList(List<ExerciseTree> tree) {
final List<ExerciseTree> copyList = List();
tree.forEach((element) {
final ExerciseTree copy = element.copy(-1);
@@ -1,5 +1,4 @@
import 'dart:convert';
import 'package:aitrainer_app/library/image_cache.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/service/api.dart';
@@ -14,9 +13,8 @@ class ExerciseTypeApi with Logging {
final Iterable json = jsonDecode(body);
final List<ExerciseType> exerciseTypes = json.map((exerciseType) => ExerciseType.fromJson(exerciseType)).toList();
if (exerciseTypes != null) {
exerciseTypes.forEach((element) async {
element.imageUrl = await _buildImage(element.imageUrl, element.exerciseTypeId);
//ImageCache().downloadAndSaveImage(element.exerciseTypeId, element.imageUrl);
await Future.forEach(exerciseTypes, (element) async {
element.imageUrl = await buildImage(element.imageUrl, element.exerciseTypeId);
});
log("ExerciseTypes downloaded");
Cache().setExerciseTypes(exerciseTypes);
@@ -25,7 +23,7 @@ class ExerciseTypeApi with Logging {
return exerciseTypes;
}
Future<String> _buildImage(String imageUrl, int exerciseTypeId) async {
Future<String> buildImage(String imageUrl, int exerciseTypeId) async {
if (imageUrl.length > 8) {
String assetImage = 'asset/menu/' + imageUrl.substring(7);
return rootBundle.load(assetImage).then((value) {
@@ -39,16 +37,4 @@ class ExerciseTypeApi with Logging {
return imageUrl;
}
}
Future<void> saveExerciseType(ExerciseType exerciseType) async {
String body = JsonEncoder().convert(exerciseType.toJson());
log(" ===== saving exerciseType id: " + exerciseType.exerciseTypeId.toString() + ":" + body);
await _client.post("exercise_type/" + exerciseType.exerciseTypeId.toString(), body);
}
Future<void> addExerciseType(ExerciseType exerciseType) async {
String body = JsonEncoder().convert(exerciseType.toJson());
log(" ===== add new exerciseType: " + body);
await _client.post("exercise_type", body);
}
}
+142
View File
@@ -0,0 +1,142 @@
import 'dart:convert';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/model/customer_exercise_device.dart';
import 'package:aitrainer_app/model/customer_property.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_device.dart';
import 'package:aitrainer_app/model/exercise_result.dart';
import 'package:aitrainer_app/model/exercise_tree.dart';
import 'package:aitrainer_app/model/exercise_tree_parents.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/product.dart';
import 'package:aitrainer_app/model/product_test.dart';
import 'package:aitrainer_app/model/property.dart';
import 'package:aitrainer_app/model/purchase.dart';
import 'package:aitrainer_app/service/api.dart';
import 'package:aitrainer_app/service/exercise_type_service.dart';
import 'package:aitrainer_app/util/not_found_exception.dart';
import 'customer_service.dart';
import 'exercise_tree_service.dart';
class PackageApi {
final APIClient _client = new APIClient();
Future<void> getPackage() async {
List<ExerciseTree> exerciseTree;
List<ExerciseTreeParents> exerciseTreeParents;
final body = await _client.get("app_package/", "");
final List<String> models = body.split("|||");
await Future.forEach(models, (element) async {
final List<String> headRecord = element.split("***");
final Iterable json = jsonDecode(headRecord[1]);
if (headRecord[0] == "ExerciseDevice") {
final List<ExerciseDevice> devices = json.map((device) => ExerciseDevice.fromJson(device)).toList();
Cache().setDevices(devices);
} else if (headRecord[0] == "Product") {
final List<Product> products = json.map((product) => Product.fromJson(product)).toList();
Cache().setProducts(products);
} else if (headRecord[0] == "Property") {
final List<Property> properties = json.map((property) => Property.fromJson(property)).toList();
Cache().setProperties(properties);
} else if (headRecord[0] == "ExerciseTree") {
exerciseTree = json.map((exerciseTree) => ExerciseTree.fromJson(exerciseTree)).toList();
} else if (headRecord[0] == "ExerciseType") {
final List<ExerciseType> exerciseTypes = json.map((exerciseType) => ExerciseType.fromJson(exerciseType)).toList();
if (exerciseTypes != null) {
await Future.forEach(exerciseTypes, (element) async {
element.imageUrl = await ExerciseTypeApi().buildImage(element.imageUrl, element.exerciseTypeId);
});
Cache().setExerciseTypes(exerciseTypes);
}
} else if (headRecord[0] == "ExerciseAbility") {
} else if (headRecord[0] == "ExerciseTreeParents") {
exerciseTreeParents = json.map((exerciseTreeParent) => ExerciseTreeParents.fromJson(exerciseTreeParent)).toList();
}
});
exerciseTree = this.getExerciseTreeParents(exerciseTree, exerciseTreeParents);
if (exerciseTree != null) {
await Future.forEach(exerciseTree, (element) async {
element.imageUrl = await ExerciseTreeApi().buildImage(element.imageUrl, element.treeId);
});
Cache().setExerciseTree(exerciseTree);
}
return;
}
List<ExerciseTree> getExerciseTreeParents(final List<ExerciseTree> exerciseTree, final List<ExerciseTreeParents> exerciseTreeParents) {
List<ExerciseTree> copyList = ExerciseTreeApi().copyList(exerciseTree);
int treeIndex = 0;
copyList.forEach((element) async {
int index = 0;
exerciseTreeParents.forEach((parent) {
if (parent.exerciseTreeChildId == element.treeId) {
if (index > 0) {
ExerciseTree newElement = element.copy(parent.exerciseTreeParentId);
exerciseTree.add(newElement);
} else {
element.parentId = parent.exerciseTreeParentId;
exerciseTree[treeIndex].parentId = parent.exerciseTreeParentId;
}
index++;
}
});
treeIndex++;
});
return exerciseTree;
}
Future<void> getCustomerPackage(int customerId) async {
try {
final body = await _client.get("app_customer_package/" + customerId.toString(), "");
final List<String> models = body.split("|||");
await Future.forEach(models, (element) async {
final List<String> headRecord = element.split("***");
//print("Class " + headRecord[0]);
if (headRecord[0] == "Customer") {
Customer customer = Customer.fromJson(jsonDecode(headRecord[1]));
Cache().userLoggedIn = customer;
} else if (headRecord[0] == "CustomerExerciseDevice") {
final Iterable json = jsonDecode(headRecord[1]);
final List<CustomerExerciseDevice> devices = json.map((device) => CustomerExerciseDevice.fromJson(device)).toList();
Cache().setCustomerDevices(devices);
// ToDo
} else if (headRecord[0] == "Exercises") {
final Iterable json = jsonDecode(headRecord[1]);
final List<Exercise> exercises = json.map((exerciseType) => Exercise.fromJson(exerciseType)).toList();
Cache().setExercises(exercises);
} else if (headRecord[0] == "ProductTest") {
final Iterable json = jsonDecode(headRecord[1]);
final List<ProductTest> productTests = json.map((productTest) => ProductTest.fromJson(productTest)).toList();
Cache().productTests = productTests;
} else if (headRecord[0] == "Purchase") {
final Iterable json = jsonDecode(headRecord[1]);
final List<Purchase> purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList();
Cache().setPurchases(purchases);
} else if (headRecord[0] == "CustomerProperty") {
final Iterable json = jsonDecode(headRecord[1]);
final List<CustomerProperty> customerProperties = json.map((property) => CustomerProperty.fromJson(property)).toList();
CustomerApi().initProperties(customerProperties);
} else if (headRecord[0] == "ExerciseResult") {
final Iterable json = jsonDecode(headRecord[1]);
final List<ExerciseResult> exerciseResults = json.map((exerciseResult) {
ExerciseResult item = ExerciseResult.fromJson(exerciseResult);
return item;
}).toList();
// ToDo
}
});
} on NotFoundException catch (_) {
throw Exception("Please log in");
}
}
}
+14
View File
@@ -0,0 +1,14 @@
import 'package:aitrainer_app/model/tracking.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'dart:convert';
import 'api.dart';
class TrackingApi with Logging {
final APIClient _client = new APIClient();
Future<void> saveTracking(Tracking tracking) async {
String body = JsonEncoder().convert(tracking.toJson());
log(" ===== saving tracking:" + body);
await _client.post("tracking/", body);
}
}
+58
View File
@@ -4,3 +4,61 @@ extension LoginTypeExt on LoginType {
bool equalsTo(LoginType type) => this.toString() == type.toString();
bool equalsStringTo(String type) => this.toString() == type;
}
enum TrackingEvent {
enter,
login,
logout,
registration,
home,
sizes,
sizes_save,
my_development,
my_exerciseplan,
account,
settings,
sales_page,
purchase_request,
purchase_successful,
exercise_new,
result,
exercise_log,
exercise_log_open,
exercise_log_delete,
exercise_log_result,
my_body_development,
my_muscle_development,
my_size_development,
my_custom_exercise_plan,
my_custom_exercise_plan_save,
my_exercise_plan_execute_open,
my_exercise_plan_execute_save,
my_special_plan,
my_suggested_plan,
prediction,
exercise_device,
customer_change,
settings_lang,
settings_server
}
T enumFromString<T>(Iterable<T> values, String value) {
return values.firstWhere((type) => type.toString().split(".").last == value, orElse: () => null);
}
extension TrackingEventExt on TrackingEvent {
String enumToString() => this.toString().split(".").last;
bool equalsTo(TrackingEvent event) => this.toString() == event.toString();
bool equalsStringTo(String event) => this.toString() == event;
}
enum PropertyEnum { Ectomorph, Mesomorph, Endomorph }
extension PropertyExt on PropertyEnum {
String toStr() => this.toString().split(".").last;
bool equalsTo(PropertyEnum event) => this.toString() == event.toString();
bool equalsStringTo(String event) => this.toString() == event;
}
+1
View File
@@ -26,6 +26,7 @@ class RevenueCatPurchases with Logging {
await Purchases.setup("yLxGFWaeRtThLImqznvBnUEKjgArSsZE", appUserId: Cache().userLoggedIn.customerId.toString());
appUserId = await Purchases.appUserID;
log("AppUserId: " + appUserId);
await Purchases.setAllowSharingStoreAccount(true);
await this.restore();
}
}
+7 -6
View File
@@ -2,13 +2,17 @@ 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/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';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:aitrainer_app/model/cache.dart';
@@ -21,6 +25,7 @@ class Session with Logging {
log(" -- Session: await prefs..");
_sharedPreferences = await _prefs;
print("Platform: " + Platform.localeName);
Cache().packageInfo = await PackageInfo.fromPlatform();
if (Cache().firstLoad) {
log(" -- Session: fetch locale..");
await AppLanguage().getLocale(_sharedPreferences);
@@ -30,10 +35,6 @@ class Session with Logging {
Cache().getHardware(_sharedPreferences);
await _fetchToken(_sharedPreferences);
await RevenueCatPurchases().initPlatform();
//initDeviceLocale();
// Create the initialization Future outside of `build`:
}
}
@@ -70,8 +71,8 @@ class Session with Logging {
prefs.setString(Cache.authTokenKey, responseJson['token']);
Cache().authToken = responseJson['token'];
Cache().firebaseUid = prefs.get(Cache.firebaseUidKey);
await PropertyApi().getProperties();
await ProductApi().getProducts();
await PackageApi().getPackage();
if (prefs.get(Cache.customerIdKey) == null) {
log("************** Registration");
// registration
+31
View File
@@ -0,0 +1,31 @@
import 'package:aitrainer_app/main.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/service/tracking_service.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:flurry/flurry.dart';
import 'package:aitrainer_app/model/tracking.dart' as model;
class Track with Logging {
static final Track _singleton = Track._internal();
factory Track() {
return _singleton;
}
Track._internal();
void track(TrackingEvent event, {String eventValue = ""}) {
if (!isInDebugMode) {
Flurry.logEvent(event.toString());
model.Tracking tracking = model.Tracking();
tracking.customerId = Cache().userLoggedIn.customerId;
tracking.event = event.enumToString();
if (eventValue.isNotEmpty) {
tracking.eventValue = eventValue;
}
tracking.dateAdd = DateTime.now();
TrackingApi().saveTracking(tracking);
}
}
}
+92 -32
View File
@@ -1,8 +1,13 @@
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/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';
@@ -24,7 +29,7 @@ class AccountPage extends StatelessWidget with Trans {
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -35,41 +40,27 @@ class AccountPage extends StatelessWidget with Trans {
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is AccountLoading) {}
}, builder: (context, state) {
if (state is AccountInitial) {
String customerName = accountBloc.customerRepository.firstName + " " + accountBloc.customerRepository.name;
if (customerName.length < 3) {
customerName = t("Personal data");
}
return accountWidget(context, customerName, accountBloc);
} else if (state is AccountLoggedIn) {
String customerName = accountBloc.customerRepository.firstName + " " + accountBloc.customerRepository.name;
if (customerName.length < 3) {
customerName = t("Personal data");
}
return accountWidget(context, customerName, accountBloc);
} else if (state is AccountLoggedOut) {
String customerName = "";
if (customerName.length < 3) {
customerName = t("Personal data");
}
return accountWidget(context, customerName, accountBloc);
} else if (state is AccountReady) {
String customerName = accountBloc.customerRepository.firstName + " " + accountBloc.customerRepository.name;
if (customerName.length < 3) {
customerName = t("Personal data");
}
return accountWidget(context, customerName, accountBloc);
} else {
return accountWidget(context, t("Personal data"), accountBloc);
}
return accountWidget(context, accountBloc);
}),
),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 3));
}
ListView accountWidget(BuildContext context, String customerName, AccountBloc accountBloc) {
ListView accountWidget(BuildContext context, AccountBloc accountBloc) {
String customerName = "";
String goal = t("Set your goal");
String fitnessLevel = t("Set your fitness level");
String bodyType = "";
if (accountBloc.customerRepository.customer != null) {
customerName = accountBloc.customerRepository.firstName + " " + accountBloc.customerRepository.name;
customerName = customerName.length < 3 ? t("Personal data") : customerName;
goal = accountBloc.customerRepository.customer.goal != null ? t(accountBloc.customerRepository.customer.goal) : goal;
fitnessLevel = accountBloc.customerRepository.customer.fitnessLevel != null
? t(capitalize(accountBloc.customerRepository.customer.fitnessLevel))
: fitnessLevel;
bodyType = accountBloc.getAccurateBodyType();
}
final HashMap<String, dynamic> args = HashMap();
return ListView(padding: EdgeInsets.only(top: 35), children: <Widget>[
ListTile(
leading: Common.badgedIcon(Colors.grey, Icons.perm_identity, "personalData"), //Icon(Icons.perm_identity),
@@ -84,7 +75,68 @@ class AccountPage extends StatelessWidget with Trans {
onPressed: () => {
if (accountBloc.customerRepository.customer != null && Cache().userLoggedIn != null)
{
Navigator.of(context).pushNamed('customerModifyPage'),
args['personal_data'] = true,
Navigator.of(context).pushNamed('customerModifyPage', arguments: args),
}
},
),
),
ListTile(
leading: Common.badgedIcon(Colors.grey, Icons.arrow_forward_sharp, "Goal"), //Icon(Icons.arrow_forward_sharp),
subtitle: Text(t("Goal")),
title: FlatButton(
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(goal, style: TextStyle(color: Colors.blue)),
Icon(Icons.arrow_forward_ios),
]),
textColor: Colors.grey,
color: Colors.white,
onPressed: () => {
if (accountBloc.customerRepository.customer != null && Cache().userLoggedIn != null)
{
args['personal_data'] = true,
args['bloc'] = accountBloc.customerRepository,
Navigator.of(context).pushNamed('customerGoalPage', arguments: args),
}
},
),
),
ListTile(
leading: Common.badgedIcon(Colors.grey, Icons.perm_contact_cal, "FitnessLevel"), //Icon(Icons.perm_contact_cal),
subtitle: Text(t("Activity")),
title: FlatButton(
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(fitnessLevel, style: TextStyle(color: Colors.blue)),
Icon(Icons.arrow_forward_ios),
]),
textColor: Colors.grey,
color: Colors.white,
onPressed: () => {
if (accountBloc.customerRepository.customer != null && Cache().userLoggedIn != null)
{
args['personal_data'] = true,
args['bloc'] = accountBloc.customerRepository,
Navigator.of(context).pushNamed('customerFitnessPage', arguments: args),
}
},
),
),
ListTile(
leading: Common.badgedIcon(Colors.grey, CustomIcon.people_arrows, "bodyType"), //Icon(CustomIcon.people_arrows),
subtitle: Text(t("Body Type")),
title: FlatButton(
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(t(bodyType), style: TextStyle(color: Colors.blue)),
Icon(Icons.arrow_forward_ios),
]),
textColor: Colors.grey,
color: Colors.white,
onPressed: () => {
if (accountBloc.customerRepository.customer != null && Cache().userLoggedIn != null)
{
args['personal_data'] = true,
args['bloc'] = accountBloc.customerRepository,
Navigator.of(context).pushNamed('customerBodyTypePage', arguments: args),
}
},
),
@@ -99,6 +151,7 @@ class AccountPage extends StatelessWidget with Trans {
ListTile element = ListTile();
element = ListTile(
leading: Common.badgedIcon(Colors.grey, Icons.device_hub, "customerDevice"),
subtitle: Text(t("These equipments and devices are available")),
title: FlatButton(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -240,4 +293,11 @@ class AccountPage extends StatelessWidget with Trans {
],
));
}
String capitalize(String s) {
if (s == null || s.isEmpty) {
return " ";
}
return s[0].toUpperCase() + s.substring(1);
}
}
+1 -1
View File
@@ -64,7 +64,7 @@ class _CustomExerciseNewPageState extends State<CustomExercisePage> with Logging
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
+675
View File
@@ -0,0 +1,675 @@
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/repository/customer_repository.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/dialog_html.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:liquid_progress_indicator/liquid_progress_indicator.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:rainbow_color/rainbow_color.dart';
class CustomerBodyTypeAnimationPage extends StatefulWidget {
@override
_CustomerBodyTypeAnimationPageState createState() => _CustomerBodyTypeAnimationPageState();
}
class _CustomerBodyTypeAnimationPageState extends State<CustomerBodyTypeAnimationPage> with Trans {
bool fulldata;
@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;
}
setContext(context);
return Scaffold(
appBar: AppBarNav(depth: 0),
body: Container(
height: double.infinity,
width: double.infinity,
alignment: Alignment.center,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_G_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.topCenter,
),
),
child: BlocProvider(
create: (context) => BodytypeBloc(repository: customerRepository),
child: BlocConsumer<BodytypeBloc, BodytypeState>(listener: (context, state) {
if (state is BodytypeError) {
Scaffold.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.error, style: TextStyle(color: Colors.white))));
}
}, builder: (context, state) {
final bloc = BlocProvider.of<BodytypeBloc>(context);
return ModalProgressHUD(
child: getBodyTypeAnimation(bloc),
inAsyncCall: state is BodytypeLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}))),
);
}
Widget getBodyTypeAnimation(BodytypeBloc bloc) {
return Column(
children: [
Text(t("Body Type Analyser"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
fontSize: 24,
color: Colors.yellow[300],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
SizedBox(
height: 30,
),
_AnimatedLiquidCustomProgressIndicator(
percentFrom: ((bloc.step - 1) / 22 * 100).toInt(),
percentTo: (bloc.step / 22 * 100).toInt(),
),
Divider(
color: Colors.transparent,
),
Text(t("How likely is it true about you?"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
fontSize: 16,
color: Colors.yellow[300],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
SizedBox(
height: 30,
),
Divider(
color: Colors.white54,
),
Question(
bloc: bloc,
text: bloc.getQuestion(),
),
Divider(color: Colors.transparent),
drawCircles(bloc),
Divider(
color: Colors.transparent,
),
getLegend("Very unlikely", "Maybe", "Very likely"),
Divider(color: Colors.transparent),
InkWell(
onTap: () => bloc.add(BodytypeBack()),
child: Text(t("« Back"),
textAlign: TextAlign.center,
style: GoogleFonts.inter(
fontSize: 16,
color: Colors.blue[300],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
))),
Divider(
color: Colors.white54,
),
SizedBox(
height: 20,
),
bloc.showResults()
? Text(t("Your Bodytype result"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.yellow[300],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
))
: Offstage(),
SizedBox(
height: 30,
),
bloc.showResults() ? BodyTypeResult(bloc: bloc) : Offstage(),
Divider(
color: Colors.transparent,
),
bloc.showResults()
? getLegend(PropertyEnum.Ectomorph.toStr(), PropertyEnum.Mesomorph.toStr(), PropertyEnum.Endomorph.toStr(), info: true)
: Offstage(),
],
);
}
Widget getLegend(String text1, String text2, String text3, {bool info = false}) {
return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(t(text1),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
fontSize: 14,
color: Colors.green[300],
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 14.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
info
? GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogHTML(
title: t(text1),
htmlData: t(text1 + "_desc"),
);
}),
child: Icon(
Icons.info_outline_rounded,
color: Colors.yellow[100],
))
: Offstage(),
SizedBox(
width: 5,
),
Text(t(text2),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
fontSize: 14,
color: Colors.green[300],
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,
),
],
)),
info
? GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogHTML(
title: t(text2),
htmlData: t(text2 + "_desc"),
);
}),
child: Icon(
Icons.info_outline_rounded,
color: Colors.yellow[100],
))
: Offstage(),
SizedBox(
width: 5,
),
Text(t(text3),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
fontSize: 14,
color: Colors.green[300],
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,
),
],
)),
info
? GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogHTML(
title: t(text3),
htmlData: t(text3 + "_desc"),
);
}),
child: Icon(
Icons.info_outline_rounded,
color: Colors.yellow[100],
))
: Offstage(),
]);
}
Widget drawCircles(BodytypeBloc bloc) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
CircleButton(value: 1, bloc: bloc, onTap: () => bloc.add(BodytypeClick(value: 1))),
CircleButton(value: 2, bloc: bloc, onTap: () => bloc.add(BodytypeClick(value: 2))),
CircleButton(value: 3, bloc: bloc, onTap: () => bloc.add(BodytypeClick(value: 3))),
CircleButton(value: 4, bloc: bloc, onTap: () => bloc.add(BodytypeClick(value: 4))),
CircleButton(value: 5, bloc: bloc, onTap: () => bloc.add(BodytypeClick(value: 5))),
],
);
}
}
class BodyTypeResult extends StatefulWidget {
final BodytypeBloc bloc;
const BodyTypeResult({this.bloc});
@override
_BodyTypeResultState createState() => _BodyTypeResultState();
}
class _BodyTypeResultState extends State<BodyTypeResult> with TickerProviderStateMixin {
Animation<Color> colorAnim;
AnimationController colorController;
@override
void initState() {
buildAnimation();
super.initState();
}
void buildAnimation() {
colorController = AnimationController(duration: Duration(seconds: 2), vsync: this);
colorAnim = RainbowColorTween([
Colors.green[800],
Colors.green[700],
Colors.green[600],
Colors.green[500],
Colors.green[400],
Colors.green[300],
Colors.green[200],
Colors.green[100],
Color(0xffb4f500),
]).animate(colorController)
..addListener(() {
setState(() {});
});
colorController.forward();
}
@override
void didUpdateWidget(BodyTypeResult oldWidget) {
buildAnimation();
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
colorController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(left: 15, right: 15),
width: MediaQuery.of(context).size.width - 20,
height: 5,
child: CustomPaint(
painter: CurvePainter(value: widget.bloc.getBodyTypeValue(), color: colorAnim.value),
));
}
}
class CurvePainter extends CustomPainter {
final linePainter = Paint();
final circlePainter = Paint();
final Color color;
final int value;
CurvePainter({this.value, this.color});
@override
void paint(Canvas canvas, Size size) {
var paint = linePainter;
paint.color = Colors.green[800];
paint.strokeWidth = 5;
paint.style = PaintingStyle.fill;
canvas.drawLine(
Offset(0, size.height / 2),
Offset(size.width, size.height / 2),
paint,
);
paint.strokeWidth = 12;
canvas.drawCircle(Offset(size.width / 2, size.height / 2), 6, paint);
canvas.drawCircle(Offset(0, size.height / 2), 6, paint);
canvas.drawCircle(Offset(size.width, size.height / 2), 6, paint);
var paint2 = circlePainter;
paint2.color = this.color; //Color(0xffb4f500);
paint2.strokeWidth = 30;
canvas.drawCircle(Offset(size.width * (value / 100), size.height / 2), 15, paint2);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}
class Question extends StatefulWidget {
final String text;
final BodytypeBloc bloc;
const Question({this.text, this.bloc});
@override
_QuestionState createState() => _QuestionState();
}
class _QuestionState extends State<Question> with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;
@override
void initState() {
super.initState();
buildAnimation();
}
@override
void didUpdateWidget(Question oldWidget) {
if (oldWidget.text != widget.text) {
buildAnimation();
}
super.didUpdateWidget(oldWidget);
}
void buildAnimation() {
_controller = AnimationController(duration: const Duration(milliseconds: 1000), vsync: this);
_animation = CurvedAnimation(parent: _controller, curve: Curves.slowMiddle);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: FadeTransition(
key: ValueKey(widget.text),
opacity: _animation,
child: Text(AppLocalizations.of(context).translate(widget.bloc.getQuestion()),
textAlign: TextAlign.center,
maxLines: 3,
style: GoogleFonts.archivoBlack(
fontSize: 18,
color: Color(0xffb4f500),
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
))));
}
}
class CircleButton extends StatefulWidget {
final GestureTapCallback onTap;
final BodytypeBloc bloc;
final int value;
CircleButton({Key key, this.onTap, this.bloc, this.value}) : super(key: key);
@override
_CircleButtonState createState() => _CircleButtonState();
}
class _CircleButtonState extends State<CircleButton> with TickerProviderStateMixin {
Animation<Color> colorAnim;
AnimationController colorController;
@override
void initState() {
buildAnimation();
super.initState();
}
@override
void dispose() {
colorController.dispose();
super.dispose();
}
@override
void didUpdateWidget(CircleButton oldWidget) {
if (widget.bloc.getPrevValue() == widget.value) {
buildAnimation();
}
super.didUpdateWidget(oldWidget);
}
void buildAnimation() {
colorController = AnimationController(duration: Duration(seconds: 2), vsync: this);
colorAnim = RainbowColorTween([
Color(0xffb4f500),
Color(0xffb4f500),
Color(0xffb4f500),
Color(0xffb4f500),
Color(0xffb4f500),
Color(0xffb4f500),
Colors.green[100],
Colors.green[200],
Colors.green[300],
Colors.green[400],
Colors.green[500],
Colors.green[600],
Colors.green[700],
Colors.green[800],
]).animate(colorController)
..addListener(() {
setState(() {});
});
colorController.forward();
}
@override
Widget build(BuildContext context) {
final double size = 50.0;
return InkResponse(
onTap: () => {
widget.bloc.add(BodytypeClick(value: widget.value)),
},
child: Container(
key: UniqueKey(),
width: size,
height: size,
decoration: BoxDecoration(
color: widget.value == widget.bloc.getPrevValue() ? colorAnim.value : Colors.green[800],
shape: BoxShape.circle,
)));
}
}
class _AnimatedLiquidCustomProgressIndicator extends StatefulWidget {
final int percentTo;
final int percentFrom;
const _AnimatedLiquidCustomProgressIndicator({this.percentTo, this.percentFrom});
@override
State<StatefulWidget> createState() => _AnimatedLiquidCustomProgressIndicatorState();
}
class _AnimatedLiquidCustomProgressIndicatorState extends State<_AnimatedLiquidCustomProgressIndicator> with TickerProviderStateMixin {
AnimationController _animationController;
bool switching = false;
@override
void didChangeDependencies() {
buildAnimation();
super.didChangeDependencies();
}
@override
void didUpdateWidget(_AnimatedLiquidCustomProgressIndicator oldWidget) {
if (oldWidget.percentFrom != widget.percentFrom) {
buildAnimation();
}
super.didUpdateWidget(oldWidget);
}
void buildAnimation() {
_animationController = AnimationController(
lowerBound: (widget.percentFrom / 100).toDouble(),
upperBound: (widget.percentTo / 100).toDouble(),
vsync: this,
duration: Duration(seconds: 3),
)..addListener(() {
setState(() {});
});
_animationController.forward();
}
@override
void initState() {
buildAnimation();
super.initState();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final percentage = _animationController.value * 100;
return Center(
key: ValueKey(widget.percentFrom),
child: LiquidCustomProgressIndicator(
value: _animationController.value,
direction: Axis.vertical,
backgroundColor: Colors.white,
valueColor: AlwaysStoppedAnimation(Colors.blue[200]),
shapePath: _buildHeartPath(),
center: Text(
"${percentage.toStringAsFixed(0)}%",
style: TextStyle(
color: Colors.blue[800],
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
);
}
Path _buildHeartPath() {
return Path()
..moveTo(55, 15)
..cubicTo(55, 12, 50, 0, 30, 0)
..cubicTo(0, 0, 0, 37.5, 0, 37.5)
..cubicTo(0, 55, 20, 77, 55, 95)
..cubicTo(90, 77, 110, 55, 110, 37.5)
..cubicTo(110, 37.5, 110, 0, 80, 0)
..cubicTo(65, 0, 55, 12, 55, 15)
..close();
}
Path _buildManPath() {
return Path()
..moveTo(55, 15)
..cubicTo(75, 20, 75, 32, 68, 38)
..lineTo(68, 43)
..lineTo(116, 43)
..lineTo(116, 55)
..lineTo(75, 55)
..conicTo(68, 80, 80, 120, 20)
..lineTo(68, 120)
..lineTo(55, 90)
..lineTo(42, 120)
..lineTo(20, 120)
..conicTo(42, 80, 40, 55, 40)
..lineTo(0, 55)
..lineTo(0, 43)
..lineTo(48, 43)
..lineTo(48, 38)
..cubicTo(25, 20, 25, 32, 55, 15)
..close();
}
}
+20 -6
View File
@@ -1,8 +1,10 @@
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/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';
@@ -26,18 +28,30 @@ class BodyTypeItem {
class _CustomerBodyTypePageState extends State<CustomerBodyTypePage> with Trans {
String selected;
bool fulldata = false;
@override
Widget build(BuildContext context) {
final CustomerRepository customerRepository = ModalRoute.of(context).settings.arguments;
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: AppBarMin(),
appBar: fulldata
? AppBarMin(
back: true,
)
: AppBarProgress(min: 76, max: 100),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -178,11 +192,11 @@ class _CustomerBodyTypePageState extends State<CustomerBodyTypePage> with Trans
RaisedButton(
color: Colors.orange,
textColor: Colors.white,
child: InkWell(child: Text(AppLocalizations.of(context).translate("Next"))),
child: Text(fulldata ? t("Save") : t("Next")),
onPressed: () => {
changeBloc.add(CustomerSave()),
Navigator.of(context).pop(),
Navigator.of(context).pushNamed("customerWelcomePage", arguments: customerRepository)
if (fulldata == false) {Navigator.of(context).pushNamed("customerWelcomePage", arguments: customerRepository)}
},
)
],
+3 -3
View File
@@ -27,7 +27,7 @@ class CustomerExerciseDevicePage extends StatelessWidget with Trans {
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.png'),
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -189,7 +189,7 @@ class CustomerExerciseDevicePage extends StatelessWidget with Trans {
devices.sort((a, b) => a.sort.compareTo(b.sort));
devices.forEach((element) {
if (element.place == false) {
final String url = "asset/image/" + element.imageUrl.substring(7);
final String url = "asset/equipment/" + element.imageUrl.substring(7);
ImageButton button = ImageButton(
width: cWidth / 2 - 10,
height: cWidth / 2 - 10,
@@ -219,7 +219,7 @@ class CustomerExerciseDevicePage extends StatelessWidget with Trans {
devices.sort((a, b) => a.sort.compareTo(b.sort));
devices.forEach((element) {
if (element.place) {
final String url = "asset/image/" + element.imageUrl.substring(7);
final String url = "asset/equipment/" + element.imageUrl.substring(7);
ImageButton button = ImageButton(
width: cWidth - 60,
height: cWidth / 2 - 40,
+32 -33
View File
@@ -1,7 +1,12 @@
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/repository/customer_repository.dart';
import 'package:aitrainer_app/model/fitness_state.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/app_bar_progress.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
@@ -17,51 +22,45 @@ class CustomerFitnessPage extends StatefulWidget {
}
}
/* class FitnessItem {
static String beginner = "beginner";
static String intermediate = "intermediate";
static String advanced = "advanced";
static String professional = "professional";
}
*/
//TODO
// dropbox for professional sport
class _CustomerFitnessPageState extends State<CustomerFitnessPage> {
class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
String selected;
bool fulldata = false;
@override
Widget build(BuildContext context) {
setContext(context);
final double cWidth = MediaQuery.of(context).size.width * 0.75;
final CustomerRepository customerRepository = ModalRoute.of(context).settings.arguments;
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;
}
selected = customerRepository.customer.fitnessLevel;
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
backgroundColor: Colors.transparent,
),
appBar: fulldata
? AppBarMin(
back: true,
)
: AppBarProgress(max: 75, min: 51),
body: BlocProvider(
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
child: Builder(builder: (context) {
// ignore: close_sinks
CustomerChangeBloc changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
padding: EdgeInsets.only(bottom: 200),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -75,7 +74,7 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> {
alignment: WrapAlignment.center,
children: [
Text(
AppLocalizations.of(context).translate("Your Fitness State"),
t("Your Fitness State"),
textAlign: TextAlign.center,
style: TextStyle(color: Colors.orange, fontSize: 42, fontFamily: 'Arial', fontWeight: FontWeight.w900),
)
@@ -86,11 +85,11 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> {
width: cWidth,
child: Column(
children: [
Text(AppLocalizations.of(context).translate("Beginner"),
Text(t("Beginner"),
textWidthBasis: TextWidthBasis.longestLine,
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900)),
Text(
AppLocalizations.of(context).translate("I am beginner"),
t("I am beginner"),
style: TextStyle(color: Colors.black, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
],
@@ -111,14 +110,14 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> {
children: [
InkWell(
child: Text(
AppLocalizations.of(context).translate("Intermediate"),
t("Intermediate"),
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
highlightColor: Colors.white,
),
InkWell(
child: Text(
AppLocalizations.of(context).translate("I am intermediate"),
t("I am intermediate"),
style: TextStyle(color: Colors.black, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
highlightColor: Colors.white,
@@ -143,14 +142,14 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> {
children: [
InkWell(
child: Text(
AppLocalizations.of(context).translate("Advanced"),
t("Advanced"),
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
highlightColor: Colors.white,
),
InkWell(
child: Text(
AppLocalizations.of(context).translate("I am advanced"),
t("I am advanced"),
style: TextStyle(color: Colors.black, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
highlightColor: Colors.white,
@@ -203,11 +202,11 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> {
RaisedButton(
color: Colors.orange,
textColor: Colors.white,
child: InkWell(child: Text(AppLocalizations.of(context).translate("Next"))),
child: Text(fulldata ? t("Save") : t("Next")),
onPressed: () => {
changeBloc.add(CustomerSave()),
Navigator.of(context).pop(),
Navigator.of(context).pushNamed("customerBodyTypePage", arguments: customerRepository)
if (!fulldata) {Navigator.of(context).pushNamed("customerBodyTypePage", arguments: customerRepository)}
},
)
],
+27 -20
View File
@@ -1,6 +1,11 @@
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/repository/customer_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/app_bar_progress.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
@@ -16,31 +21,33 @@ class CustomerGoalPage extends StatefulWidget {
State<StatefulWidget> createState() => _CustomerGoalPage();
}
class _CustomerGoalPage extends State<CustomerGoalPage> {
class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
String selected;
bool fulldata = false;
@override
Widget build(BuildContext context) {
final CustomerRepository customerRepository = ModalRoute.of(context).settings.arguments;
setContext(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;
}
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
backgroundColor: Colors.transparent,
),
appBar: fulldata
? AppBarMin(
back: true,
)
: AppBarProgress(max: 50, min: 26),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -67,7 +74,7 @@ class _CustomerGoalPage extends State<CustomerGoalPage> {
Stack(alignment: Alignment.bottomLeft, overflow: Overflow.visible, children: [
FlatButton(
child: Image.asset(
"asset/image/Gain_muscle.png",
"asset/image/Gain_muscle.jpg",
height: 180,
),
padding: EdgeInsets.all(0.0),
@@ -90,7 +97,7 @@ class _CustomerGoalPage extends State<CustomerGoalPage> {
Stack(alignment: Alignment.bottomLeft, overflow: Overflow.visible, children: [
FlatButton(
child: Image.asset(
"asset/image/WT_weight_loss.png",
"asset/image/WT_weight_loss.jpg",
height: 180,
),
padding: EdgeInsets.all(0.0),
@@ -113,12 +120,12 @@ class _CustomerGoalPage extends State<CustomerGoalPage> {
RaisedButton(
color: Colors.orange,
textColor: Colors.white,
child: InkWell(child: Text(AppLocalizations.of(context).translate("Next"))),
child: Text(fulldata ? t("Save") : t("Next")),
onPressed: () => {
//changingViewModel.saveCustomer(),
changeBloc.add(CustomerSave()),
Navigator.of(context).pop(),
Navigator.of(context).pushNamed("customerFitnessPage", arguments: changeBloc.customerRepository)
if (!fulldata) {Navigator.of(context).pushNamed("customerFitnessPage", arguments: changeBloc.customerRepository)}
},
)
],
+46 -58
View File
@@ -1,10 +1,13 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/numberpicker.dart';
import 'package:aitrainer_app/model/cache.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:aitrainer_app/widgets/app_bar_progress.dart';
import 'package:aitrainer_app/widgets/number_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
@@ -19,9 +22,15 @@ import '../library_keys.dart';
// ignore: must_be_immutable
class CustomerModifyPage extends StatelessWidget with Trans {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
bool fulldata = false;
@override
Widget build(BuildContext context) {
dynamic arguments = ModalRoute.of(context).settings.arguments;
if (arguments is HashMap && arguments['personal_data'] != null) {
fulldata = arguments['personal_data'];
}
setContext(context);
// ignore: close_sinks
final accountBloc = BlocProvider.of<AccountBloc>(context);
@@ -34,13 +43,15 @@ class CustomerModifyPage extends StatelessWidget with Trans {
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBarMin(
back: true,
),
appBar: fulldata
? AppBarMin(
back: true,
)
: AppBarProgress(max: 25, min: 0),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
@@ -56,7 +67,11 @@ class CustomerModifyPage extends StatelessWidget with Trans {
SnackBar(backgroundColor: Colors.orange, content: Text(message, style: TextStyle(color: Colors.white))));
}
} else if (state is CustomerSaveSuccess) {
Navigator.of(context).pushNamed("customerGoalPage", arguments: customerBloc.customerRepository);
if (fulldata) {
Navigator.of(context).pop();
} else {
Navigator.of(context).pushNamed("customerGoalPage", arguments: customerBloc.customerRepository);
}
}
},
builder: (context, state) {
@@ -83,14 +98,11 @@ class CustomerModifyPage extends StatelessWidget with Trans {
alignment: Alignment.center,
child: Column(
children: [
Text(t("Please provide us some personal data"),
style: GoogleFonts.inter(color: Colors.indigo, fontSize: 16), textAlign: TextAlign.center),
Text(t("To lift your experience using the app"),
style: GoogleFonts.inter(color: Colors.orange[700], fontSize: 16), textAlign: TextAlign.center),
Text(t("Edit Profile"), style: GoogleFonts.inter(color: Colors.indigo, fontSize: 16), textAlign: TextAlign.center),
Divider(
color: Colors.transparent,
),
Cache().getLoginType() == LoginType.email
Cache().getLoginType() == LoginType.email || fulldata
? TextFormField(
key: LibraryKeys.loginEmailField,
decoration: InputDecoration(
@@ -148,7 +160,7 @@ class CustomerModifyPage extends StatelessWidget with Trans {
Divider(
color: Colors.transparent,
),
Cache().getLoginType() != LoginType.apple
Cache().getLoginType() != LoginType.apple || fulldata
? TextFormField(
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 15, top: 15, bottom: 15),
@@ -173,7 +185,7 @@ class CustomerModifyPage extends StatelessWidget with Trans {
Divider(
color: Colors.transparent,
),
Cache().getLoginType() != LoginType.apple
Cache().getLoginType() != LoginType.apple || fulldata
? TextFormField(
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 15, top: 15, bottom: 15),
@@ -203,75 +215,51 @@ class CustomerModifyPage extends StatelessWidget with Trans {
children: [
Expanded(
flex: 4,
child: Text(t("Birth Year"), style: TextStyle(fontWeight: FontWeight.normal, fontSize: 14)),
child: Text(t("Birth Year"), style: TextStyle(fontWeight: FontWeight.normal, fontSize: 18)),
),
Flexible(
fit: FlexFit.tight,
flex: 8,
child: NumberPicker.horizontal(
highlightSelectedValue: true,
initialValue: customerBloc.year,
NumberPickerWidget(
minValue: 1930,
maxValue: 2100,
step: 1,
textStyle: TextStyle(fontWeight: FontWeight.bold),
textStyleHighlighted: TextStyle(fontSize: 16, color: Colors.indigo, fontWeight: FontWeight.bold),
onChanged: (value) => {customerBloc.add(CustomerBirthYearChange(year: value))},
listViewHeight: 60,
//decoration: _decoration,
),
),
initalValue: customerBloc.year.toInt(),
unit: " ",
color: Colors.indigo,
onChange: (value) => {customerBloc.add(CustomerBirthYearChange(year: value.toInt()))}),
SizedBox(width: 80),
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
flex: 4,
child: Text(t("Weight"), style: TextStyle(fontWeight: FontWeight.normal, fontSize: 14)),
child: Text(t("Weight"), style: TextStyle(fontWeight: FontWeight.normal, fontSize: 18)),
),
Flexible(
fit: FlexFit.tight,
flex: 8,
child: NumberPicker.horizontal(
highlightSelectedValue: true,
initialValue: customerBloc.weight.toInt(),
NumberPickerWidget(
minValue: 0,
maxValue: 200,
step: 1,
textStyle: TextStyle(fontWeight: FontWeight.bold),
textStyleHighlighted: TextStyle(fontSize: 18, color: Colors.indigo, fontWeight: FontWeight.bold),
onChanged: (value) => {customerBloc.add(CustomerWeightChange(weight: value))},
listViewHeight: 60,
),
),
initalValue: customerBloc.weight.toInt(),
unit: " ",
color: Colors.indigo,
onChange: (value) => {customerBloc.add(CustomerWeightChange(weight: value.toInt()))}),
SizedBox(width: 80),
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
flex: 4,
child: Text(t("Height"), style: TextStyle(fontWeight: FontWeight.normal, fontSize: 14)),
child: Text(t("Height"), style: TextStyle(fontWeight: FontWeight.normal, fontSize: 18)),
),
Flexible(
fit: FlexFit.tight,
flex: 8,
child: NumberPicker.horizontal(
highlightSelectedValue: true,
initialValue: customerBloc.height.toInt(),
NumberPickerWidget(
minValue: 0,
maxValue: 230,
step: 1,
textStyle: TextStyle(fontWeight: FontWeight.bold),
textStyleHighlighted: TextStyle(fontSize: 18, color: Colors.indigo, fontWeight: FontWeight.bold),
onChanged: (value) => {customerBloc.add(CustomerHeightChange(height: value))},
listViewHeight: 60,
),
),
initalValue: customerBloc.height.toInt(),
unit: " ",
color: Colors.indigo[300],
onChange: (value) => {customerBloc.add(CustomerHeightChange(height: value.toInt()))}),
SizedBox(width: 80),
],
),
@@ -298,7 +286,7 @@ class CustomerModifyPage extends StatelessWidget with Trans {
children: [
Image.asset('asset/icon/gomb_orange_a.png', width: 140, height: 60),
Text(
t("Next"),
fulldata ? t("Save") : t("Next"),
style: TextStyle(fontSize: 16, color: Colors.white),
),
],
+1 -1
View File
@@ -35,7 +35,7 @@ class _CustomerWelcomePageState extends State<CustomerWelcomePage> {
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_welcome.png'),
image: AssetImage('asset/image/WT_welcome.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
+8 -13
View File
@@ -35,10 +35,10 @@ class EvaluationPage extends StatelessWidget with Trans {
String imageUrl = "";
if (Cache().userLoggedIn.sex == "m") {
resultType = ResultType.man;
imageUrl = 'asset/image/WT_Results_for_men.png';
imageUrl = 'asset/image/WT_Results_for_men.jpg';
} else {
resultType = ResultType.man;
imageUrl = 'asset/image/WT_Results_for_female.png';
imageUrl = 'asset/image/WT_Results_for_female.jpg';
}
if (arguments['past'] != null && arguments['past'] == true) {
@@ -53,7 +53,7 @@ class EvaluationPage extends StatelessWidget with Trans {
}
if (exerciseRepository.exerciseType.getAbility().equalsTo(ExerciseAbility.running)) {
resultType = ResultType.running;
imageUrl = 'asset/image/WT_Results_for_runners.png';
imageUrl = 'asset/image/WT_Results_for_runners.jpg';
}
setContext(context);
@@ -81,11 +81,6 @@ class EvaluationPage extends StatelessWidget with Trans {
if (state is ResultError) {
Scaffold.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.error, style: TextStyle(color: Colors.white))));
} else if (state is ResultLoading) {
Scaffold.of(context).showSnackBar(SnackBar(
duration: Duration(milliseconds: 100),
backgroundColor: Colors.transparent,
content: Container(child: Center(child: CircularProgressIndicator()))));
}
}, builder: (context, state) {
final resultBloc = BlocProvider.of<ResultBloc>(context);
@@ -110,9 +105,9 @@ class EvaluationPage extends StatelessWidget with Trans {
SliverAppBar(
pinned: true,
backgroundColor: Colors.transparent,
expandedHeight: 120.0,
collapsedHeight: 80,
toolbarHeight: 30,
expandedHeight: 100.0,
collapsedHeight: 100,
toolbarHeight: 40,
automaticallyImplyLeading: false,
flexibleSpace: FlexibleSpaceBar(
title: Text(exerciseName,
@@ -120,8 +115,8 @@ class EvaluationPage extends StatelessWidget with Trans {
maxLines: 3,
//softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 24,
color: Colors.white,
fontSize: 20,
color: Colors.yellow[300],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
+145 -45
View File
@@ -78,8 +78,8 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
decoration: BoxDecoration(
image: DecorationImage(
image: Cache().userLoggedIn.sex == "m"
? AssetImage("asset/image/WT_Results_for_men.png")
: AssetImage("asset/image/WT_Results_for_female.png"),
? AssetImage("asset/image/WT_Results_for_men.jpg")
: AssetImage("asset/image/WT_Results_for_female.jpg"),
fit: BoxFit.cover,
alignment: Alignment.topCenter,
),
@@ -229,7 +229,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
numberPickForm(exerciseBloc, 3),
]),
))),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 1),
//bottomNavigationBar: BottomNavigator(bottomNavIndex: 1),
),
);
}
@@ -253,19 +253,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
}
Widget numberPickForm(ExerciseControlBloc exerciseBloc, int step) {
String strTimes = step == 2 ? exerciseBloc.origQuantity.toStringAsFixed(0) : "max.";
String textInstruction = "";
textInstruction = t("Please repeat with ") +
exerciseBloc.unitQuantity.toStringAsFixed(0) +
" " +
exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit +
t("hu_with") +
" " +
strTimes +
" " +
t(
"times!",
);
final String strTimes = step == 2 ? exerciseBloc.origQuantity.toStringAsFixed(0) : "max.";
String title = (step + 1).toString() + "/4 " + t("Control Exercise:");
LinkedHashMap args = LinkedHashMap();
@@ -275,44 +263,55 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
title,
style: GoogleFonts.inter(color: Colors.yellow[300], fontSize: 18, fontWeight: FontWeight.bold),
),
RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Colors.yellow[300],
),
children: [
TextSpan(text: t("Please repeat with ")),
TextSpan(
text: exerciseBloc.unitQuantity.toStringAsFixed(0) + " " + exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit,
GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return UnitQuantityControl(
exerciseBloc: exerciseBloc,
step: step,
);
}),
child: RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.yellow[400],
fontWeight: FontWeight.normal,
color: Colors.yellow[300],
),
),
TextSpan(
text: t("hu_with") +
" " +
strTimes +
" " +
t(
"times!",
))
]),
),
/* Text(
textInstruction,
style: GoogleFonts.inter(color: Colors.yellow[300], fontSize: 16),
), */
children: [
TextSpan(text: t("Please repeat with ")),
TextSpan(
text:
exerciseBloc.unitQuantity.toStringAsFixed(0) + " " + exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit,
style: GoogleFonts.inter(
decoration: TextDecoration.underline,
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.yellow[100],
),
),
TextSpan(text: t("hu_with") + " "),
TextSpan(
text: strTimes + " ",
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.yellow[100],
)),
TextSpan(
text: t(
"times!",
)),
]),
)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
NumberPickerWidget(
minValue: 0,
maxValue: 200,
initalValue: exerciseBloc.quantity.toInt(),
initalValue: exerciseBloc.quantity.round(),
unit: t("reps"),
color: Colors.yellow[50],
onChange: (value) => {exerciseBloc.add(ExerciseControlQuantityChange(quantity: value.toDouble(), step: step))}),
@@ -354,3 +353,104 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
);
}
}
class UnitQuantityControl extends StatefulWidget {
final ExerciseControlBloc exerciseBloc;
final int step;
const UnitQuantityControl({this.exerciseBloc, this.step});
@override
_UnitQuantityControlState createState() => _UnitQuantityControlState();
}
class _UnitQuantityControlState extends State<UnitQuantityControl> with Trans {
double changedValue;
@override
Widget build(BuildContext context) {
changedValue = widget.exerciseBloc.unitQuantity;
setContext(context);
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(31),
),
elevation: 0,
backgroundColor: Colors.transparent,
child: contentBox(context),
);
}
contentBox(context) {
return Stack(alignment: AlignmentDirectional.topStart, children: <Widget>[
Container(
padding: EdgeInsets.only(left: 20, top: 24, right: 20, bottom: 30),
margin: EdgeInsets.only(top: 30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
boxShadow: [BoxShadow(color: Colors.black, offset: Offset(0, 10), blurRadius: 10)],
image: DecorationImage(
image: AssetImage('asset/image/WT_results_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Column(mainAxisSize: MainAxisSize.min, children: [
Text(
t("Change the weight to"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
fontSize: 24,
color: Colors.yellow[100],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
),
SizedBox(
height: 20,
),
NumberPickerWidget(
minValue: (widget.exerciseBloc.unitQuantity - 10).round(),
maxValue: (widget.exerciseBloc.unitQuantity + 10).round(),
initalValue: widget.exerciseBloc.unitQuantity.round(),
unit: t("kg"),
color: Colors.yellow[50],
onChange: (value) => {changedValue = value}),
Align(
alignment: Alignment.center,
child: GestureDetector(
onTap: () => {
widget.exerciseBloc.add(ExerciseControlUnitQuantityChange(quantity: changedValue.toDouble(), step: widget.step)),
Navigator.of(context).pop(),
},
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_c.png', width: 100, height: 45),
Text(
t("OK"),
style: TextStyle(fontSize: 16, color: Colors.white),
),
],
))),
])),
GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: CircleAvatar(
backgroundColor: Colors.transparent,
radius: 28,
child: Text(
"X",
style: GoogleFonts.archivoBlack(fontSize: 32, color: Colors.white54),
),
)),
]);
}
}
+2 -2
View File
@@ -49,8 +49,8 @@ class _ExerciseExecutePage extends State<ExerciseExecutePage> with Trans {
decoration: BoxDecoration(
image: DecorationImage(
image: customerId == Cache().userLoggedIn.customerId
? AssetImage('asset/image/WT_black_background.png')
: AssetImage('asset/image/WT_light_background.png'),
? AssetImage('asset/image/WT_black_background.jpg')
: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
+134 -53
View File
@@ -2,16 +2,18 @@ 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/model/workout_menu_tree.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/library/numberpicker.dart';
import 'package:aitrainer_app/widgets/number_picker.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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';
class ExerciseExecutePlanAddPage extends StatefulWidget {
@@ -19,6 +21,15 @@ class ExerciseExecutePlanAddPage extends StatefulWidget {
}
class _ExerciseExecuteAddPage extends State<ExerciseExecutePlanAddPage> with Trans {
final ScrollController _controller = ScrollController();
double offset = 0;
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
LinkedHashMap arguments = ModalRoute.of(context).settings.arguments;
@@ -44,7 +55,9 @@ class _ExerciseExecuteAddPage extends State<ExerciseExecutePlanAddPage> with Tra
}, builder: (context, state) {
// ignore: close_sinks
final exerciseBloc = BlocProvider.of<ExerciseExecutePlanAddBloc>(context);
if (state is ExerciseExecutePlanAddReady) {
_controller.animateTo(exerciseBloc.scrollOffset, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
}
return ModalProgressHUD(
child: getControlForm(exerciseBloc),
inAsyncCall: state is ExerciseExecutePlanAddLoading,
@@ -69,7 +82,7 @@ class _ExerciseExecuteAddPage extends State<ExerciseExecutePlanAddPage> with Tra
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
@@ -79,16 +92,33 @@ class _ExerciseExecuteAddPage extends State<ExerciseExecutePlanAddPage> with Tra
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
physics: BouncingScrollPhysics(),
controller: ScrollController(
initialScrollOffset: exerciseBloc.scrollOffset,
),
controller: _controller,
child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
Text(t("Save Exercise")),
Text(
t("Save Exercise"),
style: GoogleFonts.inter(fontSize: 16, color: Colors.orange[50]),
),
Text(
exerciseName,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.deepOrange),
style: GoogleFonts.archivoBlack(
fontSize: 24,
color: Colors.orange[700],
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,
),
],
),
textAlign: TextAlign.center,
overflow: TextOverflow.fade,
maxLines: 1,
maxLines: 3,
softWrap: true,
),
Divider(
@@ -115,52 +145,85 @@ class _ExerciseExecuteAddPage extends State<ExerciseExecutePlanAddPage> with Tra
Divider(
color: Colors.transparent,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.baseline,
children: [
Text(
t("Execute the") + " ",
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
(i + 1).toString() + ". ",
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
Text(
t("set!"),
style: TextStyle(fontWeight: FontWeight.bold),
),
],
RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Colors.yellow[300],
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,
),
],
),
children: [
TextSpan(text: t("Execute the") + " "),
TextSpan(
text: (i + 1).toString() + ". ",
style: GoogleFonts.inter(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.yellow[600],
),
),
TextSpan(text: t("set!"))
]),
),
Divider(
color: Colors.transparent,
),
Text(t("Please repeat with") +
" " +
exerciseBloc.unitQuantity.toStringAsFixed(0) +
" " +
exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit +
" " +
exerciseBloc.exercisePlanRepository.getActualPlanDetail().repeats.toString() +
" " +
t("times!")),
Row(children: [
NumberPicker.horizontal(
highlightSelectedValue: (i + 1) == exerciseBloc.step,
initialValue: exerciseBloc.unitQuantity.toInt(),
minValue: 0,
maxValue: 650,
step: 1,
textStyle: TextStyle(fontWeight: FontWeight.bold),
textStyleHighlighted: TextStyle(fontSize: 24, color: Colors.indigo, fontWeight: FontWeight.bold),
onChanged: (value) => {exerciseBloc.add(ExerciseExecutePlanAddChangeUnitQuantity(quantity: value.toDouble()))},
listViewHeight: 80,
//decoration: _decoration,
),
Text(exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit),
Row(mainAxisAlignment: MainAxisAlignment.start, children: [
exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit == null
? Offstage()
: NumberPickerWidget(
minValue: 0,
maxValue: 1000,
fontSize: 16,
initalValue: exerciseBloc.unitQuantity.toInt(),
unit: t(exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit),
color: Colors.yellow[50],
onChange: (value) => {exerciseBloc.add(ExerciseExecutePlanAddChangeUnitQuantity(quantity: value.toDouble()))}),
NumberPickerWidget(
minValue: 0,
maxValue: 200,
fontSize: 16,
initalValue: exerciseBloc.quantity.toInt(),
unit: t(exerciseBloc.exerciseRepository.exerciseType.unit), //t("repeat"),
color: Colors.yellow[50],
onChange: (value) => {exerciseBloc.add(ExerciseExecutePlanAddChangeQuantity(quantity: value.toDouble()))}),
]),
Row(children: [
FlatButton(
padding: EdgeInsets.all(0),
textColor: Colors.white,
focusColor: Colors.blueAccent,
onPressed: () => {
if (exerciseBloc.step == i + 1) {exerciseBloc.add(ExerciseExecutePlanAddSubmit())},
if (i + 1 == exerciseBloc.countSteps) {Navigator.of(context).pop()}
},
child: exerciseBloc.step == i + 1
? Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_c.png', width: 140, height: 60),
Text(
t("Save"),
style: TextStyle(fontSize: 16, color: Colors.white),
),
],
)
: Stack(
alignment: Alignment.center,
children: getButton(i + 1, exerciseBloc),
)),
/* Row(children: [
NumberPicker.horizontal(
highlightSelectedValue: (i + 1) == exerciseBloc.step,
initialValue: exerciseBloc.quantity.toInt(),
@@ -174,8 +237,8 @@ class _ExerciseExecuteAddPage extends State<ExerciseExecutePlanAddPage> with Tra
//decoration: _decoration,
),
Text(t("repeat")),
]),
RaisedButton(
]), */
/* RaisedButton(
padding: EdgeInsets.all(0),
textColor: Colors.white,
color: exerciseBloc.step == i + 1 ? Colors.blue : Colors.black26,
@@ -187,7 +250,7 @@ class _ExerciseExecuteAddPage extends State<ExerciseExecutePlanAddPage> with Tra
child: Text(
t("Save"),
style: TextStyle(fontSize: 12),
)),
)), */
Divider(),
],
);
@@ -195,4 +258,22 @@ class _ExerciseExecuteAddPage extends State<ExerciseExecutePlanAddPage> with Tra
}
return listColumns;
}
List<Widget> getButton(int step, ExerciseExecutePlanAddBloc exerciseBloc) {
List<Widget> widgets = List();
if (step < exerciseBloc.step) {
widgets.add(Icon(
CustomIcon.check_circle,
color: Color(0xffb4f500),
size: 36,
));
} else {
widgets.add(Icon(
CustomIcon.question,
color: Colors.grey[700],
size: 36,
));
}
return widgets;
}
}
+2 -2
View File
@@ -58,8 +58,8 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
decoration: BoxDecoration(
image: DecorationImage(
image: customerId == Cache().userLoggedIn.customerId
? AssetImage('asset/image/WT_black_background.png')
: AssetImage('asset/image/WT_light_background.png'),
? AssetImage('asset/image/WT_black_background.jpg')
: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
+43 -15
View File
@@ -16,6 +16,7 @@ import 'package:aitrainer_app/widgets/bmi_widget.dart';
import 'package:aitrainer_app/widgets/bmr_widget.dart';
import 'package:aitrainer_app/widgets/size_widget.dart';
import 'package:aitrainer_app/widgets/time_picker.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -33,6 +34,29 @@ class ExerciseNewPage extends StatefulWidget {
class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
final FocusNode _nodeText1 = FocusNode();
final FocusNode _nodeText2 = FocusNode();
final _controller1 = TextEditingController();
final _controller2 = TextEditingController();
initState() {
super.initState();
_controller1.text = "30";
_nodeText1.addListener(() {
if (_nodeText1.hasFocus) {
_controller1.selection = TextSelection(baseOffset: 0, extentOffset: _controller1.text.length);
}
});
SchedulerBinding.instance.addPostFrameCallback((_) {
// ignore: close_sinks
final menuBloc = BlocProvider.of<MenuBloc>(context);
_controller2.text = menuBloc.ability.toString() == ExerciseAbility.oneRepMax.toString() ? "12" : "20";
_nodeText2.addListener(() {
if (_nodeText2.hasFocus) {
_controller2.selection = TextSelection(baseOffset: 0, extentOffset: _controller2.text.length);
}
});
});
}
KeyboardActionsConfig _buildConfig(BuildContext context) {
return KeyboardActionsConfig(
@@ -150,7 +174,7 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.png'),
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
@@ -234,18 +258,20 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
Divider(
color: Colors.transparent,
),
Text(
t("Step" + ": " + "1/4"),
style: GoogleFonts.inter(
fontSize: 22,
color: Colors.white,
fontWeight: FontWeight.bold,
),
maxLines: 3,
textAlign: TextAlign.center,
overflow: TextOverflow.fade,
softWrap: true,
),
exerciseBloc.exerciseRepository.exerciseType.unitQuantity == "1"
? Text(
t("Step") + ": " + "1/4",
style: GoogleFonts.inter(
fontSize: 22,
color: Colors.white,
fontWeight: FontWeight.bold,
),
maxLines: 3,
textAlign: TextAlign.center,
overflow: TextOverflow.fade,
softWrap: true,
)
: Offstage(),
Divider(
color: Colors.transparent,
),
@@ -278,6 +304,7 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
row = Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
TextFormField(
focusNode: _nodeText1,
controller: _controller1,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 25, top: 5, bottom: 5),
labelText: t(bloc.exerciseRepository.exerciseType.unitQuantityUnit),
@@ -290,7 +317,7 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
borderSide: BorderSide(color: Colors.white12, width: 0.4),
),
),
initialValue: "30",
//initialValue: "30",
keyboardType: TextInputType.numberWithOptions(decimal: true),
textInputAction: TextInputAction.done,
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.yellow[300]),
@@ -388,6 +415,7 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
Column row = Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
TextFormField(
focusNode: _nodeText2,
controller: _controller2,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 25, top: 5, bottom: 5),
labelText: t(bloc.exerciseRepository.exerciseType.unit),
@@ -400,7 +428,7 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
borderSide: BorderSide(color: Colors.black26, width: 0.4),
),
),
initialValue: bloc.quantity.toStringAsFixed(0),
//initialValue: bloc.quantity.toStringAsFixed(0),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.orange[200]),
@@ -15,6 +15,7 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:keyboard_actions/keyboard_actions_config.dart';
import 'package:keyboard_actions/keyboard_actions_item.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
class ExercisePlanDetailAddPage extends StatefulWidget {
@override
@@ -104,21 +105,21 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
..add(ExercisePlanCustomAddLoad()),
child: BlocConsumer<ExercisePlanCustomAddBloc, ExercisePlanCustomAddState>(
listener: (context, state) {
if (state is ExercisePlanCustomAddLoading) {
//LoadingDialog.show(context);
} else if (state is ExercisePlanCustomAddError) {
//LoadingDialog.hide(context);
if (state is ExercisePlanCustomAddError) {
Scaffold.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
}
},
builder: (context, state) {
if (state is ExercisePlanCustomAddReady) {
//LoadingDialog.hide(context);
}
// ignore: close_sinks
final bloc = BlocProvider.of<ExercisePlanCustomAddBloc>(context);
return getForm(bloc, workoutMenuTree);
return ModalProgressHUD(
child: getForm(bloc, workoutMenuTree),
inAsyncCall: state is ExercisePlanCustomAddLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
));
}
@@ -130,6 +131,12 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
? bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.name
: bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.nameTranslation;
}
final bool weightVisible = bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.unitQuantityUnit != null;
String summary = bloc.serie.toStringAsFixed(0) + " x " + bloc.quantity.toStringAsFixed(0);
if (bloc.quantityUnit > 0) {
summary += " x " + bloc.quantityUnit.toStringAsFixed(0) + " kg";
}
final String unit = bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.unit;
return Form(
child: Scaffold(
resizeToAvoidBottomInset: true,
@@ -139,7 +146,7 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.png'),
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
@@ -195,7 +202,7 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
TextFormField(
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 25, top: 5, bottom: 5),
labelText: t('Repeats'),
labelText: t(unit),
fillColor: Colors.white24,
labelStyle: GoogleFonts.inter(fontSize: 20, color: Colors.yellow[50]),
filled: true,
@@ -210,37 +217,33 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
keyboardType: TextInputType.number,
style: GoogleFonts.archivoBlack(fontSize: 60, color: Colors.yellow[200]),
onChanged: (value) => {bloc.add(ExercisePlanCustomAddChangeQuantity(quantity: double.parse(value)))}),
//]),
Divider(),
TextFormField(
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 25, top: 5, bottom: 5),
labelText: t('Weight'),
fillColor: Colors.white24,
labelStyle: GoogleFonts.inter(fontSize: 20, color: Colors.yellow[50]),
filled: true,
border: OutlineInputBorder(
gapPadding: 2.0,
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide(color: Colors.green[50], width: 0.4),
),
),
focusNode: _nodeText3,
initialValue: bloc.quantityUnit.toStringAsFixed(0),
keyboardType: TextInputType.numberWithOptions(decimal: true),
style: GoogleFonts.archivoBlack(fontSize: 60, color: Colors.yellow[200]),
onChanged: (value) => {bloc.add(ExercisePlanCustomAddChangeQuantityUnit(quantity: double.parse(value)))}),
//]),
weightVisible
? TextFormField(
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 25, top: 5, bottom: 5),
labelText: t('Weight'),
fillColor: Colors.white24,
labelStyle: GoogleFonts.inter(fontSize: 20, color: Colors.yellow[50]),
filled: true,
border: OutlineInputBorder(
gapPadding: 2.0,
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide(color: Colors.green[50], width: 0.4),
),
),
focusNode: _nodeText3,
initialValue: bloc.quantityUnit.toStringAsFixed(0),
keyboardType: TextInputType.numberWithOptions(decimal: true),
style: GoogleFonts.archivoBlack(fontSize: 60, color: Colors.yellow[200]),
onChanged: (value) => {bloc.add(ExercisePlanCustomAddChangeQuantityUnit(quantity: double.parse(value)))})
: Offstage(),
Divider(),
Text(
bloc.serie.toStringAsFixed(0) +
" x " +
bloc.quantity.toStringAsFixed(0) +
" x " +
bloc.quantityUnit.toStringAsFixed(0) +
" kg",
summary,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.normal, color: Colors.yellow[50]),
),
Divider(),
+13 -22
View File
@@ -14,6 +14,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
class ExercisePlanCustomPage extends StatefulWidget {
@override
@@ -51,8 +52,8 @@ class _ExercisePlanCustomPage extends State<ExercisePlanCustomPage> with Trans {
decoration: BoxDecoration(
image: DecorationImage(
image: customerId == Cache().userLoggedIn.customerId
? AssetImage('asset/image/WT_black_background.png')
: AssetImage('asset/image/WT_light_background.png'),
? AssetImage('asset/image/WT_black_background.jpg')
: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -65,17 +66,15 @@ class _ExercisePlanCustomPage extends State<ExercisePlanCustomPage> with Trans {
),
backgroundColor: Colors.orange,
));
} else if (state is ExercisePlanLoading) {
//LoadingDialog.show(context);
}
},
// ignore: missing_return
builder: (context, state) {
if (state is ExercisePlanReady) {
//LoadingDialog.hide(context);
return exerciseWidget(bloc);
}
return Container();
}, builder: (context, state) {
return ModalProgressHUD(
child: exerciseWidget(bloc),
inAsyncCall: state is ExercisePlanLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
})),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 2),
);
@@ -138,6 +137,7 @@ class _ExercisePlanCustomPage extends State<ExercisePlanCustomPage> with Trans {
List<Widget> _getChildList(List<WorkoutMenuTree> listWorkoutTree, ExercisePlanBloc bloc) {
List<Widget> list = List();
listWorkoutTree.forEach((element) {
final String unitQuantityUnit = element.exerciseType.unitQuantityUnit != null ? element.exerciseType.unitQuantityUnit : "";
list.add(TreeViewChild(
startExpanded: false,
parent: Card(
@@ -180,20 +180,11 @@ class _ExercisePlanCustomPage extends State<ExercisePlanCustomPage> with Trans {
bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId].repeats.toString() +
" x " +
bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId].weightEquation +
" " +
element.exerciseType.unitQuantityUnit,
unitQuantityUnit,
style: TextStyle(fontSize: 9, color: Colors.green),
),
onTap: () => clickAddDetail(bloc, element),
),
/* IconButton(
padding: EdgeInsets.all(0),
icon: Icon(
Icons.info,
color: Colors.black12,
),
onPressed: () {},
), */
]),
)),
children: []));
+27 -30
View File
@@ -7,46 +7,43 @@ import 'package:flutter/material.dart';
class ExerciseTypeDescription extends StatelessWidget {
@override
Widget build(BuildContext context) {
final ExerciseRepository exerciseRepository =
ModalRoute.of(context).settings.arguments;
final ExerciseRepository exerciseRepository = ModalRoute.of(context).settings.arguments;
String exerciseDescription = AppLanguage().appLocal == Locale("en")
? exerciseRepository.exerciseType.description
: exerciseRepository.exerciseType.descriptionTranslation;
String exerciseName = AppLanguage().appLocal == Locale("en") ?
exerciseRepository.exerciseType.name :
exerciseRepository.exerciseType.nameTranslation;
String exerciseName =
AppLanguage().appLocal == Locale("en") ? exerciseRepository.exerciseType.name : exerciseRepository.exerciseType.nameTranslation;
return Scaffold(
appBar: AppBarMin(back: true,),
appBar: AppBarMin(
back: true,
),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
fit: BoxFit.fill,
alignment: Alignment.center,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
),
),
padding: EdgeInsets.only(left: 20, top: 20, right: 15),
child: ListView(
children: [
Text(exerciseName,
style: TextStyle(color: Colors.blueGrey,
fontSize: 20, fontWeight: FontWeight.bold),
padding: EdgeInsets.only(left: 20, top: 20, right: 15),
child: ListView(children: [
Text(
exerciseName,
style: TextStyle(color: Colors.blueGrey, fontSize: 20, fontWeight: FontWeight.bold),
),
Divider(
color: Colors.transparent,
),
Divider(color: Colors.transparent,),
InkWell(
child: Text(exerciseDescription,
style: TextStyle(color: Colors.blueGrey,
fontSize: 18, fontWeight: FontWeight.normal),),
child: Text(
exerciseDescription,
style: TextStyle(color: Colors.blueGrey, fontSize: 18, fontWeight: FontWeight.normal),
),
),
]
)
)
);
])));
}
}
+1 -1
View File
@@ -56,7 +56,7 @@ class LoginPage extends StatelessWidget with Trans {
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_login.png'),
image: AssetImage('asset/image/WT_login.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
+1 -1
View File
@@ -36,7 +36,7 @@ class _MenuPage extends State<MenuPage> {
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_menu_dark.png'),
image: AssetImage('asset/image/WT_menu_dark.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
+2 -4
View File
@@ -4,7 +4,6 @@ import 'package:aitrainer_app/library/radar_chart.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/dialog_premium.dart';
import 'package:flurry/flurry.dart';
import 'package:flutter/scheduler.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/util/common.dart';
@@ -27,7 +26,6 @@ class _MyDevelopmentBodyPage extends State<MyDevelopmentBodyPage> with Trans, Co
@override
void initState() {
super.initState();
Flurry.logEvent("myDevelopmentBody");
if (!Cache().hasPurchased || true) {
Timer(
Duration(milliseconds: 2000),
@@ -69,8 +67,8 @@ class _MyDevelopmentBodyPage extends State<MyDevelopmentBodyPage> with Trans, Co
decoration: BoxDecoration(
image: DecorationImage(
image: customerId == Cache().userLoggedIn.customerId
? AssetImage('asset/image/WT_light_background.png')
: AssetImage('asset/image/WT_menu_dark.png'),
? AssetImage('asset/image/WT_light_background.jpg')
: AssetImage('asset/image/WT_menu_dark.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
+1 -3
View File
@@ -11,7 +11,6 @@ import 'package:aitrainer_app/bloc/development_by_muscle/development_by_muscle_b
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/library/tree_view.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flurry/flurry.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
@@ -32,7 +31,6 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
@override
void initState() {
super.initState();
Flurry.logEvent("myDevelopmentMuscle");
if (!Cache().hasPurchased) {
Timer(
Duration(milliseconds: 2000),
@@ -71,7 +69,7 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_menu_dark.png'),
image: AssetImage('asset/image/WT_menu_dark.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
+23 -14
View File
@@ -3,8 +3,9 @@ import 'dart:collection';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/widgets/dialog_premium.dart';
import 'package:flurry/flurry.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
@@ -34,7 +35,7 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_menu_dark.png'),
image: AssetImage('asset/image/WT_menu_dark.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -68,8 +69,11 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
image: "asset/image/testemfejl400x400.jpg",
left: 5,
onTap: () => {
args['customerId'] = Cache().userLoggedIn.customerId,
Navigator.of(context).pushNamed('mydevelopmentBodyPage', arguments: args)
if (Cache().userLoggedIn != null)
{
args['customerId'] = Cache().userLoggedIn.customerId,
Navigator.of(context).pushNamed('mydevelopmentBodyPage', arguments: args)
}
},
isLocked: true,
),
@@ -101,7 +105,7 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
backgroundColor: Colors.black54.withOpacity(0.4))),
image: "asset/image/predictions.jpg",
onTap: () => {
Flurry.logEvent("Predictions"),
Track().track(TrackingEvent.prediction),
showDialog(
context: context,
builder: (BuildContext context) {
@@ -138,10 +142,13 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
color: Colors.black12,
focusColor: Colors.blueAccent,
onPressed: () => {
args['exerciseRepository'] = exerciseRepository,
args['customerRepository'] = customerRepository,
args['customerId'] = Cache().getTrainee().customerId,
Navigator.of(context).pushNamed('exerciseLogPage', arguments: args)
if (Cache().getTrainee() != null)
{
args['exerciseRepository'] = exerciseRepository,
args['customerRepository'] = customerRepository,
args['customerId'] = Cache().getTrainee().customerId,
Navigator.of(context).pushNamed('exerciseLogPage', arguments: args)
},
},
child: Text(
t("My Trainee's Exercise Logs"),
@@ -153,10 +160,12 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
}
void callBackExerciseLog(ExerciseRepository exerciseRepository, CustomerRepository customerRepository) {
final LinkedHashMap args = LinkedHashMap();
args['exerciseRepository'] = exerciseRepository;
args['customerRepository'] = customerRepository;
args['customerId'] = Cache().userLoggedIn.customerId;
Navigator.of(context).pushNamed('exerciseLogPage', arguments: args);
if (Cache().userLoggedIn != null) {
final LinkedHashMap args = LinkedHashMap();
args['exerciseRepository'] = exerciseRepository;
args['customerRepository'] = customerRepository;
args['customerId'] = Cache().userLoggedIn.customerId;
Navigator.of(context).pushNamed('exerciseLogPage', arguments: args);
}
}
}
+28 -15
View File
@@ -2,12 +2,13 @@ import 'dart:collection';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/dialog_premium.dart';
import 'package:aitrainer_app/widgets/image_button.dart';
import 'package:flurry/flurry.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
@@ -33,7 +34,7 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_menu_dark.png'),
image: AssetImage('asset/image/WT_menu_dark.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -54,9 +55,12 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
image: "asset/image/exercise_plan_custom.jpg",
left: 5,
onTap: () => {
args['exerciseRepository'] = exerciseRepository,
args['customerId'] = Cache().userLoggedIn.customerId,
Navigator.of(context).pushNamed('exercisePlanCustomPage', arguments: args)
if (Cache().userLoggedIn != null)
{
args['exerciseRepository'] = exerciseRepository,
args['customerId'] = Cache().userLoggedIn.customerId,
Navigator.of(context).pushNamed('exercisePlanCustomPage', arguments: args)
}
},
isLocked: false,
),
@@ -74,8 +78,11 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
top: 130,
left: 5,
onTap: () => {
args['customerId'] = Cache().userLoggedIn.customerId,
Navigator.of(context).pushNamed('exerciseExecutePlanPage', arguments: args)
if (Cache().userLoggedIn != null)
{
args['customerId'] = Cache().userLoggedIn.customerId,
Navigator.of(context).pushNamed('exerciseExecutePlanPage', arguments: args)
}
},
isLocked: false,
),
@@ -92,7 +99,7 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
image: "asset/image/exercise_plan_suggested.jpg",
left: 2,
onTap: () => {
Flurry.logEvent("SuggestedTrainingPlan"),
Track().track(TrackingEvent.my_suggested_plan),
showDialog(
context: context,
builder: (BuildContext context) {
@@ -121,7 +128,7 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
image: "asset/image/exercise_plan_stars.jpg",
left: 5,
onTap: () => {
Flurry.logEvent("SpecialTraining Programs"),
Track().track(TrackingEvent.my_special_plan),
showDialog(
context: context,
builder: (BuildContext context) {
@@ -150,7 +157,7 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
image: "asset/image/exercise_plan_stars.jpg",
left: 5,
onTap: () => {
Flurry.logEvent("StarTrainingPlan"),
showDialog(
context: context,
builder: (BuildContext context) {
@@ -189,9 +196,12 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
color: Colors.black12,
focusColor: Colors.blueAccent,
onPressed: () => {
args['exerciseRepository'] = exerciseRepository,
args['customerId'] = Cache().getTrainee().customerId,
Navigator.of(context).pushNamed('exercisePlanCustomPage', arguments: args)
if (Cache().getTrainee() != null)
{
args['exerciseRepository'] = exerciseRepository,
args['customerId'] = Cache().getTrainee().customerId,
Navigator.of(context).pushNamed('exercisePlanCustomPage', arguments: args)
}
},
child: Text(
t("My Trainee's Plan"),
@@ -212,8 +222,11 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans, Logging
color: Colors.black12,
focusColor: Colors.blueAccent,
onPressed: () => {
args['customerId'] = Cache().getTrainee().customerId,
Navigator.of(context).pushNamed('exerciseExecutePlanPage', arguments: args)
if (Cache().getTrainee() != null)
{
args['customerId'] = Cache().getTrainee().customerId,
Navigator.of(context).pushNamed('exerciseExecutePlanPage', arguments: args)
}
},
child: Text(
t("Execute My Trainee's Training Plan"),
+17 -12
View File
@@ -6,6 +6,7 @@ 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';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/dialog_long.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
@@ -39,7 +40,21 @@ class RegistrationPage extends StatelessWidget with Trans {
SnackBar(backgroundColor: Colors.orange, content: Text(message, style: TextStyle(color: Colors.white))));
}
} else if (state is LoginSuccess) {
Navigator.of(context).pushNamed('customerModifyPage');
//Navigator.of(context).pushNamed('customerModifyPage');
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("Successful Registration"),
descriptions: t("Now we would like to know you better to lift the experience of the app."),
description2: t("Please go through the pages, it will take couple of minutes!"),
text: "OK",
onTap: () => {Navigator.of(context).pushNamed('customerModifyPage')},
onCancel: () => {
Navigator.of(context).pushNamed("home"),
},
);
});
}
}, builder: (context, state) {
final loginBloc = BlocProvider.of<LoginBloc>(context);
@@ -61,7 +76,7 @@ class RegistrationPage extends StatelessWidget with Trans {
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_login.png'),
image: AssetImage('asset/image/WT_login.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -109,16 +124,6 @@ class RegistrationPage extends StatelessWidget with Trans {
],
),
ListTile(title: Text(t("OR"), style: GoogleFonts.inter())),
/* Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
InkWell(
child: Text(AppLocalizations.of(context).translate('SignUp with Email'),
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24)),
),
],
), */
TextFormField(
key: LibraryKeys.loginEmailField,
decoration: InputDecoration(
+1 -1
View File
@@ -44,7 +44,7 @@ class ResetPasswordPage extends StatelessWidget with Trans {
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_login.png'),
image: AssetImage('asset/image/WT_login.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
+1 -1
View File
@@ -60,7 +60,7 @@ class SalesPage extends StatelessWidget with Trans, Logging {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.png'),
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
+2 -2
View File
@@ -29,7 +29,7 @@ class SettingsPage extends StatelessWidget with Trans {
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -78,7 +78,7 @@ class SettingsPage extends StatelessWidget with Trans {
}
ListTile getServer(SettingsBloc settingsBloc) {
if (Cache().userLoggedIn.admin != 1) {
if (Cache().userLoggedIn == null || Cache().userLoggedIn.admin != 1) {
return ListTile(
title: Container(),
);
-1
View File
@@ -5,7 +5,6 @@ import 'package:aitrainer_app/localization/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';
import 'package:aitrainer_app/util/trans.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
+75
View File
@@ -0,0 +1,75 @@
import 'package:aitrainer_app/util/common.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:liquid_progress_indicator/liquid_progress_indicator.dart';
class AppBarProgress extends StatefulWidget implements PreferredSizeWidget {
final int max;
final int min;
const AppBarProgress({this.max, this.min});
@override
_AppBarNav createState() => _AppBarNav();
@override
Size get preferredSize => const Size.fromHeight(50);
}
class _AppBarNav extends State<AppBarProgress> with SingleTickerProviderStateMixin, Common {
AnimationController _animationController;
@override
void initState() {
_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();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: Colors.black,
title: getAnimatedWidget(),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => {Navigator.of(context).pop()},
));
}
Widget getAnimatedWidget() {
final percentage = _animationController.value;
return Container(
width: double.infinity,
height: 35,
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: LiquidLinearProgressIndicator(
value: _animationController.value / 100,
backgroundColor: Colors.black,
valueColor: AlwaysStoppedAnimation(Color(0xffb4f500)),
borderRadius: 12.0,
center: Text(
"${percentage.toStringAsFixed(0)}%",
style: TextStyle(
color: Colors.yellow[50],
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
));
}
}
+2 -2
View File
@@ -84,7 +84,7 @@ class _BMIState extends State<BMI> with Trans {
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.png'),
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
@@ -141,7 +141,7 @@ class _BMIState extends State<BMI> with Trans {
Container(
padding: EdgeInsets.only(left: 30, right: 30),
child: Image.asset(
"asset/image/BMI_graph_c.png",
"asset/image/BMI_graph_C.png",
),
),
Positioned(
+1 -1
View File
@@ -99,7 +99,7 @@ class _BMRState extends State<BMR> with Trans {
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.png'),
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
+21 -6
View File
@@ -1,8 +1,10 @@
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:flurry/flurry.dart';
import 'package:flutter/material.dart';
import 'package:gradient_bottom_navigation_bar/gradient_bottom_navigation_bar.dart';
@@ -23,6 +25,19 @@ class _NawDrawerWidget extends State<BottomNavigator> with Trans, Logging {
super.initState();
}
@override
void didUpdateWidget(BottomNavigator oldWidget) {
Cache().initBadges();
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
Cache().initBadges();
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
final Color bgrColor = Color(0xffb4f500);
@@ -87,30 +102,30 @@ class _NawDrawerWidget extends State<BottomNavigator> with Trans, Logging {
switch (index) {
case 0:
Navigator.of(context).pop();
Flurry.logEvent("Home");
Track().track(TrackingEvent.home);
Navigator.of(context).pushNamed('home');
break;
case 1:
Navigator.of(context).pop();
Flurry.logEvent("myDevelopment");
Track().track(TrackingEvent.my_development);
Navigator.of(context).pushNamed('myDevelopment');
break;
case 2:
Navigator.of(context).pop();
Flurry.logEvent("myExercisePlan");
Track().track(TrackingEvent.my_exerciseplan);
Navigator.of(context).pushNamed('myExercisePlan');
break;
case 3:
Navigator.of(context).pop();
Flurry.logEvent("Account");
Track().track(TrackingEvent.account);
Navigator.of(context).pushNamed('account');
break;
case 4:
Navigator.of(context).pop();
Flurry.logEvent("Settings");
Track().track(TrackingEvent.settings);
Navigator.of(context).pushNamed('settings');
break;
+1 -1
View File
@@ -49,7 +49,7 @@ class _DialogPremiumState extends State<DialogCommon> with Trans {
borderRadius: BorderRadius.circular(24),
boxShadow: [BoxShadow(color: Colors.black, offset: Offset(0, 10), blurRadius: 10)],
image: DecorationImage(
image: AssetImage('asset/image/WT_black_G_background.png'),
image: AssetImage('asset/image/WT_black_G_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
+1 -1
View File
@@ -360,7 +360,7 @@ class _DialogPremiumState extends State<DialogGDPR> with Trans {
borderRadius: BorderRadius.circular(24),
boxShadow: [BoxShadow(color: Colors.black, offset: Offset(0, 10), blurRadius: 10)],
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
+1 -1
View File
@@ -72,7 +72,7 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
borderRadius: BorderRadius.circular(24),
boxShadow: [BoxShadow(color: Colors.black, offset: Offset(0, 10), blurRadius: 10)],
image: DecorationImage(
image: AssetImage('asset/image/WT_black_G_background.png'),
image: AssetImage('asset/image/WT_black_G_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
+3 -2
View File
@@ -79,8 +79,9 @@ class _HomePageState extends State<AitrainerHome> with Logging {
return MenuPage(parent: 0);
}
} else {
log("else");
return MenuPage(parent: 0);
log("home: unknown state");
//return MenuPage(parent: 0);
return LoginPage();
}
}),
);
+24 -16
View File
@@ -58,7 +58,7 @@ class ImageButton extends StatelessWidget {
return Stack(alignment: AlignmentDirectional.bottomStart, children: [
FlatButton(
child: image == null
? _getButtonImage("asset/image/WT_menu_dark.png")
? _getButtonImage("asset/image/WT_menu_dark.jpg")
: isMarked
? Stack(
children: [
@@ -103,31 +103,39 @@ class ImageButton extends StatelessWidget {
],
)),
)),
Cache().hasPurchased
isMarked == null || Cache().hasPurchased
? Offstage()
: Stack(alignment: Alignment.topCenter, children: [
Positioned(
top: 10,
left: (width / 2 - 30) / 2 - 75,
child: !isLocked
? Offstage()
: GestureDetector(
child: Image.asset(
'asset/image/lock.png',
height: 150,
width: 150,
),
onTap: onTap ?? onTap,
))
]),
isLocked == null
? Offstage()
: Stack(alignment: Alignment.topCenter, children: [
Positioned(
top: 10,
left: (width / 2 - 30) / 2 - 75,
child: this.isLocked
child: isMarked
? GestureDetector(
child: Image.asset(
'asset/image/lock.png',
height: 150,
width: 150,
'asset/image/haken.png',
height: 70,
width: 70,
),
onTap: onTap ?? onTap,
)
: isMarked
? GestureDetector(
child: Image.asset(
'asset/image/haken.png',
height: 70,
width: 70,
),
onTap: onTap ?? onTap,
)
: Container(),
: Offstage(),
)
]),
]
+1 -1
View File
@@ -6,7 +6,7 @@ class LoadingScreenMain extends StatelessWidget {
@override
Widget build(BuildContext context) {
final Image _backgroundImage = Image.asset(
'asset/image/WT01_loading_layers.png',
'asset/image/WT_loading_layers.jpg',
fit: BoxFit.cover,
height: double.infinity,
width: double.infinity,
+17 -12
View File
@@ -142,19 +142,23 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
])))));
});
}
/* LiveSliverList sliverList = LiveSliverList(
// And attach root sliver scrollController to widgets
controller: scrollController,
itemCount: _columnChildren.length,
reAnimateOnVisibility: false,
showItemDuration: Duration(milliseconds: 100),
itemBuilder: (BuildContext context, int index, Animation<double> animation) => FadeTransition(
opacity: animation,
child: _columnChildren[index],
),
*/
//delegate: SliverChildListDelegate(_columnChildren),
SliverList sliverList = SliverList(
//itemCount: _columnChildren.length,
//reAnimateOnVisibility: false,
//showItemDuration: Duration(milliseconds: 150),
//itemBuilder: (BuildContext context, int index, Animation<double> animation) => FadeTransition(
// opacity: animation,
// child: _columnChildren[index],
//),
//controller: scrollController,
delegate: SliverChildListDelegate(_columnChildren),
);
slivers.add(sliverList);
return slivers;
}
@@ -377,11 +381,12 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: Colors.transparent,
child: FadeInImage(
fadeInDuration: Duration(milliseconds: 200),
child: Image.asset(workoutTree.imageName),
/* FadeInImage(
fadeInDuration: Duration(milliseconds: 50),
image: AssetImage(workoutTree.imageName),
placeholder: MemoryImage(kTransparentImage),
),
), */
));
}
}
+26 -7
View File
@@ -2,6 +2,7 @@ import 'package:aitrainer_app/util/trans.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class NumberPickerWidget extends StatefulWidget {
final Function(double) onChange;
final int minValue;
@@ -9,18 +10,35 @@ class NumberPickerWidget extends StatefulWidget {
final int initalValue;
final String unit;
final Color color;
double fontSize;
const NumberPickerWidget({Key key, this.minValue, this.maxValue, this.initalValue, this.unit, this.color, this.onChange})
: super(key: key);
NumberPickerWidget({Key key, this.minValue, this.maxValue, this.initalValue, this.unit, this.fontSize, this.color, this.onChange})
: super(key: key) {
fontSize = fontSize ?? 20;
}
@override
_NumberPickerWidgetState createState() => _NumberPickerWidgetState();
}
class _NumberPickerWidgetState extends State<NumberPickerWidget> with Trans {
FixedExtentScrollController _scrollController;
@override
void initState() {
super.initState();
_scrollController = FixedExtentScrollController(initialItem: widget.initalValue);
}
@override
void didUpdateWidget(NumberPickerWidget oldWidget) {
super.didUpdateWidget(oldWidget);
_scrollController.animateToItem(widget.initalValue, duration: Duration(milliseconds: 100), curve: Curves.easeIn);
}
Widget durationPicker({bool inSeconds = false, bool inHundredths = false}) {
double value = 0;
return CupertinoPicker(
scrollController: FixedExtentScrollController(initialItem: widget.initalValue),
scrollController: _scrollController,
backgroundColor: Colors.transparent,
onSelectedItemChanged: (x) {
currentData = x.toDouble();
@@ -29,7 +47,8 @@ class _NumberPickerWidgetState extends State<NumberPickerWidget> with Trans {
setState(() {});
widget.onChange(value);
},
children: List.generate(widget.maxValue, (index) => Text('$index ' + widget.unit, style: TextStyle(color: widget.color))),
children: List.generate(
widget.maxValue, (index) => Text('$index ' + widget.unit, style: TextStyle(color: widget.color, fontSize: widget.fontSize))),
itemExtent: 40,
);
}
@@ -40,16 +59,16 @@ class _NumberPickerWidgetState extends State<NumberPickerWidget> with Trans {
setContext(context);
return Container(
//color: Colors.white24,
width: MediaQuery.of(context).size.width * .45,
width: MediaQuery.of(context).size.width * .40,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color: Colors.transparent,
width: MediaQuery.of(context).size.width * .3,
width: MediaQuery.of(context).size.width * .35,
child: Center(
child: Container(
color: Colors.transparent,
+1 -1
View File
@@ -41,7 +41,7 @@ class SalesButton extends StatelessWidget {
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_sales_background_3x5.png'),
image: AssetImage('asset/image/WT_sales_background_3x5.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
+1 -1
View File
@@ -32,7 +32,7 @@ class _SizeState extends State<SizeWidget> with Trans {
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.png'),
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),