WT 1.1.14 Tutorial, Sports, New goals

This commit is contained in:
bossanyit
2021-05-02 17:12:42 +02:00
parent 5fe8f76f48
commit c901b07bf8
65 changed files with 2472 additions and 620 deletions
@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/sport.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:bloc/bloc.dart';
@@ -8,8 +9,6 @@ import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import '../../model/fitness_state.dart';
part 'customer_change_event.dart';
part 'customer_change_state.dart';
@@ -30,24 +29,7 @@ class CustomerChangeBloc extends Bloc<CustomerChangeEvent, CustomerChangeState>
weight = this.customerRepository.getWeight() == 0 ? 60 : this.customerRepository.getWeight();
height = this.customerRepository.getHeight() == 0 ? 170 : this.customerRepository.getHeight();
print("fitnesslevel " + customerRepository.customer!.fitnessLevel.toString());
if (customerRepository.customer!.fitnessLevel != null) {
if (!FitnessItem().elements.contains(customerRepository.customer!.fitnessLevel)) {
Sport.values.forEach((element) {
print(" .. ${element.toStr()}");
if (element.equalsStringTo(customerRepository.customer!.fitnessLevel!)) {
selectedSport = element;
selectedFitnessItem = FitnessState.professional;
}
});
if (selectedSport == null) {
selectedFitnessItem = customerRepository.customer!.fitnessLevel;
}
} else {
selectedFitnessItem = customerRepository.customer!.fitnessLevel;
}
}
selectedSport = customerRepository.getSport();
print("selected: $selectedFitnessItem sport: $selectedSport " + customerRepository.customer!.fitnessLevel.toString());
}
@@ -63,13 +45,16 @@ class CustomerChangeBloc extends Bloc<CustomerChangeEvent, CustomerChangeState>
yield CustomerChangeLoading();
yield CustomerDataChanged();
} else if (event is CustomerGoalChange) {
yield CustomerChangeLoading();
customerRepository.setGoal(event.goal);
yield CustomerDataChanged();
} else if (event is CustomerChangePasswordObscure) {
yield CustomerChangeLoading();
visiblePassword = !visiblePassword;
yield CustomerDataChanged();
} else if (event is CustomerFitnessChange) {
//customerRepository.setFitnessLevel(event.fitness);
yield CustomerChangeLoading();
customerRepository.setFitnessLevel(event.fitness);
selectedFitnessItem = event.fitness;
yield CustomerDataChanged();
} else if (event is CustomerBirthYearChange) {
@@ -108,22 +93,17 @@ class CustomerChangeBloc extends Bloc<CustomerChangeEvent, CustomerChangeState>
} else if (event is CustomerSportChange) {
yield CustomerChangeLoading();
selectedSport = event.sport;
//customerRepository.setFitnessLevel(event.sport.toStr());
yield CustomerDataChanged();
} else if (event is CustomerSave) {
yield CustomerSaving();
if (validation()) {
if (selectedFitnessItem != null) {
if (selectedFitnessItem == FitnessState.professional) {
if (selectedSport != null) {
customerRepository.setFitnessLevel(selectedSport!.toStr());
} else {
customerRepository.setFitnessLevel(FitnessState.professional);
}
} else {
customerRepository.setFitnessLevel(selectedFitnessItem!);
}
customerRepository.setFitnessLevel(selectedFitnessItem!);
}
if (selectedSport != null) {
customerRepository.customer!.sportId = selectedSport!.sportId;
}
await customerRepository.saveCustomer();
Cache().initBadges();
yield CustomerSaveSuccess();
@@ -369,7 +369,7 @@ class DevelopmentByMuscleBloc extends Bloc<DevelopmentByMuscleEvent, Development
if (event is DevelopmentByMuscleLoad) {
yield DevelopmentByMuscleLoadingState();
Track().track(TrackingEvent.my_muscle_development);
Cache().setMuscleDevelopmentSeen();
Cache().setActivityDonePrefs(ActivityDone.isMuscleDevelopmentSeen);
await getData();
yield DevelopmentByMuscleReadyState();
} else if (event is DevelopmentByMuscleDiagramTypeChange) {
+1 -1
View File
@@ -22,7 +22,7 @@ class ExerciseLogBloc extends Bloc<ExerciseLogEvent, ExerciseLogState> {
try {
if (event is ExerciseLogLoad) {
yield ExerciseLogLoading();
await Cache().setExerciseLogSeen();
await Cache().setActivityDonePrefs(ActivityDone.isExerciseLogSeen);
Track().track(TrackingEvent.exercise_log_open);
yield ExerciseLogReady();
} else if (event is ExerciseLogDelete) {
@@ -158,6 +158,9 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
} else if (event is ExerciseNewBMIAnimate) {
yield ExerciseNewLoading();
yield ExerciseNewReady();
} else if (event is ExerciseNewAddError) {
yield ExerciseNewLoading();
yield ExerciseNewError(message: event.message);
}
} on Exception catch (e) {
yield ExerciseNewError(message: e.toString());
@@ -73,7 +73,7 @@ class ExerciseNewSaveWeight extends ExerciseNewEvent {
class ExerciseNewBMIAnimate extends ExerciseNewEvent {
final dynamic value;
const ExerciseNewBMIAnimate({this.value});
const ExerciseNewBMIAnimate({required this.value});
@override
List<Object> get props => [value];
@@ -82,3 +82,10 @@ class ExerciseNewBMIAnimate extends ExerciseNewEvent {
class ExerciseNewSubmit extends ExerciseNewEvent {
const ExerciseNewSubmit();
}
class ExerciseNewAddError extends ExerciseNewEvent {
final String message;
const ExerciseNewAddError({required this.message});
@override
List<Object> get props => [message];
}
+13
View File
@@ -22,6 +22,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
final BuildContext context;
final bool isRegistration;
bool dataPolicyAllowed = false;
bool emailSubscription = false;
bool obscure = true;
LoginBloc({required this.accountBloc, required this.userRepository, required this.context, required this.isRegistration})
@@ -81,6 +82,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
} else {
await userRepository.addUser();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
await saveCustomer();
Track().track(TrackingEvent.registration, eventValue: "email");
Cache().setLoginType(LoginType.email);
@@ -94,6 +96,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
Cache().setLoginType(LoginType.fb);
await userRepository.addUserFB();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
await saveCustomer();
Track().track(TrackingEvent.registration, eventValue: "FB");
yield LoginSuccess();
@@ -105,6 +108,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
Cache().setLoginType(LoginType.google);
await userRepository.addUserGoogle();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
await saveCustomer();
Track().track(TrackingEvent.registration, eventValue: "Google");
yield LoginSuccess();
@@ -116,6 +120,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
Cache().setLoginType(LoginType.apple);
await userRepository.addUserApple();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
await saveCustomer();
Track().track(TrackingEvent.registration, eventValue: "Apple");
@@ -124,10 +129,18 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
yield LoginLoading();
this.dataPolicyAllowed = !dataPolicyAllowed;
yield LoginReady();
} else if (event is EmailSubscriptionClicked) {
yield LoginLoading();
this.emailSubscription = !emailSubscription;
yield LoginReady();
} else if (event is LoginPasswordChangeObscure) {
yield LoginLoading();
this.obscure = !this.obscure;
yield LoginReady();
} else if (event is LoginSkip) {
yield LoginLoading();
Cache().startPage = "home";
yield LoginSkipped();
}
} on Exception catch (e) {
yield LoginError(message: e.toString());
+9
View File
@@ -43,11 +43,20 @@ class LoginApple extends LoginEvent {
const LoginApple();
}
class LoginSkip extends LoginEvent {
const LoginSkip();
}
class DataProtectionClicked extends LoginEvent {
final bool marked;
const DataProtectionClicked({required this.marked});
}
class EmailSubscriptionClicked extends LoginEvent {
final bool marked;
const EmailSubscriptionClicked({required this.marked});
}
class RegistrationSubmit extends LoginEvent {
const RegistrationSubmit();
}
+4
View File
@@ -23,6 +23,10 @@ class LoginSuccess extends LoginState {
const LoginSuccess();
}
class LoginSkipped extends LoginState {
const LoginSkipped();
}
class LoginError extends LoginState {
final String message;
const LoginError({required this.message});
+1 -48
View File
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:collection';
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
@@ -26,11 +27,6 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
WorkoutMenuTree? workoutItem;
final List<int> listFilterDevice = [];
String infoTitle = "";
String infoText = "";
String infoText2 = "";
String infoText3 = "";
String infoLink = "";
int missingParent = 0;
String? missingTreeName = "";
@@ -42,48 +38,6 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
parent = 0;
}
void setMenuInfo() {
double percent = Cache().getPercentExercises();
if (percent == -1) {
exerciseRepository.getBaseExerciseFinishedPercent();
percent = Cache().getPercentExercises();
}
percent = percent * 100;
//log("Percent " + percent.toString());
if (percent == -1 || percent == 0) {
infoTitle = t("Greetings!");
infoText = t("The purpose is to measure you physical condition") +
" " +
t("The suggested order of the exercises: chest - biceps - triceps - back - shoulders - core - tigh - calf.");
infoText2 = t("I suggest begin your tests with a");
infoText3 = t("Go to the menu Strength - One Rep Max - Chest, and select your favourite exercise.");
infoLink = t("Bring me there");
} else if (percent > 0 && percent < 20) {
infoTitle = t("Nice! This is a good start");
} else if (percent > 20 && percent < 40) {
infoTitle = t("Go on!") + " " + t("You are on track");
} else if (percent > 60 && percent < 80) {
infoTitle = t("Persistence!") + " " + t("Not so much left");
} else if (percent > 80 && percent < 100) {
infoTitle = t("Almost!") + " " + t("You have only 1-2 exercise left to finish!");
} else {
infoTitle = t("Congratulation!");
infoText2 = t("You have achieved to first 100% test-round!");
infoText3 = t("Now you unlocked: Development By Muscles and the Suggested Trainings Plan");
}
menuTreeRepository.sortByMuscleType();
missingTreeName = exerciseRepository.nextMissingBaseExercise(menuTreeRepository.sortedTree);
//log("Missing " + missingTreeName);
if (missingTreeName != null) {
if (percent > 0) {
infoText = t("Please continue your tests with a") + " '" + missingTreeName! + "' " + t("exercise!");
infoLink = t("Bring me there");
}
}
}
void setContext(BuildContext context) {
this.context = context;
}
@@ -118,7 +72,6 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
final LinkedHashMap<String, WorkoutMenuTree> branch = menuTreeRepository.getBranch(event.parent);
await getImages(branch);
//await Future.delayed(Duration(seconds: 2));
yield MenuReady();
} else if (event is MenuTreeUp) {
yield MenuLoading();
+5
View File
@@ -61,6 +61,11 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> with Logging {
}
Cache().initBadges();
yield SettingsReady();
} else if (event is SettingsActivateTutorial) {
yield SettingsLoading();
Cache().activitiesDone[event.activity.toStr()] = false;
print(" ----------------- Setting ${event.activity} to false");
yield SettingsReady();
}
}
+8
View File
@@ -31,3 +31,11 @@ class SettingsSetHardware extends SettingsEvent {
@override
List<Object> get props => [this.hasHardware];
}
class SettingsActivateTutorial extends SettingsEvent {
final ActivityDone activity;
const SettingsActivateTutorial({required this.activity});
@override
List<Object> get props => [this.activity];
}
@@ -113,6 +113,8 @@ class TestSetEditBloc extends Bloc<TestSetEditEvent, TestSetEditState> {
Cache().saveActiveExercisePlan(exercisePlan, details);
Track().track(TrackingEvent.test_set_edit, eventValue: templateName);
yield TestSetEditSaved();
} else if (event is TestSetEditAddError) {
yield TestSetEditError(message: event.message);
}
} on Exception catch (e) {
yield TestSetEditError(message: e.toString());
@@ -47,3 +47,10 @@ class TestSetEditSkipExerciseType extends TestSetEditEvent {
class TestSetEditSubmit extends TestSetEditEvent {
const TestSetEditSubmit();
}
class TestSetEditAddError extends TestSetEditEvent {
final String message;
const TestSetEditAddError({required this.message});
@override
List<Object> get props => [message];
}
+214
View File
@@ -0,0 +1,214 @@
import 'dart:async';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/tutorial.dart';
import 'package:aitrainer_app/model/tutorial_step.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
part 'tutorial_event.dart';
part 'tutorial_state.dart';
class TutorialBloc extends Bloc<TutorialEvent, TutorialState> with Logging {
late String tutorialName;
bool isActive = false;
bool canActivate = false;
Tutorial? tutorial;
String? actualText;
String? actualCheck;
List<String> checks = [];
double calculatedHeight = 0;
TutorialStepAction? action;
double? top;
double left = 20;
bool showCheckText = true;
int parent = 0;
int step = 0;
MenuBloc? menuBloc;
TutorialBloc({required this.tutorialName}) : super(TutorialInitial());
init() {
if (Cache().tutorials != null) {
print("Actual step: $step");
final List<Tutorial> tutorials = Cache().tutorials!;
tutorials.forEach((element) {
final String realTutorialName = tutorialName.replaceFirst("tutorial", "").toLowerCase();
if (element.name.toLowerCase() == realTutorialName) {
tutorial = element;
setNextStepData(step);
isActive = true;
}
});
}
}
void setNextStepData(int step) {
if (step == -1) {
isActive = false;
return;
}
if (tutorial != null && tutorial!.steps != null) {
actualText = tutorial!.steps![step].tutorialTextTranslation;
print("Step: $step, text: $actualText");
this.actualCheck = tutorial!.steps![step].checkText;
this.checks = [];
if (this.actualCheck != null) {
this.checks = this.actualCheck!.split("|");
} else {
this.checks.add("Next");
}
if (this.tutorial!.steps![step].action != null) {
this.action = this.tutorial!.steps![step].action;
this.top = action!.top.toDouble();
this.left = action!.left == -1 ? 20 : action!.left.toDouble();
this.showCheckText = action!.showCheckText == true;
this.parent = action!.parent;
}
calculateHeight();
}
/* else {
this.add(TutorialFinished());
} */
}
bool activateTutorial() {
if (!canActivate) {
print("Tutorial canActivate false");
return false;
}
ActivityDone? activityDone = ActivityDone.tutorialBasic.searchByString(tutorialName);
if (activityDone == null) {
return false;
}
bool? isActivityDone = Cache().activitiesDone[activityDone.toStr()];
log("isActivityDone? $isActivityDone");
if (isActivityDone == null || isActivityDone == true) {
return false;
}
log("Running tutorial $activityDone");
init();
return true;
}
void calculateHeight() {
int count = getElementCount('<p>');
count += getElementCount('<br/>');
double lines = (actualText!.length / 32 + count);
if (lines < 5) {
lines = lines + 2;
}
calculatedHeight = lines * 15;
print("Calculated Height: $calculatedHeight length: ${actualText!.length} lines: $lines count: $count");
}
int getElementCount(String elem) {
int pos = 0;
int count = 0;
bool out = false;
while (out == false) {
pos = actualText!.indexOf(elem, pos);
if (pos == -1) {
out = true;
} else {
count++;
pos++;
}
}
return count;
}
int getNextStep(int step) {
int next = 0;
if (action == null) {
return step + 1;
}
/* bool found = false;
if (tutorial != null && tutorial!.steps != null) {
for (var nextStep in tutorial!.steps!) {
print("step $step parent: ${nextStep.action!.parent}");
if (step + 1 == nextStep.step) {
next = nextStep.step!;
found = true;
break;
}
}
} */
step++;
next = step;
print("Next step:! $next");
if (step >= tutorial!.steps!.length) {
next = -1;
this.add(TutorialFinished());
}
return next;
}
bool checkAction(String checkText) {
final bool nextStep = checkText == actualCheck;
if (nextStep) {
this.add(TutorialNext(text: actualCheck!));
}
return nextStep;
}
@override
Stream<TutorialState> mapEventToState(TutorialEvent event) async* {
if (event is TutorialLoad) {
init();
if (menuBloc != null) {
menuBloc!.add(MenuCreate());
}
} else if (event is TutorialNext) {
if (tutorial != null) {
yield TutorialLoading();
step = this.getNextStep(step);
if (step == -1) {
print("Tutorial $tutorialName finished!");
return;
}
print("Step: $step");
setNextStepData(step);
print("Menu rebuild $menuBloc");
if (menuBloc != null) {
menuBloc!.add(MenuCreate());
}
yield TutorialReady();
}
} else if (event is TutorialWrongAction) {
yield TutorialLoading();
actualText = tutorial!.steps![step].errorTextTranslation!;
yield TutorialReady();
} else if (event is TutorialStart) {
yield TutorialLoading();
isActive = true;
canActivate = true;
step = 0;
yield TutorialReady();
} else if (event is TutorialFinished) {
yield TutorialLoading();
isActive = false;
canActivate = false;
ActivityDone? activityDone = ActivityDone.tutorialBasic.searchByString(tutorialName);
print("activity Finished: $activityDone");
if (activityDone != null) {
await Cache().setActivityDonePrefs(activityDone);
}
yield TutorialReady();
}
}
}
+29
View File
@@ -0,0 +1,29 @@
part of 'tutorial_bloc.dart';
abstract class TutorialEvent extends Equatable {
const TutorialEvent();
@override
List<Object> get props => [];
}
class TutorialLoad extends TutorialEvent {
const TutorialLoad();
}
class TutorialStart extends TutorialEvent {
const TutorialStart();
}
class TutorialNext extends TutorialEvent {
final String text;
const TutorialNext({required this.text});
}
class TutorialFinished extends TutorialEvent {
const TutorialFinished();
}
class TutorialWrongAction extends TutorialEvent {
const TutorialWrongAction();
}
+28
View File
@@ -0,0 +1,28 @@
part of 'tutorial_bloc.dart';
abstract class TutorialState extends Equatable {
const TutorialState();
@override
List<Object> get props => [];
}
class TutorialInitial extends TutorialState {
const TutorialInitial();
}
class TutorialLoading extends TutorialState {
const TutorialLoading();
}
class TutorialReady extends TutorialState {
const TutorialReady();
}
class TutorialError extends TutorialState {
final String message;
const TutorialError({required this.message});
@override
List<Object> get props => [message];
}