workouttest_app/lib/bloc/training_plan/training_plan_bloc.dart
Tibor Bossanyi (Freelancer) 3b96d81a85 WT 1.26
2022-04-09 11:22:34 +02:00

1013 lines
35 KiB
Dart

import 'dart:collection';
import 'package:aitrainer_app/main.dart';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer_training_plan.dart';
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/model/training_plan_detail.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/mautic_repository.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/service/exercise_service.dart';
import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/widgets/exercise_save.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
part 'training_plan_event.dart';
part 'training_plan_state.dart';
class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> with Common {
final TrainingPlanRepository trainingPlanRepository;
final MenuBloc menuBloc;
TrainingPlanBloc({required this.trainingPlanRepository, required this.menuBloc}) : super(TrainingPlanInitial()) {
on<TrainingPlanCreateException>(_onCreateException);
on<TrainingPlanActivate>(_onActivate);
on<TrainingPlanWeightChangeRecalculate>(_onWeightChangeRecalculate);
on<TrainingPlanSaveExercise>(_onSaveExercise);
on<TrainingPlanAlternateChange>(_onChangeAlternate);
on<TrainingPlanSkipExercise>(_onSkipExercise);
on<TrainingPlanSkipEntireExercise>(_onSkipEntireExercise);
on<TrainingPlanFinishDropset>(_onFinishDropSet);
on<TrainingPlanFinishDay>(_onFinishDay);
on<TrainingPlanChangeCancel>(_onChangeCancel);
on<TrainingPlanAddLoad>(_onCustomLoad);
on<TrainingPlanDeleteExerciseType>(_onDeleteExerciseType);
on<TrainingPlanWeightChange>(_onCustomWeightChange);
on<TrainingPlanSetChange>(_onCustomPlanSetChange);
on<TrainingPlanRepeatsChange>(_onCustomPlanRepeatChange);
on<TrainingPlanAddExerciseType>(_onCustomPlanAddExerciseType);
on<TrainingPlanGoToRestart>(_onRestarting);
// on<TrainingPlanError>(_onTrainingPlanError);
}
CustomerTrainingPlan? _myPlan;
CustomerTrainingPlanDetails? _myDetail;
CustomerTrainingPlanDetails? _backupDetail;
TrainingPlan? _myTrainingPlan;
final List<String> trainingPlanDayNames = [];
bool started = false;
final List<String> dayNames = [];
bool restarting = false;
bool celebrating = false;
int activeDayIndex = 0;
double base1RM = 0;
CustomerTrainingPlan? getMyPlan() => this._myPlan;
setMyPlan(CustomerTrainingPlan? myPlan) => this._myPlan = myPlan;
TrainingPlan? getMyTrainingPlan() => this._myTrainingPlan;
setMyTrainingPlan(TrainingPlan? myTrainingPlan) => this._myTrainingPlan = myTrainingPlan;
CustomerTrainingPlanDetails? getMyDetail() => this._myDetail;
setMyDetail(CustomerTrainingPlanDetails? value) => this._myDetail = value;
HashMap<int, List<CustomerTrainingPlanDetails>> _alternatives = HashMap();
get alternatives => this._alternatives;
/// _onActivate
/// activating the training plan, calculating the weights to the given repeats
/// from previous exercises
///
/// event: TrainingPlanActivate
void _onActivate(TrainingPlanActivate event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
_myPlan = trainingPlanRepository.activateTrainingPlan(event.trainingPlanId);
_myPlan!.type = CustomerTrainingPlanType.template;
this.createAlternatives();
menuBloc.menuTreeRepository.sortedTree.forEach((name, list) {
final List<WorkoutMenuTree> menuList = list as List<WorkoutMenuTree>;
menuList.forEach((element) {
element.exerciseType!.trainingPlanState = ExerciseTypeTrainingPlanState.none;
});
});
this.activateDays();
Cache().myTrainingPlan = _myPlan;
await Cache().saveMyTrainingPlan();
Track().track(TrackingEvent.training_plan_start, eventValue: event.trainingPlanId.toString());
emit(TrainingPlanFinished());
}
void _onWeightChangeRecalculate(TrainingPlanWeightChangeRecalculate event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanExerciseLoading());
if (event.detail.baseOneRepMax > 0 && event.detail.repeats != -1) {
if (_myTrainingPlan == null) {
setTrainingPlanFromCache();
}
final int originalRepeats = trainingPlanRepository.getOriginalRepeats(_myTrainingPlan!.trainingPlanId, event.detail);
event.detail.repeats = Common.calculateQuantityByChangedWeight(event.detail.baseOneRepMax, event.weight, originalRepeats.toDouble());
print("Base1RM ${event.detail.baseOneRepMax} repeats: ${event.detail.repeats}");
if (event.detail.repeats! < 1) {
event.detail.repeats = 1;
event.detail.weight = trainingPlanRepository.getOriginalWeight(_myTrainingPlan!.trainingPlanId, event.detail);
}
ExerciseSaveStream().repeats = event.detail.repeats!;
ExerciseSaveStream().getStreamController().add(true);
}
event.detail.weight = event.weight;
///yield TrainingPlanExerciseReady();
emit(TrainingPlanReady());
}
/// _onSaveExercise
/// - save the executed exercise to the DB
/// - recalculate, if necessary the next weight to the give repeats
/// - track this event
/// - send the data to Mautic
/// if [DropSet], the just set the state of the detail to finish
///
/// event: TrainingPlanWeightChange
void _onSaveExercise(TrainingPlanSaveExercise event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
try {
if (event.detail.repeats == -1) {
emit(TrainingPlanReady());
throw Exception("Please type your repeats!");
}
print("SAVE for ExerciseTypeID: ${event.detail.exerciseTypeId} weight: ${event.detail.weight}");
if (event.detail.weight == -3) {
print("DropSet");
event.detail.state = ExercisePlanDetailState.finished;
emit(TrainingPlanReady());
} else {
final Exercise exercise = Exercise();
exercise.customerId = Cache().userLoggedIn!.customerId!;
exercise.exerciseTypeId = event.detail.exerciseTypeId;
exercise.quantity = event.detail.repeats!.toDouble();
exercise.unit = event.detail.exerciseType!.unit;
exercise.unitQuantity = event.detail.weight;
exercise.dateAdd = DateTime.now();
event.detail.exercises.add(exercise);
if (this.isAllDetailsSameExerciseFinished(event.detail)) {
event.detail.state = ExercisePlanDetailState.finished;
}
// recalculate the weight to the original planned repeats for the next details
this.recalculateNextDetails(event.detail);
exercise.trainingPlanDetailsId = _myPlan!.trainingPlanId;
// save Exercise
Exercise savedExercise = await ExerciseApi().addExercise(exercise);
Cache().addExercise(savedExercise);
Cache().myTrainingPlan = _myPlan;
await Cache().saveMyTrainingPlan();
}
if (!isInDebugMode) {
CustomerRepository customerRepository = CustomerRepository();
customerRepository.customer = Cache().userLoggedIn;
MauticRepository mauticRepository = MauticRepository(customerRepository: customerRepository);
await mauticRepository.sendMauticExercise();
}
Track().track(TrackingEvent.training_plan_execute, eventValue: event.detail.exerciseType!.name);
if (isDayDone()) {
this.add(TrainingPlanFinishDay());
} else {
emit(TrainingPlanReady());
}
} on Exception catch (e) {
emit(TrainingPlanError(message: e.toString()));
}
}
void recalculateNextDetails(CustomerTrainingPlanDetails eventDetail) {
int id = 0;
bool recalculate = false;
int baseCustomerTrainingPlanDetailsId = 0;
if (eventDetail.exerciseType!.unitQuantity != null && eventDetail.weight! > 0) {
for (var nextDetail in _myPlan!.details) {
if (nextDetail.exerciseTypeId == eventDetail.exerciseTypeId) {
if (id == 0 && nextDetail.customerTrainingPlanDetailsId == eventDetail.customerTrainingPlanDetailsId) {
id = nextDetail.customerTrainingPlanDetailsId!;
recalculate = true;
}
if (id == 0) {
// we are after the first exercise
baseCustomerTrainingPlanDetailsId = nextDetail.customerTrainingPlanDetailsId!;
}
double weightFromPlan = trainingPlanRepository.getOriginalWeight(this.getMyPlan()!.trainingPlanId!, nextDetail);
print("NextDetail detail: $nextDetail *** PlanWeight: $weightFromPlan");
if (nextDetail.weight == -2 && nextDetail.customerTrainingPlanDetailsId != eventDetail.customerTrainingPlanDetailsId) {
print("Nr 1. - recalculating -2 ${eventDetail.customerTrainingPlanDetailsId}");
trainingPlanRepository.recalculateDetail(_myPlan!.trainingPlanId!, eventDetail, nextDetail);
nextDetail.baseOneRepMax = calculate1RM(nextDetail.weight!, nextDetail.repeats!.toDouble());
} /* else if (weightFromPlan == -1 && nextDetail.set! > 1 && nextDetail.exercises.length == 1) {
print("Nr 2. recalculating -1 ${event.detail.customerTrainingPlanDetailsId}");
nextDetail = trainingPlanRepository.recalculateDetailFixRepeats(_myPlan!.trainingPlanId!, nextDetail);
nextDetail.baseOneRepMax = Common.calculate1RM(nextDetail.weight!, nextDetail.repeats!.toDouble());
} */
else if (nextDetail.weight == -1 && nextDetail.set! == 1) {
print("Nr 3. recalculating -1, set 1 ${eventDetail.customerTrainingPlanDetailsId}");
nextDetail = trainingPlanRepository.recalculateDetailFixRepeatsSet1(_myPlan!.trainingPlanId!, nextDetail, eventDetail);
nextDetail.baseOneRepMax = calculate1RM(nextDetail.weight!, nextDetail.repeats!.toDouble());
} else if (eventDetail.set! == 1 &&
(weightFromPlan == -2 || weightFromPlan == -1) &&
nextDetail.customerTrainingPlanDetailsId! == id + 1 &&
recalculate) {
print("Nr 4. recalculating after the first exercise ${eventDetail.customerTrainingPlanDetailsId}");
nextDetail = trainingPlanRepository.recalculateDetailFixRepeatsSet1(_myPlan!.trainingPlanId!, nextDetail, eventDetail);
nextDetail.baseOneRepMax = calculate1RM(nextDetail.weight!, nextDetail.repeats!.toDouble());
} else if (eventDetail.set! == 1 &&
(weightFromPlan == -2 || weightFromPlan == -1) &&
nextDetail.customerTrainingPlanDetailsId! > id + 1 &&
recalculate) {
print("Nr 5. recalculating after the second exercise ${eventDetail.customerTrainingPlanDetailsId}");
nextDetail = trainingPlanRepository.recalculateDetailFixRepeatsSet1(_myPlan!.trainingPlanId!, nextDetail, eventDetail);
nextDetail.baseOneRepMax = calculate1RM(nextDetail.weight!, nextDetail.repeats!.toDouble());
} else if (id != 0) {
// calculate weight and repeat based on the first baseOneRepMax
if (baseCustomerTrainingPlanDetailsId != 0) {
CustomerTrainingPlanDetails? firstDetail = trainingPlanRepository.getDetailById(_myPlan, baseCustomerTrainingPlanDetailsId);
if (firstDetail != null) {
print("Nr 6. recalculating based on the first exercise $nextDetail");
nextDetail = trainingPlanRepository.recalculateDetailFixRepeatsSet1(_myPlan!.trainingPlanId!, nextDetail, firstDetail);
}
}
}
}
}
}
}
void _onChangeAlternate(TrainingPlanAlternateChange event, Emitter<TrainingPlanState> emit) {
emit(TrainingPlanLoading());
if (_myPlan == null || _myPlan!.details.length == 0) {
emit(TrainingPlanReady());
return;
}
int index = 0;
for (var planDetail in _myPlan!.details) {
int key = planDetail.customerTrainingPlanDetailsId!;
if (_alternatives[key]!.length >= event.index + 1 && _alternatives[key]![event.index].exerciseTypeId == event.detail.exerciseTypeId) {
CustomerTrainingPlanDetails alternative = _alternatives[key]![event.index];
_myPlan!.details[index] = alternative;
changeExerciseInDayNames(planDetail.exerciseTypeId!, planDetail.day!, alternative);
print("Changed alternative $alternative");
}
index++;
}
emit(TrainingPlanReady());
}
void changeExerciseInDayNames(int exerciseTypeId, String dayName, CustomerTrainingPlanDetails alternative) {
if (_myPlan != null && _myPlan!.days[dayName] != null) {
int index = 0;
for (var detail in _myPlan!.days[dayName]!) {
if (detail.exerciseTypeId == exerciseTypeId) {
_myPlan!.days[dayName]![index] = alternative;
}
index++;
}
}
}
void _onSkipExercise(TrainingPlanSkipExercise event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
event.detail.state = ExercisePlanDetailState.skipped;
this.recalculateNextDetails(event.detail);
print(" * Skipping ${event.detail.exerciseTypeId}");
Cache().myTrainingPlan = _myPlan;
await Cache().saveMyTrainingPlan();
if (isDayDone()) {
this.add(TrainingPlanFinishDay());
} else {
emit(TrainingPlanReady());
}
}
void _onSkipEntireExercise(TrainingPlanSkipEntireExercise event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
List<CustomerTrainingPlanDetails> list = getAllDetailsSameExercise(event.detail);
list.forEach((element) {
if (!element.state.equalsTo(ExercisePlanDetailState.finished)) {
element.state = ExercisePlanDetailState.skipped;
}
Cache().myTrainingPlan = _myPlan;
});
await Cache().saveMyTrainingPlan();
if (isDayDone()) {
this.add(TrainingPlanFinishDay());
} else {
emit(TrainingPlanReady());
}
}
void _onFinishDropSet(TrainingPlanFinishDropset event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
event.detail.state = ExercisePlanDetailState.finished;
emit(TrainingPlanReady());
}
void _onFinishDay(TrainingPlanFinishDay event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
celebrating = true;
Track().track(TrackingEvent.training_plan_finished);
emit(TrainingPlanDayFinished());
}
void _onChangeCancel(TrainingPlanChangeCancel event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
print("Backup $_backupDetail");
if (_backupDetail != null) {
event.detail.repeats = _backupDetail!.repeats;
event.detail.weight = _backupDetail!.weight;
}
emit(TrainingPlanReady());
}
void _onCustomLoad(TrainingPlanAddLoad event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
addNewPlan();
_myDetail = CustomerTrainingPlanDetails();
_myDetail!.exerciseType = event.exerciseType;
_myDetail!.exerciseTypeId = event.exerciseType.exerciseTypeId;
_myDetail!.repeats = 12;
_myDetail!.weight = 30;
_myDetail!.set = 3;
_myDetail!.parallel = false;
_myDetail!.day = "";
_myDetail!.restingTime = 2;
_myDetail!.state = ExercisePlanDetailState.start;
if (_myDetail!.exerciseType!.unitQuantityUnit != null) {
_myDetail = trainingPlanRepository.getCalculatedWeightRepeats(event.exerciseType.exerciseTypeId, _myDetail!);
} else {
_myDetail!.weight = 0;
}
Track().track(TrackingEvent.training_plan_custom, eventValue: event.exerciseType.name);
emit(TrainingPlanReady());
}
void _onDeleteExerciseType(TrainingPlanDeleteExerciseType event, Emitter<TrainingPlanState> emit) async {
if (_myPlan == null || _myPlan!.details.isEmpty) {
throw Exception("No MyPlan");
}
emit(TrainingPlanLoading());
CustomerTrainingPlanDetails? remove;
for (var detail in _myPlan!.details) {
if (event.exerciseType.exerciseTypeId == detail.exerciseTypeId) {
remove = detail;
break;
}
}
if (remove != null) {
_myPlan!.details.remove(remove);
}
event.exerciseType.trainingPlanState = ExerciseTypeTrainingPlanState.none;
emit(TrainingPlanReady());
}
/// _onWeightChange
/// change the weight of the actual [CustomerTrainingPlanDetails] from the UI
///
/// event: TrainingPlanWeightChange
void _onCustomWeightChange(TrainingPlanWeightChange event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanExerciseLoading());
event.detail.weight = event.weight;
emit(TrainingPlanExerciseReady());
emit(TrainingPlanReady());
}
void _onCustomPlanSetChange(TrainingPlanSetChange event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
event.detail.set = event.set;
emit(TrainingPlanReady());
}
void _onCustomPlanRepeatChange(TrainingPlanRepeatsChange event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
event.detail.repeats = event.repeats;
emit(TrainingPlanReady());
}
void _onCustomPlanAddExerciseType(TrainingPlanAddExerciseType event, Emitter<TrainingPlanState> emit) async {
if (_myDetail == null) {
throw Exception("Create new Detail");
}
emit(TrainingPlanLoading());
_myDetail!.exerciseType!.trainingPlanState = ExerciseTypeTrainingPlanState.added;
_myDetail!.customerTrainingPlanDetailsId = _myPlan!.details.length + 1;
_myPlan!.details.add(this._myDetail!);
emit(TrainingPlanReady());
}
void _onRestarting(TrainingPlanGoToRestart event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
restarting = true;
emit(TrainingPlanDayReadyToRestart());
}
void _onCreateException(TrainingPlanCreateException event, Emitter<TrainingPlanState> emit) async {
emit(TrainingPlanLoading());
print("Bloc execption caught: ${event.message}");
emit(TrainingPlanError(message: event.message));
}
/* ***************************************************
* Helper Functions
******************************************************/
void createAlternatives() {
if (_myPlan == null || _myPlan!.details.length == 0 || _myPlan!.trainingPlanId == null) {
return;
}
_alternatives.clear();
TrainingPlanDetail? trainingPlanDetail;
_myTrainingPlan = trainingPlanRepository.getTrainingPlanById(_myPlan!.trainingPlanId!);
_myPlan!.details.forEach((detail) {
if (detail.alternatives.length > 0) {
detail.alternatives.forEach((alternative) {
if (_myTrainingPlan != null) {
for (var planDetail in _myTrainingPlan!.details!) {
if (planDetail.exerciseTypeId == detail.exerciseTypeId!) {
trainingPlanDetail = planDetail;
CustomerTrainingPlanDetails alternativeDetail =
trainingPlanRepository.createAlternativeDetail(_myPlan!, detail, trainingPlanDetail!, alternative.exerciseTypeId);
if (_alternatives[alternativeDetail.customerTrainingPlanDetailsId!] == null) {
_alternatives[alternativeDetail.customerTrainingPlanDetailsId!] = [];
_alternatives[detail.customerTrainingPlanDetailsId!]!.add(detail); // element zero
}
if (!existsAlternativeExercise(detail.customerTrainingPlanDetailsId!, alternativeDetail)) {
_alternatives[alternativeDetail.customerTrainingPlanDetailsId!]!.add(alternativeDetail);
}
}
}
} else {
if (_alternatives[detail.customerTrainingPlanDetailsId!] == null) {
_alternatives[detail.customerTrainingPlanDetailsId!] = [];
_alternatives[detail.customerTrainingPlanDetailsId!]!.add(detail); // element zero
}
}
});
} else {
if (_alternatives[detail.customerTrainingPlanDetailsId!] == null) {
_alternatives[detail.customerTrainingPlanDetailsId!] = [];
}
_alternatives[detail.customerTrainingPlanDetailsId!]!.add(detail);
}
//print(
// "Created alternaties for ${detail.exerciseTypeId} and repeat ${detail.repeats} -- ${_alternatives[detail.customerTrainingPlanDetailsId!]}");
});
}
bool existsAlternativeExercise(int customerTrainingPlanDetailsId, CustomerTrainingPlanDetails alternative) {
bool exists = false;
for (var actual in _alternatives[customerTrainingPlanDetailsId]!) {
if (actual.exerciseTypeId == alternative.exerciseTypeId) {
exists = true;
break;
}
}
return exists;
}
void backupDetail(CustomerTrainingPlanDetails detail) {
if (_backupDetail == null) {
_backupDetail = CustomerTrainingPlanDetails();
}
_backupDetail!.copy(detail);
}
void setTrainingPlanFromCache() {
if (_myPlan == null) {
setMyPlan(Cache().myTrainingPlan);
}
Cache().getTrainingPlans()!.forEach((element) {
if (_myPlan!.trainingPlanId == element.trainingPlanId) {
_myTrainingPlan = element;
}
});
}
void addNewPlan() {
if (Cache().userLoggedIn == null) {
throw Exception("Please log in");
}
if (_myPlan == null) {
_myPlan = CustomerTrainingPlan();
} else {
if (!_myPlan!.type.equalsTo(CustomerTrainingPlanType.custom)) {
_myPlan!.details.clear();
}
}
_myPlan!.trainingPlanId = 0;
_myPlan!.name = "Custom";
_myPlan!.dateAdd = DateTime.now();
_myPlan!.customerId = Cache().userLoggedIn == null ? Cache().userLoggedIn!.customerId : 0;
_myPlan!.type = CustomerTrainingPlanType.custom;
restart();
print("New custom plan: $_myPlan");
}
void restart() {
if (_myPlan == null) {
return;
}
for (var day in dayNames) {
_myPlan!.days[day]!.clear();
}
_myPlan!.details.forEach((element) {
element.state = ExercisePlanDetailState.start;
element.exercises.clear();
});
dayNames.clear();
Cache().myTrainingPlan = _myPlan;
Cache().saveMyTrainingPlan();
restarting = false;
print("Restarting finished");
}
void activateDays() {
if (_myPlan == null) {
return;
}
if (isDone100Percent()) {
this.add(TrainingPlanGoToRestart());
print("---------------- TrainingPlanGoToRestart");
}
dayNames.clear();
_myPlan!.days.clear();
String dayName = ".";
String previousDay = ".";
_myPlan!.details.forEach((element) {
if (element.day != null && element.day != dayName) {
dayNames.add(element.day!);
dayName = element.day!;
if (previousDay != ".") {
this.addExtraExerciseType("Stretching", previousDay);
}
}
if (_myPlan!.days[dayName] == null) {
if (dayName == ".") {
dayName = "";
}
_myPlan!.days[dayName] = [];
this.addExtraExerciseType("Warming Up", dayName);
previousDay = dayName;
}
_myPlan!.days[dayName]!.add(element);
});
this.addExtraExerciseType("Stretching", previousDay);
if (dayNames.length == 0) {
dayName = "";
dayNames.add(dayName);
_myPlan!.days[dayName] = [];
_myPlan!.days[dayName]!.addAll(_myPlan!.details);
}
getActiveDayIndex();
createAlternatives();
}
void activateTrainingPlanDays() {
if (_myTrainingPlan == null || _myTrainingPlan!.details == null) {
return;
}
trainingPlanDayNames.clear();
String dayName = ".";
_myTrainingPlan!.details!.forEach((element) {
if (element.day != null && element.day != dayName) {
trainingPlanDayNames.add(element.day!);
dayName = element.day!;
}
});
if (trainingPlanDayNames.length == 0) {
dayName = "";
trainingPlanDayNames.add(dayName);
}
}
List<TrainingPlanDetail> trainingPlanDetailSummary(TrainingPlan plan, String dayName) {
List<TrainingPlanDetail> details = [];
TrainingPlanDetail? prev;
plan.details!.forEach((element) {
if (prev == null || element.exerciseTypeId != prev!.exerciseTypeId) {
if (element.day! == dayName) {
element.summary = getSummary(element);
details.add(element);
}
prev = element;
}
});
return details;
}
List<TrainingPlanDetail> getAllTrainingPlanDetailsSameExercise(TrainingPlanDetail detail) {
List<TrainingPlanDetail> list = [];
getMyTrainingPlan()!.details!.forEach((element) {
if (detail.exerciseTypeId == element.exerciseTypeId) {
list.add(element);
}
});
return list;
}
String getSummary(TrainingPlanDetail detail) {
String summary = "";
List<TrainingPlanDetail> details = getAllTrainingPlanDetailsSameExercise(detail);
int index = 0;
String quantities = "";
details.forEach((element) {
String delimiter = ", ";
if (index == 0) {
delimiter = "";
}
if (element.repeats == -1) {
quantities += delimiter + " MAX ";
} else {
quantities += delimiter + "${element.repeats}";
}
index++;
});
//quantities += " / ? kg";
summary = quantities;
return summary;
}
void addExtraExerciseType(String name, String dayName) {
if (Cache().getExerciseTypes() == null) {
return;
}
for (var exerciseType in Cache().getExerciseTypes()!) {
if (exerciseType.name == name) {
CustomerTrainingPlanDetails detail = CustomerTrainingPlanDetails();
detail.customerTrainingPlanDetailsId = 0;
detail.trainingPlanDetailsId = 0;
detail.exerciseTypeId = exerciseType.exerciseTypeId;
detail.repeats = 1;
detail.set = 1;
detail.day = "";
detail.parallel = false;
detail.restingTime = 0;
detail.exerciseType = exerciseType;
detail.state = ExercisePlanDetailState.extra;
if (_myPlan!.days[dayName] == null) {
_myPlan!.days[dayName] = [];
}
_myPlan!.days[dayName]!.add(detail);
break;
}
}
}
CustomerTrainingPlanDetails? getTrainingPlanDetail(int trainingPlanDetailsId) {
CustomerTrainingPlanDetails? detail;
if (_myPlan == null || _myPlan!.details.isEmpty) {
return null;
}
for (final det in this._myPlan!.details) {
if (det.customerTrainingPlanDetailsId == trainingPlanDetailsId) {
detail = det;
break;
}
}
return detail;
}
int? getActualWorkoutTreeId(int exerciseTypeId) {
final WorkoutMenuTree? workoutTree = this.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(exerciseTypeId);
if (workoutTree == null) {
return null;
}
return workoutTree.id;
}
String getActualImageName(int exerciseTypeId) {
if (exerciseTypeId <= 0) {
return "";
}
final WorkoutMenuTree? workoutTree = this.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(exerciseTypeId);
if (workoutTree == null) {
return "";
}
return workoutTree.imageName;
}
int getStep(CustomerTrainingPlanDetails detail) {
List<CustomerTrainingPlanDetails> details = getAllDetailsSameExercise(detail);
int step = 0;
details.forEach((element) {
if (element.exercises.length < element.set! && element.exercises.length > 0) {
step = element.exercises.length;
}
});
step++;
//print("STEP: $step ");
return step;
}
int getHighlightStep(CustomerTrainingPlanDetails detail) {
List<CustomerTrainingPlanDetails> details = getAllDetailsSameExercise(detail);
int step = 0;
details.forEach((element) {
//print("Highlight element $element");
if (element.exercises.length >= element.set!) {
step++;
}
});
//print("Highlight step: $step ");
return step;
}
CustomerTrainingPlanDetails? getNext() {
if (_myPlan == null || _myPlan!.details.isEmpty) {
return null;
}
CustomerTrainingPlanDetails? next;
int minStep = 99;
for (final detail in this._myPlan!.details) {
if (!detail.state.equalsTo(ExercisePlanDetailState.finished)) {
final day = dayNames[this.activeDayIndex];
if (detail.exercises.isEmpty && !detail.state.equalsTo(ExercisePlanDetailState.skipped) && day == detail.day) {
next = detail;
minStep = 1;
break;
} else {
final int step = detail.exercises.length;
if (step < minStep &&
step < detail.set! &&
!isAllDetailsSameExerciseFinished(detail) &&
!detail.state.equalsTo(ExercisePlanDetailState.skipped) &&
day == detail.day) {
next = detail;
minStep = step;
//if (detail.parallel != true) {
break;
//}
}
}
}
}
//print("Next detail $next");
if (next != null) {
//this.recalculateNextDetails(next);
}
return next;
}
bool isStarted() {
if (_myPlan == null || _myPlan!.details.isEmpty) {
return false;
}
if (_myPlan!.details[0].state == ExercisePlanDetailState.start) {
return false;
} else {
return true;
}
}
bool isDayDone() {
bool isDone = true;
final String day = dayNames[activeDayIndex];
for (var detail in _myPlan!.days[day]!) {
//print("daydone ${detail.state}");
if (!detail.state.equalsTo(ExercisePlanDetailState.extra) &&
!detail.state.equalsTo(ExercisePlanDetailState.finished) &&
!detail.state.equalsTo(ExercisePlanDetailState.skipped)) {
isDone = false;
}
}
print("Is Day '$day' done: $isDone");
return isDone;
}
double getOffset() {
double offset = 5;
if (_myPlan == null) {
return offset;
}
int indexInProgress = 0;
int indexInStart = 0;
final String day = dayNames[this.activeDayIndex];
CustomerTrainingPlanDetails? prev;
for (var detail in _myPlan!.days[day]!) {
//print("Offset detail $detail");
if (detail.state == ExercisePlanDetailState.inProgress || detail.state == ExercisePlanDetailState.start) {
prev = detail;
break;
}
if (prev != null && prev.exerciseTypeId != detail.exerciseTypeId || detail.state == ExercisePlanDetailState.extra) {
//print(" --- offset + 1");
indexInStart++;
indexInProgress++;
}
prev = detail;
}
double index = indexInStart > indexInProgress ? indexInStart.toDouble() : indexInProgress.toDouble();
offset = 325 * index;
print("Offset: $offset day: $day ($indexInStart, $indexInProgress)");
return offset;
}
bool isDone100Percent() {
bool done = true;
if (_myPlan == null || _myPlan!.details.isEmpty) {
return false;
}
_myPlan!.details.forEach((element) {
if (!element.state.equalsTo(ExercisePlanDetailState.finished) && !element.state.equalsTo(ExercisePlanDetailState.skipped)) {
done = false;
}
});
return done;
}
int getActiveDayIndex() {
activeDayIndex = 0;
if (restarting) {
return 0;
}
if (_myPlan == null || _myPlan!.details.isEmpty) {
return 0;
}
if (dayNames.isEmpty || dayNames.length == 1) {
activeDayIndex = 0;
return 0;
}
for (var day in dayNames) {
if (_myPlan!.days[day] == null) {
throw Exception("Wrong activated day: $day does not exist");
}
bool isDone = true;
_myPlan!.days[day]!.forEach((element) {
if (!element.state.equalsTo(ExercisePlanDetailState.finished) && !element.state.equalsTo(ExercisePlanDetailState.skipped)) {
isDone = false;
}
});
if (!isDone) {
break;
}
activeDayIndex++;
}
if (activeDayIndex >= dayNames.length) {
activeDayIndex = 0;
this.add(TrainingPlanGoToRestart());
print("---------------- TrainingPlanGoToRestart");
}
print("ActiveDayIndex $activeDayIndex");
return activeDayIndex;
}
String getCustomAddSummary() {
String summary = "";
if (_myDetail == null || _myDetail!.set == null || _myDetail!.repeats == null) {
return summary;
}
summary = getMyDetail()!.set!.toStringAsFixed(0) + " x " + getMyDetail()!.repeats!.toStringAsFixed(0);
return summary;
}
String getExerciseName(Locale locale) {
String exerciseName = "";
if (_myDetail == null || _myDetail!.exerciseType == null) {
return exerciseName;
}
exerciseName = AppLanguage().appLocal == Locale("en") ? getMyDetail()!.exerciseType!.name : getMyDetail()!.exerciseType!.nameTranslation;
return exerciseName;
}
String getWeightByExerciseType(ExerciseType exerciseType) {
double weight = 0;
if (_myPlan == null || _myPlan!.details.isEmpty) {
return weight.toStringAsFixed(0);
}
for (var detail in _myPlan!.details) {
if (exerciseType.exerciseTypeId == detail.exerciseTypeId) {
weight = detail.weight!;
break;
}
}
int decimal = weight % weight.round() == 0 ? 0 : 1;
return weight.toStringAsFixed(decimal);
}
String getSetByExerciseType(ExerciseType exerciseType) {
int value = 0;
if (_myPlan == null || _myPlan!.details.isEmpty) {
return value.toStringAsFixed(0);
}
for (var detail in _myPlan!.details) {
if (exerciseType.exerciseTypeId == detail.exerciseTypeId) {
value = detail.set!;
break;
}
}
return value.toStringAsFixed(0);
}
String getRepeatsByExerciseType(ExerciseType exerciseType) {
int value = 0;
if (_myPlan == null || _myPlan!.details.isEmpty) {
return value.toStringAsFixed(0);
}
for (var detail in _myPlan!.details) {
if (exerciseType.exerciseTypeId == detail.exerciseTypeId) {
value = detail.repeats!;
break;
}
}
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;
}
List<CustomerTrainingPlanDetails> getAllDetailsSameExercise(CustomerTrainingPlanDetails detail) {
List<CustomerTrainingPlanDetails> list = [];
getMyPlan()!.details.forEach((element) {
if (detail.exerciseTypeId == element.exerciseTypeId) {
list.add(element);
}
});
return list;
}
bool isAllDetailsSameExerciseFinished(CustomerTrainingPlanDetails detail) {
bool allFinished = true;
List<CustomerTrainingPlanDetails> list = getAllDetailsSameExercise(detail);
//print("SAME count: ${list.length}");
for (var listDetail in list) {
//print("SAME $listDetail");
if (listDetail.exercises.length >= listDetail.set!) {
listDetail.state = ExercisePlanDetailState.finished;
}
allFinished = allFinished && (listDetail.exercises.length >= listDetail.set! || listDetail.state.equalsTo(ExercisePlanDetailState.skipped));
}
//print("All finished: $allFinished for ${detail.exerciseTypeId}");
return allFinished;
}
}