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

BIN
asset/image/Congrats_N1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

BIN
asset/menu/Back_pullup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
asset/menu/biceps.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
asset/menu/calf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
asset/menu/legpress.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
asset/menu/squat.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

BIN
asset/menu/tricdip.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@ -170,5 +170,29 @@
"Custom Exercise Plan": "Custom Exercise Plan",
"Select manually the exercises what you would like to have in your plan. At the end don't forget to save.": "Select manually the exercises what you would like to have in your plan. At the end don't forget to save.",
"In this list you will find all your executed exercises grouped by the date.": "In this list you will find all your executed exercises grouped by the date."
"In this list you will find all your executed exercises grouped by the date.": "In this list you will find all your executed exercises grouped by the date.",
"Persistence!": "Persistence!",
"Greetings!": "Greetings!",
"The purpose is to measure you physical condition": "The purpose is to measure you physical condition.",
"The suggested order of the exercises: chest - biceps - triceps - back - shoulders - core - tigh - calf.": "The suggested order of the exercises: chest - biceps - triceps - back - shoulders - core - tigh - calf.",
"Go to the menu Strength - One Rep Max - Chest, and select your favourite exercise.": "Go to the menu Strength - One Rep Max - Chest, and select your favourite exercise.",
"Please continue your tests with a": "Please continue your tests with a",
"I suggest begin your tests with a": "I suggest begin your tests with a 'chest' exercise",
"Nice! This is a good start": "Nice! This is a good start",
"Go on!":"Go on!",
"You are on track": "You are on track",
"Not so much left": "Not so much left",
"Almost!": "Almost done!",
"You have only 1-2 exercise left to finish!": "You have only 1-2 exercise left to finish!",
"exercise!": "exercise!",
"Chest": "Chest",
"Back": "Back",
"Thigh": "Thigh",
"Calf": "Calf",
"Bring me there": "Bring me there",
"My Body Development": "My Body Development",
"You see here your whole body development by muscle groups.": "You see here your whole body development by muscle groups."
}

View File

@ -169,5 +169,29 @@
"Select the muscle type and tap on the exercise. One the next page enter the weight and repeat.": "Válaszd ki az izomcsoporton belül a gyakorlatot, és a következő oldalon add meg a súlyt és az ismétlés számot.",
"Custom Exercise Plan": "Egyedi edzésterv",
"Select manually the exercises what you would like to have in your plan. At the end don't forget to save.": "Válaszd ki a gyakorlatokat, amelyeket szeretnél végrehajtani a tervedben. Utána ne felejtsd el elmenteni.",
"In this list you will find all your executed exercises grouped by the date.": "Ebben a listában találod az eddig végrehajtott gyakorlataid dátum szerint csoportosítva."
"In this list you will find all your executed exercises grouped by the date.": "Ebben a listában találod az eddig végrehajtott gyakorlataid dátum szerint csoportosítva.",
"Persistence!": "Kitartás!",
"Greetings!": "Üdvözöllek!",
"The purpose is to measure you physical condition": "A cél a jelenlegi fizikai kondíciód felmérése.",
"The suggested order of the exercises: chest - biceps - triceps - back - shoulders - core - tigh - calf.": "A gyakorlatok javasolt végrehajtási sorrendje: mell - bicepsz - tricepsz - hát - váll - has - comb - vádli.",
"Go to the menu Strength - One Rep Max - Chest, and select your favourite exercise.": "Menj a menüben az Erő - Max Erő - Mell menüpontba, és válaszd ki a kedvenc gyakorlatod.",
"Please continue your tests with a": "Kérlek folytasd a gyakorlatokat egy",
"I suggest begin your tests with a": "Azt javaslom, kezdd a teszteket egy 'mell' gyakorlattal",
"Nice! This is a good start": "Nagyon jó! Ez egy kitűnő start a teszthez",
"Go on!":"Gyerünk tovább!",
"You are on track": "Jó úton haladsz",
"Not so much left": "Már nincs sok hátra",
"Almost!": "Majdnem a végén vagy!",
"You have only 1-2 exercise left to finish!": "Már csak 1-2 gyakorlat van a végéig!",
"exercise!": "gyakorlattal!",
"Chest": "mell",
"Back": "hát",
"Thigh": "comb",
"Calf": "vádli",
"Bring me there": "Vigyél oda",
"My Body Development": "Testem fejlődése",
"You see here your whole body development by muscle groups.": "Itt láthatod a tested fejlődését izomcsoportonként"
}

View File

@ -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());
}
}
}

View File

@ -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();
}

View File

@ -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];
}

View File

@ -95,6 +95,7 @@ class CustomerChangeFormBloc extends FormBloc<String, String> {
birthYearField.close();
weightField.close();
genderField.close();
goalField.close();
return super.close();
}

View File

@ -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) {

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> {

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) {

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();

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];

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';

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;
}
}

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");

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 {
}

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);
}

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;

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);
}

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) );
}

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;
}
}

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);
}
}

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;
}
}

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
lib/util/group_data.dart Normal file
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();
}

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"),

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;

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,

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(

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),
),
);
}

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(

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;
}

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) =>
{

View File

@ -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,

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),

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(

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),
),
],
)
)
);
}
}

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;
},
),

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);
}
}

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(

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';

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,

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,
),
],
);
}
}
}

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

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;
}
}

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))
}
);
}
}

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) {

View File

@ -35,7 +35,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.5.0-nullsafety"
version: "2.4.2"
bloc:
dependency: transitive
description:
@ -56,7 +56,7 @@ packages:
name: boolean_selector
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0-nullsafety"
version: "2.0.0"
build:
dependency: transitive
description:
@ -91,14 +91,14 @@ packages:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.2"
version: "1.10.0"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.1"
version: "5.2.0"
built_collection:
dependency: transitive
description:
@ -119,14 +119,14 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0-nullsafety.2"
version: "1.0.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0-nullsafety"
version: "1.1.3"
checked_yaml:
dependency: transitive
description:
@ -147,7 +147,7 @@ packages:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0-nullsafety"
version: "1.0.1"
code_builder:
dependency: transitive
description:
@ -161,7 +161,7 @@ packages:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.15.0-nullsafety.2"
version: "1.14.13"
convert:
dependency: transitive
description:
@ -224,7 +224,7 @@ packages:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0-nullsafety"
version: "1.1.0"
ffi:
dependency: transitive
description:
@ -238,7 +238,7 @@ packages:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.0-nullsafety.1"
version: "5.2.1"
fixnum:
dependency: transitive
description:
@ -415,7 +415,7 @@ packages:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.3-nullsafety.1"
version: "0.6.2"
json_annotation:
dependency: transitive
description:
@ -443,14 +443,14 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.10-nullsafety"
version: "0.12.8"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0-nullsafety.2"
version: "1.1.8"
mime:
dependency: transitive
description:
@ -506,7 +506,7 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0-nullsafety"
version: "1.7.0"
path_drawing:
dependency: transitive
description:
@ -548,7 +548,7 @@ packages:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0-nullsafety.1"
version: "1.9.0"
percent_indicator:
dependency: "direct main"
description:
@ -562,14 +562,14 @@ packages:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
version: "3.0.4"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0-nullsafety.1"
version: "2.2.1"
plugin_platform_interface:
dependency: transitive
description:
@ -583,14 +583,14 @@ packages:
name: pool
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.0-nullsafety.1"
version: "1.4.0"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0-nullsafety.1"
version: "3.0.13"
provider:
dependency: transitive
description:
@ -735,21 +735,21 @@ packages:
name: source_map_stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0-nullsafety.2"
version: "2.0.0"
source_maps:
dependency: transitive
description:
name: source_maps
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.10-nullsafety.1"
version: "0.10.9"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0-nullsafety"
version: "1.7.0"
spider_chart:
dependency: "direct main"
description:
@ -763,14 +763,14 @@ packages:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0-nullsafety"
version: "1.9.5"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0-nullsafety"
version: "2.0.0"
stream_transform:
dependency: transitive
description:
@ -784,7 +784,7 @@ packages:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0-nullsafety"
version: "1.0.5"
sync_http:
dependency: transitive
description:
@ -798,28 +798,28 @@ packages:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0-nullsafety"
version: "1.1.0"
test:
dependency: "direct dev"
description:
name: test
url: "https://pub.dartlang.org"
source: hosted
version: "1.16.0-nullsafety.4"
version: "1.15.2"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.19-nullsafety"
version: "0.2.17"
test_core:
dependency: transitive
description:
name: test_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.12-nullsafety.4"
version: "0.3.10"
timing:
dependency: transitive
description:
@ -833,7 +833,7 @@ packages:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0-nullsafety.2"
version: "1.2.0"
usage:
dependency: transitive
description:
@ -854,14 +854,14 @@ packages:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0-nullsafety.2"
version: "2.0.8"
vm_service:
dependency: transitive
description:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.0"
version: "4.2.0"
vm_service_client:
dependency: transitive
description:
@ -910,7 +910,7 @@ packages:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
version: "0.1.0"
xml:
dependency: transitive
description:
@ -926,5 +926,5 @@ packages:
source: hosted
version: "2.2.1"
sdks:
dart: ">=2.10.0-4.0.dev <2.10.0"
dart: ">=2.9.0-14.0.dev <3.0.0"
flutter: ">=1.16.0 <2.0.0"

View File

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.1.0+23
version: 1.1.2+2
environment:
sdk: ">=2.7.0 <3.1.0"
@ -24,8 +24,6 @@ dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.0
devicelocale: ^0.3.2
sentry: ^3.0.1
@ -94,6 +92,9 @@ flutter:
- asset/image/WT_welcome.png
- asset/image/login_fb.png
- asset/image/lock.png
- asset/image/Congrats_N1.jpg
- asset/image/development_muscles.jpg
- asset/image/exercise_log.jpg
- asset/menu/1.cardio.png
- asset/menu/1.1.aerob.png
- asset/menu/1.2.anaerob.png
@ -118,6 +119,14 @@ flutter:
- asset/menu/3.1.BMI.png
- asset/menu/3.2.BMR.png
- asset/menu/3.3.sizes.png
- asset/menu/cable triceps.png
- asset/menu/Back_pullup.png
- asset/menu/biceps.jpg
- asset/menu/calf.png
- asset/menu/legpress.jpg
- asset/menu/shoulder press.png
- asset/menu/squat.jpg
- asset/menu/tricdip.jpg
- i18n/en.json
- i18n/hu.json

View File

@ -1,9 +1,8 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/service/customer_service.dart';
import 'package:aitrainer_app/util/env.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
//import 'package:mockito/mockito.dart';
// Create a MockClient using the Mock class provided by the Mockito package.

View File

@ -11,8 +11,6 @@ main() {
SimExercisePlanRepository _exercisePlanRepository;
ExercisePlanBloc bloc;
int _customerId;
Future<void> setUpPlan() async {
final String planName2 = "Test Plan2";
ExercisePlan plan2 = ExercisePlan(planName2, 101);
@ -42,7 +40,6 @@ main() {
WorkoutTreeRepository menuTreeRepository = WorkoutTreeRepository();
bloc = ExercisePlanBloc(menuTreeRepository: menuTreeRepository);
bloc.setExercisePlanRepository(_exercisePlanRepository);
_customerId = 62;
await setUpPlan();
});

View File

@ -1,7 +1,6 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_plan.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
import 'mocks.dart';

View File

@ -13,7 +13,7 @@ class MockExercisePlanApi extends Mock implements ExercisePlanApi {
return _singleton;
}
MockExercisePlanApi._internal() {}
MockExercisePlanApi._internal();
final List<ExercisePlan> memoryExercisePlan = List();
final List<ExercisePlanDetail> memoryExercisePlanDetail = List();

View File

@ -52,13 +52,11 @@ class MockCommon with Common {
void main() {
group('LoginScreen', () {
MockLoginBloc loginBloc;
MockUserRepository userRepository;
Widget loginWidget;
MockCommon common;
setUp(() {
loginBloc = MockLoginBloc();
userRepository = MockUserRepository();
common = MockCommon();
loginWidget =

View File

@ -1,5 +1,4 @@
// Imports the Flutter Driver API.
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';
void main() {