WT 1.1.18+4 A/B Test sales page
This commit is contained in:
parent
d5deaf48a9
commit
0ca3b71c03
10
i18n/en.json
10
i18n/en.json
@ -454,5 +454,13 @@
|
|||||||
"Do you want to override it with": "Do you want to override it with",
|
"Do you want to override it with": "Do you want to override it with",
|
||||||
"Calculated Weight": "Calculated Weight",
|
"Calculated Weight": "Calculated Weight",
|
||||||
"The weight is based on your previuos tests - if they exist.": "The weight is based on your previuos tests - if they exist.",
|
"The weight is based on your previuos tests - if they exist.": "The weight is based on your previuos tests - if they exist.",
|
||||||
"If it does not exist, your very first exercise will be a test.": "If it does not exist, your very first exercise will be a test."
|
"If it does not exist, your very first exercise will be a test.": "If it does not exist, your very first exercise will be a test.",
|
||||||
|
"Tap on the button below the reach all premium content!": "Tap on the button below the reach all premium content!",
|
||||||
|
"Enjoy also this premium feature": "Enjoy also this premium feature",
|
||||||
|
"to activate all available training programs.": "to activate all available training programs.",
|
||||||
|
"because only that way can we generated the training plan for you.": "because only that way can we generate the personalized training plan for you.",
|
||||||
|
"This is a premium function": "This is a premium function",
|
||||||
|
"because only that way can we show you your exercises, results and evaluations.": "because only that way can we show you your exercises, results and evaluations.",
|
||||||
|
"because only that way can we show you the personalized development diagrams and analysises": "because only that way can we show you the personalized development diagrams and analysises",
|
||||||
|
"because only in that way can you begin to execute a training plan": "because only in that way can you begin to execute a training plan"
|
||||||
}
|
}
|
12
i18n/hu.json
12
i18n/hu.json
@ -279,7 +279,7 @@
|
|||||||
"feature is reachable after you finished": "funkció elérhető számodra, miután teljesítetted",
|
"feature is reachable after you finished": "funkció elérhető számodra, miután teljesítetted",
|
||||||
"100% test circles": "100%-os teszt-köröd",
|
"100% test circles": "100%-os teszt-köröd",
|
||||||
"Keep testing": "Folytasd a tesztelést",
|
"Keep testing": "Folytasd a tesztelést",
|
||||||
"Enjoy also this premium fetaure to show all old evaluation data of your successful exercises.": "Élvezd ezt a prémium funkciót is, amely megjeleníti a korábbi gyakorlatok teljes kiértékelését",
|
"Enjoy also this premium feature to show all old evaluation data of your successful exercises.": "Élvezd ezt a prémium funkciót is, amely megjeleníti a korábbi gyakorlatok teljes kiértékelését",
|
||||||
"Please define your Exercise Plan": "Kérlek készíts edzéstervet!",
|
"Please define your Exercise Plan": "Kérlek készíts edzéstervet!",
|
||||||
"Go to: 'Training Plan' - 'Edit My Custom Plan'": "Menj a 'Edzéstervem' - 'Egyéni edzésterv' menübe",
|
"Go to: 'Training Plan' - 'Edit My Custom Plan'": "Menj a 'Edzéstervem' - 'Egyéni edzésterv' menübe",
|
||||||
"Jump there »": "Vigyél oda »",
|
"Jump there »": "Vigyél oda »",
|
||||||
@ -452,5 +452,13 @@
|
|||||||
"Do you want to override it with": "Ezt az edzéstervet akarod ezentúl használni?",
|
"Do you want to override it with": "Ezt az edzéstervet akarod ezentúl használni?",
|
||||||
"Calculated Weight": "Kalkulált súly",
|
"Calculated Weight": "Kalkulált súly",
|
||||||
"The weight is based on your previuos tests - if they exist.": "A súlyt kikalkuláltuk az előző teszted alapján - ha létezik.",
|
"The weight is based on your previuos tests - if they exist.": "A súlyt kikalkuláltuk az előző teszted alapján - ha létezik.",
|
||||||
"If it does not exist, your very first exercise will be a test.": "Ha nem létezik 3 hétnél korábbi teszt, akkor a legelső gyakorlatod egy teszt lesz."
|
"If it does not exist, your very first exercise will be a test.": "Ha nem létezik 3 hétnél korábbi teszt, akkor a legelső gyakorlatod egy teszt lesz.",
|
||||||
|
"Tap on the button below the reach all premium content!": "Kattints a gombra, hogy hozzáférhess a prémium funkciókhoz!",
|
||||||
|
"Enjoy also this premium feature": "Élvezd ezt a prémium funkciót is, ",
|
||||||
|
"to activate all available training programs.": "amellyel aktiválhatod az összes haladó tréning programot.",
|
||||||
|
"because only that way can we generated the training plan for you.": "mert csak így tudjuk neked a személyre szabott edzéstervet generálni.",
|
||||||
|
"This is a premium function": "Ez egy prémium funkció",
|
||||||
|
"because only that way can we show you your exercises, results and evaluations.": "mert csak így tudjuk neked megmutatni a korábbi gyakorlataidat, eredményeket és kiértékeléseket.",
|
||||||
|
"because only that way can we show you the personalized development diagrams and analysises": "mert csak így tudjuk neked megmutatni a személyre szabott diagramokat és analíziseket.",
|
||||||
|
"because only in that way can you begin to execute a training plan": "mert csak így tudod elkezdeni az edzésterved végrehajtását"
|
||||||
}
|
}
|
@ -388,7 +388,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 3;
|
CURRENT_PROJECT_VERSION = 4;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@ -531,7 +531,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 3;
|
CURRENT_PROJECT_VERSION = 4;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@ -566,7 +566,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 3;
|
CURRENT_PROJECT_VERSION = 4;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'package:aitrainer_app/model/exercise_type.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:bloc/bloc.dart';
|
|
||||||
import 'package:equatable/equatable.dart';
|
|
||||||
import 'package:meta/meta.dart';
|
|
||||||
|
|
||||||
part 'exercise_execute_plan_event.dart';
|
|
||||||
|
|
||||||
part 'exercise_execute_plan_state.dart';
|
|
||||||
|
|
||||||
class ExerciseExecutePlanBloc extends Bloc<ExerciseExecutePlanEvent, ExerciseExecutePlanState> {
|
|
||||||
final WorkoutTreeRepository menuTreeRepository;
|
|
||||||
final ExercisePlanRepository exercisePlanRepository = ExercisePlanRepository();
|
|
||||||
int? customerId;
|
|
||||||
int selectedNumber = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
ExerciseExecutePlanBloc({required this.menuTreeRepository}) : super(ExerciseByPlanStateInitial());
|
|
||||||
|
|
||||||
Future<void> getData() async {
|
|
||||||
exercisePlanRepository.setCustomerId(customerId!);
|
|
||||||
await exercisePlanRepository.getLastExercisePlan();
|
|
||||||
await exercisePlanRepository.getExercisePlanDetails();
|
|
||||||
menuTreeRepository.sortedTree.clear();
|
|
||||||
menuTreeRepository.sortByMuscleType();
|
|
||||||
|
|
||||||
menuTreeRepository.sortedTree.forEach((key, value) {
|
|
||||||
List<WorkoutMenuTree> listWorkoutTree = value;
|
|
||||||
listWorkoutTree.forEach((workoutTree) {
|
|
||||||
workoutTree.selected = false;
|
|
||||||
if (exercisePlanRepository.getExercisePlanDetailSize() > 0) {
|
|
||||||
if (exercisePlanRepository.getExercisePlanDetailByExerciseId(workoutTree.exerciseTypeId) != null) {
|
|
||||||
workoutTree.selected = true;
|
|
||||||
this.selectedNumber++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<ExerciseExecutePlanState> mapEventToState(ExerciseExecutePlanEvent event) async* {
|
|
||||||
try {
|
|
||||||
if (event is ExerciseByPlanLoad) {
|
|
||||||
yield ExerciseByPlanLoading();
|
|
||||||
await this.getData();
|
|
||||||
yield ExerciseByPlanReady();
|
|
||||||
} else if (event is AddExerciseByPlanEvent) {
|
|
||||||
yield ExerciseByPlanLoading();
|
|
||||||
yield ExerciseByPlanReady();
|
|
||||||
}
|
|
||||||
} on Exception catch (e) {
|
|
||||||
yield ExerciseByPlanError(message: e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
part of 'exercise_execute_plan_bloc.dart';
|
|
||||||
|
|
||||||
@immutable
|
|
||||||
abstract class ExerciseExecutePlanEvent extends Equatable {
|
|
||||||
const ExerciseExecutePlanEvent();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [];
|
|
||||||
}
|
|
||||||
|
|
||||||
class AddExerciseByPlanEvent extends ExerciseExecutePlanEvent {
|
|
||||||
final ExerciseType exerciseType;
|
|
||||||
const AddExerciseByPlanEvent({required this.exerciseType});
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [exerciseType];
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExerciseByPlanLoad extends ExerciseExecutePlanEvent {
|
|
||||||
const ExerciseByPlanLoad();
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
part of 'exercise_execute_plan_bloc.dart';
|
|
||||||
|
|
||||||
@immutable
|
|
||||||
abstract class ExerciseExecutePlanState extends Equatable {
|
|
||||||
const ExerciseExecutePlanState();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [];
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExerciseByPlanStateInitial extends ExerciseExecutePlanState {
|
|
||||||
const ExerciseByPlanStateInitial();
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExerciseByPlanLoading extends ExerciseExecutePlanState {
|
|
||||||
const ExerciseByPlanLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
// updated screen
|
|
||||||
class ExerciseByPlanReady extends ExerciseExecutePlanState {
|
|
||||||
const ExerciseByPlanReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
// error splash screen
|
|
||||||
class ExerciseByPlanError extends ExerciseExecutePlanState {
|
|
||||||
final String message;
|
|
||||||
const ExerciseByPlanError({required this.message});
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [message];
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'package:aitrainer_app/bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart';
|
|
||||||
import 'package:aitrainer_app/model/cache.dart';
|
|
||||||
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:meta/meta.dart';
|
|
||||||
|
|
||||||
part 'exercise_execute_plan_add_event.dart';
|
|
||||||
|
|
||||||
part 'exercise_execute_plan_add_state.dart';
|
|
||||||
|
|
||||||
class ExerciseExecutePlanAddBloc extends Bloc<ExerciseExecutePlanAddEvent, ExerciseExecutePlanAddState> {
|
|
||||||
final ExerciseRepository exerciseRepository;
|
|
||||||
final ExercisePlanRepository exercisePlanRepository;
|
|
||||||
final WorkoutMenuTree workoutTree;
|
|
||||||
final ExerciseExecutePlanBloc planBloc;
|
|
||||||
final int customerId;
|
|
||||||
|
|
||||||
late Customer customer;
|
|
||||||
int step = 1;
|
|
||||||
int countSteps = 1;
|
|
||||||
|
|
||||||
double? quantity;
|
|
||||||
double? unitQuantity;
|
|
||||||
|
|
||||||
double scrollOffset = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
ExerciseExecutePlanAddBloc(
|
|
||||||
{required this.exerciseRepository,
|
|
||||||
required this.exercisePlanRepository,
|
|
||||||
required this.customerId,
|
|
||||||
required this.workoutTree,
|
|
||||||
required this.planBloc})
|
|
||||||
: super(ExerciseExecutePlanAddInitial());
|
|
||||||
|
|
||||||
void init() {
|
|
||||||
exerciseRepository.exerciseType = workoutTree.exerciseType;
|
|
||||||
if (Cache().userLoggedIn!.customerId == customerId) {
|
|
||||||
customer = Cache().userLoggedIn!;
|
|
||||||
} else if (Cache().getTrainee()!.customerId == customerId) {
|
|
||||||
customer = Cache().getTrainee()!;
|
|
||||||
}
|
|
||||||
exercisePlanRepository.setActualPlanDetailByExerciseType(workoutTree.exerciseType!);
|
|
||||||
exerciseRepository.customer = customer;
|
|
||||||
countSteps = exercisePlanRepository.getActualPlanDetail()!.serie!;
|
|
||||||
if (exercisePlanRepository.getActualPlanDetail()!.weightEquation == null) {
|
|
||||||
unitQuantity = 0.0;
|
|
||||||
} else {
|
|
||||||
unitQuantity = double.parse(exercisePlanRepository.getActualPlanDetail()!.weightEquation!);
|
|
||||||
}
|
|
||||||
quantity = exercisePlanRepository.getActualPlanDetail()!.repeats!.toDouble();
|
|
||||||
|
|
||||||
exerciseRepository.setQuantity(quantity!);
|
|
||||||
exerciseRepository.setUnitQuantity(unitQuantity!);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<ExerciseExecutePlanAddState> mapEventToState(ExerciseExecutePlanAddEvent event) async* {
|
|
||||||
try {
|
|
||||||
if (event is ExerciseExecutePlanAddLoad) {
|
|
||||||
yield ExerciseExecutePlanAddLoading();
|
|
||||||
init();
|
|
||||||
Track().track(TrackingEvent.my_exercise_plan_execute_open);
|
|
||||||
yield ExerciseExecutePlanAddReady();
|
|
||||||
} else if (event is ExerciseExecutePlanAddChangeQuantity) {
|
|
||||||
yield ExerciseExecutePlanAddLoading();
|
|
||||||
quantity = event.quantity;
|
|
||||||
exerciseRepository.setQuantity(quantity!);
|
|
||||||
yield ExerciseExecutePlanAddReady();
|
|
||||||
} else if (event is ExerciseExecutePlanAddChangeUnitQuantity) {
|
|
||||||
yield ExerciseExecutePlanAddLoading();
|
|
||||||
unitQuantity = event.quantity;
|
|
||||||
exerciseRepository.setUnitQuantity(unitQuantity!);
|
|
||||||
yield ExerciseExecutePlanAddReady();
|
|
||||||
} else if (event is ExerciseExecutePlanAddSubmit) {
|
|
||||||
yield ExerciseExecutePlanAddLoading();
|
|
||||||
exerciseRepository.exercise!.exercisePlanDetailId = exercisePlanRepository.getActualPlanDetail()!.exercisePlanDetailId;
|
|
||||||
exerciseRepository.exercise!.unit = workoutTree.exerciseType!.unit;
|
|
||||||
workoutTree.executed = true;
|
|
||||||
await exerciseRepository.addExercise();
|
|
||||||
exerciseRepository.initExercise();
|
|
||||||
Track().track(TrackingEvent.my_exercise_plan_execute_save);
|
|
||||||
step++;
|
|
||||||
scrollOffset = step * 200.0;
|
|
||||||
planBloc.add(ExerciseByPlanLoad());
|
|
||||||
yield ExerciseExecutePlanAddReady();
|
|
||||||
}
|
|
||||||
} on Exception catch (e) {
|
|
||||||
yield ExerciseExecutePlanAddError(message: e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
part of 'exercise_execute_plan_add_bloc.dart';
|
|
||||||
|
|
||||||
@immutable
|
|
||||||
abstract class ExerciseExecutePlanAddEvent extends Equatable {
|
|
||||||
const ExerciseExecutePlanAddEvent();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [];
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExerciseExecutePlanAddLoad extends ExerciseExecutePlanAddEvent {
|
|
||||||
const ExerciseExecutePlanAddLoad();
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExerciseExecutePlanAddChangeQuantity extends ExerciseExecutePlanAddEvent {
|
|
||||||
final double quantity;
|
|
||||||
const ExerciseExecutePlanAddChangeQuantity({required this.quantity});
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [quantity];
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExerciseExecutePlanAddChangeUnitQuantity extends ExerciseExecutePlanAddEvent {
|
|
||||||
final double quantity;
|
|
||||||
const ExerciseExecutePlanAddChangeUnitQuantity({required this.quantity});
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [quantity];
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExerciseExecutePlanAddSubmit extends ExerciseExecutePlanAddEvent {
|
|
||||||
const ExerciseExecutePlanAddSubmit();
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
part of 'exercise_execute_plan_add_bloc.dart';
|
|
||||||
|
|
||||||
@immutable
|
|
||||||
abstract class ExerciseExecutePlanAddState extends Equatable {
|
|
||||||
const ExerciseExecutePlanAddState();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [];
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExerciseExecutePlanAddInitial extends ExerciseExecutePlanAddState {
|
|
||||||
const ExerciseExecutePlanAddInitial();
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExerciseExecutePlanAddLoading extends ExerciseExecutePlanAddState {
|
|
||||||
const ExerciseExecutePlanAddLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
// updated screen
|
|
||||||
class ExerciseExecutePlanAddReady extends ExerciseExecutePlanAddState {
|
|
||||||
const ExerciseExecutePlanAddReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
// error splash screen
|
|
||||||
class ExerciseExecutePlanAddError extends ExerciseExecutePlanAddState {
|
|
||||||
final String message;
|
|
||||||
const ExerciseExecutePlanAddError({required this.message});
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [message];
|
|
||||||
}
|
|
@ -3,6 +3,7 @@ import 'dart:async';
|
|||||||
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
|
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
|
||||||
import 'package:aitrainer_app/model/cache.dart';
|
import 'package:aitrainer_app/model/cache.dart';
|
||||||
import 'package:aitrainer_app/repository/customer_repository.dart';
|
import 'package:aitrainer_app/repository/customer_repository.dart';
|
||||||
|
import 'package:aitrainer_app/repository/split_test_respository.dart';
|
||||||
import 'package:aitrainer_app/repository/user_repository.dart';
|
import 'package:aitrainer_app/repository/user_repository.dart';
|
||||||
import 'package:aitrainer_app/util/common.dart';
|
import 'package:aitrainer_app/util/common.dart';
|
||||||
import 'package:aitrainer_app/util/enums.dart';
|
import 'package:aitrainer_app/util/enums.dart';
|
||||||
@ -19,14 +20,27 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
|
|||||||
final AccountBloc accountBloc;
|
final AccountBloc accountBloc;
|
||||||
final UserRepository userRepository;
|
final UserRepository userRepository;
|
||||||
final CustomerRepository customerRepository = CustomerRepository();
|
final CustomerRepository customerRepository = CustomerRepository();
|
||||||
|
final SplitTestRepository splitTestRepository = SplitTestRepository();
|
||||||
final BuildContext context;
|
final BuildContext context;
|
||||||
final bool isRegistration;
|
final bool isRegistration;
|
||||||
bool dataPolicyAllowed = false;
|
bool dataPolicyAllowed = false;
|
||||||
bool emailSubscription = false;
|
bool emailSubscription = false;
|
||||||
bool obscure = true;
|
bool obscure = true;
|
||||||
|
|
||||||
|
Color testColor = Colors.green[800]!;
|
||||||
|
bool emailCheckbox = true;
|
||||||
|
|
||||||
LoginBloc({required this.accountBloc, required this.userRepository, required this.context, required this.isRegistration})
|
LoginBloc({required this.accountBloc, required this.userRepository, required this.context, required this.isRegistration})
|
||||||
: super(LoginInitial());
|
: super(LoginInitial()) {
|
||||||
|
String colorString = splitTestRepository.getSplitTestValue("registration_skip");
|
||||||
|
if (colorString == "red") {
|
||||||
|
testColor = Colors.red[800]!;
|
||||||
|
}
|
||||||
|
String emailCheckboxString = splitTestRepository.getSplitTestValue("email_checkbox");
|
||||||
|
if (emailCheckboxString == "0") {
|
||||||
|
emailCheckbox = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<LoginState> mapEventToState(
|
Stream<LoginState> mapEventToState(
|
||||||
|
@ -66,7 +66,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
|
|||||||
workoutItem = event.item;
|
workoutItem = event.item;
|
||||||
|
|
||||||
if (workoutItem != null) {
|
if (workoutItem != null) {
|
||||||
setAbility(workoutItem!.nameEnglish);
|
setAbility(workoutItem!.internalName);
|
||||||
}
|
}
|
||||||
final LinkedHashMap<String, WorkoutMenuTree> branch = menuTreeRepository.getBranch(event.parent);
|
final LinkedHashMap<String, WorkoutMenuTree> branch = menuTreeRepository.getBranch(event.parent);
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
|
|||||||
|
|
||||||
LinkedHashMap<String, WorkoutMenuTree> branch;
|
LinkedHashMap<String, WorkoutMenuTree> branch;
|
||||||
if (workoutItem != null) {
|
if (workoutItem != null) {
|
||||||
setAbility(workoutItem!.nameEnglish);
|
setAbility(workoutItem!.internalName);
|
||||||
branch = menuTreeRepository.getBranch(workoutItem!.parent);
|
branch = menuTreeRepository.getBranch(workoutItem!.parent);
|
||||||
await getImages(branch);
|
await getImages(branch);
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
|
|||||||
workoutItem = menuTreeRepository.getParentItem(parent);
|
workoutItem = menuTreeRepository.getParentItem(parent);
|
||||||
|
|
||||||
if (workoutItem != null) {
|
if (workoutItem != null) {
|
||||||
setAbility(workoutItem!.nameEnglish);
|
setAbility(workoutItem!.internalName);
|
||||||
}
|
}
|
||||||
final LinkedHashMap<String, WorkoutMenuTree> branch = menuTreeRepository.getBranch(workoutItem!.parent);
|
final LinkedHashMap<String, WorkoutMenuTree> branch = menuTreeRepository.getBranch(workoutItem!.parent);
|
||||||
await getImages(branch);
|
await getImages(branch);
|
||||||
@ -119,22 +119,19 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
|
|||||||
|
|
||||||
void setAbility(String name) {
|
void setAbility(String name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "Muscle Build / Shape Toning":
|
case "one_rep_max":
|
||||||
ability = ExerciseAbility.oneRepMax;
|
ability = ExerciseAbility.oneRepMax;
|
||||||
break;
|
break;
|
||||||
case "Endurance":
|
case "cardio":
|
||||||
ability = ExerciseAbility.endurance;
|
|
||||||
break;
|
|
||||||
case "Cardio":
|
|
||||||
ability = ExerciseAbility.running;
|
ability = ExerciseAbility.running;
|
||||||
break;
|
break;
|
||||||
case "Test Center":
|
case "test_center":
|
||||||
ability = ExerciseAbility.mini_test_set;
|
ability = ExerciseAbility.mini_test_set;
|
||||||
break;
|
break;
|
||||||
case "Training Plans":
|
case "training_plans":
|
||||||
ability = ExerciseAbility.training;
|
ability = ExerciseAbility.training;
|
||||||
break;
|
break;
|
||||||
case "My Body":
|
case "my_body":
|
||||||
ability = ExerciseAbility.none;
|
ability = ExerciseAbility.none;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math' as math;
|
|
||||||
|
|
||||||
import 'package:aitrainer_app/model/cache.dart';
|
import 'package:aitrainer_app/model/cache.dart';
|
||||||
import 'package:aitrainer_app/model/product.dart';
|
import 'package:aitrainer_app/model/product.dart';
|
||||||
import 'package:aitrainer_app/model/product_test.dart';
|
|
||||||
import 'package:aitrainer_app/model/purchase.dart';
|
import 'package:aitrainer_app/model/purchase.dart';
|
||||||
import 'package:aitrainer_app/repository/description_repository.dart';
|
import 'package:aitrainer_app/repository/description_repository.dart';
|
||||||
|
import 'package:aitrainer_app/repository/split_test_respository.dart';
|
||||||
import 'package:aitrainer_app/service/logging.dart';
|
import 'package:aitrainer_app/service/logging.dart';
|
||||||
import 'package:aitrainer_app/service/purchase_service.dart';
|
import 'package:aitrainer_app/service/purchase_service.dart';
|
||||||
import 'package:aitrainer_app/util/enums.dart';
|
import 'package:aitrainer_app/util/enums.dart';
|
||||||
@ -14,37 +13,43 @@ import 'package:aitrainer_app/util/purchases.dart';
|
|||||||
import 'package:aitrainer_app/util/track.dart';
|
import 'package:aitrainer_app/util/track.dart';
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:firebase_remote_config/firebase_remote_config.dart';
|
|
||||||
import 'package:purchases_flutter/offering_wrapper.dart';
|
import 'package:purchases_flutter/offering_wrapper.dart';
|
||||||
|
|
||||||
part 'sales_event.dart';
|
part 'sales_event.dart';
|
||||||
part 'sales_state.dart';
|
part 'sales_state.dart';
|
||||||
|
|
||||||
class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
||||||
List<ProductTest>? tests = [];
|
|
||||||
List<Product> product2Display = [];
|
List<Product> product2Display = [];
|
||||||
|
List<String> productText2Display = ["WorkoutTest annual", "WorkoutTest montly"];
|
||||||
|
final SplitTestRepository splitTestRepository = SplitTestRepository();
|
||||||
|
|
||||||
int productSet = -1;
|
int productSet = -1;
|
||||||
final DescriptionRepository descriptionRepository = DescriptionRepository();
|
final DescriptionRepository descriptionRepository = DescriptionRepository();
|
||||||
SalesBloc() : super(SalesInitial());
|
SalesBloc() : super(SalesInitial());
|
||||||
|
|
||||||
String? salesText;
|
String? salesText;
|
||||||
|
String? premiumFunctions = "";
|
||||||
|
|
||||||
String salesButtonText = "<h1>Workout Test Monthly</h1><p>localizedPrice</p><p><small>cancel any time</small></p>";
|
void init() async {
|
||||||
Product? offeredProduct;
|
if (Cache().userLoggedIn == null) {
|
||||||
|
throw Exception("Please log in");
|
||||||
Product? getProductByName(String name) {
|
|
||||||
Product? product;
|
|
||||||
if (product2Display.isNotEmpty) {
|
|
||||||
product2Display.forEach((element) {
|
|
||||||
if (element.type == name) {
|
|
||||||
product = element;
|
|
||||||
salesButtonText = salesButtonText.replaceFirst(RegExp(r'localizedPrice'), product!.localizedPrice!);
|
|
||||||
print("Localized Price ${product!.localizedPrice!} - Text: $salesButtonText");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return product;
|
salesText = splitTestRepository.getSplitTestValue("sales_page_text_a");
|
||||||
|
if (salesText == null || salesText!.isEmpty) {
|
||||||
|
salesText = descriptionRepository.getDescriptionByName("sales_page_text_a");
|
||||||
|
}
|
||||||
|
print("sales Text: $salesText");
|
||||||
|
getProductsTexts();
|
||||||
|
|
||||||
|
premiumFunctions = descriptionRepository.getDescriptionByName("premium_functions");
|
||||||
|
if (premiumFunctions == null || premiumFunctions!.isEmpty) {
|
||||||
|
premiumFunctions = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
await RevenueCatPurchases().getOfferings();
|
||||||
|
this.getProductSet();
|
||||||
|
Track().track(TrackingEvent.sales_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -53,33 +58,11 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
|||||||
) async* {
|
) async* {
|
||||||
try {
|
try {
|
||||||
if (event is SalesLoad) {
|
if (event is SalesLoad) {
|
||||||
|
log(" -- start SalesLoad");
|
||||||
yield SalesLoading();
|
yield SalesLoading();
|
||||||
log("Load Sales");
|
init();
|
||||||
if (Cache().userLoggedIn == null) {
|
|
||||||
throw Exception("Please log in");
|
|
||||||
}
|
|
||||||
|
|
||||||
String descriptionName = "sales_page_text";
|
|
||||||
RemoteConfig? remoteConfig = Cache().remoteConfig;
|
|
||||||
if (remoteConfig != null) {
|
|
||||||
remoteConfig.fetchAndActivate();
|
|
||||||
Map config = remoteConfig.getAll();
|
|
||||||
RemoteConfigValue? value = config['sales_page_text_a'];
|
|
||||||
if (value != null) {
|
|
||||||
log("RemoteConfig sales_page_text value: ${value.asString()}");
|
|
||||||
if (value.asString() == "1") {
|
|
||||||
descriptionName = "sales_page_text_a";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await RevenueCatPurchases().getOfferings();
|
|
||||||
this.getProductSet();
|
|
||||||
salesText = descriptionRepository.getDescriptionByName(descriptionName);
|
|
||||||
log(salesText!);
|
|
||||||
salesButtonText = descriptionRepository.getDescriptionByName("sales_button_monthly");
|
|
||||||
offeredProduct = getProductByName("wt_sub_2_3");
|
|
||||||
Track().track(TrackingEvent.sales_page);
|
|
||||||
yield SalesReady();
|
yield SalesReady();
|
||||||
|
log(" -- finish SalesLoad");
|
||||||
} else if (event is SalesPurchase) {
|
} else if (event is SalesPurchase) {
|
||||||
if (Cache().hasPurchased) {
|
if (Cache().hasPurchased) {
|
||||||
throw Exception("You have already a successfull subscription");
|
throw Exception("You have already a successfull subscription");
|
||||||
@ -104,28 +87,34 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
|||||||
} else {
|
} else {
|
||||||
yield SalesError(message: "No selected product");
|
yield SalesError(message: "No selected product");
|
||||||
}
|
}
|
||||||
} else if (event is SalesChangeSubscription) {
|
|
||||||
yield SalesLoading();
|
|
||||||
print("offered product .. $offeredProduct");
|
|
||||||
if (offeredProduct != null) {
|
|
||||||
if (offeredProduct!.type == "wt_sub_2_3") {
|
|
||||||
print("go yearly");
|
|
||||||
salesButtonText = descriptionRepository.getDescriptionByName("sales_button_yearly");
|
|
||||||
offeredProduct = getProductByName("wt_sub_2_1");
|
|
||||||
} else {
|
|
||||||
print("go monthly");
|
|
||||||
salesButtonText = descriptionRepository.getDescriptionByName("sales_button_monthly");
|
|
||||||
offeredProduct = getProductByName("wt_sub_2_3");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yield SalesReady();
|
|
||||||
}
|
}
|
||||||
} on Exception catch (ex) {
|
} on Exception catch (ex) {
|
||||||
yield SalesError(message: ex.toString());
|
yield SalesError(message: ex.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getProductsTexts() {
|
||||||
|
Product product;
|
||||||
|
if (product2Display.isNotEmpty) {
|
||||||
|
String salesButtonText;
|
||||||
|
product2Display.forEach((element) {
|
||||||
|
product = element;
|
||||||
|
if (product.sort == 3) {
|
||||||
|
salesButtonText = descriptionRepository.getDescriptionByName("sales_button_monthly");
|
||||||
|
productText2Display[1] = salesButtonText.replaceFirst(RegExp(r'localizedPrice'), product.localizedPrice!);
|
||||||
|
} else if (product.sort == 1) {
|
||||||
|
salesButtonText = descriptionRepository.getDescriptionByName("sales_button_yearly");
|
||||||
|
productText2Display[0] = salesButtonText.replaceFirst(RegExp(r'localizedPrice'), product.localizedPrice!);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
print("product Text $productText2Display");
|
||||||
|
|
||||||
|
splitTestRepository.getSplitTestValue("product_set_2");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Product? getSelectedProduct(int productId) {
|
Product? getSelectedProduct(int productId) {
|
||||||
Product? prod;
|
Product? prod;
|
||||||
for (var product in this.product2Display) {
|
for (var product in this.product2Display) {
|
||||||
@ -161,38 +150,37 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void getProductSet() {
|
void getProductSet() {
|
||||||
int productId = 0;
|
|
||||||
//this.tests = Cache().productTests;
|
|
||||||
List<Product>? products = Cache().products;
|
List<Product>? products = Cache().products;
|
||||||
if (products == null) {
|
if (products == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if (tests != null && tests!.isEmpty) {
|
String productSetString = splitTestRepository.getSplitTestValue("product_set_2");
|
||||||
var rand = math.Random.secure();
|
log("ProductSetString: $productSetString");
|
||||||
productSet = rand.nextInt(5) + 1;
|
try {
|
||||||
} else {
|
productSet = int.parse(productSetString);
|
||||||
trace("Previous ProductTest: " + tests![0].toJson().toString());
|
} on Exception catch (e) {
|
||||||
productId = tests![0].productId;
|
log("Define the right productset!");
|
||||||
for (var elem in products) {
|
|
||||||
final Product product = elem;
|
|
||||||
if (product.productId == productId) {
|
|
||||||
productSet = product.productSet;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
//ProductTest productTest = ProductTest();
|
|
||||||
|
|
||||||
productSet = 2;
|
productSet = 2;
|
||||||
log("ProductSet: " + productSet.toString());
|
}
|
||||||
|
|
||||||
|
log("ProductSet: $productSet");
|
||||||
|
|
||||||
for (var elem in products) {
|
for (var elem in products) {
|
||||||
Product product = elem;
|
Product product = elem;
|
||||||
|
|
||||||
if (product.productSet == productSet) {
|
if (product.productSet == productSet) {
|
||||||
productId = product.productId;
|
String? platformProductId;
|
||||||
final String platformProductId = Platform.isAndroid ? product.productIdAndroid! : product.productIdIos!;
|
if (product.productIdAndroid == null || product.productIdIos == null) {
|
||||||
|
log("Define the product ID for the different Platforms!!");
|
||||||
|
} else {
|
||||||
|
platformProductId = Platform.isAndroid ? product.productIdAndroid! : product.productIdIos!;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (platformProductId == null) {
|
||||||
|
log("Not defined platform product id!!");
|
||||||
|
platformProductId = "";
|
||||||
|
}
|
||||||
product.localizedPrice = getLocalizedPrice(platformProductId, product);
|
product.localizedPrice = getLocalizedPrice(platformProductId, product);
|
||||||
log("product with localized price: $product");
|
log("product with localized price: $product");
|
||||||
product2Display.add(product);
|
product2Display.add(product);
|
||||||
@ -203,10 +191,6 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
|||||||
return a.sort < b.sort ? -1 : 1;
|
return a.sort < b.sort ? -1 : 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
//productTest.productId = productId;
|
this.getProductsTexts();
|
||||||
//productTest.customerId = Cache().userLoggedIn!.customerId!;
|
|
||||||
//productTest.dateView = DateTime.now();
|
|
||||||
//ProductTestApi().saveProductTest(productTest);
|
|
||||||
//Cache().productTests.add(productTest);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,11 +92,16 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
|
|||||||
event.detail.state = ExercisePlanDetailState.inProgress;
|
event.detail.state = ExercisePlanDetailState.inProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// recalculate the weight to the original planned repeats
|
||||||
|
if (event.detail.isTest && event.detail.exercises.length == 1) {
|
||||||
|
trainingPlanRepository.recalculateDetail(_myPlan!.trainingPlanId!, event.detail);
|
||||||
|
}
|
||||||
|
|
||||||
exercise.trainingPlanDetailsId = _myPlan!.trainingPlanId;
|
exercise.trainingPlanDetailsId = _myPlan!.trainingPlanId;
|
||||||
|
|
||||||
// save Exercise
|
// save Exercise
|
||||||
await ExerciseApi().addExercise(exercise);
|
Exercise savedExercise = await ExerciseApi().addExercise(exercise);
|
||||||
Cache().addExercise(exercise);
|
Cache().addExercise(savedExercise);
|
||||||
|
|
||||||
Cache().myTrainingPlan = _myPlan;
|
Cache().myTrainingPlan = _myPlan;
|
||||||
await Cache().saveMyTrainingPlan();
|
await Cache().saveMyTrainingPlan();
|
||||||
@ -108,7 +113,6 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
|
|||||||
}
|
}
|
||||||
} else if (event is TrainingPlanSkipExercise) {
|
} else if (event is TrainingPlanSkipExercise) {
|
||||||
yield TrainingPlanLoading();
|
yield TrainingPlanLoading();
|
||||||
print("Skipping ${event.detail.exerciseTypeId}");
|
|
||||||
event.detail.state = ExercisePlanDetailState.skipped;
|
event.detail.state = ExercisePlanDetailState.skipped;
|
||||||
Cache().myTrainingPlan = _myPlan;
|
Cache().myTrainingPlan = _myPlan;
|
||||||
await Cache().saveMyTrainingPlan();
|
await Cache().saveMyTrainingPlan();
|
||||||
@ -378,7 +382,8 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (_myPlan == null || _myPlan!.details.isEmpty) {
|
if (_myPlan == null || _myPlan!.details.isEmpty) {
|
||||||
throw Exception("No defined Training Plan");
|
// throw Exception("No defined Training Plan");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dayNames.isEmpty || dayNames.length == 1) {
|
if (dayNames.isEmpty || dayNames.length == 1) {
|
||||||
@ -402,7 +407,7 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
|
|||||||
}
|
}
|
||||||
activeDayIndex++;
|
activeDayIndex++;
|
||||||
}
|
}
|
||||||
print("Active Day Index: $activeDayIndex");
|
|
||||||
if (activeDayIndex >= dayNames.length) {
|
if (activeDayIndex >= dayNames.length) {
|
||||||
activeDayIndex = 0;
|
activeDayIndex = 0;
|
||||||
this.add(TrainingPlanGoToRestart());
|
this.add(TrainingPlanGoToRestart());
|
||||||
@ -481,4 +486,17 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
|
|||||||
|
|
||||||
return value.toStringAsFixed(0);
|
return value.toStringAsFixed(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool existsAddedExerciseTypeInTree(String name) {
|
||||||
|
bool exists = false;
|
||||||
|
final List<WorkoutMenuTree>? listWorkoutTree = menuBloc.menuTreeRepository.sortedTree[name];
|
||||||
|
if (listWorkoutTree != null) {
|
||||||
|
listWorkoutTree.forEach((element) {
|
||||||
|
if (element.exerciseType!.trainingPlanState.equalsTo(ExerciseTypeTrainingPlanState.added)) {
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,6 @@ import 'package:aitrainer_app/view/customer_modify_page.dart';
|
|||||||
import 'package:aitrainer_app/view/customer_welcome_page.dart';
|
import 'package:aitrainer_app/view/customer_welcome_page.dart';
|
||||||
import 'package:aitrainer_app/view/evaluation_page.dart';
|
import 'package:aitrainer_app/view/evaluation_page.dart';
|
||||||
import 'package:aitrainer_app/view/exercise_control_page.dart';
|
import 'package:aitrainer_app/view/exercise_control_page.dart';
|
||||||
import 'package:aitrainer_app/view/exercise_execute_page.dart';
|
|
||||||
import 'package:aitrainer_app/view/exercise_execute_plan_add_page.dart';
|
|
||||||
import 'package:aitrainer_app/view/exercise_log_page.dart';
|
import 'package:aitrainer_app/view/exercise_log_page.dart';
|
||||||
import 'package:aitrainer_app/view/exercise_plan_custom_page.dart';
|
import 'package:aitrainer_app/view/exercise_plan_custom_page.dart';
|
||||||
import 'package:aitrainer_app/view/exercise_plan_custom_detail_add_page.dart';
|
import 'package:aitrainer_app/view/exercise_plan_custom_detail_add_page.dart';
|
||||||
@ -198,8 +196,8 @@ Future<void> initThirdParty() async {
|
|||||||
if (!isInDebugMode) {
|
if (!isInDebugMode) {
|
||||||
await Flurry.initialize(androidKey: "JNYCTCWBT34FM3J8TV36", iosKey: "3QBG7BSMGPDH24S8TRQP", enableLog: true);
|
await Flurry.initialize(androidKey: "JNYCTCWBT34FM3J8TV36", iosKey: "3QBG7BSMGPDH24S8TRQP", enableLog: true);
|
||||||
FlutterUxcam.optIntoSchematicRecordings();
|
FlutterUxcam.optIntoSchematicRecordings();
|
||||||
PushNotificationsManager().init();
|
|
||||||
}
|
}
|
||||||
|
PushNotificationsManager().init();
|
||||||
}
|
}
|
||||||
|
|
||||||
class WorkoutTestApp extends StatelessWidget {
|
class WorkoutTestApp extends StatelessWidget {
|
||||||
@ -258,8 +256,6 @@ class WorkoutTestApp extends StatelessWidget {
|
|||||||
'exerciseLogPage': (context) => ExerciseLogPage(),
|
'exerciseLogPage': (context) => ExerciseLogPage(),
|
||||||
'exercisePlanCustomPage': (context) => ExercisePlanCustomPage(),
|
'exercisePlanCustomPage': (context) => ExercisePlanCustomPage(),
|
||||||
'exercisePlanDetailAdd': (context) => ExercisePlanDetailAddPage(),
|
'exercisePlanDetailAdd': (context) => ExercisePlanDetailAddPage(),
|
||||||
'exerciseExecutePlanPage': (context) => ExerciseExecutePage(),
|
|
||||||
'exerciseExecuteAddPage': (context) => ExerciseExecutePlanAddPage(),
|
|
||||||
'mydevelopmentMusclePage': (context) => MyDevelopmentMusclePage(),
|
'mydevelopmentMusclePage': (context) => MyDevelopmentMusclePage(),
|
||||||
'mydevelopmentBodyPage': (context) => MyDevelopmentBodyPage(),
|
'mydevelopmentBodyPage': (context) => MyDevelopmentBodyPage(),
|
||||||
'mydevelopmentSizesPage': (context) => SizesDevelopmentPage(),
|
'mydevelopmentSizesPage': (context) => SizesDevelopmentPage(),
|
||||||
|
@ -14,9 +14,9 @@ import 'package:aitrainer_app/model/faq.dart';
|
|||||||
import 'package:aitrainer_app/model/model_change.dart';
|
import 'package:aitrainer_app/model/model_change.dart';
|
||||||
import 'package:aitrainer_app/model/product.dart' as wt_product;
|
import 'package:aitrainer_app/model/product.dart' as wt_product;
|
||||||
import 'package:aitrainer_app/model/product.dart';
|
import 'package:aitrainer_app/model/product.dart';
|
||||||
import 'package:aitrainer_app/model/product_test.dart';
|
|
||||||
import 'package:aitrainer_app/model/property.dart';
|
import 'package:aitrainer_app/model/property.dart';
|
||||||
import 'package:aitrainer_app/model/purchase.dart';
|
import 'package:aitrainer_app/model/purchase.dart';
|
||||||
|
import 'package:aitrainer_app/model/split_test.dart';
|
||||||
import 'package:aitrainer_app/model/sport.dart';
|
import 'package:aitrainer_app/model/sport.dart';
|
||||||
import 'package:aitrainer_app/model/training_plan.dart';
|
import 'package:aitrainer_app/model/training_plan.dart';
|
||||||
import 'package:aitrainer_app/model/tutorial.dart';
|
import 'package:aitrainer_app/model/tutorial.dart';
|
||||||
@ -136,7 +136,8 @@ class Cache with Logging {
|
|||||||
List<Sport>? _sports;
|
List<Sport>? _sports;
|
||||||
List<wt_product.Product>? _products;
|
List<wt_product.Product>? _products;
|
||||||
List<Purchase> _purchases = [];
|
List<Purchase> _purchases = [];
|
||||||
List<ProductTest>? _productTests;
|
List<SplitTest> _splitTests = [];
|
||||||
|
|
||||||
List<ExercisePlanTemplate> _exercisePlanTemplates = [];
|
List<ExercisePlanTemplate> _exercisePlanTemplates = [];
|
||||||
|
|
||||||
ExercisePlan? activeExercisePlan;
|
ExercisePlan? activeExercisePlan;
|
||||||
@ -242,7 +243,7 @@ class Cache with Logging {
|
|||||||
Map<String, dynamic> map;
|
Map<String, dynamic> map;
|
||||||
try {
|
try {
|
||||||
map = JsonDecoder().convert(savedTrainingPlanJson);
|
map = JsonDecoder().convert(savedTrainingPlanJson);
|
||||||
print("Training plan: $savedTrainingPlanJson");
|
//print("Training plan: $savedTrainingPlanJson");
|
||||||
this.myTrainingPlan = CustomerTrainingPlan.fromJsonWithDetails(map);
|
this.myTrainingPlan = CustomerTrainingPlan.fromJsonWithDetails(map);
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
@ -662,11 +663,6 @@ class Cache with Logging {
|
|||||||
List<Purchase> get purchases => _purchases;
|
List<Purchase> get purchases => _purchases;
|
||||||
setPurchases(List<Purchase> value) => _purchases = value;
|
setPurchases(List<Purchase> value) => _purchases = value;
|
||||||
|
|
||||||
// ignore: unnecessary_getters_setters
|
|
||||||
List<ProductTest>? get productTests => _productTests;
|
|
||||||
// ignore: unnecessary_getters_setters
|
|
||||||
set productTests(List<ProductTest>? value) => _productTests = value;
|
|
||||||
|
|
||||||
Future<void> initCustomer(int customerId) async {
|
Future<void> initCustomer(int customerId) async {
|
||||||
log(" *** initCustomer");
|
log(" *** initCustomer");
|
||||||
await PackageApi().getCustomerPackage(customerId);
|
await PackageApi().getCustomerPackage(customerId);
|
||||||
@ -738,4 +734,7 @@ class Cache with Logging {
|
|||||||
|
|
||||||
List<CustomerTrainingPlan>? getCustomerTrainingPlans() => this._customerTrainingPlans;
|
List<CustomerTrainingPlan>? getCustomerTrainingPlans() => this._customerTrainingPlans;
|
||||||
setCustomerTrainingPlans(value) => this._customerTrainingPlans = value;
|
setCustomerTrainingPlans(value) => this._customerTrainingPlans = value;
|
||||||
|
|
||||||
|
List<SplitTest> getSplitTests() => this._splitTests;
|
||||||
|
setSplitTests(value) => this._splitTests = value;
|
||||||
}
|
}
|
||||||
|
@ -57,10 +57,6 @@ class CustomerTrainingPlan {
|
|||||||
jsonDetails =
|
jsonDetails =
|
||||||
jsonDetails.replaceAllMapped(RegExp(r'([0-9]{4}\-[0-9]{2}\-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})'), (Match m) => "\"${m[0]}\"");
|
jsonDetails.replaceAllMapped(RegExp(r'([0-9]{4}\-[0-9]{2}\-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})'), (Match m) => "\"${m[0]}\"");
|
||||||
|
|
||||||
// jsonDetails = jsonDetails.replaceAll(r'\"null\"', 'null');
|
|
||||||
// jsonDetails = jsonDetails.replaceAll(r'\"false\"', 'false');
|
|
||||||
// jsonDetails = jsonDetails.replaceAll(r'\"true\"', 'true');
|
|
||||||
|
|
||||||
print("detail: $jsonDetails");
|
print("detail: $jsonDetails");
|
||||||
|
|
||||||
Iterable iterable = jsonDecode(jsonDetails);
|
Iterable iterable = jsonDecode(jsonDetails);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:aitrainer_app/model/cache.dart';
|
import 'package:aitrainer_app/model/cache.dart';
|
||||||
import 'package:aitrainer_app/model/exercise.dart';
|
import 'package:aitrainer_app/model/exercise.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
||||||
@ -9,6 +7,9 @@ class CustomerTrainingPlanDetails {
|
|||||||
/// customerTrainingPlanDetails
|
/// customerTrainingPlanDetails
|
||||||
int? customerTrainingPlanDetailsId;
|
int? customerTrainingPlanDetailsId;
|
||||||
|
|
||||||
|
/// trainingPlanDetailsId
|
||||||
|
int? trainingPlanDetailsId;
|
||||||
|
|
||||||
/// exerciseTypeId
|
/// exerciseTypeId
|
||||||
int? exerciseTypeId;
|
int? exerciseTypeId;
|
||||||
|
|
||||||
@ -32,6 +33,8 @@ class CustomerTrainingPlanDetails {
|
|||||||
|
|
||||||
List<Exercise> exercises = [];
|
List<Exercise> exercises = [];
|
||||||
|
|
||||||
|
bool isTest = false;
|
||||||
|
|
||||||
CustomerTrainingPlanDetails();
|
CustomerTrainingPlanDetails();
|
||||||
|
|
||||||
CustomerTrainingPlanDetails.fromJson(Map json) {
|
CustomerTrainingPlanDetails.fromJson(Map json) {
|
||||||
@ -49,6 +52,7 @@ class CustomerTrainingPlanDetails {
|
|||||||
this.customerTrainingPlanDetailsId = json['customerTrainingPlanDetailsId'] == "null" || json['customerTrainingPlanDetailsId'] == null
|
this.customerTrainingPlanDetailsId = json['customerTrainingPlanDetailsId'] == "null" || json['customerTrainingPlanDetailsId'] == null
|
||||||
? 0
|
? 0
|
||||||
: json['customerTrainingPlanDetailsId'];
|
: json['customerTrainingPlanDetailsId'];
|
||||||
|
this.trainingPlanDetailsId = json['trainingPlanDetailsId'];
|
||||||
this.exerciseTypeId = json['exerciseTypeId'];
|
this.exerciseTypeId = json['exerciseTypeId'];
|
||||||
this.set = json['set'];
|
this.set = json['set'];
|
||||||
this.repeats = json['repeats'] == "null" ? -1 : json['repeats'];
|
this.repeats = json['repeats'] == "null" ? -1 : json['repeats'];
|
||||||
@ -79,6 +83,7 @@ class CustomerTrainingPlanDetails {
|
|||||||
} else {
|
} else {
|
||||||
this.state = ExercisePlanDetailState.start;
|
this.state = ExercisePlanDetailState.start;
|
||||||
}
|
}
|
||||||
|
this.isTest = json['isTest'] == "true" ? true : false;
|
||||||
|
|
||||||
this.exerciseType = Cache().getExerciseTypeById(exerciseTypeId!);
|
this.exerciseType = Cache().getExerciseTypeById(exerciseTypeId!);
|
||||||
}
|
}
|
||||||
@ -98,7 +103,8 @@ class CustomerTrainingPlanDetails {
|
|||||||
|
|
||||||
Map<String, dynamic> toJsonWithExercises() {
|
Map<String, dynamic> toJsonWithExercises() {
|
||||||
final Map<String, dynamic> jsonMap = {
|
final Map<String, dynamic> jsonMap = {
|
||||||
//"customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId,
|
"customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId,
|
||||||
|
"trainingPlanDetailsId": this.trainingPlanDetailsId,
|
||||||
"exerciseTypeId": this.exerciseTypeId,
|
"exerciseTypeId": this.exerciseTypeId,
|
||||||
"set": this.set,
|
"set": this.set,
|
||||||
"repeats": this.repeats,
|
"repeats": this.repeats,
|
||||||
@ -107,6 +113,7 @@ class CustomerTrainingPlanDetails {
|
|||||||
"parallel": this.parallel,
|
"parallel": this.parallel,
|
||||||
'exercises': exercises.isEmpty ? [].toString() : exercises.map((exercise) => exercise.toJson()).toList().toString(),
|
'exercises': exercises.isEmpty ? [].toString() : exercises.map((exercise) => exercise.toJson()).toList().toString(),
|
||||||
'state': this.state.toStr(),
|
'state': this.state.toStr(),
|
||||||
|
"isTest": this.isTest,
|
||||||
};
|
};
|
||||||
if (this.day != null && this.day!.isNotEmpty) {
|
if (this.day != null && this.day!.isNotEmpty) {
|
||||||
jsonMap["day"] = this.day;
|
jsonMap["day"] = this.day;
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
import 'package:intl/intl.dart';
|
|
||||||
|
|
||||||
class ProductTest {
|
|
||||||
late int? productTestId;
|
|
||||||
late int customerId;
|
|
||||||
late int productId;
|
|
||||||
|
|
||||||
late DateTime dateView;
|
|
||||||
late bool purchaseClick;
|
|
||||||
|
|
||||||
ProductTest();
|
|
||||||
|
|
||||||
ProductTest.fromJson(Map json) {
|
|
||||||
this.productTestId = json['productTestId'];
|
|
||||||
this.customerId = json['customerId'];
|
|
||||||
this.productId = json['productId'];
|
|
||||||
this.dateView = DateTime.parse(json['dateView']);
|
|
||||||
this.purchaseClick = json['purchaseClick'];
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
if (productTestId != null) {
|
|
||||||
return {
|
|
||||||
"productTestId": productTestId,
|
|
||||||
"customerId": customerId,
|
|
||||||
"productId": productId,
|
|
||||||
"dateView": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateView),
|
|
||||||
"purchaseClick": purchaseClick
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
"customerId": customerId,
|
|
||||||
"productId": productId,
|
|
||||||
"dateView": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateView),
|
|
||||||
"purchaseClick": purchaseClick
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
36
lib/model/split_test.dart
Normal file
36
lib/model/split_test.dart
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
class SplitTest {
|
||||||
|
late int testId;
|
||||||
|
late String name;
|
||||||
|
late String remoteConfigKey;
|
||||||
|
late String remoteConfigValue;
|
||||||
|
late String testValue;
|
||||||
|
String? source;
|
||||||
|
late bool active;
|
||||||
|
DateTime? validTo;
|
||||||
|
|
||||||
|
SplitTest.fromJson(Map json) {
|
||||||
|
this.testId = json['testId'];
|
||||||
|
this.name = json['name'];
|
||||||
|
this.remoteConfigKey = json['remoteConfigKey'];
|
||||||
|
this.remoteConfigValue = json['remoteConfigValue'];
|
||||||
|
this.testValue = json['testValue'];
|
||||||
|
this.source = json['source'];
|
||||||
|
this.active = json['active'];
|
||||||
|
this.validTo = json['validTo'] == null ? null : DateTime.parse(json['validTo']);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
Map<String, dynamic> json = {
|
||||||
|
'productId': this.testId,
|
||||||
|
'name': this.name,
|
||||||
|
'remoteConfigKey': this.remoteConfigKey,
|
||||||
|
'remoteConfigValue': this.remoteConfigValue,
|
||||||
|
'testValue': this.testValue,
|
||||||
|
'source': this.source,
|
||||||
|
'active': this.active,
|
||||||
|
'validTo': validTo,
|
||||||
|
};
|
||||||
|
return json.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ class PushNotificationsManager with Logging {
|
|||||||
static final PushNotificationsManager _instance = PushNotificationsManager._();
|
static final PushNotificationsManager _instance = PushNotificationsManager._();
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
|
log(" --- Firebase Messagein init..");
|
||||||
const AndroidNotificationChannel channel = AndroidNotificationChannel(
|
const AndroidNotificationChannel channel = AndroidNotificationChannel(
|
||||||
'high_importance_channel', // id
|
'high_importance_channel', // id
|
||||||
'High Importance Notifications', // title
|
'High Importance Notifications', // title
|
||||||
@ -28,6 +29,6 @@ class PushNotificationsManager with Logging {
|
|||||||
sound: true,
|
sound: true,
|
||||||
);
|
);
|
||||||
String? token = await FirebaseMessaging.instance.getToken();
|
String? token = await FirebaseMessaging.instance.getToken();
|
||||||
print("FirebaseMessaging tokne $token");
|
log("FirebaseMessaging token $token");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,14 @@ import 'dart:collection';
|
|||||||
import 'package:aitrainer_app/model/cache.dart';
|
import 'package:aitrainer_app/model/cache.dart';
|
||||||
import 'package:aitrainer_app/model/customer.dart';
|
import 'package:aitrainer_app/model/customer.dart';
|
||||||
import 'package:aitrainer_app/model/customer_property.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/property.dart';
|
||||||
import 'package:aitrainer_app/model/purchase.dart';
|
import 'package:aitrainer_app/model/purchase.dart';
|
||||||
import 'package:aitrainer_app/model/sport.dart';
|
import 'package:aitrainer_app/model/sport.dart';
|
||||||
import 'package:aitrainer_app/repository/property_repository.dart';
|
import 'package:aitrainer_app/repository/property_repository.dart';
|
||||||
import 'package:aitrainer_app/service/customer_service.dart';
|
import 'package:aitrainer_app/service/customer_service.dart';
|
||||||
import 'package:aitrainer_app/service/logging.dart';
|
import 'package:aitrainer_app/service/logging.dart';
|
||||||
import 'package:aitrainer_app/service/product_test_service.dart';
|
|
||||||
import 'package:aitrainer_app/service/purchase_service.dart';
|
import 'package:aitrainer_app/service/purchase_service.dart';
|
||||||
import 'package:aitrainer_app/util/enums.dart';
|
import 'package:aitrainer_app/util/enums.dart';
|
||||||
import 'package:aitrainer_app/util/not_found_exception.dart';
|
|
||||||
|
|
||||||
class GenderItem {
|
class GenderItem {
|
||||||
GenderItem(this.dbValue, this.name);
|
GenderItem(this.dbValue, this.name);
|
||||||
@ -354,25 +351,6 @@ class CustomerRepository with Logging {
|
|||||||
await PurchaseApi().savePurchase(purchase);
|
await PurchaseApi().savePurchase(purchase);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<ProductTest>> getProductTests() async {
|
|
||||||
List<ProductTest> tests = [];
|
|
||||||
try {
|
|
||||||
int customerId = Cache().userLoggedIn!.customerId!;
|
|
||||||
tests = await ProductTestApi().getProductTestByCustomer(customerId);
|
|
||||||
} on NotFoundException catch (_) {
|
|
||||||
log("Product Tests not found");
|
|
||||||
Cache().productTests = tests;
|
|
||||||
} on Exception catch (ex) {
|
|
||||||
log(ex.toString());
|
|
||||||
Cache().productTests = tests;
|
|
||||||
}
|
|
||||||
return tests;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> addProductTest(ProductTest productTest) async {
|
|
||||||
await ProductTestApi().saveProductTest(productTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMediaDimensions(double width, double height) {
|
void setMediaDimensions(double width, double height) {
|
||||||
this.mediaHeight = height;
|
this.mediaHeight = height;
|
||||||
this.mediaWidth = width;
|
this.mediaWidth = width;
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import 'package:aitrainer_app/model/cache.dart';
|
import 'package:aitrainer_app/model/cache.dart';
|
||||||
import 'package:aitrainer_app/model/description.dart';
|
import 'package:aitrainer_app/model/description.dart';
|
||||||
|
import 'package:aitrainer_app/util/app_language.dart';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class DescriptionRepository {
|
class DescriptionRepository {
|
||||||
List<Description>? descriptions;
|
List<Description>? descriptions;
|
||||||
@ -12,10 +15,13 @@ class DescriptionRepository {
|
|||||||
String descriptionText = "";
|
String descriptionText = "";
|
||||||
if (descriptions != null) {
|
if (descriptions != null) {
|
||||||
this.descriptions!.forEach((element) {
|
this.descriptions!.forEach((element) {
|
||||||
print("Desc ${element.name} - $name");
|
|
||||||
if (element.name == name) {
|
if (element.name == name) {
|
||||||
|
if (AppLanguage().appLocal == Locale('en')) {
|
||||||
|
descriptionText = element.description;
|
||||||
|
} else {
|
||||||
descriptionText = element.descriptionTranslation != null ? element.descriptionTranslation! : element.description;
|
descriptionText = element.descriptionTranslation != null ? element.descriptionTranslation! : element.description;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return descriptionText;
|
return descriptionText;
|
||||||
|
63
lib/repository/split_test_respository.dart
Normal file
63
lib/repository/split_test_respository.dart
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import 'package:aitrainer_app/model/cache.dart';
|
||||||
|
import 'package:aitrainer_app/repository/description_repository.dart';
|
||||||
|
import 'package:aitrainer_app/service/logging.dart';
|
||||||
|
import 'package:firebase_remote_config/firebase_remote_config.dart';
|
||||||
|
|
||||||
|
class SplitTestRepository with Logging {
|
||||||
|
final RemoteConfig? _remoteConfig = Cache().remoteConfig;
|
||||||
|
final DescriptionRepository descriptionRepository = DescriptionRepository();
|
||||||
|
|
||||||
|
String getSplitTestValue(String remoteConfigKey) {
|
||||||
|
String testValue = "";
|
||||||
|
|
||||||
|
if (_remoteConfig != null) {
|
||||||
|
_remoteConfig!.fetchAndActivate();
|
||||||
|
Map configs = _remoteConfig!.getAll();
|
||||||
|
RemoteConfigValue? value = configs[remoteConfigKey];
|
||||||
|
if (value != null) {
|
||||||
|
log("A/B Test RemoteConfig $remoteConfigKey value: ${value.asString()}");
|
||||||
|
final String remoteConfigValue = value.asString();
|
||||||
|
testValue = this.getSplitTestValueByRemoteConfig(remoteConfigKey, remoteConfigValue);
|
||||||
|
} else {
|
||||||
|
log("RemoteConfig value $remoteConfigKey is null!!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log(" !! remoteConfig isnull");
|
||||||
|
}
|
||||||
|
|
||||||
|
return testValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getSource(String remoteConfigKey) {
|
||||||
|
String source = "";
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getSplitTestValueByRemoteConfig(String key, String value) {
|
||||||
|
String testValue = "";
|
||||||
|
if (Cache().getSplitTests().isEmpty) {
|
||||||
|
log("Splittests empty");
|
||||||
|
return testValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache().getSplitTests().forEach((element) {
|
||||||
|
if (element.remoteConfigKey == key && element.remoteConfigValue == value && element.active) {
|
||||||
|
testValue = element.testValue;
|
||||||
|
log("A/B Test testValue: $testValue");
|
||||||
|
|
||||||
|
if (element.source != null && element.source!.isNotEmpty) {
|
||||||
|
final List<String> sourceElements = element.source!.split(".");
|
||||||
|
if (sourceElements.length > 1) {
|
||||||
|
final String modelName = sourceElements[0];
|
||||||
|
if (modelName == "description") {
|
||||||
|
testValue = descriptionRepository.getDescriptionByName(element.testValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return testValue;
|
||||||
|
}
|
||||||
|
}
|
@ -65,8 +65,11 @@ class TrainingPlanRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3 calculate weights
|
// 3 calculate weights
|
||||||
|
int index = 0;
|
||||||
trainingPlan.details!.forEach((elem) {
|
trainingPlan.details!.forEach((elem) {
|
||||||
CustomerTrainingPlanDetails detail = CustomerTrainingPlanDetails();
|
CustomerTrainingPlanDetails detail = CustomerTrainingPlanDetails();
|
||||||
|
detail.customerTrainingPlanDetailsId = ++index;
|
||||||
|
detail.trainingPlanDetailsId = elem.trainingPlanDetailId;
|
||||||
detail.exerciseTypeId = elem.exerciseTypeId;
|
detail.exerciseTypeId = elem.exerciseTypeId;
|
||||||
detail.repeats = elem.repeats;
|
detail.repeats = elem.repeats;
|
||||||
detail.set = elem.set;
|
detail.set = elem.set;
|
||||||
@ -111,6 +114,7 @@ class TrainingPlanRepository {
|
|||||||
double weight = -1;
|
double weight = -1;
|
||||||
if (Cache().getExercises() == null) {
|
if (Cache().getExercises() == null) {
|
||||||
detail.weight = weight;
|
detail.weight = weight;
|
||||||
|
detail.isTest = true;
|
||||||
return detail;
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +128,7 @@ class TrainingPlanRepository {
|
|||||||
|
|
||||||
if (lastExercise1RM == null || lastExercise1RM!.unitQuantity == null) {
|
if (lastExercise1RM == null || lastExercise1RM!.unitQuantity == null) {
|
||||||
detail.weight = weight;
|
detail.weight = weight;
|
||||||
|
detail.isTest = true;
|
||||||
return detail;
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,4 +143,34 @@ class TrainingPlanRepository {
|
|||||||
detail.weight = weight;
|
detail.weight = weight;
|
||||||
return detail;
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CustomerTrainingPlanDetails recalculateDetail(int trainingPlanId, CustomerTrainingPlanDetails detail) {
|
||||||
|
CustomerTrainingPlanDetails recalculatedDetail = detail;
|
||||||
|
|
||||||
|
// 1. get original repeats
|
||||||
|
|
||||||
|
// 1a get original plan
|
||||||
|
TrainingPlan? plan = getTrainingPlanById(trainingPlanId);
|
||||||
|
if (plan == null) {
|
||||||
|
return recalculatedDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.b get the original detail's repeat
|
||||||
|
int originalRepeats = detail.repeats!;
|
||||||
|
plan.details!.forEach((element) {
|
||||||
|
if (element.trainingPlanDetailId == detail.trainingPlanDetailsId) {
|
||||||
|
print("element $element");
|
||||||
|
originalRepeats = element.repeats;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2 get recalculated repeats
|
||||||
|
|
||||||
|
recalculatedDetail.weight =
|
||||||
|
Common.calculateWeigthByChangedQuantity(detail.weight!, detail.repeats!.toDouble(), originalRepeats.toDouble());
|
||||||
|
print("recalculated repeats for $originalRepeats: ${recalculatedDetail.weight}");
|
||||||
|
recalculatedDetail.repeats = originalRepeats;
|
||||||
|
|
||||||
|
return recalculatedDetail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,9 @@ class ExerciseApi with Logging {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteExercise(Exercise exercise) async {
|
Future<void> deleteExercise(Exercise exercise) async {
|
||||||
|
if (exercise.exerciseId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int exerciseId = exercise.exerciseId!;
|
int exerciseId = exercise.exerciseId!;
|
||||||
log(" ===== delete exercise: " + exerciseId.toString());
|
log(" ===== delete exercise: " + exerciseId.toString());
|
||||||
await _client.post("exercises/" + exerciseId.toString(), "");
|
await _client.post("exercises/" + exerciseId.toString(), "");
|
||||||
|
@ -291,21 +291,25 @@ class FirebaseApi with logging.Logging {
|
|||||||
|
|
||||||
Future<void> setupRemoteConfig() async {
|
Future<void> setupRemoteConfig() async {
|
||||||
initializeFlutterFire();
|
initializeFlutterFire();
|
||||||
final RemoteConfig remoteConfig = RemoteConfig.instance;
|
RemoteConfig? remoteConfig;
|
||||||
|
try {
|
||||||
|
remoteConfig = RemoteConfig.instance;
|
||||||
await remoteConfig.setConfigSettings(RemoteConfigSettings(
|
await remoteConfig.setConfigSettings(RemoteConfigSettings(
|
||||||
fetchTimeout: const Duration(seconds: 10),
|
fetchTimeout: const Duration(seconds: 60),
|
||||||
minimumFetchInterval: const Duration(seconds: 1),
|
minimumFetchInterval: const Duration(hours: 6),
|
||||||
));
|
));
|
||||||
await remoteConfig.setDefaults(<String, dynamic>{
|
|
||||||
'sales_page_text': '0',
|
|
||||||
'sales_page_bkg': 'dark',
|
|
||||||
'sales_page_offer': 'monthly',
|
|
||||||
'please_log_in': '',
|
|
||||||
});
|
|
||||||
RemoteConfigValue(null, ValueSource.valueStatic);
|
RemoteConfigValue(null, ValueSource.valueStatic);
|
||||||
Cache().setRemoteConfig(remoteConfig);
|
Cache().setRemoteConfig(remoteConfig);
|
||||||
|
} on Exception catch (e) {
|
||||||
Map config = remoteConfig.getAll();
|
print('Unable to fetch remote config. Cached or default values will be used: $e');
|
||||||
print("RemoteConfig sales_page_text Value : ${config['sales_page_text'].asString()}");
|
if (remoteConfig != null) {
|
||||||
|
await remoteConfig.setDefaults(<String, dynamic>{
|
||||||
|
'sales_page_text_a': '',
|
||||||
|
'product_set_2': '',
|
||||||
|
});
|
||||||
|
Cache().setRemoteConfig(remoteConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,9 @@ import 'package:aitrainer_app/model/exercise_tree_parents.dart';
|
|||||||
import 'package:aitrainer_app/model/exercise_type.dart';
|
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||||
import 'package:aitrainer_app/model/faq.dart';
|
import 'package:aitrainer_app/model/faq.dart';
|
||||||
import 'package:aitrainer_app/model/product.dart';
|
import 'package:aitrainer_app/model/product.dart';
|
||||||
import 'package:aitrainer_app/model/product_test.dart';
|
|
||||||
import 'package:aitrainer_app/model/property.dart';
|
import 'package:aitrainer_app/model/property.dart';
|
||||||
import 'package:aitrainer_app/model/purchase.dart';
|
import 'package:aitrainer_app/model/purchase.dart';
|
||||||
|
import 'package:aitrainer_app/model/split_test.dart';
|
||||||
import 'package:aitrainer_app/model/training_plan.dart';
|
import 'package:aitrainer_app/model/training_plan.dart';
|
||||||
import 'package:aitrainer_app/model/tutorial.dart';
|
import 'package:aitrainer_app/model/tutorial.dart';
|
||||||
import 'package:aitrainer_app/service/api.dart';
|
import 'package:aitrainer_app/service/api.dart';
|
||||||
@ -92,6 +92,11 @@ class PackageApi {
|
|||||||
final List<TrainingPlan>? plans = json.map((plan) => TrainingPlan.fromJson(plan)).toList();
|
final List<TrainingPlan>? plans = json.map((plan) => TrainingPlan.fromJson(plan)).toList();
|
||||||
|
|
||||||
Cache().setTrainingPlans(plans);
|
Cache().setTrainingPlans(plans);
|
||||||
|
} else if (headRecord[0] == "SplitTests") {
|
||||||
|
final Iterable json = jsonDecode(headRecord[1]);
|
||||||
|
final List<SplitTest>? tests = json.map((test) => SplitTest.fromJson(test)).toList();
|
||||||
|
//print("A/B tests: $tests");
|
||||||
|
Cache().setSplitTests(tests);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -156,10 +161,6 @@ class PackageApi {
|
|||||||
final Iterable json = jsonDecode(headRecord[1]);
|
final Iterable json = jsonDecode(headRecord[1]);
|
||||||
final List<Exercise> exercises = json.map((exerciseType) => Exercise.fromJson(exerciseType)).toList();
|
final List<Exercise> exercises = json.map((exerciseType) => Exercise.fromJson(exerciseType)).toList();
|
||||||
Cache().setExercises(exercises);
|
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") {
|
} else if (headRecord[0] == "Purchase") {
|
||||||
final Iterable json = jsonDecode(headRecord[1]);
|
final Iterable json = jsonDecode(headRecord[1]);
|
||||||
final List<Purchase> purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList();
|
final List<Purchase> purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList();
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import 'package:aitrainer_app/model/cache.dart';
|
|
||||||
import 'package:aitrainer_app/model/product_test.dart';
|
|
||||||
import 'package:aitrainer_app/service/logging.dart';
|
|
||||||
import 'dart:convert';
|
|
||||||
import 'api.dart';
|
|
||||||
|
|
||||||
class ProductTestApi with Logging {
|
|
||||||
final APIClient _client = new APIClient();
|
|
||||||
|
|
||||||
Future<List<ProductTest>> getProductTestByCustomer(int customerId) async {
|
|
||||||
final body = await _client.get("product_test/customer/" + customerId.toString(), "");
|
|
||||||
final Iterable json = jsonDecode(body);
|
|
||||||
final List<ProductTest> productTests = json.map((productTest) => ProductTest.fromJson(productTest)).toList();
|
|
||||||
Cache().productTests = productTests;
|
|
||||||
return productTests;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> saveProductTest(ProductTest productTest) async {
|
|
||||||
String body = JsonEncoder().convert(productTest.toJson());
|
|
||||||
log(" ===== saving productTest:" + body);
|
|
||||||
await _client.post("product_test/", body);
|
|
||||||
}
|
|
||||||
}
|
|
@ -139,6 +139,9 @@ mixin Common {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static normalizeDecimal(String value) {
|
static normalizeDecimal(String value) {
|
||||||
|
if (value.isEmpty) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
value = value.replaceFirst(",", ".");
|
value = value.replaceFirst(",", ".");
|
||||||
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
|
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
|
||||||
return value;
|
return value;
|
||||||
@ -193,7 +196,6 @@ mixin Common {
|
|||||||
static int calculateQuantityByChangedWeight(double initialRM, double weight, double repeat) {
|
static int calculateQuantityByChangedWeight(double initialRM, double weight, double repeat) {
|
||||||
final double rmWendler = weight * repeat * 0.0333 + weight;
|
final double rmWendler = weight * repeat * 0.0333 + weight;
|
||||||
final double rmOconner = weight * (1 + repeat / 40);
|
final double rmOconner = weight * (1 + repeat / 40);
|
||||||
//print("Weight: $weight oneRepQuantity: $repeat, $rmWendler, Oconner: $rmOconner");
|
|
||||||
|
|
||||||
final double repeatWendler = (rmWendler - weight) / 0.0333 / weight;
|
final double repeatWendler = (rmWendler - weight) / 0.0333 / weight;
|
||||||
final double repeatOconner = (rmOconner / weight - 1) * 40;
|
final double repeatOconner = (rmOconner / weight - 1) * 40;
|
||||||
@ -201,4 +203,17 @@ mixin Common {
|
|||||||
//print("Initial 1RM: $initialRM Weight: $weight repeatWendler: $repeatWendler repeat Oconner: $repeatOconner. NEW REPEAT: $newRepeat");
|
//print("Initial 1RM: $initialRM Weight: $weight repeatWendler: $repeatWendler repeat Oconner: $repeatOconner. NEW REPEAT: $newRepeat");
|
||||||
return newRepeat;
|
return newRepeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double calculateWeigthByChangedQuantity(double weight, double repeat, double changedRepeats) {
|
||||||
|
final double rmWendler = weight * repeat * 0.0333 + weight;
|
||||||
|
final double rmOconner = weight * (1 + repeat / 40);
|
||||||
|
final double initialRM = (rmWendler + rmOconner) / 2;
|
||||||
|
|
||||||
|
final double weightWendler = rmWendler / (changedRepeats * 0.0333 + 1);
|
||||||
|
final double weightOconner = rmOconner / (1 + changedRepeats / 40);
|
||||||
|
final double newWeight = ((weightWendler + weightOconner) / 2);
|
||||||
|
print(
|
||||||
|
"Initial 1RM: $initialRM repeat: $repeat changedRepeat: $changedRepeats Weight: $weight weightWendler: $weightWendler weight Oconner: $weightOconner. NEW WEIGHT: $newWeight");
|
||||||
|
return newWeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,227 +0,0 @@
|
|||||||
import 'dart:collection';
|
|
||||||
import 'package:aitrainer_app/bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart';
|
|
||||||
import 'package:aitrainer_app/model/cache.dart';
|
|
||||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
|
||||||
import 'package:aitrainer_app/library/tree_view.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/treeview_parent_widget.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/scheduler.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
|
||||||
|
|
||||||
class ExerciseExecutePage extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
_ExerciseExecutePage createState() => _ExerciseExecutePage();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ExerciseExecutePage extends State<ExerciseExecutePage> with Trans {
|
|
||||||
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
|
|
||||||
// ignore: close_sinks
|
|
||||||
late ExerciseExecutePlanBloc bloc;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
/// We require the initializers to run after the loading screen is rendered
|
|
||||||
SchedulerBinding.instance!.addPostFrameCallback((_) {
|
|
||||||
BlocProvider.of<ExerciseExecutePlanBloc>(context).add(ExerciseByPlanLoad());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
LinkedHashMap arguments = ModalRoute.of(context)!.settings.arguments as LinkedHashMap;
|
|
||||||
final int customerId = arguments['customerId'];
|
|
||||||
bloc = BlocProvider.of<ExerciseExecutePlanBloc>(context);
|
|
||||||
bloc.customerId = customerId;
|
|
||||||
setContext(context);
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
key: _scaffoldKey,
|
|
||||||
appBar: AppBarNav(depth: 1),
|
|
||||||
body: Container(
|
|
||||||
padding: EdgeInsets.all(20),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
image: DecorationImage(
|
|
||||||
image: customerId == Cache().userLoggedIn!.customerId
|
|
||||||
? AssetImage('asset/image/WT_black_background.jpg')
|
|
||||||
: AssetImage('asset/image/WT_light_background.jpg'),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: BlocConsumer<ExerciseExecutePlanBloc, ExerciseExecutePlanState>(listener: (context, state) {
|
|
||||||
if (state is ExerciseByPlanError) {
|
|
||||||
//LoadingDialog.hide(context);
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
|
||||||
content: Text(
|
|
||||||
state.message,
|
|
||||||
),
|
|
||||||
backgroundColor: Colors.orange,
|
|
||||||
));
|
|
||||||
} else if (state is ExerciseByPlanLoading) {
|
|
||||||
//LoadingDialog.show(context);
|
|
||||||
}
|
|
||||||
}, builder: (context, state) {
|
|
||||||
if (state is ExerciseByPlanStateInitial || state is ExerciseByPlanLoading) {
|
|
||||||
return Container();
|
|
||||||
} else if (state is ExerciseByPlanReady) {
|
|
||||||
//LoadingDialog.hide(context);
|
|
||||||
return exerciseWidget(bloc);
|
|
||||||
} else {
|
|
||||||
return exerciseWidget(bloc);
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
bottomNavigationBar: BottomNavigator(bottomNavIndex: 2),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget exerciseWidget(ExerciseExecutePlanBloc bloc) {
|
|
||||||
return TreeView(
|
|
||||||
startExpanded: false,
|
|
||||||
children: nodeExercisePlan(bloc),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> nodeExercisePlan(ExerciseExecutePlanBloc bloc) {
|
|
||||||
List<Widget> exerciseTypes = [];
|
|
||||||
Card explanation = Card(
|
|
||||||
color: Colors.white38,
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.only(left: 10, right: 5, top: 12, bottom: 8),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.info,
|
|
||||||
color: Colors.orangeAccent,
|
|
||||||
),
|
|
||||||
Text(" "),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
t("Execute your active Exercise Plan!"),
|
|
||||||
style: GoogleFonts.archivoBlack(
|
|
||||||
fontSize: 20,
|
|
||||||
),
|
|
||||||
maxLines: 2,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Divider(
|
|
||||||
color: Colors.transparent,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
t("Select the muscle type and tap on the exercise. One the next page enter the weight and repeat."),
|
|
||||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.normal),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)));
|
|
||||||
|
|
||||||
exerciseTypes.add(explanation);
|
|
||||||
|
|
||||||
if (bloc.selectedNumber == 0) {
|
|
||||||
exerciseTypes.add(Container(
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
t("Please define your Exercise Plan"),
|
|
||||||
style: GoogleFonts.inter(color: Colors.white),
|
|
||||||
))));
|
|
||||||
exerciseTypes.add(Container(
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
t("Go to: 'Training Plan' - 'Edit My Custom Plan'"),
|
|
||||||
style: GoogleFonts.inter(color: Colors.white),
|
|
||||||
))));
|
|
||||||
exerciseTypes.add(Container(
|
|
||||||
child: Center(
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
final LinkedHashMap args = LinkedHashMap();
|
|
||||||
args['customerId'] = Cache().userLoggedIn!.customerId;
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
Navigator.of(context).pushNamed('exercisePlanCustomPage', arguments: args);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
t("Jump there »"),
|
|
||||||
style: GoogleFonts.inter(color: Colors.blue[200], decorationStyle: TextDecorationStyle.solid),
|
|
||||||
)))));
|
|
||||||
} else {
|
|
||||||
bloc.menuTreeRepository.sortedTree.forEach((name, list) {
|
|
||||||
exerciseTypes.add(Container(
|
|
||||||
margin: const EdgeInsets.only(left: 4.0),
|
|
||||||
child: TreeViewChild(
|
|
||||||
startExpanded: true,
|
|
||||||
parent: TreeviewParentWidget(text: name),
|
|
||||||
children: _getChildList(list, bloc),
|
|
||||||
)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return exerciseTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> _getChildList(List<WorkoutMenuTree> listWorkoutTree, ExerciseExecutePlanBloc bloc) {
|
|
||||||
List<Widget> list = [];
|
|
||||||
listWorkoutTree.forEach((element) {
|
|
||||||
if (element.selected) {
|
|
||||||
list.add(TreeViewChild(
|
|
||||||
startExpanded: false,
|
|
||||||
parent: Card(
|
|
||||||
margin: EdgeInsets.only(left: 10, top: 5),
|
|
||||||
color: Colors.white54,
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.only(left: 5, top: 0, right: 5, bottom: 0),
|
|
||||||
child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [
|
|
||||||
IconButton(
|
|
||||||
icon: element.executed
|
|
||||||
? Icon(Icons.check_box, color: Colors.green[200])
|
|
||||||
: Icon(
|
|
||||||
Icons.indeterminate_check_box,
|
|
||||||
color: Colors.blue.shade800,
|
|
||||||
),
|
|
||||||
onPressed: () => {addExerciseByPlanEvent(bloc, element)},
|
|
||||||
),
|
|
||||||
SizedBox(width: 20),
|
|
||||||
Flexible(
|
|
||||||
fit: FlexFit.tight,
|
|
||||||
child: InkWell(
|
|
||||||
child: Text(
|
|
||||||
element.name,
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
style: GoogleFonts.inter(fontSize: 17, color: Colors.black),
|
|
||||||
),
|
|
||||||
onTap: () => {addExerciseByPlanEvent(bloc, element)},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
padding: EdgeInsets.all(0),
|
|
||||||
icon: Icon(
|
|
||||||
Icons.info,
|
|
||||||
color: Colors.black12,
|
|
||||||
),
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
)),
|
|
||||||
children: []));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addExerciseByPlanEvent(ExerciseExecutePlanBloc bloc, WorkoutMenuTree workoutTree) {
|
|
||||||
LinkedHashMap args = LinkedHashMap();
|
|
||||||
args['blocExerciseByPlan'] = bloc;
|
|
||||||
args['customerId'] = bloc.customerId;
|
|
||||||
args['workoutTree'] = workoutTree;
|
|
||||||
Navigator.of(context).pushNamed("exerciseExecuteAddPage", arguments: args);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,284 +0,0 @@
|
|||||||
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/util/app_language.dart';
|
|
||||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
|
||||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
|
||||||
import 'package:aitrainer_app/util/trans.dart';
|
|
||||||
import 'package:aitrainer_app/widgets/app_bar.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:google_fonts/google_fonts.dart';
|
|
||||||
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
|
|
||||||
|
|
||||||
class ExerciseExecutePlanAddPage extends StatefulWidget {
|
|
||||||
_ExerciseExecuteAddPage createState() => _ExerciseExecuteAddPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 as LinkedHashMap;
|
|
||||||
// ignore: close_sinks
|
|
||||||
final ExerciseExecutePlanBloc planBloc = arguments['blocExerciseByPlan'];
|
|
||||||
final int customerId = arguments['customerId'];
|
|
||||||
final WorkoutMenuTree workoutTree = arguments['workoutTree'];
|
|
||||||
final ExerciseRepository exerciseRepository = ExerciseRepository();
|
|
||||||
setContext(context);
|
|
||||||
|
|
||||||
return BlocProvider(
|
|
||||||
create: (context) => ExerciseExecutePlanAddBloc(
|
|
||||||
exerciseRepository: exerciseRepository,
|
|
||||||
exercisePlanRepository: planBloc.exercisePlanRepository,
|
|
||||||
customerId: customerId,
|
|
||||||
workoutTree: workoutTree,
|
|
||||||
planBloc: planBloc)
|
|
||||||
..add(ExerciseExecutePlanAddLoad()),
|
|
||||||
child: BlocConsumer<ExerciseExecutePlanAddBloc, ExerciseExecutePlanAddState>(listener: (context, state) {
|
|
||||||
if (state is ExerciseExecutePlanAddError) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
|
|
||||||
}
|
|
||||||
}, builder: (context, state) {
|
|
||||||
// ignore: close_sinks
|
|
||||||
final exerciseBloc = BlocProvider.of<ExerciseExecutePlanAddBloc>(context);
|
|
||||||
if (state is ExerciseExecutePlanAddReady && _controller.hasClients) {
|
|
||||||
_controller.animateTo(exerciseBloc.scrollOffset, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
|
|
||||||
}
|
|
||||||
return ModalProgressHUD(
|
|
||||||
child: getControlForm(exerciseBloc),
|
|
||||||
inAsyncCall: state is ExerciseExecutePlanAddLoading,
|
|
||||||
opacity: 0.5,
|
|
||||||
color: Colors.black54,
|
|
||||||
progressIndicator: CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget getControlForm(ExerciseExecutePlanAddBloc exerciseBloc) {
|
|
||||||
if (exerciseBloc.exerciseRepository.exerciseType == null || exerciseBloc.quantity == null) {
|
|
||||||
return Offstage();
|
|
||||||
}
|
|
||||||
String exerciseName = AppLanguage().appLocal == Locale("en")
|
|
||||||
? exerciseBloc.exerciseRepository.exerciseType!.name
|
|
||||||
: exerciseBloc.exerciseRepository.exerciseType!.nameTranslation;
|
|
||||||
|
|
||||||
return Form(
|
|
||||||
child: Scaffold(
|
|
||||||
resizeToAvoidBottomInset: true,
|
|
||||||
appBar: AppBarNav(depth: 1),
|
|
||||||
body: Container(
|
|
||||||
width: MediaQuery.of(context).size.width,
|
|
||||||
height: MediaQuery.of(context).size.height,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
image: DecorationImage(
|
|
||||||
image: AssetImage('asset/image/WT_black_background.jpg'),
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.only(top: 25, left: 25, right: 25),
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.vertical,
|
|
||||||
physics: BouncingScrollPhysics(),
|
|
||||||
controller: _controller,
|
|
||||||
child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
|
|
||||||
Text(
|
|
||||||
t("Save Exercise"),
|
|
||||||
style: GoogleFonts.inter(fontSize: 16, color: Colors.orange[50]),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
exerciseName,
|
|
||||||
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: 3,
|
|
||||||
softWrap: true,
|
|
||||||
),
|
|
||||||
Divider(
|
|
||||||
color: Colors.transparent,
|
|
||||||
),
|
|
||||||
Divider(),
|
|
||||||
Column(
|
|
||||||
children: repeatExercises(exerciseBloc),
|
|
||||||
),
|
|
||||||
Divider(),
|
|
||||||
]),
|
|
||||||
))),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Column> repeatExercises(ExerciseExecutePlanAddBloc exerciseBloc) {
|
|
||||||
List<Column> listColumns = [];
|
|
||||||
for (int i = 0; i < exerciseBloc.countSteps; i++) {
|
|
||||||
Column col = Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Divider(
|
|
||||||
color: Colors.transparent,
|
|
||||||
),
|
|
||||||
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,
|
|
||||||
),
|
|
||||||
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()))}),
|
|
||||||
]),
|
|
||||||
TextButton(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: EdgeInsets.all(0),
|
|
||||||
primary: Colors.white,
|
|
||||||
onSurface: 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(),
|
|
||||||
minValue: 0,
|
|
||||||
maxValue: 200,
|
|
||||||
step: 1,
|
|
||||||
textStyle: TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
textStyleHighlighted: TextStyle(fontSize: 24, color: Colors.deepOrange, fontWeight: FontWeight.bold),
|
|
||||||
onChanged: (value) => {exerciseBloc.add(ExerciseExecutePlanAddChangeQuantity(quantity: value.toDouble()))},
|
|
||||||
listViewHeight: 80,
|
|
||||||
//decoration: _decoration,
|
|
||||||
),
|
|
||||||
Text(t("repeat")),
|
|
||||||
]), */
|
|
||||||
/* RaisedButton(
|
|
||||||
padding: EdgeInsets.all(0),
|
|
||||||
textColor: Colors.white,
|
|
||||||
color: exerciseBloc.step == i + 1 ? Colors.blue : Colors.black26,
|
|
||||||
focusColor: Colors.blueAccent,
|
|
||||||
onPressed: () => {
|
|
||||||
if (exerciseBloc.step == i + 1) {exerciseBloc.add(ExerciseExecutePlanAddSubmit())},
|
|
||||||
if (i + 1 == exerciseBloc.countSteps) {Navigator.of(context).pop()}
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
t("Save"),
|
|
||||||
style: TextStyle(fontSize: 12),
|
|
||||||
)), */
|
|
||||||
Divider(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
listColumns.add(col);
|
|
||||||
}
|
|
||||||
return listColumns;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> getButton(int step, ExerciseExecutePlanAddBloc exerciseBloc) {
|
|
||||||
List<Widget> widgets = [];
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -220,7 +220,7 @@ class ExerciseLogPage extends StatelessWidget with Trans, Common {
|
|||||||
return DialogPremium(
|
return DialogPremium(
|
||||||
unlocked: Cache().hasPurchased,
|
unlocked: Cache().hasPurchased,
|
||||||
unlockRound: 1,
|
unlockRound: 1,
|
||||||
unlockedText: t("Enjoy also this premium fetaure to show all old evaluation data of your successful exercises."),
|
unlockedText: t("Enjoy also this premium feature to show all old evaluation data of your successful exercises."),
|
||||||
function: "My Exercise Logs",
|
function: "My Exercise Logs",
|
||||||
onTap: () => {Navigator.of(context).pop()},
|
onTap: () => {Navigator.of(context).pop()},
|
||||||
onCancel: () => {Navigator.of(context).pop()},
|
onCancel: () => {Navigator.of(context).pop()},
|
||||||
|
@ -5,6 +5,7 @@ import 'package:aitrainer_app/repository/customer_repository.dart';
|
|||||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
||||||
import 'package:aitrainer_app/util/enums.dart';
|
import 'package:aitrainer_app/util/enums.dart';
|
||||||
import 'package:aitrainer_app/util/track.dart';
|
import 'package:aitrainer_app/util/track.dart';
|
||||||
|
import 'package:aitrainer_app/widgets/dialog_common.dart';
|
||||||
import 'package:aitrainer_app/widgets/dialog_premium.dart';
|
import 'package:aitrainer_app/widgets/dialog_premium.dart';
|
||||||
import 'package:badges/badges.dart';
|
import 'package:badges/badges.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
@ -93,29 +94,27 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
|
|||||||
Navigator.of(context).pushNamed('mydevelopmentBodyPage', arguments: args)
|
Navigator.of(context).pushNamed('mydevelopmentBodyPage', arguments: args)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{}
|
|
||||||
},
|
|
||||||
isLocked: true,
|
|
||||||
),
|
|
||||||
/* ImageButton(
|
|
||||||
width: imageWidth,
|
|
||||||
textAlignment: Alignment.topLeft,
|
|
||||||
text: t("My Sizes Development"),
|
|
||||||
style: GoogleFonts.robotoMono(
|
|
||||||
textStyle: TextStyle(
|
|
||||||
fontSize: 14, color: Colors.white, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4)),
|
|
||||||
),
|
|
||||||
image: "asset/image/testemfejl400x400.jpg",
|
|
||||||
left: 5,
|
|
||||||
onTap: () => {
|
|
||||||
if (Cache().userLoggedIn != null)
|
|
||||||
{
|
{
|
||||||
args['customerId'] = Cache().userLoggedIn.customerId,
|
showDialog(
|
||||||
Navigator.of(context).pushNamed('mydevelopmentSizesPage', arguments: args)
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return DialogCommon(
|
||||||
|
warning: true,
|
||||||
|
title: t("Warning"),
|
||||||
|
descriptions: t("Please log in"),
|
||||||
|
description2:
|
||||||
|
t("because only that way can we show you the personalized development diagrams and analysises"),
|
||||||
|
text: "OK",
|
||||||
|
onTap: () => Navigator.of(context).popAndPushNamed("login"),
|
||||||
|
onCancel: () => {
|
||||||
|
Navigator.of(context).pop(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isLocked: true,
|
isLocked: true,
|
||||||
), */
|
),
|
||||||
Badge(
|
Badge(
|
||||||
padding: EdgeInsets.all(8),
|
padding: EdgeInsets.all(8),
|
||||||
position: BadgePosition.topEnd(top: -5, end: -3),
|
position: BadgePosition.topEnd(top: -5, end: -3),
|
||||||
@ -221,6 +220,22 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
|
|||||||
args['customerRepository'] = customerRepository;
|
args['customerRepository'] = customerRepository;
|
||||||
args['customerId'] = Cache().userLoggedIn!.customerId;
|
args['customerId'] = Cache().userLoggedIn!.customerId;
|
||||||
Navigator.of(context).pushNamed('exerciseLogPage', arguments: args);
|
Navigator.of(context).pushNamed('exerciseLogPage', arguments: args);
|
||||||
|
} else {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return DialogCommon(
|
||||||
|
warning: true,
|
||||||
|
title: t("Warning"),
|
||||||
|
descriptions: t("Please log in"),
|
||||||
|
description2: t("because only that way can we show you your exercises, results and evaluations."),
|
||||||
|
text: "OK",
|
||||||
|
onTap: () => Navigator.of(context).popAndPushNamed("login"),
|
||||||
|
onCancel: () => {
|
||||||
|
Navigator.of(context).pop(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ class RegistrationPage extends StatelessWidget with Trans {
|
|||||||
child: Text(
|
child: Text(
|
||||||
t("Skip"),
|
t("Skip"),
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
style: GoogleFonts.inter(color: Colors.black, decoration: TextDecoration.underline),
|
style: GoogleFonts.inter(color: loginBloc.testColor, decoration: TextDecoration.underline),
|
||||||
)),
|
)),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 120,
|
height: 120,
|
||||||
@ -203,7 +203,7 @@ class RegistrationPage extends StatelessWidget with Trans {
|
|||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
),
|
),
|
||||||
getDataProtection(loginBloc),
|
getDataProtection(loginBloc),
|
||||||
getEmailSubscription(loginBloc),
|
loginBloc.emailCheckbox ? getEmailSubscription(loginBloc) : Offstage(),
|
||||||
Divider(
|
Divider(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
),
|
),
|
||||||
@ -220,7 +220,6 @@ class RegistrationPage extends StatelessWidget with Trans {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
//Image.asset('asset/icon/gomb_zold_b-1.png', width: 100, height: 100),
|
|
||||||
onPressed: () => {loginBloc.add(RegistrationSubmit())}),
|
onPressed: () => {loginBloc.add(RegistrationSubmit())}),
|
||||||
]),
|
]),
|
||||||
Divider(
|
Divider(
|
||||||
|
@ -62,6 +62,8 @@ class SalesPage extends StatelessWidget with Trans, Logging {
|
|||||||
final salesText = bloc.salesText != null ? bloc.salesText! : "";
|
final salesText = bloc.salesText != null ? bloc.salesText! : "";
|
||||||
final String html = salesText;
|
final String html = salesText;
|
||||||
|
|
||||||
|
log("start SalesPageBuild");
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
@ -80,12 +82,124 @@ class SalesPage extends StatelessWidget with Trans, Logging {
|
|||||||
"p": Style(
|
"p": Style(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: FontSize(16),
|
fontSize: FontSize(16),
|
||||||
padding: const EdgeInsets.only(left: 20, right: 8, bottom: 4),
|
padding: const EdgeInsets.only(left: 10, right: 8, bottom: 4),
|
||||||
|
textShadow: <Shadow>[
|
||||||
|
Shadow(
|
||||||
|
offset: Offset(3.0, 3.0),
|
||||||
|
blurRadius: 12.0,
|
||||||
|
color: Colors.black54,
|
||||||
|
),
|
||||||
|
Shadow(
|
||||||
|
offset: Offset(-3.0, 3.0),
|
||||||
|
blurRadius: 6.0,
|
||||||
|
color: Colors.black54,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
"strong": Style(
|
"strong": Style(
|
||||||
color: Colors.yellow[600],
|
color: Colors.orange[600],
|
||||||
fontSize: FontSize(16),
|
fontSize: FontSize(16),
|
||||||
),
|
),
|
||||||
|
"h3": Style(
|
||||||
|
color: Colors.orange[600],
|
||||||
|
fontSize: FontSize(16),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
),
|
||||||
|
"li": Style(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: FontSize(16),
|
||||||
|
padding: const EdgeInsets.only(left: 10, bottom: 10, right: 8),
|
||||||
|
//before: "*",
|
||||||
|
textShadow: <Shadow>[
|
||||||
|
Shadow(
|
||||||
|
offset: Offset(3.0, 3.0),
|
||||||
|
blurRadius: 12.0,
|
||||||
|
color: Colors.black54,
|
||||||
|
),
|
||||||
|
Shadow(
|
||||||
|
offset: Offset(-3.0, 3.0),
|
||||||
|
blurRadius: 6.0,
|
||||||
|
color: Colors.black54,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
//display: Display.LIST_ITEM,
|
||||||
|
),
|
||||||
|
"h2": Style(
|
||||||
|
color: Colors.orange[600],
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: FontSize(24),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
textShadow: <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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
//padding: const EdgeInsets.all(4),
|
||||||
|
),
|
||||||
|
"h1": Style(
|
||||||
|
color: Colors.orange[400],
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: FontSize.larger,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
), // final Color bgrColor = Color(0xffb4f500);
|
||||||
|
//final Color bgrColorEnd = Colors.blue;
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.only(left: 55, right: 55),
|
||||||
|
child: Text(
|
||||||
|
t("Tap on the button below the reach all premium content!"),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: GoogleFonts.inter(color: Colors.white, fontSize: 13),
|
||||||
|
)),
|
||||||
|
Divider(),
|
||||||
|
Row(
|
||||||
|
children: [0, 1].map((idx) {
|
||||||
|
return Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
child: AnimatedButton(
|
||||||
|
duration: 600,
|
||||||
|
darkShadow: true,
|
||||||
|
blurRadius: 12,
|
||||||
|
animationCurve: Curves.easeIn,
|
||||||
|
height: 150,
|
||||||
|
width: 160,
|
||||||
|
onTap: () => bloc.add(SalesPurchase(productId: bloc.product2Display[idx].productId)),
|
||||||
|
isMultiColor: true,
|
||||||
|
colors: [
|
||||||
|
//Colors.blue,
|
||||||
|
//Color(0xffb4f500),
|
||||||
|
//Color(0xffb4f500),
|
||||||
|
Colors.white,
|
||||||
|
Colors.yellow[50]!,
|
||||||
|
Colors.yellow[300]!,
|
||||||
|
],
|
||||||
|
child: Html(
|
||||||
|
data: bloc.productText2Display[idx],
|
||||||
|
//Optional parameters:
|
||||||
|
style: {
|
||||||
|
"p": Style(
|
||||||
|
color: Colors.blue,
|
||||||
|
fontSize: FontSize(14),
|
||||||
|
padding: const EdgeInsets.only(left: 5, right: 8, bottom: 5),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
"strong": Style(
|
||||||
|
color: Colors.red[800],
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: FontSize(14),
|
||||||
|
),
|
||||||
"h3": Style(
|
"h3": Style(
|
||||||
color: Colors.yellow[600],
|
color: Colors.yellow[600],
|
||||||
fontSize: FontSize(16),
|
fontSize: FontSize(16),
|
||||||
@ -95,121 +209,83 @@ class SalesPage extends StatelessWidget with Trans, Logging {
|
|||||||
"li": Style(
|
"li": Style(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: FontSize(14),
|
fontSize: FontSize(14),
|
||||||
padding: const EdgeInsets.only(left: 20, bottom: 10, right: 8),
|
padding: const EdgeInsets.only(left: 5, bottom: 10, right: 5),
|
||||||
//before: "*",
|
//before: "*",
|
||||||
display: Display.LIST_ITEM),
|
display: Display.LIST_ITEM),
|
||||||
"h2": Style(
|
"h2": Style(
|
||||||
color: Colors.yellow[600],
|
color: Colors.blue[600],
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: FontSize(24),
|
fontSize: FontSize(16),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
//padding: const EdgeInsets.all(4),
|
/* textShadow: <Shadow>[
|
||||||
|
Shadow(
|
||||||
|
offset: Offset(3.0, 3.0),
|
||||||
|
blurRadius: 4.0,
|
||||||
|
color: Colors.black54,
|
||||||
|
),
|
||||||
|
], */
|
||||||
),
|
),
|
||||||
"h1": Style(
|
"h1": Style(
|
||||||
color: Colors.yellow[400],
|
color: Colors.blue[400],
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: FontSize.larger,
|
fontSize: FontSize.larger,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
padding: const EdgeInsets.all(4),
|
padding: const EdgeInsets.all(4),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
), // final Color bgrColor = Color(0xffb4f500);
|
), // final Color bgr
|
||||||
//final Color bgrColorEnd = Colors.blue;
|
)),
|
||||||
AnimatedButton(
|
);
|
||||||
child: Html(
|
}).toList(),
|
||||||
data: bloc.salesButtonText,
|
),
|
||||||
|
|
||||||
|
getTrialDescription(),
|
||||||
|
Html(
|
||||||
|
data: bloc.premiumFunctions,
|
||||||
//Optional parameters:
|
//Optional parameters:
|
||||||
style: {
|
style: {
|
||||||
"p": Style(
|
"p": Style(
|
||||||
color: Colors.black,
|
color: Colors.white,
|
||||||
fontSize: FontSize(16),
|
fontSize: FontSize(14),
|
||||||
padding: const EdgeInsets.all(4),
|
padding: const EdgeInsets.only(left: 10, right: 8, bottom: 4),
|
||||||
textAlign: TextAlign.center,
|
),
|
||||||
textShadow: [
|
"strong": Style(
|
||||||
|
color: Colors.orange[600],
|
||||||
|
fontSize: FontSize(14),
|
||||||
|
textShadow: <Shadow>[
|
||||||
Shadow(
|
Shadow(
|
||||||
offset: Offset(2.0, 2.0),
|
offset: Offset(2.0, 2.0),
|
||||||
blurRadius: 6.0,
|
blurRadius: 4.0,
|
||||||
color: Colors.black54,
|
color: Colors.black54,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
"li": Style(
|
"li": Style(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: FontSize(14),
|
fontSize: FontSize(14),
|
||||||
padding: const EdgeInsets.only(left: 10, bottom: 10),
|
padding: const EdgeInsets.only(left: 10, bottom: 3, right: 10),
|
||||||
before: "*",
|
|
||||||
),
|
),
|
||||||
"h2": Style(
|
"h2": Style(
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: FontSize.larger,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
textShadow: [
|
|
||||||
Shadow(
|
|
||||||
offset: Offset(2.0, 2.0),
|
|
||||||
blurRadius: 12.0,
|
|
||||||
color: Colors.black54,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
//padding: const EdgeInsets.all(4),
|
|
||||||
),
|
|
||||||
"h1": Style(
|
|
||||||
color: Colors.yellow[600],
|
color: Colors.yellow[600],
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: FontSize.xLarge,
|
fontSize: FontSize(16),
|
||||||
alignment: Alignment.center,
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
textShadow: [
|
textShadow: <Shadow>[
|
||||||
Shadow(
|
Shadow(
|
||||||
offset: Offset(5.0, 5.0),
|
offset: Offset(5.0, 5.0),
|
||||||
blurRadius: 12.0,
|
blurRadius: 12.0,
|
||||||
color: Colors.black54,
|
color: Colors.black54,
|
||||||
)
|
),
|
||||||
|
Shadow(
|
||||||
|
offset: Offset(-3.0, 3.0),
|
||||||
|
blurRadius: 12.0,
|
||||||
|
color: Colors.black54,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
|
//padding: const EdgeInsets.all(4),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
duration: 600,
|
|
||||||
darkShadow: true,
|
|
||||||
blurRadius: 12,
|
|
||||||
animationCurve: Curves.easeIn,
|
|
||||||
height: 120,
|
|
||||||
width: 320,
|
|
||||||
onTap: () => bloc.add(SalesPurchase(productId: bloc.offeredProduct!.productId)),
|
|
||||||
//color: Color(0xffb4f500),
|
|
||||||
isMultiColor: true,
|
|
||||||
colors: [
|
|
||||||
Colors.blue,
|
|
||||||
Color(0xffb4f500),
|
|
||||||
Color(0xffb4f500),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
getTrialDescription(),
|
|
||||||
//Divider(),
|
|
||||||
AnimatedButton(
|
|
||||||
child: Html(
|
|
||||||
data: "<p>" + t("View other alternatives") + "</p>",
|
|
||||||
//Optional parameters:
|
|
||||||
style: {
|
|
||||||
"p": Style(
|
|
||||||
color: Colors.black,
|
|
||||||
fontSize: FontSize(14),
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
onTap: () => bloc.add(SalesChangeSubscription()),
|
|
||||||
width: 320,
|
|
||||||
blurRadius: 6,
|
|
||||||
isMultiColor: true,
|
|
||||||
colors: [
|
|
||||||
Colors.white,
|
|
||||||
Colors.yellow[300]!,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 30,
|
height: 30,
|
||||||
|
@ -11,6 +11,7 @@ import 'package:aitrainer_app/util/app_language.dart';
|
|||||||
import 'package:aitrainer_app/util/trans.dart';
|
import 'package:aitrainer_app/util/trans.dart';
|
||||||
import 'package:aitrainer_app/widgets/app_bar.dart';
|
import 'package:aitrainer_app/widgets/app_bar.dart';
|
||||||
import 'package:aitrainer_app/widgets/dialog_common.dart';
|
import 'package:aitrainer_app/widgets/dialog_common.dart';
|
||||||
|
import 'package:aitrainer_app/widgets/dialog_premium.dart';
|
||||||
import 'package:aitrainer_app/widgets/menu_image.dart';
|
import 'package:aitrainer_app/widgets/menu_image.dart';
|
||||||
import 'package:aitrainer_app/widgets/treeview_parent_widget.dart';
|
import 'package:aitrainer_app/widgets/treeview_parent_widget.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
@ -192,6 +193,8 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
|
|||||||
List<Widget> _getChildList(TrainingPlan plan, TrainingPlanBloc bloc) {
|
List<Widget> _getChildList(TrainingPlan plan, TrainingPlanBloc bloc) {
|
||||||
List<Widget> list = [];
|
List<Widget> list = [];
|
||||||
|
|
||||||
|
bool restricted = (!plan.free && !Cache().hasPurchased);
|
||||||
|
|
||||||
list.add(Card(
|
list.add(Card(
|
||||||
margin: EdgeInsets.only(left: 10, top: 5),
|
margin: EdgeInsets.only(left: 10, top: 5),
|
||||||
color: Colors.white60,
|
color: Colors.white60,
|
||||||
@ -236,6 +239,58 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
|
|||||||
),
|
),
|
||||||
child: Text(t("Start")),
|
child: Text(t("Start")),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
if (Cache().userLoggedIn == null) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return DialogCommon(
|
||||||
|
warning: true,
|
||||||
|
title: t("Warning"),
|
||||||
|
descriptions: t("Please log in"),
|
||||||
|
description2: t("because only that way can we generated the training plan for you."),
|
||||||
|
text: "OK",
|
||||||
|
onTap: () => Navigator.of(context).popAndPushNamed("login"),
|
||||||
|
onCancel: () => {
|
||||||
|
Navigator.of(context).pop(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (restricted) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return DialogPremium(
|
||||||
|
unlocked: Cache().hasPurchased,
|
||||||
|
unlockRound: 1,
|
||||||
|
unlockedText: t("Enjoy also this premium feature") + " " + t("to activate all available training programs."),
|
||||||
|
function: "Training Programs",
|
||||||
|
onTap: () => {Navigator.of(context).pop()},
|
||||||
|
onCancel: () => {Navigator.of(context).pop()},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
activate(plan, bloc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
restricted
|
||||||
|
? Container(
|
||||||
|
padding: EdgeInsets.only(bottom: 8),
|
||||||
|
child: Text(
|
||||||
|
t("This is a premium function"),
|
||||||
|
style: GoogleFonts.inter(color: Colors.blue[700]),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Offstage(),
|
||||||
|
]),
|
||||||
|
)));
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void activate(TrainingPlan plan, TrainingPlanBloc bloc) {
|
||||||
if (Cache().myTrainingPlan != null) {
|
if (Cache().myTrainingPlan != null) {
|
||||||
showCupertinoDialog(
|
showCupertinoDialog(
|
||||||
useRootNavigator: true,
|
useRootNavigator: true,
|
||||||
@ -270,12 +325,6 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
|
|||||||
} else {
|
} else {
|
||||||
bloc.add(TrainingPlanActivate(trainingPlanId: plan.trainingPlanId));
|
bloc.add(TrainingPlanActivate(trainingPlanId: plan.trainingPlanId));
|
||||||
}
|
}
|
||||||
},
|
|
||||||
)
|
|
||||||
]),
|
|
||||||
)));
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget getPlanDetails(TrainingPlan plan, TrainingPlanBloc bloc) {
|
Widget getPlanDetails(TrainingPlan plan, TrainingPlanBloc bloc) {
|
||||||
|
@ -123,7 +123,7 @@ class _ExercisePlanCustomPage extends State<TrainingPlanCustomPage> with Trans {
|
|||||||
exerciseTypes.add(Container(
|
exerciseTypes.add(Container(
|
||||||
margin: const EdgeInsets.only(left: 4.0),
|
margin: const EdgeInsets.only(left: 4.0),
|
||||||
child: TreeViewChild(
|
child: TreeViewChild(
|
||||||
startExpanded: false,
|
startExpanded: bloc.existsAddedExerciseTypeInTree(name),
|
||||||
parent: TreeviewParentWidget(text: name),
|
parent: TreeviewParentWidget(text: name),
|
||||||
children: getTiles(list, bloc),
|
children: getTiles(list, bloc),
|
||||||
)));
|
)));
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
|
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
|
||||||
import 'package:aitrainer_app/util/app_language.dart';
|
import 'package:aitrainer_app/util/app_language.dart';
|
||||||
import 'package:aitrainer_app/util/trans.dart';
|
import 'package:aitrainer_app/util/trans.dart';
|
||||||
import 'package:aitrainer_app/widgets/app_bar.dart';
|
|
||||||
import 'package:aitrainer_app/widgets/app_bar_min.dart';
|
import 'package:aitrainer_app/widgets/app_bar_min.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
@ -111,6 +110,9 @@ class _ExercisePlanDetailAddPage extends State<TrainingPlanCustomAddPage> with T
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget getForm(TrainingPlanBloc bloc) {
|
Widget getForm(TrainingPlanBloc bloc) {
|
||||||
|
if (bloc.getMyDetail() == null) {
|
||||||
|
return Offstage();
|
||||||
|
}
|
||||||
String exerciseName = "";
|
String exerciseName = "";
|
||||||
|
|
||||||
exerciseName = bloc.getExerciseName(AppLanguage().appLocal);
|
exerciseName = bloc.getExerciseName(AppLanguage().appLocal);
|
||||||
@ -124,7 +126,10 @@ class _ExercisePlanDetailAddPage extends State<TrainingPlanCustomAddPage> with T
|
|||||||
return Form(
|
return Form(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
resizeToAvoidBottomInset: true,
|
resizeToAvoidBottomInset: true,
|
||||||
appBar: AppBarMin(back: true),
|
appBar: AppBarMin(
|
||||||
|
back: true,
|
||||||
|
onTap: () => Navigator.of(context).popAndPushNamed("myTrainingPlanCustom"),
|
||||||
|
),
|
||||||
body: Container(
|
body: Container(
|
||||||
width: MediaQuery.of(context).size.width,
|
width: MediaQuery.of(context).size.width,
|
||||||
height: MediaQuery.of(context).size.height,
|
height: MediaQuery.of(context).size.height,
|
||||||
@ -139,7 +144,7 @@ class _ExercisePlanDetailAddPage extends State<TrainingPlanCustomAddPage> with T
|
|||||||
config: _buildConfig(context),
|
config: _buildConfig(context),
|
||||||
child: Container(
|
child: Container(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.only(top: 25, left: 95, right: 95),
|
padding: EdgeInsets.only(top: 25, left: 95, right: 95),
|
||||||
scrollDirection: Axis.vertical,
|
scrollDirection: Axis.vertical,
|
||||||
child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
|
child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
|
||||||
Text(t('Save The Exercise To The Training Plan'),
|
Text(t('Save The Exercise To The Training Plan'),
|
||||||
|
@ -111,19 +111,37 @@ class MyTrainingPlans extends StatelessWidget with Trans, Logging {
|
|||||||
left: 5,
|
left: 5,
|
||||||
textColor: color,
|
textColor: color,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (Cache().userLoggedIn != null) {
|
// if (Cache().userLoggedIn != null) {
|
||||||
if (route == "myTrainingPlanActivate") {
|
if (route == "myTrainingPlanActivate") {
|
||||||
HashMap<String, dynamic> args = HashMap();
|
HashMap<String, dynamic> args = HashMap();
|
||||||
args['parentName'] = parentName;
|
args['parentName'] = parentName;
|
||||||
Navigator.of(context).pushNamed(route, arguments: args);
|
Navigator.of(context).pushNamed(route, arguments: args);
|
||||||
} else if (route == "myTrainingPlanExecute") {
|
} else if (route == "myTrainingPlanExecute") {
|
||||||
|
if (Cache().userLoggedIn != null) {
|
||||||
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
|
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
|
||||||
bloc.setMyPlan(Cache().myTrainingPlan);
|
bloc.setMyPlan(Cache().myTrainingPlan);
|
||||||
Navigator.of(context).pushNamed(route);
|
Navigator.of(context).pushNamed(route);
|
||||||
|
} else {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return DialogCommon(
|
||||||
|
warning: true,
|
||||||
|
title: t("Warning"),
|
||||||
|
descriptions: t("Please log in"),
|
||||||
|
description2: t("because only in that way can you begin to execute a training plan"),
|
||||||
|
text: "OK",
|
||||||
|
onTap: () => Navigator.of(context).pushNamed("login"),
|
||||||
|
onCancel: () => {
|
||||||
|
Navigator.of(context).pop(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Navigator.of(context).pushNamed(route);
|
Navigator.of(context).pushNamed(route);
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
},
|
},
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
);
|
);
|
||||||
|
@ -156,7 +156,9 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin, C
|
|||||||
}
|
}
|
||||||
int sizeExerciseList = Cache().getExercises() == null ? 0 : Cache().getExercises()!.length;
|
int sizeExerciseList = Cache().getExercises() == null ? 0 : Cache().getExercises()!.length;
|
||||||
if (sizeExerciseList == 0) {
|
if (sizeExerciseList == 0) {
|
||||||
String text = AppLocalizations.of(context)!.translate("Make your first test");
|
String text = Cache().userLoggedIn == null
|
||||||
|
? AppLocalizations.of(context)!.translate("Please log in")
|
||||||
|
: AppLocalizations.of(context)!.translate("Make your first test");
|
||||||
double fontSize = text.length > 24 ? 13 : 16;
|
double fontSize = text.length > 24 ? 13 : 16;
|
||||||
return Stack(alignment: Alignment.topLeft, children: [
|
return Stack(alignment: Alignment.topLeft, children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
|
@ -9,7 +9,8 @@ import 'package:google_fonts/google_fonts.dart';
|
|||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class AppBarMin extends StatefulWidget implements PreferredSizeWidget {
|
class AppBarMin extends StatefulWidget implements PreferredSizeWidget {
|
||||||
bool back = false;
|
bool back = false;
|
||||||
AppBarMin({this.back = false});
|
VoidCallback? onTap;
|
||||||
|
AppBarMin({this.back = false, this.onTap});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AppBarNav createState() => _AppBarNav();
|
_AppBarNav createState() => _AppBarNav();
|
||||||
@ -46,9 +47,13 @@ class _AppBarNav extends State<AppBarMin> with Common {
|
|||||||
),
|
),
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: Icon(Icons.arrow_back, color: widget.back ? Colors.white : Colors.black),
|
icon: Icon(Icons.arrow_back, color: widget.back ? Colors.white : Colors.black),
|
||||||
onPressed: () => {
|
onPressed: () {
|
||||||
timerBloc.add(TimerEnd(duration: 0)),
|
timerBloc.add(TimerEnd(duration: 0));
|
||||||
if (widget.back) {Navigator.of(context).pop()}
|
if (widget.onTap != null) {
|
||||||
|
widget.onTap!();
|
||||||
|
} else if (widget.back) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -313,9 +313,12 @@ class _BMIState extends State<BMI> with Trans {
|
|||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
||||||
onChanged: (value) => {
|
onChanged: (value) => {
|
||||||
|
if (value.isNotEmpty)
|
||||||
|
{
|
||||||
value = value.replaceFirst(",", "."),
|
value = value.replaceFirst(",", "."),
|
||||||
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
||||||
widget.exerciseBloc.add(ExerciseNewHeightChange(value: double.parse(value))),
|
widget.exerciseBloc.add(ExerciseNewHeightChange(value: double.parse(value))),
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -397,9 +400,12 @@ class _BMIState extends State<BMI> with Trans {
|
|||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
||||||
onChanged: (value) => {
|
onChanged: (value) => {
|
||||||
|
if (value.isNotEmpty)
|
||||||
|
{
|
||||||
value = value.replaceFirst(",", "."),
|
value = value.replaceFirst(",", "."),
|
||||||
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
||||||
widget.exerciseBloc.add(ExerciseNewWeightChange(value: double.parse(value))),
|
widget.exerciseBloc.add(ExerciseNewWeightChange(value: double.parse(value))),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -217,9 +217,12 @@ class _BMRState extends State<BMR> with Trans {
|
|||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
||||||
onChanged: (value) => {
|
onChanged: (value) => {
|
||||||
|
if (value.isNotEmpty)
|
||||||
|
{
|
||||||
value = value.replaceFirst(",", "."),
|
value = value.replaceFirst(",", "."),
|
||||||
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
||||||
widget.exerciseBloc.add(ExerciseNewHeightChange(value: double.parse(value))),
|
widget.exerciseBloc.add(ExerciseNewHeightChange(value: double.parse(value))),
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -248,8 +251,11 @@ class _BMRState extends State<BMR> with Trans {
|
|||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
||||||
onChanged: (value) => {
|
onChanged: (value) => {
|
||||||
|
if (value.isNotEmpty)
|
||||||
|
{
|
||||||
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
||||||
widget.exerciseBloc.add(ExerciseNewBirthyearChange(value: int.parse(value)))
|
widget.exerciseBloc.add(ExerciseNewBirthyearChange(value: int.parse(value)))
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -373,9 +379,12 @@ class _BMRState extends State<BMR> with Trans {
|
|||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
||||||
onChanged: (value) => {
|
onChanged: (value) => {
|
||||||
|
if (value.isNotEmpty)
|
||||||
|
{
|
||||||
value = value.replaceFirst(",", "."),
|
value = value.replaceFirst(",", "."),
|
||||||
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
||||||
widget.exerciseBloc.add(ExerciseNewWeightChange(value: double.parse(value))),
|
widget.exerciseBloc.add(ExerciseNewWeightChange(value: double.parse(value))),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -162,7 +162,7 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
|
|||||||
Align(
|
Align(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => widget.unlocked ? Navigator.of(context).pop() : Navigator.of(context).pushNamed("salesPage"),
|
onTap: () => widget.unlocked ? Navigator.of(context).pop() : Navigator.of(context).popAndPushNamed("salesPage"),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
@ -281,10 +281,12 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
|||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.yellow[300]),
|
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.yellow[300]),
|
||||||
onChanged: (value) => {
|
onChanged: (value) {
|
||||||
value = value.replaceFirst(",", "."),
|
if (value.isNotEmpty) {
|
||||||
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
value = value.replaceFirst(",", ".");
|
||||||
widget.onUnitQuantityChanged!(double.parse(value)),
|
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
|
||||||
|
widget.onUnitQuantityChanged!(double.parse(value));
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
@ -395,9 +397,11 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
|||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.orange[200]),
|
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.orange[200]),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
if (value.isNotEmpty) {
|
||||||
value = value.replaceFirst(",", ".");
|
value = value.replaceFirst(",", ".");
|
||||||
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
|
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
|
||||||
widget.onQuantityChanged(double.parse(value));
|
widget.onQuantityChanged(double.parse(value));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]));
|
]));
|
||||||
|
@ -157,9 +157,12 @@ class _InputDialogState<Event> extends State<InputDialog<Event>> with Trans {
|
|||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
||||||
onChanged: (value) => {
|
onChanged: (value) => {
|
||||||
|
if (value.isNotEmpty)
|
||||||
|
{
|
||||||
value = value.replaceFirst(",", "."),
|
value = value.replaceFirst(",", "."),
|
||||||
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
value = value.replaceAll(RegExp(r'[^0-9.]'), ""),
|
||||||
this.inputValue = double.parse(value),
|
this.inputValue = double.parse(value),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -81,9 +81,7 @@ class _VictoryState extends State<Victory> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
animation.start();
|
animation.start();
|
||||||
animation.addStatusListener((status) {
|
animation.addStatusListener((status) {
|
||||||
if (status == AnimationStatus.completed) {
|
if (status == AnimationStatus.completed) {}
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
version: 1.1.18+82
|
version: 1.1.18+83
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.12.0 <3.0.0"
|
sdk: ">=2.12.0 <3.0.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user