WT1.1.6+3 bodyType animation, bug fixes
This commit is contained in:
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 +
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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)}
|
||||
},
|
||||
)
|
||||
],
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)}
|
||||
},
|
||||
)
|
||||
],
|
||||
|
||||
@@ -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)}
|
||||
},
|
||||
)
|
||||
],
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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: []));
|
||||
|
||||
@@ -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
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
]),
|
||||
]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
), */
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user