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';
+325
View File
@@ -0,0 +1,325 @@
library flutter_radar_chart;
import 'dart:ui';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'dart:math' show pi, cos, sin;
const defaultGraphColors = [
Colors.green,
Colors.blue,
Colors.red,
Colors.orange,
];
class RadarChart extends StatefulWidget {
final List<int> ticks;
final List<String> features;
final List<List<int>> data;
final bool reverseAxis;
final TextStyle ticksTextStyle;
final TextStyle featuresTextStyle;
final Color outlineColor;
final Color axisColor;
final List<Color> graphColors;
final int sides;
const RadarChart({
Key key,
@required this.ticks,
@required this.features,
@required this.data,
this.reverseAxis = false,
this.ticksTextStyle = const TextStyle(color: Colors.grey, fontSize: 12),
this.featuresTextStyle = const TextStyle(color: Colors.black, fontSize: 16),
this.outlineColor = Colors.black,
this.axisColor = Colors.grey,
this.graphColors = defaultGraphColors,
this.sides = 0,
}) : super(key: key);
factory RadarChart.light({
@required List<int> ticks,
@required List<String> features,
@required List<List<int>> data,
bool reverseAxis = false,
bool useSides = false,
}) {
return RadarChart(
ticks: ticks,
features: features,
data: data,
reverseAxis: reverseAxis,
sides: useSides ? features.length : 0);
}
factory RadarChart.dark({
@required List<int> ticks,
@required List<String> features,
@required List<List<int>> data,
bool reverseAxis = false,
bool useSides = false,
}) {
return RadarChart(
ticks: ticks,
features: features,
data: data,
featuresTextStyle: const TextStyle(color: Colors.white, fontSize: 16),
outlineColor: Colors.white,
axisColor: Colors.grey,
reverseAxis: reverseAxis,
sides: useSides ? features.length : 0);
}
@override
_RadarChartState createState() => _RadarChartState();
}
class _RadarChartState extends State<RadarChart>
with SingleTickerProviderStateMixin {
double fraction = 0;
Animation<double> animation;
AnimationController animationController;
@override
void initState() {
super.initState();
animationController = AnimationController(
duration: Duration(milliseconds: 1000), vsync: this);
animation = Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
curve: Curves.fastOutSlowIn,
parent: animationController,
))
..addListener(() {
setState(() {
fraction = animation.value;
});
});
animationController.forward();
}
@override
void didUpdateWidget(RadarChart oldWidget) {
super.didUpdateWidget(oldWidget);
animationController.reset();
animationController.forward();
}
@override
Widget build(BuildContext context) {
return CustomPaint(
size: Size(double.infinity, double.infinity),
painter: RadarChartPainter(
widget.ticks,
widget.features,
widget.data,
widget.reverseAxis,
widget.ticksTextStyle,
widget.featuresTextStyle,
widget.outlineColor,
widget.axisColor,
widget.graphColors,
widget.sides,
this.fraction),
);
}
@override
void dispose() {
animationController.dispose();
super.dispose();
}
}
class RadarChartPainter extends CustomPainter {
final List<int> ticks;
final List<String> features;
final List<List<int>> data;
final bool reverseAxis;
final TextStyle ticksTextStyle;
final TextStyle featuresTextStyle;
final Color outlineColor;
final Color axisColor;
final List<Color> graphColors;
final int sides;
final double fraction;
RadarChartPainter(
this.ticks,
this.features,
this.data,
this.reverseAxis,
this.ticksTextStyle,
this.featuresTextStyle,
this.outlineColor,
this.axisColor,
this.graphColors,
this.sides,
this.fraction,
);
Path variablePath(Size size, double radius, int sides) {
var path = Path();
var angle = (math.pi * 2) / sides;
Offset center = Offset(size.width / 2, size.height / 2);
if (sides < 3) {
// Draw a circle
path.addOval(Rect.fromCircle(
center: Offset(size.width / 2, size.height / 2),
radius: radius,
));
} else {
// Draw a polygon
Offset startPoint = Offset(radius * cos(-pi / 2), radius * sin(-pi / 2));
path.moveTo(startPoint.dx + center.dx, startPoint.dy + center.dy);
for (int i = 1; i <= sides; i++) {
double x = radius * cos(angle * i - pi / 2) + center.dx;
double y = radius * sin(angle * i - pi / 2) + center.dy;
path.lineTo(x, y);
}
path.close();
}
return path;
}
@override
void paint(Canvas canvas, Size size) {
final centerX = size.width / 2.0;
final centerY = size.height / 2.0;
final centerOffset = Offset(centerX, centerY);
final radius = math.min(centerX, centerY) * 0.8;
final scale = radius / ticks.last;
// Painting the chart outline
var outlinePaint = Paint()
..color = outlineColor
..style = PaintingStyle.stroke
..strokeWidth = 2.0
..isAntiAlias = true;
var ticksPaint = Paint()
..color = axisColor
..style = PaintingStyle.stroke
..strokeWidth = 1.0
..isAntiAlias = true;
canvas.drawPath(variablePath(size, radius, this.sides), outlinePaint);
// Painting the circles and labels for the given ticks (could be auto-generated)
// The last tick is ignored, since it overlaps with the feature label
var tickDistance = radius / (ticks.length);
var tickLabels = reverseAxis ? ticks.reversed.toList() : ticks;
if (reverseAxis) {
TextPainter(
text: TextSpan(text: tickLabels[0].toString(), style: ticksTextStyle),
textDirection: TextDirection.ltr,
)
..layout(minWidth: 0, maxWidth: size.width)
..paint(canvas, Offset(centerX, centerY - ticksTextStyle.fontSize));
}
tickLabels
.sublist(
reverseAxis ? 1 : 0, reverseAxis ? ticks.length : ticks.length - 1)
.asMap()
.forEach((index, tick) {
var tickRadius = tickDistance * (index + 1);
canvas.drawPath(variablePath(size, tickRadius, this.sides), ticksPaint);
TextPainter(
text: TextSpan(text: tick.toString(), style: ticksTextStyle),
textDirection: TextDirection.ltr,
)
..layout(minWidth: 0, maxWidth: size.width)
..paint(canvas,
Offset(centerX, centerY - tickRadius - ticksTextStyle.fontSize));
});
// Painting the axis for each given feature
var angle = (2 * pi) / features.length;
features.asMap().forEach((index, feature) {
var xAngle = cos(angle * index - pi / 2);
var yAngle = sin(angle * index - pi / 2);
var featureOffset =
Offset(centerX + radius * xAngle, centerY + radius * yAngle);
canvas.drawLine(centerOffset, featureOffset, ticksPaint);
var featureLabelFontHeight = featuresTextStyle.fontSize;
var featureLabelFontWidth = featuresTextStyle.fontSize - 5;
var labelYOffset = yAngle < 0 ? -featureLabelFontHeight : 0;
var labelXOffset =
xAngle < 0 ? -featureLabelFontWidth * feature.length : 0;
TextPainter(
text: TextSpan(text: feature, style: featuresTextStyle),
textAlign: TextAlign.left,
textDirection: TextDirection.ltr,
)
..layout(minWidth: 0, maxWidth: size.width)
..paint(
canvas,
Offset(featureOffset.dx + labelXOffset,
featureOffset.dy + labelYOffset));
});
// Painting each graph
data.asMap().forEach((index, graph) {
var graphPaint = Paint()
..color = graphColors[index % graphColors.length].withOpacity(0.3)
..style = PaintingStyle.fill;
var graphOutlinePaint = Paint()
..color = graphColors[index % graphColors.length]
..style = PaintingStyle.stroke
..strokeWidth = 2.0
..isAntiAlias = true;
// Start the graph on the initial point
var scaledPoint = scale * graph[0] * fraction;
var path = Path();
if (reverseAxis) {
path.moveTo(centerX, centerY - (radius * fraction - scaledPoint));
} else {
path.moveTo(centerX, centerY - scaledPoint);
}
graph.asMap().forEach((index, point) {
if (index == 0) return;
var xAngle = cos(angle * index - pi / 2);
var yAngle = sin(angle * index - pi / 2);
var scaledPoint = scale * point * fraction;
if (reverseAxis) {
path.lineTo(centerX + (radius * fraction - scaledPoint) * xAngle,
centerY + (radius * fraction - scaledPoint) * yAngle);
} else {
path.lineTo(
centerX + scaledPoint * xAngle, centerY + scaledPoint * yAngle);
}
});
path.close();
canvas.drawPath(path, graphPaint);
canvas.drawPath(path, graphOutlinePaint);
});
}
@override
bool shouldRepaint(RadarChartPainter oldDelegate) {
return oldDelegate.fraction != fraction;
}
}
+1
View File
@@ -34,6 +34,7 @@ class AppLanguage{
String langCode = prefs.getString('language_code');
if ( langCode == null) {
_appLocale = Locale('en');
langCode = "en";
}
_appLocale = Locale(langCode);
print(" ---- Get lang: " + _appLocale.toString() + " lang code $langCode");
+9 -1
View File
@@ -20,6 +20,7 @@ import 'package:aitrainer_app/view/gdpr.dart';
import 'package:aitrainer_app/view/login.dart';
import 'package:aitrainer_app/view/exercise_new_page.dart';
import 'package:aitrainer_app/view/menu_page.dart';
import 'package:aitrainer_app/view/mydevelopment_body_page.dart';
import 'package:aitrainer_app/view/mydevelopment_muscle_page.dart';
import 'package:aitrainer_app/view/mydevelopment_page.dart';
import 'package:aitrainer_app/view/myexcercise_plan_page.dart';
@@ -34,6 +35,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:sentry/sentry.dart';
import 'bloc/account/account_bloc.dart';
import 'bloc/body_development/body_development_bloc.dart';
import 'bloc/development_by_muscle/development_by_muscle_bloc.dart';
import 'bloc/exercise_by_plan/exercise_by_plan_bloc.dart';
import 'bloc/exercise_plan/exercise_plan_bloc.dart';
@@ -133,6 +135,10 @@ Future<Null> main() async {
create: (BuildContext context) => DevelopmentByMuscleBloc(
workoutTreeRepository: menuTreeRepository),
),
BlocProvider<BodyDevelopmentBloc>(
create: (BuildContext context) => BodyDevelopmentBloc(
workoutTreeRepository: menuTreeRepository),
),
],
child: AitrainerApp(),
@@ -173,7 +179,7 @@ class AitrainerApp extends StatelessWidget {
}
});
if ( locale != null && realSupportedLocale.countryCode != locale.countryCode ) {
print ("Locale " + locale.countryCode + " not supported on this device :(");
//print ("Locale " + locale.countryCode + " not supported on this device :(");
}
return realSupportedLocale;
},
@@ -202,6 +208,7 @@ class AitrainerApp extends StatelessWidget {
'exerciseByPlanPage': (context) => ExerciseByPlanPage(),
'exerciseAddByPlanPage': (context) => ExerciseAddByPlanPage(),
'mydevelopmentMusclePage': (context) => MyDevelopmentMusclePage(),
'mydevelopmentBodyPage': (context) => MyDevelopmentBodyPage(),
},
initialRoute: 'home',
title: 'WorkoutTest',
@@ -220,3 +227,4 @@ class AitrainerApp extends StatelessWidget {
}
+1 -1
View File
@@ -126,8 +126,8 @@ class Cache {
_exercisesTrainee = null;
_traineeExercisePlan = null;
_exercises = List();
_myExercisesPlanDetails = LinkedHashMap();
print("Trainees is null? " + (_trainee == null).toString() );
//firstLoad = true;
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
await setPreferences(prefs, SharePrefsChange.logout, 0);
}
+14 -1
View File
@@ -1,4 +1,3 @@
import 'package:aitrainer_app/util/common.dart';
import 'package:intl/intl.dart';
class Exercise {
@@ -12,6 +11,7 @@ class Exercise {
int exercisePlanDetailId;
String datePart;
double calculated;
@@ -25,6 +25,7 @@ class Exercise {
this.unitQuantity = json['unitQuantity'];
this.dateAdd = DateTime.parse( json['dateAdd'] );
this.datePart = DateFormat('yyyy-MM-dd').format(this.dateAdd);
this.calculated = quantity;
}
Map<String, dynamic> toJson() =>
@@ -38,6 +39,18 @@ class Exercise {
"exercisePlanDetailId": exercisePlanDetailId,
};
Map<String, dynamic> toJsonDatePart() =>
{
"exerciseTypeId": exerciseTypeId,
"customerId": customerId,
"quantity": quantity,
'calculated': calculated,
"unit": unit,
"unitQuantity": unitQuantity,
"datePart": this.datePart,
};
Exercise copy() {
Exercise newExercise = Exercise();
newExercise.exerciseTypeId = this.exerciseTypeId;
+3 -1
View File
@@ -28,7 +28,9 @@ class ExercisePlanRepository {
ExercisePlan getExercisePlan() => exercisePlan;
void addDetailToPlan() {
actualPlanDetail.exercisePlanId = exercisePlan.exercisePlanId;
if ( exercisePlan != null ) {
actualPlanDetail.exercisePlanId = exercisePlan.exercisePlanId;
}
exercisePlanDetails[actualPlanDetail.exerciseTypeId] = actualPlanDetail;
Cache().addToMyExercisePlanDetails(actualPlanDetail);
}
+51 -27
View File
@@ -56,17 +56,11 @@ class ExerciseRepository {
this.exercise.dateAdd = datetimeExercise;
}
double get unitQuantity {
return this.exercise.unitQuantity;
}
double get unitQuantity => this.exercise.unitQuantity;
double get quantity {
return this.exercise.quantity;
}
double get quantity => this.exercise.quantity;
Exercise getExercise() {
return this.exercise;
}
Exercise getExercise() => this.exercise;
Future<void> addExercise() async {
final Exercise modelExercise = this.exercise;
@@ -81,13 +75,9 @@ class ExerciseRepository {
}
setCustomer(Customer customer) {
this.customer = customer;
}
setCustomer(Customer customer) => this.customer = customer;
setExerciseType( ExerciseType exerciseType) {
this.exerciseType = exerciseType;
}
setExerciseType( ExerciseType exerciseType) => this.exerciseType = exerciseType;
Future<List<Exercise>> getExercisesByCustomer( int customerId ) async {
@@ -102,17 +92,53 @@ class ExerciseRepository {
}
List<Exercise> getExerciseList() {
//if ( this.exerciseList == null || this.exerciseList.length == 0 ) {
return this.exerciseList = Cache().getExercises();
//}
//return this.exerciseList;
this.exerciseList = Cache().getExercises();
return this.exerciseList;
}
List<Exercise> getExerciseListTrainee() {
//if ( this.exerciseList == null || this.exerciseList.length == 0 ) {
return this.exerciseList = Cache().getExercisesTrainee();
//}
//return this.exerciseList;
this.exerciseList = Cache().getExercisesTrainee();
return this.exerciseList;
}
String nextMissingBaseExercise(SplayTreeMap sortedTree) {
if ( exerciseList == null ) {
exerciseList = Cache().getExercises();
}
if ( exerciseList == null ) {
return "";
}
String missingTreeName;
String foundTreeName;
bool isBreak = false;
sortedTree.forEach((key, list) {
List<WorkoutMenuTree> listByMuscle = list as List<WorkoutMenuTree>;
String treeName = key as String;
treeName = treeName.substring(3);
foundTreeName = null;
listByMuscle.forEach((exercise) {
if ( missingTreeName == null ) {
missingTreeName = treeName;
}
if ( exercise.base ) {
exerciseList.forEach((element) {
if ( element.exerciseTypeId == exercise.exerciseTypeId ) {
foundTreeName = treeName;
//print("Found " + foundTreeName + " Missing actual: " + missingTreeName);
isBreak = true;
}
});
}
});
if ( foundTreeName == null &&! isBreak ) {
missingTreeName = treeName;
isBreak = true;
}
});
return missingTreeName;
}
void getBaseExerciseFinishedPercent() {
@@ -153,7 +179,7 @@ class ExerciseRepository {
&& treeItem.exerciseType.base == true
&& exercise.exerciseTypeId == treeItem.exerciseType.exerciseTypeId
&& !checkedBaseTreeItem.contains(treeItem.parent)) {
print ("id: " + exercise.exerciseTypeId.toString());
//print ("id: " + exercise.exerciseTypeId.toString());
checkedBaseTreeItem.add(treeItem.parent);
count1RMExercises++;
}
@@ -197,8 +223,6 @@ class ExerciseRepository {
return actualExerciseType;
}
void sortByDate() {
exerciseList.sort( (b, a) => a.dateAdd.compareTo(b.dateAdd) );
}
void sortByDate() => exerciseList.sort( (a, b) => b.dateAdd.compareTo(a.dateAdd) );
}
+24 -6
View File
@@ -44,6 +44,7 @@ class WorkoutTreeRepository {
Antagonist.calf: Antagonist.calfNr
};
Future<void> createTree() async {
isEnglish = AppLanguage().appLocal == Locale('en');
@@ -145,16 +146,21 @@ class WorkoutTreeRepository {
return branch;
}
WorkoutMenuTree getParentItem(int parent) {
WorkoutMenuTree parentItem;
tree.forEach((key, value) {
WorkoutMenuTree workoutTree = value as WorkoutMenuTree;
if ( parent == workoutTree.id) {
parentItem = workoutTree;
}
});
return parentItem;
}
void sortByMuscleType() {
sortedTree = SplayTreeMap<String, List<WorkoutMenuTree>>();
tree.forEach((key, value) {
WorkoutMenuTree workoutTree = value as WorkoutMenuTree;
//print("treeitem: " + workoutTree.toJson().toString());
/*if ( workoutTree.exerciseType != null) {
print("treeItem exerciseTye " + workoutTree.exerciseType.toJson().toString());
} else {
print("treeItem exerciseType null " + workoutTree.toJson().toString());
}*/
if ( workoutTree.nameEnglish != 'One Rep Max' && workoutTree.is1RM && workoutTree.exerciseTypeId == 0) {
String treeName = _antagonist[workoutTree.nameEnglish].toString() + ". " + workoutTree.name;
sortedTree[treeName] = this.getBranchList(workoutTree.id);
@@ -163,4 +169,16 @@ class WorkoutTreeRepository {
return;
}
int getMissingTreeIdByName(String name) {
int missingId = 0;
tree.forEach((key, value) {
WorkoutMenuTree item = value as WorkoutMenuTree;
if ( item.name == name || name == item.nameEnglish ) {
missingId = item.id;
}
});
return missingId;
}
}
+2 -2
View File
@@ -48,7 +48,7 @@ class CustomerApi {
customer = Customer.fromJson(jsonDecode(responseBody));
Cache().afterRegistration(customer);
}
} on FormatException catch (exception) {
} on FormatException {
throw new Exception(responseBody);
}
}
@@ -63,7 +63,7 @@ class CustomerApi {
try {
customer = Customer.fromJson(jsonDecode(responseBody));
await Cache().afterLogin(customer);
} on FormatException catch (exception) {
} on FormatException {
throw new Exception(responseBody);
}
}
+12 -8
View File
@@ -22,6 +22,18 @@ class ExerciseApi {
body);
}
Future<List<Exercise>> getExercisesByCustomer(int customerId ) async {
final body = await _client.get("exercises/customer/", customerId.toString() );
final Iterable json = jsonDecode(body);
final List<Exercise> exercises = json.map( (exercise) {
Exercise item = Exercise.fromJson(exercise);
return item;
}).toList();
//exercises.sort( (a, b) => b.dateAdd.compareTo(a.dateAdd) );
return exercises;
}
Future<Exercise> addExercise(Exercise exercise) async {
String body = JsonEncoder().convert(exercise.toJson());
print(" ===== add new exercise: " + body );
@@ -32,12 +44,4 @@ class ExerciseApi {
return savedExercise;
}
Future<List<Exercise>> getExercisesByCustomer(int customerId ) async {
final body = await _client.get("exercises/customer/", customerId.toString() );
final Iterable json = jsonDecode(body);
final List<Exercise> exercises = json.map( (exercise) => Exercise.fromJson(exercise) ).toList();
return exercises;
}
}
+23 -2
View File
@@ -7,6 +7,13 @@ import 'package:aitrainer_app/repository/user_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:intl/intl.dart';
class DateRate {
static String daily = "daily";
static String weekly = "weekly";
static String monthly = "monthly";
static String yearly = "yearly";
}
mixin Common {
final EMAIL_ERROR = "Please type a right email address here.";
@@ -24,7 +31,7 @@ mixin Common {
}
ExerciseType getExerciseType( int exerciseTypeId ) {
ExerciseType returnElement = null;
ExerciseType returnElement;
List<ExerciseType> listExerciseType = Cache().getExerciseTypes();
if ( listExerciseType != null ) {
for ( var element in listExerciseType ) {
@@ -32,7 +39,7 @@ mixin Common {
returnElement = element;
break;
}
};
}
}
return returnElement;
}
@@ -79,4 +86,18 @@ mixin Common {
return ((dayOfYear - date.weekday + 10) / 7).floor();
}
String getDatePart(DateTime date, String dateRate) {
String datePart = DateFormat('MM.dd', AppLanguage().appLocal.toString()).format(date);
if ( dateRate == DateRate.weekly ) {
datePart = weekNumber(date).toString();
} else if ( dateRate == DateRate.monthly ) {
datePart = DateFormat('MMM', AppLanguage().appLocal.toString()).format(date);
} else if ( dateRate == DateRate.yearly ) {
datePart = DateFormat('y', AppLanguage().appLocal.toString()).format(date);
} else if ( dateRate == DateRate.daily ) {
datePart = DateFormat('MM.dd', AppLanguage().appLocal.toString()).format(date);
}
return datePart;
}
}
+15
View File
@@ -0,0 +1,15 @@
import 'package:aitrainer_app/model/exercise.dart';
abstract class GroupData {
void iteration();
bool checkNewType(Exercise exercise);
void addTempData(Exercise element);
void temp2Output(Exercise exercise);
void resetTemp();
}
+2 -3
View File
@@ -122,7 +122,7 @@ class _CustomExerciseNewPageState extends State<CustomExercisePage> {
color: Colors.lightBlue,
fontWeight: FontWeight.bold),
inputFormatters: [
WhitelistingTextInputFormatter(RegExp(r"[\d.]"))
FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))
],
onChanged: (input) => {
print("UnitQuantity value $input"),
@@ -150,7 +150,6 @@ class _CustomExerciseNewPageState extends State<CustomExercisePage> {
),
]);
}
;
return column;
}
@@ -164,7 +163,7 @@ class _CustomExerciseNewPageState extends State<CustomExercisePage> {
color: Colors.deepOrange,
fontWeight: FontWeight.bold),
inputFormatters: [
WhitelistingTextInputFormatter (RegExp(r"[\d.]"))
FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))
],
onChanged: (input) => {
print("Quantity value $input"),
-1
View File
@@ -23,7 +23,6 @@ class _CustomerGoalPage extends State<CustomerGoalPage> {
@override
Widget build(BuildContext context) {
final double cWidth = MediaQuery.of(context).size.width * 0.75;
final CustomerRepository customerRepository =
ModalRoute.of(context).settings.arguments;
+2 -3
View File
@@ -1,6 +1,5 @@
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/bloc/customer_change_form_bloc.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
@@ -169,7 +168,7 @@ class CustomerModifyPage extends StatelessWidget with Trans {
child: TextFieldBlocBuilder(
style: TextStyle(fontSize: 12),
textFieldBloc: customerBloc.birthYearField,
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r"[\d]"))],
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d]"))],
decoration: InputDecoration(
fillColor: Colors.white24,
filled: true,
@@ -186,7 +185,7 @@ class CustomerModifyPage extends StatelessWidget with Trans {
child: TextFieldBlocBuilder(
style: TextStyle(fontSize: 12),
textFieldBloc: customerBloc.weightField,
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r"[\d]"))],
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d]"))],
decoration: InputDecoration(
fillColor: Colors.white24,
filled: true,
+2 -2
View File
@@ -148,7 +148,7 @@ class _ExerciseAddByPlanPage extends State<ExerciseAddByPlanPage> with Trans {
color: Colors.black54,
fontWeight: FontWeight.bold),
inputFormatters: [
WhitelistingTextInputFormatter(RegExp(r"[\d.]"))
FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))
],
decoration: InputDecoration(
@@ -169,7 +169,7 @@ class _ExerciseAddByPlanPage extends State<ExerciseAddByPlanPage> with Trans {
color: Colors.deepOrange,
fontWeight: FontWeight.bold),
inputFormatters: [
WhitelistingTextInputFormatter(RegExp(r"[\d.]"))
FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))
],
decoration: InputDecoration(
+8 -21
View File
@@ -4,6 +4,8 @@ import 'package:aitrainer_app/bloc/exercise_control_form_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/splash.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -48,24 +50,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> {
autovalidate: true,
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
title: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text("1RM Control"),
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.of(context).pop(),
),
),
appBar: AppBarNav(depth: 1),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
@@ -130,7 +115,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> {
textFieldBloc: exerciseBloc.quantity1Field,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 14, color: Colors.deepOrange, fontWeight: FontWeight.bold),
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r"[\d.]"))],
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))],
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
@@ -173,7 +158,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> {
textFieldBloc: exerciseBloc.quantity2Field,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 14, color: Colors.deepOrange, fontWeight: FontWeight.bold),
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r"[\d.]"))],
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))],
onChanged: (input) => {
print("Quantity 2 value $input"),
//exerciseBloc.exerciseRepository.setQuantity(double.parse(input)),
@@ -220,7 +205,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> {
textFieldBloc: exerciseBloc.quantity3Field,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 14, color: Colors.deepOrange, fontWeight: FontWeight.bold),
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r"[\d.]"))],
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))],
onChanged: (input) => {
print("Quantity 3 value $input"),
//exerciseBloc.exerciseRepository.setQuantity(double.parse(input)),
@@ -255,7 +240,9 @@ class _ExerciseControlPage extends State<ExerciseControlPage> {
),
]),
))),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 1),
),
);
}
+3 -6
View File
@@ -1,11 +1,10 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/exercise_by_plan/exercise_by_plan_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/treeview/tree_view.dart';
import 'package:aitrainer_app/library/tree_view.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_common.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:aitrainer_app/widgets/splash.dart';
@@ -44,7 +43,7 @@ class _ExerciseByPlanPage extends State<ExerciseByPlanPage> with Trans {
return Scaffold(
key: _scaffoldKey,
appBar: AppBarCommonNav(),
appBar: AppBarNav(depth: 1),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
@@ -92,8 +91,6 @@ class _ExerciseByPlanPage extends State<ExerciseByPlanPage> with Trans {
List<Widget> nodeExercisePlan(ExerciseByPlanBloc bloc) {
List<Widget> exerciseTypes = List();
bool isEnglish = AppLanguage().appLocal == Locale("en");
Card explanation = Card(
color: Colors.white38,
child: Container(
+27 -9
View File
@@ -1,14 +1,15 @@
import 'dart:collection';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:intl/intl.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/treeview/tree_view.dart';
import 'package:aitrainer_app/library/tree_view.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:flutter/material.dart';
import 'package:aitrainer_app/widgets/treeview_parent_widget.dart';
@@ -26,7 +27,7 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
setContext(context);
return Scaffold(
appBar: AppBarCommonNav(),
appBar: AppBarNav(depth: 1),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
@@ -38,7 +39,8 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
),
),
child: exerciseWidget(exerciseRepository, customerId),
)
),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 1),
);
}
@@ -95,12 +97,11 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
List<Exercise> listExercises = List();
String origDate = "";
print("start exercises");
exerciseRepository.exerciseList.forEach((exercise) {
String exerciseDate = DateFormat("yyyy-MM-dd", AppLanguage().appLocal.toString()).format(exercise.dateAdd);
if ( origDate != exerciseDate) {
if ( origDate.length == 0) {
if ( origDate.length == 0 ) {
listExercises.add(exercise);
origDate = exerciseDate;
} else {
@@ -109,18 +110,35 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild(
startExpanded: true,
parent: TreeviewParentWidget(text: exerciseDate),
parent: TreeviewParentWidget(text: origDate),
children: _getChildList(listExercises, exerciseRepository),
)
)
);
listExercises = List();
listExercises.add(exercise);
origDate = exerciseDate;
}
}
origDate = exerciseDate;
} else {
listExercises.add(exercise);
origDate = exerciseDate;
}
});
if ( listExercises.length > 0) {
listWidget.add(
Container(
margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild(
startExpanded: true,
parent: TreeviewParentWidget(text: origDate),
children: _getChildList(listExercises, exerciseRepository),
)
)
);
}
return listWidget;
}
+39 -49
View File
@@ -1,11 +1,13 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/exercise_form_bloc.dart';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
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:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/cupertino.dart';
@@ -21,13 +23,16 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> {
@override
Widget build(BuildContext context) {
final ExerciseType exerciseType = ModalRoute.of(context).settings.arguments;
// ignore: close_sinks
final menuBloc = BlocProvider.of<MenuBloc>(context);
return BlocProvider(
create: (context) => ExerciseFormBloc(exerciseRepository: ExerciseRepository()),
create: (context) => ExerciseFormBloc(exerciseRepository: ExerciseRepository(), menuBloc: menuBloc),
child: Builder(builder: (context) {
// ignore: close_sinks
final exerciseBloc = BlocProvider.of<ExerciseFormBloc>(context);
exerciseBloc.exerciseRepository.setExerciseType(exerciseType);
String exerciseName = AppLanguage().appLocal == Locale("en") ?
exerciseBloc.exerciseRepository.exerciseType.name :
@@ -37,23 +42,7 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> {
autovalidate: true,
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
title: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.of(context).pop(),
),
),
appBar: AppBarNav(depth: 1),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
@@ -139,39 +128,40 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> {
if ( bloc.exerciseRepository.exerciseType != null &&
bloc.exerciseRepository.exerciseType.unitQuantity == "1") {
column = Column(
children: [
TextFieldBlocBuilder(
textFieldBloc: bloc.unitQuantityField,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30,
color: Colors.lightBlue,
fontWeight: FontWeight.bold),
inputFormatters: [
WhitelistingTextInputFormatter (RegExp(r"[\d.]"))
],
onChanged: (input) => {
print ("UnitQuantity value $input"),
bloc.exerciseRepository.setUnitQuantity(
double.parse(input))
},
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100),
hintText: AppLocalizations.of(context).translate("The number of the exercise done with"),
labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue),
labelText: AppLocalizations.of(context).translate(
bloc.exerciseRepository.exerciseType.unitQuantityUnit),
),
),
new InkWell(
child: new Text(AppLocalizations.of(context).translate(
children: [
TextFieldBlocBuilder(
textFieldBloc: bloc.unitQuantityField,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30,
color: Colors.lightBlue,
fontWeight: FontWeight.bold),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))
],
onChanged: (input) =>
{
print("UnitQuantity value $input"),
bloc.exerciseRepository.setUnitQuantity(
double.parse(input))
},
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100),
hintText: AppLocalizations.of(context).translate("The number of the exercise done with"),
labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue),
labelText: AppLocalizations.of(context).translate(
bloc.exerciseRepository.exerciseType.unitQuantityUnit),
style: TextStyle(fontSize: 16)),
),
),
new InkWell(
child: new Text(AppLocalizations.of(context).translate(
bloc.exerciseRepository.exerciseType.unitQuantityUnit),
style: TextStyle(fontSize: 16)),
),
]);
};
]);
}
return column;
}
@@ -185,7 +175,7 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> {
color: Colors.deepOrange,
fontWeight: FontWeight.bold),
inputFormatters: [
WhitelistingTextInputFormatter (RegExp(r"[\d.]"))
FilteringTextInputFormatter.allow (RegExp(r"[\d.]"))
],
onChanged: (input) =>
{
@@ -5,7 +5,7 @@ import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/cupertino.dart';
@@ -43,7 +43,7 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
autovalidate: true,
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBarCommonNav(),
appBar: AppBarNav(depth: 1),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
@@ -72,7 +72,7 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
textFieldBloc: bloc.serieField,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold),
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r"[\d.]"))],
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))],
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
@@ -86,7 +86,7 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
textFieldBloc: bloc.quantityField,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold),
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r"[\d.]"))],
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))],
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
@@ -101,7 +101,7 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
textFieldBloc: bloc.weightField,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold),
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r"[\d.]"))],
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))],
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
+6 -5
View File
@@ -4,9 +4,9 @@ import 'package:aitrainer_app/bloc/exercise_plan/exercise_plan_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/treeview/tree_view.dart';
import 'package:aitrainer_app/library/tree_view.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_common.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:aitrainer_app/widgets/splash.dart';
@@ -45,7 +45,7 @@ class _ExercisePlanCustomPage extends State<ExercisePlanCustomPage> with Trans {
return Scaffold(
key: _scaffoldKey,
appBar: AppBarCommonNav(),
appBar: AppBarNav(depth: 1),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
@@ -181,10 +181,11 @@ class _ExercisePlanCustomPage extends State<ExercisePlanCustomPage> with Trans {
),
InkWell(
child:
element.selected && bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId].change != null ?
!element.selected || bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId] == null ||
bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId].change == null ? Text("") :
Text(bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId].repeats.toString() +
" x " + bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId].weightEquation +
" " + element.exerciseType.unitQuantityUnit, style: TextStyle(fontSize: 9, color: Colors.green),) : Text(""),
" " + element.exerciseType.unitQuantityUnit, style: TextStyle(fontSize: 9, color: Colors.green),),
onTap: () => {
bloc.add(ExercisePlanUpdateUI(workoutTree: element)),
Navigator.of(context).pushNamed("exercisePlanDetailAdd", arguments: bloc),
+1 -1
View File
@@ -28,7 +28,7 @@ class _MenuPage extends State<MenuPage> {
Widget build(BuildContext context) {
menuBloc = BlocProvider.of<MenuBloc>(context);
return Scaffold(
appBar: AppBarNav(),
appBar: AppBarNav(isMenu: true,),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
+129
View File
@@ -0,0 +1,129 @@
import 'dart:collection';
import 'package:aitrainer_app/library/radar_chart.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/splash.dart';
import 'package:flutter/scheduler.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:aitrainer_app/bloc/body_development/body_development_bloc.dart';
class MyDevelopmentBodyPage extends StatefulWidget {
@override
_MyDevelopmentBodyPage createState() => _MyDevelopmentBodyPage();
}
class _MyDevelopmentBodyPage extends State<MyDevelopmentBodyPage> with Trans, Common {
// ignore: close_sinks
BodyDevelopmentBloc bloc;
@override
void initState() {
super.initState();
/// We require the initializers to run after the loading screen is rendered
SchedulerBinding.instance.addPostFrameCallback((_) {
BlocProvider.of<BodyDevelopmentBloc>(context).add(BodyDevelopmentLoad());
});
}
@override
Widget build(BuildContext context) {
bloc = BlocProvider.of<BodyDevelopmentBloc>(context);
LinkedHashMap arguments = ModalRoute.of(context).settings.arguments;
final int customerId = arguments['customerId'];
setContext(context);
return Scaffold(
appBar: AppBarNav(depth: 1),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: customerId == Cache().userLoggedIn.customerId ? AssetImage('asset/image/WT_light_background.png'):
AssetImage('asset/image/WT_menu_dark.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: BlocConsumer<BodyDevelopmentBloc, BodyDevelopmentState>(
listener: (context, state) {
if (state is BodyDevelopmentLoading) {
LoadingDialog();
}
},
builder: (context, state) {
if ( state is BodyDevelopmentInitial) {
return Container();
} else {
return developmentWidget(customerId);
}
},
)
),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 1),
);
}
Widget developmentWidget(int customerId) {
return Column(
children: [
explanationWidget(),
Expanded(
child: exerciseWidget(customerId),
),
]
);
}
Widget exerciseWidget(int customerId) {
return RadarChart.light(
ticks: bloc.radarTicks,
features: bloc.radarFeatures,
data: bloc.radarData,
);
}
Widget explanationWidget() {
return Card(
color: Colors.white60,
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(" "),
Text(
t("My Body Development"),
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
],
),
Divider(
color: Colors.transparent,
),
Text(
t("You see here your whole body development by muscle groups."),
style: TextStyle(fontSize: 12, fontWeight: FontWeight.normal),
),
],
)
)
);
}
}
+5 -7
View File
@@ -1,12 +1,12 @@
import 'dart:collection';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/treeview_parent_widget.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/bloc/development_by_muscle/development_by_muscle_bloc.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/treeview/tree_view.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:aitrainer_app/library/tree_view.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/splash.dart';
import 'package:flutter/cupertino.dart';
@@ -43,7 +43,7 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
setContext(context);
return Scaffold(
appBar: AppBarCommonNav(),
appBar: AppBarNav(depth: 1),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
@@ -75,7 +75,6 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
children: _getTreeChildren(bloc.workoutTreeRepository.sortedTree, bloc),
);
}
;
},
),
),
@@ -209,11 +208,10 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
exerciseTypes.add(explanation);
tree.forEach((name, list) {
List<WorkoutMenuTree> listWorkoutMenuTree = list;
exerciseTypes.add(Container(
margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild(
startExpanded: true,
startExpanded: false,
parent: _getExerciseWidget(exerciseTypeName: name),
children: _getChildList(list, bloc),
)));
@@ -274,7 +272,7 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
getTitles: (double value) {
var date = new DateTime.fromMillisecondsSinceEpoch(value.toInt());
//String strDate = DateFormat('MM.dd.', AppLanguage().appLocal.toString()).format(date);
String strDate = bloc.getDatePart(date);
String strDate = getDatePart(date, bloc.dateRate);
return strDate;
},
),
+71 -12
View File
@@ -4,11 +4,11 @@ import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/image_button.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class MyDevelopmentPage extends StatefulWidget {
@override
@@ -24,7 +24,7 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
setContext(context);
return Scaffold(
appBar: AppBarCommonNav(),
appBar: AppBarNav(depth: 0),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
@@ -41,7 +41,16 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
SliverGrid(
delegate: SliverChildListDelegate(
[
FlatButton(
ImageButton(
textAlignment: Alignment.topCenter,
text: t("My Exercise Logs"),
style: TextStyle(fontSize: 20, color: Colors.orange, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4)),
image: "asset/image/exercise_log.jpg",
top: 40,
onTap:() => this.callBackExerciseLog(exerciseRepository, customerRepository),
isLocked: false,
),
/*FlatButton(
padding: EdgeInsets.all(0),
textColor: Colors.white,
color: Colors.black12,
@@ -56,8 +65,8 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
},
child: Text(t("My Exercise Logs"),
style: TextStyle(fontSize: 18),)
),
Stack(
),*/
/*Stack(
fit: StackFit.passthrough,
overflow: Overflow.clip,
alignment: Alignment.topLeft,
@@ -73,22 +82,51 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
focusColor: Colors.blueAccent,
onPressed: () =>
{
args['customerId'] = Cache().userLoggedIn.customerId,
Navigator.of(context).pushNamed('mydevelopmentBodyPage',
arguments: args)
},
child: Text(t("My Whole Body Development"),
style: TextStyle(fontSize: 18),)
),
],
),*/
ImageButton(
textAlignment: Alignment.topLeft,
text: t("My Whole Body Development"),
style: TextStyle(fontSize: 20, color: Colors.orange, fontWeight: FontWeight.bold,
backgroundColor: Colors.black54.withOpacity(0.4)),
image: "asset/menu/3.1.BMI.png",
top: 50,
onTap:() => {
args['customerId'] = Cache().userLoggedIn.customerId,
Navigator.of(context).pushNamed('mydevelopmentBodyPage',
arguments: args)
},
isLocked: true,
),
Stack(
ImageButton(
textAlignment: Alignment.topLeft,
text: t("Development Of Muscles"),
style: TextStyle(fontSize: 20, color: Colors.orange, fontWeight: FontWeight.bold,
backgroundColor: Colors.black54.withOpacity(0.4)),
image: "asset/image/development_muscles.jpg",
top: 50,
onTap:() => {
Navigator.of(context).pushNamed('mydevelopmentMusclePage',
arguments: args)
},
isLocked: true,
),
/*Stack(
fit: StackFit.passthrough,
overflow: Overflow.clip,
children: [
/*Image.asset('asset/image/lock.png',
*//*Image.asset('asset/image/lock.png',
height: 40,
width: 40,
),*/
),*//*
FlatButton(
padding: EdgeInsets.all(20),
textColor: Colors.white,
@@ -104,8 +142,20 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
),
]
),*/
ImageButton(
textAlignment: Alignment.topLeft,
text: t("Predictions"),
style: TextStyle(fontSize: 20, color: Colors.orange, fontWeight: FontWeight.bold,
backgroundColor: Colors.black54.withOpacity(0.4)),
image: "asset/menu/2.2.1.1RM.png",
top: 50,
onTap:() => {
},
isLocked: true,
),
Stack(
/*Stack(
fit: StackFit.passthrough,
overflow: Overflow.clip,
@@ -126,7 +176,7 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
style: TextStyle(fontSize: 18),)
),
]
),
),*/
hiddenWidget(customerRepository, exerciseRepository),
]
),
@@ -167,6 +217,15 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
}
}
void callBackExerciseLog(ExerciseRepository exerciseRepository, CustomerRepository customerRepository) {
final LinkedHashMap args = LinkedHashMap();
args['exerciseRepository'] = exerciseRepository;
args['customerRepository'] = customerRepository;
args['customerId'] = Cache().userLoggedIn.customerId;
Navigator.of(context).pushNamed('exerciseLogPage',
arguments: args);
}
}
+2 -2
View File
@@ -2,7 +2,7 @@ import 'dart:collection';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -20,7 +20,7 @@ class _MyExercisePlanPage extends State<MyExercisePlanPage> with Trans {
setContext(context);
return Scaffold(
appBar: AppBarCommonNav(),
appBar: AppBarNav(depth: 0),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
-1
View File
@@ -2,7 +2,6 @@ import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
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:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/splash.dart';
import 'package:flutter/material.dart';
+23 -34
View File
@@ -4,6 +4,7 @@ import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -13,20 +14,20 @@ import 'package:rainbow_color/rainbow_color.dart';
class AppBarNav extends StatefulWidget implements PreferredSizeWidget {
final MenuBloc menuBloc;
const AppBarNav({this.menuBloc});
final bool isMenu;
final int depth;
const AppBarNav({this.menuBloc, this.isMenu, this.depth});
@override
_AppBarNav createState() => _AppBarNav();
@override
Size get preferredSize => const Size.fromHeight(60);
Size get preferredSize => const Size.fromHeight(50);
}
class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin, Common {
Animation<Color> colorAnim;
//Animation<double> sizeAnim;
AnimationController colorController;
//AnimationController sizeController;
MenuBloc menuBloc;
@override
@@ -34,26 +35,7 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
colorController =
AnimationController(duration: Duration(seconds: 4), vsync:this);
//sizeController =
// AnimationController(duration: Duration(seconds: 3), vsync: this);
/* final curvedAnimation = CurvedAnimation(
parent: sizeController,
curve: Curves.easeIn,
reverseCurve: Curves.easeInOutBack,
);
sizeAnim =
Tween<double>(begin: 0, end: 1.5).animate(curvedAnimation)
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
sizeController.reverse();
} else if (status == AnimationStatus.dismissed) {
Timer(Duration(seconds: 5), () {
sizeController.forward();
});
}
}); */
colorAnim = RainbowColorTween([Colors.white70,
Colors.blueGrey,
Colors.blueAccent,
@@ -69,7 +51,6 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
Timer(Duration(seconds: 10), () {
//colorController.reset();
if ( mounted ) {
colorController.forward();
}
@@ -85,7 +66,6 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
menuBloc = BlocProvider.of<MenuBloc>(context);
//setContext(context);
return AppBar(
backgroundColor: Colors.black,
@@ -96,8 +76,8 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
getAnimatedWidget(),
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
//fit: BoxFit.cover,
height: 45.0,
),
],
),
@@ -105,8 +85,16 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () =>
{
if ( menuBloc != null ) {
menuBloc.add(MenuTreeUp(parent: 0)),
if ( widget.isMenu != null ) {
if ( menuBloc.workoutItem != null ) {
menuBloc.add(MenuTreeUp(parent: menuBloc.workoutItem.parent)),
}
} else if ( widget.depth != null ) {
if ( widget.depth == 0 ) {
Navigator.of(context).pushNamed('home')
} else {
Navigator.of(context).pop()
}
}
},
)
@@ -115,12 +103,12 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
@override
void dispose() {
//sizeController.dispose();
colorController.dispose();
super.dispose();
}
Widget getAnimatedWidget() {
double cWidth = mediaSizeWidth(context);
double percent = Cache().getPercentExercises();
if ( percent == -1) {
ExerciseRepository exerciseRepository = ExerciseRepository();
@@ -130,9 +118,10 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
int sizeExerciseList = Cache().getExercises() == null? 0 : Cache().getExercises().length;
if ( sizeExerciseList == 0 ) {
String text = AppLocalizations.of(context).translate("Make your first test");
double fontSize = text.length > 15 ? 10 : 16;
double fontSize = text.length > 24 ? 10 : 16;
return Stack(
alignment: Alignment.topLeft,
overflow: Overflow.clip,
children: [
Text(text,
style: TextStyle(fontSize: fontSize, color: colorAnim.value, shadows: [Shadow(color: Colors.purple , blurRadius: 15)]),
@@ -147,12 +136,12 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
alignment: Alignment.topLeft,
children: [
LinearPercentIndicator(
width: 120.0,
width: cWidth / 4,
lineHeight: 14.0,
percent: percent,
center: Text(
(percent * 100).toStringAsFixed(0) + "% " + AppLocalizations.of(context).translate("finished"),
style: new TextStyle(fontSize: 12.0),
style: new TextStyle(fontSize: 10.0),
),
trailing: Icon(percent > 0.6 ? Icons.mood : Icons.mood_bad, color: colorAnim.value,),
linearStrokeCap: LinearStrokeCap.roundAll,
-135
View File
@@ -1,135 +0,0 @@
import 'dart:async';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';
import 'package:rainbow_color/rainbow_color.dart';
class AppBarCommonNav extends StatefulWidget implements PreferredSizeWidget {
@override
_AppBarCommonNav createState() => _AppBarCommonNav();
@override
Size get preferredSize => const Size.fromHeight(60);
}
class _AppBarCommonNav extends State<AppBarCommonNav> with SingleTickerProviderStateMixin {
Animation<Color> colorAnim;
AnimationController colorController;
@override
void initState() {
colorController =
AnimationController(duration: Duration(seconds: 4),vsync: this);
colorAnim = RainbowColorTween([Colors.white70,
Colors.blueGrey,
Colors.blueAccent,
Colors.lightBlue,
Colors.lightBlueAccent,
Colors.yellowAccent,
Colors.orange,
Colors.orangeAccent,
Colors.yellowAccent,
Color(0xffcce6ff)])
.animate(colorController)
..addListener(() { setState(() {}); })
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
Timer(Duration(seconds: 10), () {
//colorController.reset();
if ( mounted ) {
colorController.forward();
}
});
} else if (status == AnimationStatus.dismissed) {
colorController.forward();
}
});
colorController.forward();
super.initState();
}
@override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: Colors.black,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
getAnimatedWidget(),
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () =>
{
Navigator.of(context).pushNamed('home')
},
)
);
}
@override
void dispose() {
//sizeController.dispose();
colorController.dispose();
super.dispose();
}
Widget getAnimatedWidget() {
double percent = Cache().getPercentExercises();
if ( percent == -1) {
ExerciseRepository exerciseRepository = ExerciseRepository();
exerciseRepository.getBaseExerciseFinishedPercent();
percent = Cache().getPercentExercises();
}
int sizeExerciseList = Cache().getExercises() == null? 0 : Cache().getExercises().length;
if ( sizeExerciseList == 0 ) {
String text = AppLocalizations.of(context).translate("Make your first test");
double fontSize = text.length > 17 ? 10 : 16;
return Stack(
alignment: Alignment.topLeft,
children: [
Text(text,
style: TextStyle(fontSize: fontSize, color: colorAnim.value, shadows: [Shadow(color: Colors.purple , blurRadius: 15)]),
),
//TestProgress(animation: sizeAnim),
]
);
} else {
return Stack(
alignment: Alignment.topLeft,
children: [
LinearPercentIndicator(
width: 120.0,
lineHeight: 14.0,
percent: percent,
center: Text(
(percent * 100).toStringAsFixed(0) + "% " + AppLocalizations.of(context).translate("finished"),
style: new TextStyle(fontSize: 12.0),
),
trailing: Icon(percent > 0.6 ? Icons.mood : Icons.mood_bad, color: colorAnim.value,),
linearStrokeCap: LinearStrokeCap.roundAll,
backgroundColor: colorAnim.value,
progressColor: Color(0xff73e600),
animation: true,
),
],
);
}
}
}
+1 -1
View File
@@ -1,6 +1,5 @@
import 'package:aitrainer_app/bloc/session/session_bloc.dart';
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/view/login.dart';
import 'package:aitrainer_app/view/menu_page.dart';
@@ -13,6 +12,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'loading.dart';
// ignore: must_be_immutable
class AitrainerHome extends StatefulWidget {
_HomePageState _state;
@override
+119
View File
@@ -0,0 +1,119 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:bloc/bloc.dart';
class ImageButton extends StatelessWidget {
final String text;
final TextStyle style;
final String image;
final double top;
final double height;
final double width;
final bool isShape;
final Bloc bloc;
final Alignment textAlignment;
final VoidCallback onTap;
bool isLocked;
ImageButton({
this.text,
this.style,
this.image,
this.top,
this.height,
this.width,
this.bloc,
this.isShape,
this.textAlignment,
this.onTap,
@required this.isLocked
});
@override
Widget build(BuildContext context) {
return Stack(
//alignment: textAlignment,
fit: StackFit.passthrough,
overflow: Overflow.clip,
children: [
FlatButton(
child: image == null ?
_getButtonImage("asset/image/WT_menu_dark.png") :
_getButtonImage(image),
padding: EdgeInsets.only(left: 0.0, bottom: 0),
shape: getShape(isShape),
onPressed: onTap ?? onTap,
),
Stack(
alignment: Alignment.topLeft,
children: [
this.isLocked?
Image.asset(
'asset/image/lock.png',
height: 40,
width: 40,
)
: Container(),
]),
Positioned(
top: top,
left: 10,
child: Container(
height: 100,
width: 150,
child: InkWell(
onTap: onTap ?? onTap,
child: Text(
text,
maxLines: 2,
style: style,
),
),
color: Colors.transparent,
),
),
]
//)
// )
);
}
dynamic getShape(bool isShape) {
dynamic returnCode = (isShape == true)
? RoundedRectangleBorder(
side: BorderSide(width: 4, color: Colors.orangeAccent),
)
: null;
return returnCode;
}
dynamic _getButtonImage(String imageName) {
dynamic image;
try {
image = Image.asset(
imageName,
fit: BoxFit.fitWidth,
alignment: Alignment.center,
errorBuilder: (context, error, stackTrace) {
String url = Cache.mediaUrl + 'images/' + imageName.substring(11);
Widget image = FadeInImage.assetNetwork(
placeholder: 'asset/image/dots.gif',
image: url,
height: 180,
);
return image;
},
);
} on Exception catch (_) {
String url = Cache.mediaUrl + '/images/' + imageName;
image = FadeInImage.assetNetwork(
placeholder: 'asset/image/dots.gif',
image: url,
height: 180,
);
}
return image;
}
}
+113
View File
@@ -0,0 +1,113 @@
import 'dart:ui';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class MenuInfoWidget extends StatelessWidget with Common {
final String title;
final double titleSize;
final Color titleColor;
final FontWeight titleWeight;
final String text;
final double textSize;
final Color textColor;
final FontWeight textWeight;
final Icon leadingIcon;
final Color leadingIconColor;
final String text2;
final String text3;
final String link;
final int parentMenu;
final MenuBloc bloc;
MenuInfoWidget(
{this.title,
this.titleSize,
this.titleColor,
this.titleWeight,
@required this.text,
this.textSize,
this.textColor,
this.textWeight,
this.leadingIcon,
this.leadingIconColor,
this.text2,
this.text3,
this.link,
this.parentMenu,
this.bloc});
@override
Widget build(BuildContext context) {
int length = title.length + text2.length + text3.length + link.length;
return Container(
height: length > 100? 350 : 250,
width: 180,
padding: EdgeInsets.all(25.0),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
"asset/menu/3.bcs1.png",
),
fit: BoxFit.contain),
),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 9, sigmaY: 9),
child: Container(
padding: EdgeInsets.only(top: 10.0, left: 15, right: 10, bottom: 5),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
border: Border.all(color: Colors.white60),
borderRadius: BorderRadius.all(Radius.circular(10.0)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
title,
maxLines: 1,
style:
TextStyle(color: titleColor, fontSize: titleSize, fontFamily: 'Arial', fontWeight: titleWeight),
),
Divider(),
Text(
text,
maxLines: 6,
style: TextStyle(color: textColor, fontSize: textSize, fontFamily: 'Arial', fontWeight: textWeight),
),
Divider(),
Text(
text2,
maxLines: 6,
style: TextStyle(color: textColor, fontSize: textSize, fontFamily: 'Arial', fontWeight: textWeight),
),
Divider(),
Text(
text3,
maxLines: 6,
style: TextStyle(color: textColor, fontSize: textSize, fontFamily: 'Arial', fontWeight: textWeight),
),
getLink(),
],
),
),
));
}
Widget getLink() {
int missingId;
return InkWell(
child: new Text(link, style: TextStyle(color: Colors.lightBlueAccent, fontSize: textSize, fontFamily: 'Arial', fontWeight: textWeight),),
onTap: () =>
{
missingId = bloc.menuTreeRepository.getMissingTreeIdByName(bloc.missingTreeName),
print("menu " + missingId.toString()),
bloc.add(MenuTreeJump(parent: missingId))
}
);
}
}
+28 -4
View File
@@ -4,13 +4,16 @@ import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'menu_info_widget.dart';
// ignore: must_be_immutable
class MenuPageWidget extends StatelessWidget {
class MenuPageWidget extends StatelessWidget with Trans {
int parent;
MenuPageWidget({this.parent});
@@ -18,16 +21,37 @@ class MenuPageWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
MenuBloc menuBloc = BlocProvider.of<MenuBloc>(context);
setContext(context);
return CustomScrollView(
scrollDirection: Axis.vertical,
slivers: <Widget>[buildMenuColumn(parent, context, menuBloc)]);
}
SliverList buildMenuColumn(
int parent, BuildContext context, MenuBloc menuBloc) {
SliverList buildMenuColumn(int parent, BuildContext context, MenuBloc menuBloc) {
final List<Widget> _columnChildren = List();
if ( context != null ) {
menuBloc.setContext(context);
menuBloc.setMenuInfo();
Widget info = MenuInfoWidget(
title: menuBloc.infoTitle,
titleSize: 18,
titleWeight: FontWeight.bold,
titleColor: Colors.orangeAccent,
text: menuBloc.infoText,
textSize: 13,
textColor: Colors.yellowAccent,
text2: menuBloc.infoText2,
text3: menuBloc.infoText3,
link: menuBloc.infoLink,
bloc: menuBloc,
);
_columnChildren.add(info);
}
menuBloc.menuTreeRepository
.getBranch(menuBloc.parent)
.forEach((treeName, value) {
@@ -86,7 +110,7 @@ class MenuPageWidget extends StatelessWidget {
WorkoutMenuTree workoutTree, MenuBloc menuBloc, BuildContext context) {
print("Hi!, Menu clicked " + workoutTree.id.toString());
if (workoutTree.child == false) {
menuBloc.add(MenuTreeDown(parent: workoutTree.id));
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
} else {
menuBloc.add(MenuClickExercise(exerciseTypeId: workoutTree.id));
if (Cache().userLoggedIn == null) {