WT 1.1.0+39 evaluation, health data

This commit is contained in:
bossanyit
2020-12-17 22:32:45 +01:00
parent 81f904af2c
commit 5c7a3d67e8
57 changed files with 1702 additions and 225 deletions
@@ -23,6 +23,8 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
double firstQuantity; // quantity of the first test
double firstUnitQuantity; // unit quantity of the first test
double scrollOffset = 0;
@override
ExerciseControlBloc({this.exerciseRepository, this.readonly, this.percentToCalculate}) : super(ExerciseControlInitial()) {
firstUnitQuantity = exerciseRepository.exercise.unitQuantity;
@@ -36,7 +38,6 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
origQuantity = quantity;
exerciseRepository.setUnitQuantity(unitQuantity);
}
@override
@@ -46,23 +47,31 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
yield ExerciseControlLoading();
step = 1;
yield ExerciseControlReady();
} else if (event is ExerciseControlQuantityChange ) {
} else if (event is ExerciseControlQuantityChange) {
yield ExerciseControlLoading();
if ( event.step == step) {
exerciseRepository.setQuantity(event.quantity);
quantity = event.quantity;
}
if (event.step == step) {
exerciseRepository.setQuantity(event.quantity);
quantity = event.quantity;
}
yield ExerciseControlReady();
} else if (event is ExerciseControlSubmit ) {
} else if (event is ExerciseControlSubmit) {
yield ExerciseControlLoading();
if ( event.step == step) {
if (event.step == step) {
step++;
//print("step " + step.toString() + " quantity " + quantity.toString() + " origQ: " + origQuantity.toString());
scrollOffset = step * 200.0;
print("step " +
step.toString() +
" quantity " +
quantity.toString() +
" origQuantity: " +
origQuantity.toString() +
" scrollOffset: " +
scrollOffset.toString());
repeats.add(quantity);
quantity = origQuantity;
exerciseRepository.end = DateTime.now();
await exerciseRepository.addExercise();
exerciseRepository.setQuantity(quantity);
}
yield ExerciseControlReady();
@@ -78,7 +87,7 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
}
double weight = exerciseRepository.exercise.unitQuantity;
double repeat = exerciseRepository.exercise.quantity;
if ( weight == 0 || repeat == 0) {
if (weight == 0 || repeat == 0) {
return 0;
}
@@ -86,6 +95,6 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
double rmOconner = weight * (1 + repeat / 40);
double average = (rmWendler + rmOconner) / 2;
return percent75 ? average * this.percentToCalculate : average;
return percent75 ? average * this.percentToCalculate : average;
}
}
+14 -4
View File
@@ -13,6 +13,7 @@ import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:meta/meta.dart';
import 'package:stop_watch_timer/stop_watch_timer.dart';
part 'exercise_new_event.dart';
part 'exercise_new_state.dart';
@@ -45,6 +46,11 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> {
double mediaHeight = 0;
bool isMan = true;
final StopWatchTimer stopWatchTimer = StopWatchTimer(
isLapHours: false,
);
int timerValue;
@override
ExerciseNewBloc({this.exerciseRepository, this.menuBloc, this.customerRepository, ExerciseType exerciseType})
: super(ExerciseNewInitial()) {
@@ -52,14 +58,15 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> {
exerciseRepository.setQuantity(quantity);
exerciseRepository.setUnitQuantity(unitQuantity);
exerciseRepository.exercise.exercisePlanDetailId = 0;
exerciseRepository.start = DateTime.now();
if (Cache().userLoggedIn != null) {
customerRepository.customer = Cache().userLoggedIn;
weight = customerRepository.customer.getProperty("Weight");
height = customerRepository.customer.getProperty("Height");
fitnessLevel = customerRepository.customer.fitnessLevel;
this.isMan = (customerRepository.customer.sex == "m");
print("Sex Man? " + isMan.toString() + " " + customerRepository.customer.sex);
}
stopWatchTimer.rawTime.listen((value) => timerValue = value);
}
void setMediaDimensions(double width, double height) {
@@ -75,7 +82,6 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> {
}
final double distortionWidth = mediaWidth / baseWidth;
final double distortionHeight = mediaHeight / baseHeight;
print("distiortionW " + distortionWidth.toString() + " dH " + distortionHeight.toString());
if (isMan) {
properties.forEach((element) {
if (element.propertyName == "Shoulder") {
@@ -146,12 +152,10 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> {
element.top = (122 * distortionHeight).toInt();
element.left = (151 * distortionWidth).toInt();
element.value = customerRepository.customer.getProperty("Shoulder");
print("CHEST top: " + element.top.toString() + " left " + element.left.toString());
manSizes.add(element);
} else if (element.propertyName == "Neck") {
element.top = (78 * distortionHeight).toInt();
element.left = (151 * distortionWidth).toInt();
print("Neck top: " + element.top.toString() + " left " + element.left.toString());
element.value = customerRepository.customer.getProperty("Neck");
manSizes.add(element);
} else if (element.propertyName == "Biceps") {
@@ -279,6 +283,7 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> {
yield ExerciseNewReady();
} else if (event is ExerciseNewSubmit) {
yield ExerciseNewLoading();
exerciseRepository.end = DateTime.now();
await exerciseRepository.addExercise();
menuBloc.add(MenuTreeDown(parent: 0));
Cache().initBadges();
@@ -373,4 +378,9 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> {
return goalBMI;
}
@override
void dispose() async {
await stopWatchTimer.dispose();
}
}
+4 -6
View File
@@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:collection';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/exercise_device_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
@@ -15,8 +16,6 @@ import 'package:meta/meta.dart';
part 'menu_event.dart';
part 'menu_state.dart';
enum ExerciseAbility { oneRepMax, endurance, none }
class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans {
final WorkoutTreeRepository menuTreeRepository;
final ExerciseRepository exerciseRepository = ExerciseRepository();
@@ -106,8 +105,9 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans {
yield MenuLoading();
parent = event.parent;
workoutItem = event.item;
setAbility(workoutItem.nameEnglish);
//print("menuitem " + workoutItem.id.toString() + " parent "+workoutItem.parent.toString());
if (workoutItem != null) {
setAbility(workoutItem.nameEnglish);
}
menuTreeRepository.getBranch(event.parent);
yield MenuReady();
} else if (event is MenuTreeUp) {
@@ -117,7 +117,6 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans {
workoutItem = menuTreeRepository.getParentItem(parent);
if (workoutItem != null) {
//print("UP menuitem " + workoutItem.id.toString() + " parent " + workoutItem.parent.toString());
menuTreeRepository.getBranch(workoutItem.parent);
setAbility(workoutItem.nameEnglish);
}
@@ -128,7 +127,6 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans {
workoutItem = menuTreeRepository.getParentItem(parent);
if (workoutItem != null) {
//print("JUMP menuitem " + workoutItem.id.toString() + " parent " + workoutItem.parent.toString());
menuTreeRepository.getBranch(workoutItem.parent);
setAbility(workoutItem.nameEnglish);
}
+225
View File
@@ -0,0 +1,225 @@
import 'dart:async';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/result.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/repository/exercise_result_repository.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:health/health.dart';
part 'result_event.dart';
part 'result_state.dart';
class ResultBloc extends Bloc<ResultEvent, ResultState> {
final ExerciseResultRepository resultRepository;
final ExerciseRepository exerciseRepository;
List<HealthDataPoint> _healthDataList = List();
DateTime startTime;
DateTime endTime;
final HealthFactory health = HealthFactory();
final List<HealthDataType> types = [
HealthDataType.ACTIVE_ENERGY_BURNED,
HealthDataType.WATER,
HealthDataType.STEPS,
HealthDataType.HEART_RATE,
HealthDataType.BASAL_ENERGY_BURNED,
HealthDataType.BODY_TEMPERATURE,
HealthDataType.HIGH_HEART_RATE_EVENT,
HealthDataType.LOW_HEART_RATE_EVENT,
HealthDataType.RESTING_HEART_RATE
];
ResultBloc({this.resultRepository, this.exerciseRepository}) : super(ResultInitial()) {
this.startTime = exerciseRepository.start;
this.endTime = exerciseRepository.end;
}
@override
Stream<ResultState> mapEventToState(
ResultEvent event,
) async* {
try {
if (event is ResultLoad) {
yield ResultLoading();
await _fetchHealthData();
_matchExerciseData();
yield ResultReady();
}
} on Exception catch (ex) {
yield ResultError(error: ex.toString());
}
}
void _matchExerciseData() {
resultRepository.getResults().forEach((element) {
switch (element.item) {
case ResultItem.bpm_avg:
element.data = _gethHealthDataPointValueAvg(HealthDataType.HEART_RATE).toStringAsFixed(0);
break;
case ResultItem.bpm_min:
element.data = element.data = _gethHealthDataPointValueMin(HealthDataType.HEART_RATE).toStringAsFixed(0);
break;
case ResultItem.bpm_max:
element.data = element.data = _gethHealthDataPointValueMax(HealthDataType.HEART_RATE).toStringAsFixed(0);
break;
case ResultItem.calorie:
element.data = _gethHealthDataPointValueSum(HealthDataType.ACTIVE_ENERGY_BURNED).toStringAsFixed(0);
break;
case ResultItem.development_percent_bodypart:
// TODO: Handle this case.
break;
case ResultItem.distance:
if (exerciseRepository.exerciseType.unit == "meter") {
element.data = exerciseRepository.exercise.quantity.toStringAsFixed(0);
}
break;
case ResultItem.fatburn_percent:
DateTime today = DateTime.now();
int age = today.year - Cache().userLoggedIn.birthYear;
double minBpm = (200 - age) * 0.6;
double maxBpm = (200 - age) * 0.7;
int counter = 0;
int burnCounter = 0;
_healthDataList.forEach((dataPoint) {
if (dataPoint.type == HealthDataType.ACTIVE_ENERGY_BURNED) {
if (dataPoint.value >= minBpm && dataPoint.value <= maxBpm) {
burnCounter++;
}
counter++;
}
});
if (counter > 0) {
element.data = (burnCounter / counter * 100).toStringAsFixed(2);
} else {
element.data = "0";
}
break;
case ResultItem.speed_max:
// TODO: Handle this case.
break;
case ResultItem.reps_volume:
if (exerciseRepository.exerciseType.unit == "repeat") {
double value = 0;
exerciseRepository.actualExerciseList.forEach((element) {
value += element.quantity;
});
element.data = value.toStringAsFixed(0);
}
break;
case ResultItem.steps:
element.data = _gethHealthDataPointValueSum(HealthDataType.STEPS).toStringAsFixed(0);
break;
/* case ResultItem.time:
final Duration duration = this.endTime.difference(this.startTime);
element.data = _printDuration(duration);
break; */
case ResultItem.weight_volume:
if (exerciseRepository.exerciseType.unitQuantityUnit == "kilogram") {
double value = 0;
exerciseRepository.actualExerciseList.forEach((element) {
value += element.quantity * element.unitQuantity;
});
element.data = value.toStringAsFixed(0);
}
break;
}
});
}
String _printDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes);
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
String twoDigitMilliSeconds = duration.inMilliseconds.remainder(1000).toString();
return "$twoDigitMinutes:$twoDigitSeconds:$twoDigitMilliSeconds" + '"';
}
double _gethHealthDataPointValueAvg(HealthDataType dataType) {
double value = 0;
double counter = 0;
_healthDataList.forEach((dataPoint) {
if (dataPoint.type == dataType) {
value += dataPoint.value;
counter++;
}
});
double avg = 0;
if (counter > 0) {
avg = value / counter;
}
return avg;
}
double _gethHealthDataPointValueSum(HealthDataType dataType) {
double value = 0;
_healthDataList.forEach((dataPoint) {
if (dataPoint.type == dataType) {
value += dataPoint.value;
}
});
return value;
}
double _gethHealthDataPointValueMax(HealthDataType dataType) {
double max = 0;
_healthDataList.forEach((dataPoint) {
if (dataPoint.type == dataType) {
if (max < dataPoint.value) {
max = dataPoint.value;
}
}
});
return max;
}
double _gethHealthDataPointValueMin(HealthDataType dataType) {
double min = 9999999;
_healthDataList.forEach((dataPoint) {
if (dataPoint.type == dataType) {
if (min > dataPoint.value && dataPoint.value != 0) {
min = dataPoint.value;
}
}
});
if (min == 9999999) {
min = 0;
}
return min;
}
Future<void> _fetchHealthData() async {
if (health == null) {
return;
}
try {
print("Get Health data between " + startTime.toString() + " AND " + endTime.toString());
_healthDataList = await health.getHealthDataFromTypes(this.startTime, this.endTime, types);
_healthDataList.forEach((element) {
print(element.toString());
});
} on Exception catch (e) {
print("Caught exception in getHealthDataFromTypes: $e");
throw Exception(e);
}
}
double calculate1RM({double percent}) {
if (exerciseRepository.exercise == null) {
exerciseRepository.getLastExercise();
}
double weight = exerciseRepository.exercise.unitQuantity;
double repeat = exerciseRepository.exercise.quantity;
if (weight == 0 || repeat == 0) {
return 0;
}
double rmWendler = weight * repeat * 0.0333 + weight;
double rmOconner = weight * (1 + repeat / 40);
double average = (rmWendler + rmOconner) / 2;
return average * percent;
}
}
+12
View File
@@ -0,0 +1,12 @@
part of 'result_bloc.dart';
abstract class ResultEvent extends Equatable {
const ResultEvent();
@override
List<Object> get props => [];
}
class ResultLoad extends ResultEvent {
const ResultLoad();
}
+28
View File
@@ -0,0 +1,28 @@
part of 'result_bloc.dart';
abstract class ResultState extends Equatable {
const ResultState();
@override
List<Object> get props => [];
}
class ResultInitial extends ResultState {
const ResultInitial();
}
class ResultLoading extends ResultState {
const ResultLoading();
}
class ResultReady extends ResultState {
const ResultReady();
}
class ResultError extends ResultState {
final String error;
const ResultError({this.error});
@override
List<Object> get props => [this.error];
}
+42 -6
View File
@@ -2,9 +2,11 @@ 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';
import 'package:health/health.dart';
import 'package:meta/meta.dart';
part 'settings_event.dart';
@@ -31,18 +33,52 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
) async* {
if (event is SettingsChangeLanguage) {
yield SettingsLoading();
await _changeLang( event.language);
await _changeLang(event.language);
yield SettingsReady(_locale);
} else if ( event is SettingsGetLanguage) {
} else if (event is SettingsGetLanguage) {
await AppLanguage().fetchLocale();
_locale = AppLanguage().appLocal;
yield SettingsReady(_locale);
} else if (event is SettingsSetServer) {
yield SettingsLoading();
final bool live = event.live;
Cache().setServer(live);
yield SettingsReady(_locale);
} else if (event is SettingsSetHardware) {
yield SettingsLoading();
bool selectedHardwareBefore = await Cache().selectedHardwareBefore();
print("selectedBefore " + selectedHardwareBefore.toString());
if (!selectedHardwareBefore) {
await _accessHealthData();
}
final bool hasHardware = event.hasHardware;
await Cache().setHardware(hasHardware);
yield SettingsReady(_locale);
}
}
Future<void> _changeLang( String lang ) async{
Future<void> _accessHealthData() async {
final List<HealthDataType> types = [
HealthDataType.ACTIVE_ENERGY_BURNED,
HealthDataType.WATER,
HealthDataType.STEPS,
HealthDataType.HEART_RATE,
HealthDataType.BASAL_ENERGY_BURNED,
HealthDataType.BODY_TEMPERATURE,
HealthDataType.HIGH_HEART_RATE_EVENT,
HealthDataType.LOW_HEART_RATE_EVENT,
HealthDataType.RESTING_HEART_RATE
];
final HealthFactory health = HealthFactory();
DateTime now = DateTime.now();
List<HealthDataPoint> _healthDataList = await health.getHealthDataFromTypes(now.subtract(Duration(minutes: 5)), now, types);
print(_healthDataList.toString());
}
Future<void> _changeLang(String lang) async {
print("_change to $lang");
switch ( lang ) {
switch (lang) {
case "English":
case "en":
case "Angol":
@@ -59,8 +95,8 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
await loadLang();
}
Future<void> loadLang() async{
if ( _locale != null ) {
Future<void> loadLang() async {
if (_locale != null) {
print(" -- Loading lang $_locale");
if (context != null) {
AppLocalizations.of(context).setLocale(_locale);
+16
View File
@@ -15,3 +15,19 @@ class SettingsChangeLanguage extends SettingsEvent {
class SettingsGetLanguage extends SettingsEvent {
const SettingsGetLanguage();
}
class SettingsSetServer extends SettingsEvent {
final bool live;
const SettingsSetServer({this.live});
@override
List<Object> get props => [this.live];
}
class SettingsSetHardware extends SettingsEvent {
final bool hasHardware;
const SettingsSetHardware({this.hasHardware});
@override
List<Object> get props => [this.hasHardware];
}