import 'package:aitrainer_app/util/app_language.dart'; import 'package:aitrainer_app/util/common.dart'; import 'package:intl/intl.dart'; import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/customer_property.dart'; import 'package:aitrainer_app/model/exercise.dart'; import 'package:aitrainer_app/repository/customer_repository.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/util/diagram_data.dart'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; part 'development_diagram_event.dart'; part 'development_diagram_state.dart'; enum DiagramDataSource { customerProperty, exercise } extension DiagramDataSourceExt on DiagramDataSource { String toStr() => this.toString().split(".").last; bool equalsTo(DiagramDataSource filter) => this.toString() == filter.toString(); bool equalsStringTo(String filter) => this.toString() == filter; } enum DiagramDateFilter { daily, monthly, weekly, yearly } extension DiagramDateFilterExt on DiagramDateFilter { String toStr() => this.toString().split(".").last; bool equalsTo(DiagramDateFilter filter) => this.toString() == filter.toString(); bool equalsStringTo(String filter) => this.toString() == filter; } enum DiagramGroup { none, sumMass, oneRepMax, percent } extension DiagramGroupExt on DiagramDateFilter { String toStr() => this.toString().split(".").last; bool equalsTo(DiagramGroup filter) => this.toString() == filter.toString(); bool equalsStringTo(String filter) => this.toString() == filter; } class DevelopmentDiagramBloc extends Bloc with Common { DiagramDateFilter dateFilter = DiagramDateFilter.monthly; DiagramGroup group = DiagramGroup.sumMass; final List diagramData = []; CustomerRepository? customerRepository; ExerciseRepository? exerciseRepository; String? propertyName; int? exerciseTypeId; final String diagramTitle; bool isGroup = true; DevelopmentDiagramBloc({required this.diagramTitle, this.customerRepository, this.exerciseRepository, this.propertyName, this.exerciseTypeId}) : super(DevelopmentDiagramInitial()) { _init(); on(_onLoad); on(_onChangeDateFormat); on(_onChangeGroup); } void _onLoad(DevelopmentDiagramLoad event, Emitter emit) { emit(DevelopmentDiagramLoading()); if (Cache().userLoggedIn == null) { emit(DevelopmentDiagramError(message: "Please log in")); return; } emit(DevelopmentDiagramReady()); } void _init() { if (customerRepository != null) { final List properties = this.customerRepository!.getAllCustomerPropertyByName(this.propertyName!); this.fillDataCustomerProperty(properties, this.dateFilter); this.isGroup = false; } else { this.isGroup = true; this.getExerciseData(); } this.dateFilter = DiagramDateFilter.monthly; } void _onChangeDateFormat(DevelopmentDiagramChangeDateFormat event, Emitter emit) { emit(DevelopmentDiagramLoading()); this.dateFilter = event.dateFilter; print("Filter: ${this.dateFilter} - property: ${this.propertyName}"); if (customerRepository != null) { final List properties = this.customerRepository!.getAllCustomerPropertyByName(this.propertyName!); this.fillDataCustomerProperty(properties, this.dateFilter); } else { this.getExerciseData(); } emit(DevelopmentDiagramReady()); } void _onChangeGroup(DevelopmentDiagramChangeGroup event, Emitter emit) { emit(DevelopmentDiagramLoading()); this.group = event.group; this.getExerciseData(); emit(DevelopmentDiagramReady()); } void getExerciseData() { this.diagramData.clear(); this.getChartData(); } List getChartData() { List? exercises = exerciseRepository!.getExerciseList(); List _exercises = []; if (this.exerciseTypeId != null) { exercises!.forEach((element) { if (element.exerciseTypeId == this.exerciseTypeId) { _exercises.add(element); } }); } _exercises = sort(_exercises, true); GroupDate groupDate = GroupDate(inputList: _exercises, outputList: this.diagramData); groupDate.dateRate = this.dateFilter; groupDate.diagramType = this.group; groupDate.iteration(); return this.diagramData; } List sort(List _exercises, bool asc) { _exercises.sort((a, b) { var aDateId = a.exerciseTypeId.toString() + "_" + a.datePart.toString(); var bDateId = b.exerciseTypeId.toString() + "_" + b.datePart.toString(); return asc ? aDateId.compareTo(bDateId) : bDateId.compareTo(aDateId); }); return _exercises; } void fillDataCustomerProperty(List customerProperties, DiagramDateFilter filter) { this.diagramData.clear(); this.dateFilter = filter; customerProperties.sort((a, b) => a.dateAdd!.compareTo(b.dateAdd!) > 0 ? 1 : -1); double avg = 0; String? preFilter; if (this.dateFilter == DiagramDateFilter.daily) { preFilter = customerProperties[0].dateYmd; } else if (this.dateFilter == DiagramDateFilter.weekly) { preFilter = customerProperties[0].dateYmd; } else if (this.dateFilter == DiagramDateFilter.monthly) { preFilter = customerProperties[0].dateYm; } else if (this.dateFilter == DiagramDateFilter.yearly) { preFilter = customerProperties[0].dateY; } int counter = 0; customerProperties.forEach((element) { String? condition; if (this.dateFilter == DiagramDateFilter.daily) { condition = element.dateYmd; } else if (this.dateFilter == DiagramDateFilter.monthly) { condition = element.dateYm; } else if (this.dateFilter == DiagramDateFilter.weekly) { condition = element.dateYm; } else if (this.dateFilter == DiagramDateFilter.yearly) { condition = element.dateY; } if (preFilter != condition) { int count = counter == 0 ? 1 : counter; DiagramData data = DiagramData(preFilter!, avg / count); //print("Sum: $avg count: $count Data: $data"); diagramData.add(data); counter = 1; preFilter = condition; avg = element.propertyValue; } else { avg += element.propertyValue; counter++; } }); int count = counter == 0 ? 1 : counter; if (preFilter != null) { DiagramData data = DiagramData(preFilter!, avg / count); diagramData.add(data); } print("Diagramdata: --- ${this.diagramData}"); } } class GroupDate extends GroupData with Common { final List inputList; final List outputList; String? _origDatePart; late int _origExerciseTypeId; late Exercise _origExercise; late double _sumQuantity; late double _maxQuantity; late int _countExercises; double? _basePercent; late DiagramGroup diagramType; late DiagramDateFilter dateRate; GroupDate({required this.inputList, required this.outputList}); double getQuantityByDate(Exercise exercise) { double sum = 0; if (this.diagramType == DiagramGroup.sumMass) { if (exercise.unitQuantity != null) { sum = exercise.quantity! * exercise.unitQuantity!; } else { sum = exercise.quantity!; } } else if (this.diagramType == DiagramGroup.oneRepMax) { if (exercise.unitQuantity != null) { sum = calculate1RM(exercise.unitQuantity!, exercise.quantity!); } else { sum = exercise.quantity!; } } else if (this.diagramType == DiagramGroup.percent) { if (exercise.unitQuantity != null) { sum = calculate1RM(exercise.unitQuantity!, exercise.quantity!); if (_basePercent == null) { _basePercent = sum; } sum = (sum / this._basePercent!) * 100; } else { sum = exercise.quantity!; if (_basePercent == null) { _basePercent = sum; } sum = (sum / this._basePercent!) * 100; } } return sum; } @override void addTempData(Exercise exercise) { double newQuantity = getQuantityByDate(exercise); _sumQuantity = _sumQuantity + newQuantity; if (_maxQuantity < newQuantity) { _maxQuantity = newQuantity; } _countExercises = _countExercises + 1; _origDatePart = getDatePart(exercise.dateAdd!, dateRate); _origExerciseTypeId = exercise.exerciseTypeId!; _origExercise = exercise; } @override bool checkNewType(Exercise exercise) { String exerciseDatePart = getDatePart(exercise.dateAdd!, dateRate); return _origDatePart == null || _origDatePart != exerciseDatePart || _origExerciseTypeId != exercise.exerciseTypeId; } String getDatePart(DateTime date, DiagramDateFilter dateRate) { String datePart = DateFormat('yy.MM.dd', AppLanguage().appLocal.toString()).format(date); if (dateRate == DiagramDateFilter.weekly) { datePart = weekNumber(date).toString(); } else if (dateRate == DiagramDateFilter.monthly) { datePart = DateFormat('yy.MM', AppLanguage().appLocal.toString()).format(date); } else if (dateRate == DiagramDateFilter.yearly) { datePart = DateFormat('y', AppLanguage().appLocal.toString()).format(date); } else if (dateRate == DiagramDateFilter.daily) { datePart = DateFormat('yy.MM.dd', AppLanguage().appLocal.toString()).format(date); } return datePart; } @override void iteration() { this.resetTemp(); Exercise? tempExercise; inputList.forEach((element) { tempExercise = element; if (this.checkNewType(element)) { if (_origDatePart == null) { this.addTempData(element); } else { this.temp2Output(_origExercise); this.resetTemp(); this.addTempData(element); } } else { this.addTempData(element); } }); if (tempExercise != null) { this.temp2Output(tempExercise!); } } @override void temp2Output(Exercise exercise) { if (exercise.unitQuantity == null) { return; } Exercise newExercise = exercise.copy(); newExercise.datePart = _origDatePart; if (this.diagramType == DiagramGroup.oneRepMax || this.diagramType == DiagramGroup.percent) { newExercise.calculated = _maxQuantity; } else { newExercise.calculated = _sumQuantity / _countExercises; } DiagramData data = DiagramData(newExercise.datePart!, newExercise.calculated); print("chart add $data"); outputList.add(data); } @override void resetTemp() { _countExercises = 0; _sumQuantity = 0; _maxQuantity = 0; } }