wt1.1.2d ProgressInfo+

This commit is contained in:
Bossanyi Tibor
2020-10-09 07:54:54 +02:00
parent 0cdc3a9d24
commit 35f0d0042f
66 changed files with 1615 additions and 576 deletions
@@ -0,0 +1,43 @@
import 'dart:async';
import 'package:aitrainer_app/repository/exercise_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 'body_development_event.dart';
part 'body_development_state.dart';
class BodyDevelopmentBloc extends Bloc<BodyDevelopmentEvent, BodyDevelopmentState> {
final WorkoutTreeRepository workoutTreeRepository;
final ExerciseRepository exerciseRepository = ExerciseRepository();
List<int> radarTicks = List();
List<String> radarFeatures = List();
List<List<int>> radarData = List();
@override
BodyDevelopmentBloc({this.workoutTreeRepository}): super(BodyDevelopmentInitial());
Future<void> getData() async{
radarTicks = [20, 40, 60, 80, 100];
radarFeatures = ["Mell", "Bicepsz", "Tricepsz", "Hát", "Váll"];
radarData = [
[80, 95, 45, 67, 83]
];
}
@override
Stream<BodyDevelopmentState> mapEventToState(BodyDevelopmentEvent event) async* {
try {
if (event is BodyDevelopmentLoad) {
yield BodyDevelopmentLoading();
await getData();
yield BodyDevelopmentReady();
}
} on Exception catch (e) {
yield BodyDevelopmentError(message: e.toString());
}
}
}
@@ -0,0 +1,12 @@
part of 'body_development_bloc.dart';
@immutable
abstract class BodyDevelopmentEvent extends Equatable{
const BodyDevelopmentEvent();
@override
List<Object> get props => [];
}
class BodyDevelopmentLoad extends BodyDevelopmentEvent {
const BodyDevelopmentLoad();
}
@@ -0,0 +1,30 @@
part of 'body_development_bloc.dart';
@immutable
abstract class BodyDevelopmentState extends Equatable {
const BodyDevelopmentState();
@override
List<Object> get props => [];
}
class BodyDevelopmentInitial extends BodyDevelopmentState {
const BodyDevelopmentInitial();
}
class BodyDevelopmentLoading extends BodyDevelopmentState {
const BodyDevelopmentLoading();
}
class BodyDevelopmentReady extends BodyDevelopmentState {
const BodyDevelopmentReady();
}
class BodyDevelopmentError extends BodyDevelopmentState {
final String message;
const BodyDevelopmentError({this.message});
@override
List<Object> get props => [message];
}
+1
View File
@@ -95,6 +95,7 @@ class CustomerChangeFormBloc extends FormBloc<String, String> {
birthYearField.close();
weightField.close();
genderField.close();
goalField.close();
return super.close();
}
@@ -8,6 +8,7 @@ import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/repository/workout_tree_repository.dart';
import 'package:aitrainer_app/util/calculate.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/group_data.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
@@ -20,19 +21,240 @@ part 'development_by_muscle_event.dart';
part 'development_by_muscle_state.dart';
class DateRate {
static String daily = "daily";
static String weekly = "weekly";
static String monthly = "monthly";
static String yearly = "yearly";
}
class DiagramType {
static String sumMass = "sumMass";
static String oneRepMax = "oneRepMax";
static String percent = "percent";
}
/*
=========== GROUPDATE CLASS
*/
class GroupDate extends GroupData with Calculate, Common {
final List<dynamic> inputList;
final List<dynamic> outputList;
String _origDatePart;
int _origExerciseTypeId;
Exercise _origExercise;
double _sumQuantity;
double _maxQuantity;
int _countExercises;
String diagramType;
String dateRate;
GroupDate({this.inputList, this.outputList});
double getQuantityByDate(Exercise exercise) {
double sum = 0;
if ( this.diagramType == DiagramType.sumMass ) {
if ( exercise.unitQuantity != null ) {
sum = exercise.quantity * exercise.unitQuantity;
} else {
sum = exercise.quantity;
}
} else if ( this.diagramType == DiagramType.oneRepMax || this.diagramType == DiagramType.percent ) {
if ( exercise.unitQuantity != null ) {
sum = calculate1RM(exercise.quantity, exercise.unitQuantity);
} else {
sum = exercise.quantity;
}
}
return sum;
}
@override
void addTempData(Exercise exercise) {
double newQuantity = getQuantityByDate(exercise);
_sumQuantity += newQuantity;
if (_maxQuantity < newQuantity) {
_maxQuantity = newQuantity;
}
_countExercises++;
_origDatePart = getDatePart(exercise.dateAdd, dateRate);
_origExerciseTypeId = exercise.exerciseTypeId;
_origExercise = exercise;
}
@override
bool checkNewType(Exercise exercise) {
String exerciseDatePart = getDatePart(exercise.dateAdd, dateRate);
return _origDatePart != exerciseDatePart || _origExerciseTypeId != exercise.exerciseTypeId;
}
@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) {
Exercise newExercise = exercise.copy();
newExercise.datePart = _origDatePart;
if (this.diagramType == DiagramType.oneRepMax || this.diagramType == DiagramType.percent) {
newExercise.calculated = _maxQuantity;
} else {
newExercise.calculated = _sumQuantity / _countExercises;
}
outputList.add(newExercise);
}
@override
void resetTemp() {
_countExercises = 0;
_sumQuantity = 0;
_maxQuantity = 0;
}
}
/*
=========== CHART DATA CLASS
*/
class GroupChart extends GroupData with Calculate {
final List<dynamic> inputList;
LinkedHashMap<int, ChartDataExtended> outputList = LinkedHashMap();
int _origExerciseTypeId;
double _minData = 999999999999;
double _maxData = 0;
List<BarChartGroupData> _chartData;
double _basePercent;
String diagramType = DiagramType.sumMass;
GroupChart({this.inputList, this.outputList});
double getBasePercent(Exercise exercise) {
if ( exercise.unitQuantity != null ) {
this._basePercent = calculate1RM(exercise.quantity, exercise.unitQuantity);
} else {
this._basePercent = exercise.quantity;
}
return this._basePercent;
}
double getDiagramValue(Exercise exercise) {
double value = 0;
if ( diagramType == DiagramType.percent) {
if ( exercise.unitQuantity != null ) {
double oneRepMax = calculate1RM(exercise.quantity, exercise.unitQuantity);
value = (oneRepMax / this._basePercent) * 100;
} else {
value = (exercise.quantity / this._basePercent ) * 100;
}
} else if ( diagramType == DiagramType.oneRepMax || diagramType == DiagramType.sumMass) {
value = exercise.calculated;
}
return value;
}
@override
void addTempData(Exercise exercise) {
double diagramValue = this.getDiagramValue(exercise);
if (_maxData < diagramValue) {
_maxData = diagramValue;
}
if (_minData > diagramValue) {
_minData = diagramValue;
}
BarChartGroupData data = BarChartGroupData(
x: exercise.dateAdd.millisecondsSinceEpoch,
barRods: [
BarChartRodData(y: diagramValue, width: 12, color: Colors.lightBlue)
]
);
_chartData.add(data);
_origExerciseTypeId = exercise.exerciseTypeId;
}
@override
bool checkNewType(Exercise exercise) {
return _origExerciseTypeId != exercise.exerciseTypeId;
}
@override
void iteration() {
this.resetTemp();
Exercise tempExercise;
inputList.forEach((element) {
tempExercise = element;
if ( this.checkNewType(element)) {
if ( _origExerciseTypeId == null ) {
_basePercent = getBasePercent(element);
this.addTempData(element);
} else {
this.temp2Output(element);
this.resetTemp();
_basePercent = getBasePercent(element);
this.addTempData(element);
}
} else {
this.addTempData(element);
}
});
if ( tempExercise != null) {
this.temp2Output(tempExercise);
}
}
@override
void temp2Output(Exercise exercise) {
double dInterval = ((_maxData + _minData) / 8).roundToDouble();
int gridInterval = (dInterval / 3).floor();
ChartDataExtended extended;
if ( outputList[_origExerciseTypeId] == null ) {
extended = ChartDataExtended(
data: _chartData, interval: dInterval, gridInterval: gridInterval);
outputList[_origExerciseTypeId] = extended;
} else {
extended = outputList[_origExerciseTypeId];
_chartData.forEach((element) {
extended.data.add(element);
});
}
}
@override
void resetTemp() {
_minData = 999999999999;
_maxData = 0;
_chartData = List();
}
}
class ChartDataExtended {
final List<BarChartGroupData> data;
final double interval;
@@ -40,16 +262,29 @@ class ChartDataExtended {
const ChartDataExtended({this.data, this.interval, this.gridInterval});
Map<String, dynamic> toJson() =>
{
"data": data.toString(),
"interval" : interval.toString(),
"gridInterval" : gridInterval,
Map<String, dynamic> toJson() {
List listBarChartData = List();
data.forEach((element) {
element.barRods.forEach((rods) {
var barChartData = {
'x': element.x,
'y': rods.y,
};
listBarChartData.add(barChartData);
});
});
var chartData = {
"data": listBarChartData.toString(),
"interval": interval.toString(),
"gridInterval": gridInterval,
};
return chartData;
}
}
class DevelopmentByMuscleBloc extends Bloc<DevelopmentByMuscleEvent, DevelopmentByMuscleState> with Calculate, Common {
class DevelopmentByMuscleBloc extends Bloc<DevelopmentByMuscleEvent, DevelopmentByMuscleState> with Calculate {
final WorkoutTreeRepository workoutTreeRepository;
final ExerciseRepository exerciseRepository = ExerciseRepository();
LinkedHashMap<int, ChartDataExtended> listChartData = LinkedHashMap();
@@ -81,57 +316,21 @@ class DevelopmentByMuscleBloc extends Bloc<DevelopmentByMuscleEvent, Development
void getChartData() {
List<Exercise> exercises = exerciseRepository.getExerciseList();
exercises.sort( (a, b) => a.exerciseTypeId.compareTo(b.exerciseTypeId));
//print("-- Start calculate --- ");
exercises = this.groupByDate(exercises);
int origExerciseTypeId = 0;
int x = 0;
chartData = List();
double maxData = 0;
double minData = 9999999999999;
exercises.forEach((exercise) {
if ( exercise.unitQuantity != null ) {
if (origExerciseTypeId != exercise.exerciseTypeId && diagramType == DiagramType.percent) {
this.basePercent = getBasePercent(exercise);
}
double diagramValue = this.getDiagramValue(exercise);
exercises = sort(exercises, true);
/* exercises.forEach((exercise) {
print ("Chart exercise " + exercise.toJsonDatePart().toString());
});*/
listChartData = LinkedHashMap();
GroupChart groupChart = GroupChart(inputList: exercises, outputList: listChartData);
groupChart.diagramType = this.diagramType;
groupChart.iteration();
listChartData = groupChart.outputList;
if (maxData < diagramValue) {
maxData = diagramValue;
}
if (minData > diagramValue) {
minData = diagramValue;
}
//print("exercise " + exercise.exerciseTypeId.toString() + " d " + getDateFormat(exercise.dateAdd) + " mass " + sumMass.toString());
//print("date " + exercise.dateAdd.toIso8601String() + " epoch " + exercise.dateAdd.millisecondsSinceEpoch.toString() );
BarChartGroupData data = BarChartGroupData(
x: exercise.dateAdd.millisecondsSinceEpoch,
barRods: [
BarChartRodData(y: diagramValue, width: 12, color: Colors.lightBlue)
]
);
if (origExerciseTypeId != exercise.exerciseTypeId) {
if (origExerciseTypeId == 0) {
origExerciseTypeId = exercise.exerciseTypeId;
chartData.add(data);
} else {
double dInterval = ((maxData + minData) / 8).roundToDouble();
int gridInterval = (dInterval / 3).floor();
ChartDataExtended extended = ChartDataExtended(
data: chartData, interval: dInterval, gridInterval: gridInterval);
listChartData[origExerciseTypeId] = extended;
maxData = 0;
minData = 9999999999999;
chartData = List();
chartData.add(data);
origExerciseTypeId = exercise.exerciseTypeId;
}
} else {
origExerciseTypeId = exercise.exerciseTypeId;
chartData.add(data);
}
}
});
listChartData.forEach((key, value) {
print ("typeid " + key.toString() + " chardata " + value.toJson().toString());
@@ -139,126 +338,38 @@ class DevelopmentByMuscleBloc extends Bloc<DevelopmentByMuscleEvent, Development
return;
}
String getDatePart(DateTime date) {
String datePart = DateFormat('MM.dd', AppLanguage().appLocal.toString()).format(date);;
if ( this.dateRate == DateRate.weekly ) {
datePart = weekNumber(date).toString();
} else if ( this.dateRate == DateRate.monthly ) {
datePart = DateFormat('MMM', AppLanguage().appLocal.toString()).format(date);
} else if ( this.dateRate == DateRate.yearly ) {
datePart = DateFormat('y', AppLanguage().appLocal.toString()).format(date);
} else if ( this.dateRate == DateRate.daily ) {
datePart = DateFormat('MM.dd', AppLanguage().appLocal.toString()).format(date);
}
return datePart;
}
List<Exercise> groupByDate(List<Exercise> exercises) {
List<Exercise> groupedExercises = List();
String origDatePart;
int countExercises = 0;
double sumQuantity = 0;
double maxQuantity = 0;
Exercise origExercise;
exercises = sort(exercises, false);
exercises.forEach((exercise) {
String exerciseDatePart = getDatePart(exercise.dateAdd);
if ( origExercise != null ) {
if ( origExercise.exerciseTypeId != exercise.exerciseTypeId || origDatePart != exerciseDatePart ) {
Exercise newExercise = origExercise.copy();
newExercise.datePart = origDatePart;
if (this.diagramType == DiagramType.oneRepMax || this.diagramType == DiagramType.percent) {
newExercise.quantity = maxQuantity;
} else {
newExercise.quantity = sumQuantity / countExercises;
}
groupedExercises.add(newExercise);
countExercises = 0;
sumQuantity = 0;
maxQuantity = 0;
}
}
origExercise = exercise;
origDatePart = exerciseDatePart;
double newQuantity = getQuantityByDate(exercise);
sumQuantity += newQuantity;
if (maxQuantity < newQuantity) {
maxQuantity = newQuantity;
}
countExercises++;
print ("Date exercise " + exercise.toJsonDatePart().toString());
});
groupedExercises.forEach((element) {
print("grouped " + element.toJson().toString());
});
GroupDate groupDate = GroupDate(inputList: exercises, outputList: groupedExercises);
groupDate.dateRate = this.dateRate;
groupDate.diagramType = this.diagramType;
groupDate.iteration();
groupedExercises = groupDate.outputList;
/* groupedExercises.forEach((element) {
print("Grouped " + element.toJsonDatePart().toString());
});*/
return groupedExercises;
}
double getQuantityByDate(Exercise exercise) {
double sum = 0;
if ( this.diagramType == DiagramType.sumMass ) {
if ( exercise.unitQuantity != null ) {
sum = exercise.quantity * exercise.unitQuantity;
} else {
sum = exercise.quantity;
}
} else if ( this.diagramType == DiagramType.oneRepMax || this.diagramType == DiagramType.percent ) {
if ( exercise.unitQuantity != null ) {
sum = calculate1RM(exercise.quantity, exercise.unitQuantity);
} else {
sum = exercise.quantity;
}
}
return sum;
}
List<Exercise> sort(List<Exercise> exercises, bool asc) {
exercises.sort( (a, b) {
var aDateId = a.exerciseTypeId.toString() + "_" + a.datePart.toString();
var bDateId = b.exerciseTypeId.toString() + "_" + b.datePart.toString();
double getBasePercent(Exercise exercise) {
if ( exercise.unitQuantity != null ) {
this.basePercent = calculate1RM(exercise.quantity, exercise.unitQuantity);
} else {
this.basePercent = exercise.quantity;
}
//print("Base percent of " + exercise.exerciseTypeId.toString() + ": " + basePercent.toString());
return this.basePercent;
}
double getDiagramValue(Exercise exercise) {
double value = 0;
/*if ( diagramType == DiagramType.sumMass) {
value = exercise.quantity;
if ( exercise.unitQuantity != null ) {
value *= exercise.unitQuantity;
}
} else if ( diagramType == DiagramType.oneRepMax) {
if ( exercise.unitQuantity != null ) {
value = calculate1RM(exercise.quantity, exercise.unitQuantity);
}
} else if ( diagramType == DiagramType.percent) {
if ( exercise.unitQuantity != null ) {
double oneRepMax = calculate1RM(exercise.quantity, exercise.unitQuantity);
value = (oneRepMax / this.basePercent) * 100;
//print("Percent of " + exercise.exerciseTypeId.toString() + ": " + value.toString() + " date " + exercise.dateAdd.toIso8601String() + " 1RM " + oneRepMax.toString());
} else {
value = (exercise.quantity / this.basePercent ) * 100;
}*/
if ( diagramType == DiagramType.percent) {
if ( exercise.unitQuantity != null ) {
double oneRepMax = calculate1RM(exercise.quantity, exercise.unitQuantity);
value = (oneRepMax / this.basePercent) * 100;
//print("Percent of " + exercise.exerciseTypeId.toString() + ": " + value.toString() + " date " + exercise.dateAdd.toIso8601String() + " 1RM " + oneRepMax.toString());
} else {
value = (exercise.quantity / this.basePercent ) * 100;
}
} else {
return exercise.quantity;
}
return value;
return asc ? aDateId.compareTo(bDateId) : bDateId.compareTo(aDateId);
});
return exercises;
}
String getDateFormat(DateTime datetime) {
-1
View File
@@ -1,5 +1,4 @@
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
class ExerciseControlFormBloc extends FormBloc<String, String> {
+5 -1
View File
@@ -1,8 +1,11 @@
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'menu/menu_bloc.dart';
class ExerciseFormBloc extends FormBloc<String, String> {
final ExerciseRepository exerciseRepository;
final MenuBloc menuBloc;
final quantityField = TextFieldBloc(
validators: [
@@ -19,7 +22,7 @@ class ExerciseFormBloc extends FormBloc<String, String> {
final unitQuantityField = TextFieldBloc();
final unitQuantityUnitField = TextFieldBloc();
ExerciseFormBloc({this.exerciseRepository}) {
ExerciseFormBloc({this.exerciseRepository, this.menuBloc}) {
addFieldBlocs(fieldBlocs: [
quantityField,
unitField,
@@ -46,6 +49,7 @@ class ExerciseFormBloc extends FormBloc<String, String> {
emitLoading(progress: 30);
// Emit either Loaded or Error
await exerciseRepository.addExercise();
menuBloc.add(MenuTreeDown(parent: 0));
emitSuccess(canSubmitAgain: false);
} on Exception catch (ex) {
+68 -3
View File
@@ -1,22 +1,72 @@
import 'dart:async';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/repository/workout_tree_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:meta/meta.dart';
part 'menu_event.dart';
part 'menu_state.dart';
class MenuBloc extends Bloc<MenuEvent, MenuState> {
class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans {
final WorkoutTreeRepository menuTreeRepository;
final ExerciseRepository exerciseRepository = ExerciseRepository();
int parent;
WorkoutMenuTree workoutItem;
String infoTitle = "";
String infoText = "";
String infoText2 = "";
String infoText3 = "";
String infoLink = "";
int missingParent = 0;
String missingTreeName = "";
BuildContext context;
MenuBloc({this.menuTreeRepository}) : super(MenuInitial()) {
parent = 0;
}
void setMenuInfo() {
double percent = Cache().getPercentExercises();
if ( context == null ) return;
percent = percent * 100;
print("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!");
}
menuTreeRepository.sortByMuscleType();
missingTreeName = exerciseRepository.nextMissingBaseExercise(menuTreeRepository.sortedTree);
print("Missing " + missingTreeName);
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;
}
@override
Stream<MenuState> mapEventToState(
MenuEvent event,
@@ -25,6 +75,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
if ( event is MenuCreate ) {
yield MenuLoading();
await menuTreeRepository.createTree();
setMenuInfo();
yield MenuReady();
} else if (event is MenuRecreateTree) {
// ie. at language changes
@@ -34,14 +85,28 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
// get child menus or exercises
yield MenuLoading();
parent = event.parent;
workoutItem = event.item;
//print("menuitem " + workoutItem.id.toString() + " parent "+workoutItem.parent.toString());
menuTreeRepository.getBranch(event.parent);
yield MenuReady();
} else if (event is MenuTreeUp) {
yield MenuLoading();
// get parent menus or exercises
parent = event.parent;
menuTreeRepository.getBranch(parent);
workoutItem = menuTreeRepository.getParentItem(parent);
if ( workoutItem != null) {
//print("UP menuitem " + workoutItem.id.toString() + " parent " + workoutItem.parent.toString());
menuTreeRepository.getBranch(workoutItem.parent);
}
yield MenuReady();
} else if (event is MenuTreeJump) {
yield MenuLoading();
parent = event.parent;
workoutItem = menuTreeRepository.getParentItem(parent);
if ( workoutItem != null) {
//print("JUMP menuitem " + workoutItem.id.toString() + " parent " + workoutItem.parent.toString());
menuTreeRepository.getBranch(workoutItem.parent);
}
yield MenuReady();
} else if (event is MenuClickExercise) {
yield MenuLoading();
+13 -3
View File
@@ -16,16 +16,26 @@ class MenuCreate extends MenuEvent {
}
class MenuTreeDown extends MenuEvent {
final WorkoutMenuTree item;
final int parent;
const MenuTreeDown({this.parent});
const MenuTreeDown({this.parent, this.item});
@override
List<Object> get props => [parent];
List<Object> get props => [parent, item];
}
class MenuTreeUp extends MenuEvent {
final int parent;
const MenuTreeUp({this.parent});
final WorkoutMenuTree item;
const MenuTreeUp({this.parent, this.item});
@override
List<Object> get props => [parent, item];
}
class MenuTreeJump extends MenuEvent {
final int parent;
const MenuTreeJump({this.parent});
@override
List<Object> get props => [parent];
-1
View File
@@ -2,7 +2,6 @@ import 'dart:async';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';