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

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
asset/image/pict_steps.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
asset/image/pict_time_h.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -235,5 +235,20 @@
"Live-Server":"Live-Server",
"Test-Server":"Test-Server",
"All Exercises has been filtered out":"All Exercises has been filtered out",
"base":"base"
"base":"base",
"Hypertrophy":"Hypertrophy",
"Gain Strength":"Gain Strength",
"repeats":"repeats",
"minutes":"minutes",
"Rest time":"Rest time",
"Suggestions based on your test":"Suggestions based on your test",
"Repeats volume":"Repeats volume",
"Weight volume":"Weight volume",
"Calorie":"Calorie",
"Max BPM":"Max BPM",
"Min BPM":"Min BPM",
"Average BPM":"Average BPM",
"Fatburn %":"Fatburn %",
"Health Data Summary":"Health Data Summary"
}

View File

@ -236,5 +236,20 @@
"Live-Server":"Live-Server",
"Test-Server":"Test-Server",
"All Exercises has been filtered out":"Az összes gyakorlatot kiszűrted",
"base":"alap"
"base":"alap",
"Hypertrophy":"Izomnövelés",
"Gain Strength":"Erőnövelés",
"repeats":"ismétlés",
"Rest time":"Pihenőidő",
"minutes":"perc",
"Suggestions based on your test":"Javaslatok a teszted alapján",
"Repeats volume":"Össz. ismétlés",
"Weight volume":"Össztömeg",
"Calorie":"Kalória",
"Max BPM":"Max pulzus",
"Min BPM":"Min pulzus",
"Average BPM":"Átl pulzus",
"Fatburn %":"Zsírégetés %",
"Health Data Summary":"Egészségadatok összefoglalás"
}

View File

@ -1,4 +1,6 @@
PODS:
- device_info (0.0.1):
- Flutter
- devicelocale (0.0.1):
- Flutter
- Firebase/Auth (6.33.0):
@ -84,6 +86,8 @@ PODS:
- GoogleUtilities/UserDefaults (6.7.2):
- GoogleUtilities/Logger
- GTMSessionFetcher/Core (1.5.0)
- health (1.0.1):
- Flutter
- nanopb (1.30906.0):
- nanopb/decode (= 1.30906.0)
- nanopb/encode (= 1.30906.0)
@ -100,6 +104,7 @@ PODS:
- FMDB (>= 2.7.5)
DEPENDENCIES:
- device_info (from `.symlinks/plugins/device_info/ios`)
- devicelocale (from `.symlinks/plugins/devicelocale/ios`)
- firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
@ -107,6 +112,7 @@ DEPENDENCIES:
- flurry (from `.symlinks/plugins/flurry/ios`)
- Flutter (from `Flutter`)
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- health (from `.symlinks/plugins/health/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
@ -130,6 +136,8 @@ SPEC REPOS:
- Protobuf
EXTERNAL SOURCES:
device_info:
:path: ".symlinks/plugins/device_info/ios"
devicelocale:
:path: ".symlinks/plugins/devicelocale/ios"
firebase_auth:
@ -144,6 +152,8 @@ EXTERNAL SOURCES:
:path: Flutter
flutter_keyboard_visibility:
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
health:
:path: ".symlinks/plugins/health/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
shared_preferences:
@ -152,6 +162,7 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/sqflite/ios"
SPEC CHECKSUMS:
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
devicelocale: feebbe5e7a30adb8c4f83185de1b50ff19b44f00
Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
firebase_auth: cb33b01b51904969161403bbcb20036519f0c578
@ -171,6 +182,7 @@ SPEC CHECKSUMS:
GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
health: 44840ad4328aa5586e77bef289898bfed644a81c
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f

View File

@ -15,6 +15,7 @@
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
BB69292B2521AF45001FBA4C /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BB69292A2521AF45001FBA4C /* Launch Screen.storyboard */; };
BB81345024BB4BE10078D9A4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB81344F24BB4BE10078D9A4 /* GoogleService-Info.plist */; };
BBDBEBB825862170006762F6 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBDBEBB725862170006762F6 /* HealthKit.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@ -48,6 +49,7 @@
BB43773E2540715900D74BFA /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
BB69292A2521AF45001FBA4C /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
BB81344F24BB4BE10078D9A4 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
BBDBEBB725862170006762F6 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; };
D5EDDC52125075FB9E21AD35 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
F39E6E227EB942E5663A6086 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -58,6 +60,7 @@
buildActionMask = 2147483647;
files = (
42B6B159AF35AFB6DE777DFB /* Pods_Runner.framework in Frameworks */,
BBDBEBB825862170006762F6 /* HealthKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -77,6 +80,7 @@
3ADC50290ED054951FAC1F56 /* Frameworks */ = {
isa = PBXGroup;
children = (
BBDBEBB725862170006762F6 /* HealthKit.framework */,
09BD889296C5C90D989820C8 /* Pods_Runner.framework */,
);
name = Frameworks;
@ -362,7 +366,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 38;
CURRENT_PROJECT_VERSION = 39;
DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -505,7 +509,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 38;
CURRENT_PROJECT_VERSION = 39;
DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -540,7 +544,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 38;
CURRENT_PROJECT_VERSION = 39;
DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (

View File

@ -46,6 +46,10 @@
<string>10.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSHealthShareUsageDescription</key>
<string>We will sync your data with the Apple Health app to give you better insights</string>
<key>NSHealthUpdateUsageDescription</key>
<string>We will sync your data with the Apple Health app to give you better insights</string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>

View File

@ -4,5 +4,11 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.healthkit</key>
<true/>
<key>com.apple.developer.healthkit.access</key>
<array>
<string>health-records</string>
</array>
</dict>
</plist>

View File

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

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

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;
if (workoutItem != null) {
setAbility(workoutItem.nameEnglish);
//print("menuitem " + workoutItem.id.toString() + " parent "+workoutItem.parent.toString());
}
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);
}

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

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

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

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

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

View File

@ -11,6 +11,7 @@ import 'package:aitrainer_app/view/customer_fitness_page.dart';
import 'package:aitrainer_app/view/customer_goal_page.dart';
import 'package:aitrainer_app/view/customer_modify_page.dart';
import 'package:aitrainer_app/view/customer_welcome_page.dart';
import 'package:aitrainer_app/view/evaluation.dart';
import 'package:aitrainer_app/view/exercise_control_page.dart';
import 'package:aitrainer_app/view/exercise_execute_page.dart';
import 'package:aitrainer_app/view/exercise_execute_plan_add_page.dart';
@ -216,6 +217,7 @@ class WorkoutTestApp extends StatelessWidget {
'exerciseExecuteAddPage': (context) => ExerciseExecutePlanAddPage(),
'mydevelopmentMusclePage': (context) => MyDevelopmentMusclePage(),
'mydevelopmentBodyPage': (context) => MyDevelopmentBodyPage(),
'evaluationPage': (context) => EvaluationPage(),
},
initialRoute: 'home',
title: 'WorkoutTest',

View File

@ -55,6 +55,7 @@ class Cache {
static final String isLoggedInKey = 'is_logged_in';
static final String langKey = 'lang';
static final String serverKey = 'live';
static final String hardwareKey = 'hardware';
static String baseUrl = 'http://aitrainer.info:8888/api/';
static final String mediaUrl = 'https://aitrainer.info:4343/media/';
@ -92,6 +93,7 @@ class Cache {
String startPage;
String testEnvironment;
bool liveServer = true;
bool hasHardware = false;
factory Cache() {
return _singleton;
@ -114,7 +116,7 @@ class Cache {
return this.authToken;
}
void setServer(bool live) async {
Future<void> setServer(bool live) async {
if (this.testEnvironment == "1") {
liveServer = false;
live = false;
@ -123,10 +125,34 @@ class Cache {
SharedPreferences sharedPreferences;
sharedPreferences = await prefs;
liveServer = live;
print("Set Live servier. live? " + live.toString() + " env? " + this.testEnvironment);
sharedPreferences.setBool(Cache.serverKey, live);
}
void getHardware(SharedPreferences prefs) {
final bool hasHardware = prefs.getBool(Cache.hardwareKey);
print("Has Hardware: " + hasHardware.toString());
this.hasHardware = hasHardware;
if (hasHardware == null) {
this.hasHardware = false;
}
}
Future<bool> selectedHardwareBefore() async {
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
SharedPreferences sharedPreferences = await prefs;
final bool selectedHardware = sharedPreferences.getBool(Cache.hardwareKey);
return selectedHardware == null;
}
Future<void> setHardware(bool hasHardware) async {
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
SharedPreferences sharedPreferences;
sharedPreferences = await prefs;
sharedPreferences.setBool(Cache.hardwareKey, hasHardware);
this.hasHardware = hasHardware;
}
void setServerAddress(SharedPreferences prefs) {
if (this.testEnvironment == "1") {
baseUrl = 'http://aitrainer.app:8899/api/';

View File

@ -0,0 +1,6 @@
enum ExerciseAbility { oneRepMax, endurance, running, none }
extension ExerciseAbilityExt on ExerciseAbility {
bool equalsTo(ExerciseAbility ability) => this.toString() == ability.toString();
bool equalsStringTo(String ability) => this.toString() == ability;
}

View File

@ -0,0 +1,44 @@
import 'package:aitrainer_app/model/result.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
class ExerciseResult {
int exerciseResultId;
int customerId;
int exerciseId;
int exercisePlanId;
String resultType;
double value;
DateTime dateFrom;
DateTime dateTo;
ResultExt resultExtension;
Map<String, dynamic> toJson() {
String formattedDateTo;
if (dateTo != null) {
formattedDateTo = DateFormat('yyyy-MM-dd HH:mm').format(dateTo);
}
return {
"customerId": customerId,
"exerciseId": exerciseId,
"exercisePlanId": exercisePlanId,
"resultType": resultType,
"value": value,
"dateFrom": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateFrom),
"dateTo": formattedDateTo,
};
}
ExerciseResult.fromJson(Map json) {
this.exerciseResultId = json['exerciseResultId'];
this.exerciseId = json['exerciseId'];
this.exercisePlanId = json['exercisePlanId'];
this.customerId = json['customerId'];
this.resultType = json['resultType'];
this.value = json["value"];
this.dateFrom = DateTime.parse(json['dateFrom']);
this.dateTo = DateTime.parse(json['dateTo']);
this.resultExtension = ResultExt(itemString: this.resultType);
}
}

View File

@ -37,6 +37,7 @@ class ExerciseTree {
if (parentId != -1) {
newTree.parentId = parentId;
}
newTree.active = this.active;
return newTree;
}

View File

@ -1,3 +1,4 @@
import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:flutter/services.dart';
class ExerciseType {
@ -17,8 +18,7 @@ class ExerciseType {
List<int> devices = List();
List<int> parents = List();
bool is1RM;
bool isEndurance;
ExerciseAbility ability;
ExerciseType({this.name, this.description});
@ -70,19 +70,19 @@ class ExerciseType {
"parents": this.parents.toString()
};
void set1RM(bool is1RM) {
this.is1RM = is1RM;
void setAbility(ExerciseAbility ability) {
this.ability = ability;
}
bool get1RM() {
return this.is1RM;
ExerciseAbility getAbility() {
return this.ability;
}
void setEndurance(bool isEndurance) {
this.isEndurance = isEndurance;
bool isEndurance() {
return this.ability.equalsTo(ExerciseAbility.endurance);
}
bool getEndurance() {
return this.isEndurance;
bool is1RM() {
return this.ability.equalsTo(ExerciseAbility.oneRepMax);
}
}

93
lib/model/result.dart Normal file
View File

@ -0,0 +1,93 @@
enum ResultItem {
calorie,
development_percent_bodypart,
distance,
fatburn_percent,
bpm_avg,
bpm_min,
bpm_max,
speed_max,
reps_volume,
steps,
//time,
weight_volume
}
extension ResultItemExt on ResultItem {
static const ResultItemDesc = {
ResultItem.calorie: "Calorie",
ResultItem.development_percent_bodypart: "Development in %",
ResultItem.distance: "Distance",
ResultItem.bpm_avg: "Average BPM",
ResultItem.bpm_min: "Min BPM",
ResultItem.bpm_max: "Max BPM",
ResultItem.speed_max: "Max speed",
ResultItem.reps_volume: "Repeats volume",
ResultItem.steps: "Steps",
//ResultItem.time: "Time",
ResultItem.weight_volume: "Weight volume",
ResultItem.fatburn_percent: "Fatburn %",
};
static const ResultItemImg = {
ResultItem.calorie: "pict_calorie.png",
ResultItem.development_percent_bodypart: "pic_development_by_bodypart_percent.png",
ResultItem.distance: "pict_distance_m.png",
ResultItem.bpm_avg: "pict_hravg_bpm.png",
ResultItem.bpm_min: "pict_hrmin_bpm.png",
ResultItem.bpm_max: "pict_hrmax_bpm.png",
ResultItem.speed_max: "pict_maxspeed_kmh.png",
ResultItem.reps_volume: "pict_reps_volumen_db.png",
ResultItem.steps: "pict_steps.png",
//ResultItem.time: "pict_time_h.png",
ResultItem.weight_volume: "pict_weight_volumen_tonna.png",
ResultItem.fatburn_percent: "pict_fatburn_percent.png",
};
static const HardwareData = {
ResultItem.calorie: true,
ResultItem.development_percent_bodypart: false,
ResultItem.distance: true,
ResultItem.bpm_avg: true,
ResultItem.bpm_min: true,
ResultItem.bpm_max: true,
ResultItem.speed_max: true,
ResultItem.reps_volume: false,
ResultItem.steps: true,
//ResultItem.time: false,
ResultItem.weight_volume: false,
ResultItem.fatburn_percent: true,
};
bool equals(ResultItem item) => this.toString() == item.toString();
bool equalsString(String item) => this.description == item;
String get description => ResultItemDesc[this];
String get image => ResultItemImg[this];
bool get isHardware => HardwareData[this];
String displayString() => description;
}
class ResultExt {
final String itemString;
ResultItem item;
String data = "0";
ResultExt({this.itemString}) {
ResultItem.values.forEach((element) {
if (element.equalsString(itemString)) {
item = element;
}
});
}
String getDescription() => item.description;
String getImage() => "asset/image/" + item.image;
bool isHardware() {
return item.isHardware;
}
bool equals(ResultItem item) => this.item.equals(item);
bool equalsString(String item) => this.item.equalsString(item);
}

View File

@ -2,6 +2,22 @@ import 'dart:ui';
import 'exercise_type.dart';
enum WorkoutType { endurance, oneRepMax, cardio, staticExercise }
extension WorkoutTypeExt on WorkoutType {
static const WorkoutTypeMenu = {
WorkoutType.endurance: "Endurance",
WorkoutType.cardio: "Cardio",
WorkoutType.oneRepMax: "One Rep Max",
WorkoutType.staticExercise: "Static"
};
bool equals(WorkoutType type) => this.toString() == type.toString();
bool equalsString(String type) => this.toString() == type;
String get menu => WorkoutTypeMenu[this];
}
class WorkoutMenuTree {
int id;
int parent;
@ -16,13 +32,15 @@ class WorkoutMenuTree {
bool is1RM;
bool isEndurance;
bool isRunning;
List<WorkoutType> workoutTypes = List();
bool selected = false;
bool executed = false;
String exerciseDetail;
String nameEnglish;
WorkoutMenuTree(this.id, this.parent, this.name, this.imageName, this.color, this.fontSize, this.child, this.exerciseTypeId,
this.exerciseType, this.base, this.is1RM, this.isEndurance, this.nameEnglish);
this.exerciseType, this.base, this.is1RM, this.isEndurance, this.isRunning, this.nameEnglish);
Map<String, dynamic> toJson() {
return {
@ -37,6 +55,7 @@ class WorkoutMenuTree {
"base": base.toString(),
"is1RM": is1RM.toString(),
"isEndurance": isEndurance.toString(),
"isRunning": isRunning.toString(),
};
}

View File

@ -12,6 +12,7 @@ class ExerciseRepository {
Customer customer;
ExerciseType exerciseType;
List<Exercise> exerciseList;
List<Exercise> actualExerciseList = List();
double rmWendler = 0;
double rmMcglothlin = 0;
@ -20,28 +21,35 @@ class ExerciseRepository {
double rmOconner = 0;
double rmWathen = 0;
DateTime start;
DateTime end;
ExerciseRepository() {
this.createNew();
}
createNew() {
this.exercise = Exercise();
exercise.dateAdd = DateTime.now();
}
setQuantity(double quantity) {
if ( this.exercise == null ) {
if (this.exercise == null) {
this.createNew();
}
this.exercise.quantity = quantity;
}
setUnitQuantity(double unitQuantity) {
if ( this.exercise == null ) {
if (this.exercise == null) {
this.createNew();
}
this.exercise.unitQuantity = unitQuantity;
}
setUnit( String unit) {
if ( this.exercise == null ) {
setUnit(String unit) {
if (this.exercise == null) {
this.createNew();
}
@ -49,7 +57,7 @@ class ExerciseRepository {
}
setDatetimeExercise(DateTime datetimeExercise) {
if ( this.exercise == null ) {
if (this.exercise == null) {
this.createNew();
}
@ -66,10 +74,15 @@ class ExerciseRepository {
final Exercise modelExercise = this.exercise;
modelExercise.customerId = this.customer.customerId;
modelExercise.exerciseTypeId = this.exerciseType.exerciseTypeId;
if (exerciseType.unitQuantity != "1") {
modelExercise.unitQuantity = null;
}
this.actualExerciseList.add(modelExercise);
Exercise savedExercise = await ExerciseApi().addExercise(modelExercise);
if ( customer.customerId == Cache().userLoggedIn.customerId) {
if (customer.customerId == Cache().userLoggedIn.customerId) {
Cache().addExercise(savedExercise);
} else if ( Cache().getTrainee() != null && customer.customerId == Cache().getTrainee().customerId ) {
} else if (Cache().getTrainee() != null && customer.customerId == Cache().getTrainee().customerId) {
Cache().addExerciseTrainee(savedExercise);
}
}
@ -78,21 +91,17 @@ class ExerciseRepository {
await ExerciseApi().deleteExercise(exercise);
}
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 {
Future<List<Exercise>> getExercisesByCustomer(int customerId) async {
final results = await ExerciseApi().getExercisesByCustomer(customerId);
this.exerciseList = results;
if ( Cache().userLoggedIn != null ) {
if (Cache().userLoggedIn != null) {
if (customerId == Cache().userLoggedIn.customerId) {
Cache().setExercises(exerciseList);
} else if (Cache().getTrainee() != null && customerId == Cache()
.getTrainee()
.customerId) {
} else if (Cache().getTrainee() != null && customerId == Cache().getTrainee().customerId) {
Cache().setExercisesTrainee(exerciseList);
}
}
@ -110,11 +119,11 @@ class ExerciseRepository {
}
String nextMissingBaseExercise(SplayTreeMap sortedTree) {
if ( exerciseList == null ) {
if (exerciseList == null) {
exerciseList = Cache().getExercises();
}
if ( exerciseList == null ) {
if (exerciseList == null) {
return "";
}
String missingTreeName;
@ -127,12 +136,12 @@ class ExerciseRepository {
treeName = treeName.substring(3);
foundTreeName = null;
listByMuscle.forEach((exercise) {
if ( missingTreeName == null ) {
if (missingTreeName == null) {
missingTreeName = treeName;
}
if ( exercise.base ) {
if (exercise.base) {
exerciseList.forEach((element) {
if ( element.exerciseTypeId == exercise.exerciseTypeId ) {
if (element.exerciseTypeId == exercise.exerciseTypeId) {
foundTreeName = treeName;
//print("Found " + foundTreeName + " Missing actual: " + missingTreeName);
isBreak = true;
@ -140,7 +149,7 @@ class ExerciseRepository {
});
}
});
if ( foundTreeName == null &&! isBreak ) {
if (foundTreeName == null && !isBreak) {
missingTreeName = treeName;
isBreak = true;
}
@ -156,37 +165,35 @@ class ExerciseRepository {
int count1RMExercises = 0;
LinkedHashMap<String, WorkoutMenuTree> tree = Cache().getWorkoutMenuTree();
if ( tree == null ) {
if (tree == null) {
return;
}
tree.forEach((key, value) {
WorkoutMenuTree treeItem = value;
if (treeItem.exerciseType != null &&
treeItem.exerciseType.base == true &&
!baseTreeItem.contains(treeItem.parent)) {
if (treeItem.exerciseType != null && treeItem.exerciseType.base == true && !baseTreeItem.contains(treeItem.parent)) {
baseTreeItem.add(treeItem.parent);
}
});
if ( exerciseList == null ) {
if (exerciseList == null) {
exerciseList = Cache().getExercises();
}
if ( exerciseList == null ) {
if (exerciseList == null) {
return;
}
exerciseList.forEach((element) {
Exercise exercise = element;
if ( !checkedExerciseTypeId.contains(exercise.exerciseTypeId )) {
if (!checkedExerciseTypeId.contains(exercise.exerciseTypeId)) {
checkedExerciseTypeId.add(exercise.exerciseTypeId);
tree.forEach((key, value) {
WorkoutMenuTree treeItem = value;
if (treeItem.exerciseType != null
&& treeItem.exerciseType.base == true
&& exercise.exerciseTypeId == treeItem.exerciseType.exerciseTypeId
&& !checkedBaseTreeItem.contains(treeItem.parent)) {
if (treeItem.exerciseType != null &&
treeItem.exerciseType.base == true &&
exercise.exerciseTypeId == treeItem.exerciseType.exerciseTypeId &&
!checkedBaseTreeItem.contains(treeItem.parent)) {
//print ("id: " + exercise.exerciseTypeId.toString());
checkedBaseTreeItem.add(treeItem.parent);
count1RMExercises++;
@ -207,7 +214,7 @@ class ExerciseRepository {
Exercise lastExercise = exercises[0];
exercises.forEach((element) {
Exercise actualExercise = element;
if ( actualExercise.dateAdd.compareTo(lastExercise.dateAdd) > 0 ) {
if (actualExercise.dateAdd.compareTo(lastExercise.dateAdd) > 0) {
lastExercise = actualExercise;
}
});
@ -221,16 +228,15 @@ class ExerciseRepository {
ExerciseType actualExerciseType;
Cache().getExerciseTypes().forEach((element) {
ExerciseType exerciseType = element;
if ( exerciseType.exerciseTypeId == exerciseTypeId) {
if (exerciseType.exerciseTypeId == exerciseTypeId) {
actualExerciseType = exerciseType;
}
});
if ( actualExerciseType == null ) {
throw Exception("Data error, no ExerciseType for exerciseTypeId $exerciseTypeId" );
if (actualExerciseType == null) {
throw Exception("Data error, no ExerciseType for exerciseTypeId $exerciseTypeId");
}
return actualExerciseType;
}
void sortByDate() => exerciseList.sort( (a, b) => b.dateAdd.compareTo(a.dateAdd) );
void sortByDate() => exerciseList.sort((a, b) => b.dateAdd.compareTo(a.dateAdd));
}

View File

@ -0,0 +1,40 @@
import 'package:aitrainer_app/model/result.dart';
enum ResultType { running, man, woman, none }
extension ResultTypeExt on ResultType {
bool equals(ResultType type) => this.toString() == type.toString();
}
class ExerciseResultRepository {
final List<ResultExt> _results = List();
ResultType resultType;
ExerciseResultRepository({this.resultType}) {
if (resultType == null) {
resultType = ResultType.man;
}
if (resultType.equals(ResultType.man) || resultType.equals(ResultType.woman)) {
//_results.add(ResultExt(itemString: ResultItem.time.description));
_results.add(ResultExt(itemString: ResultItem.reps_volume.description));
_results.add(ResultExt(itemString: ResultItem.weight_volume.description));
_results.add(ResultExt(itemString: ResultItem.bpm_max.description));
_results.add(ResultExt(itemString: ResultItem.calorie.description));
_results.add(ResultExt(itemString: ResultItem.bpm_avg.description));
_results.add(ResultExt(itemString: ResultItem.fatburn_percent.description));
_results.add(ResultExt(itemString: ResultItem.bpm_min.description));
} else {
//_results.add(ResultExt(itemString: ResultItem.time.description));
_results.add(ResultExt(itemString: ResultItem.distance.description));
_results.add(ResultExt(itemString: ResultItem.bpm_max.description));
_results.add(ResultExt(itemString: ResultItem.calorie.description));
_results.add(ResultExt(itemString: ResultItem.bpm_avg.description));
_results.add(ResultExt(itemString: ResultItem.fatburn_percent.description));
_results.add(ResultExt(itemString: ResultItem.bpm_min.description));
_results.add(ResultExt(itemString: ResultItem.steps.description));
_results.add(ResultExt(itemString: ResultItem.speed_max.description));
}
}
List<ResultExt> getResults() => this._results;
}

View File

@ -1,6 +1,7 @@
import 'dart:collection';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:aitrainer_app/model/exercise_tree.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
@ -32,6 +33,7 @@ class WorkoutTreeRepository {
final LinkedHashMap tree = LinkedHashMap<String, WorkoutMenuTree>();
SplayTreeMap sortedTree = SplayTreeMap<String, List<WorkoutMenuTree>>();
bool isEnglish;
WorkoutType workoutType;
final Map<String, int> _antagonist = {
Antagonist.chest: Antagonist.chestNr,
@ -59,8 +61,8 @@ class WorkoutTreeRepository {
}
exerciseTree.forEach((treeItem) async {
//print(" -- TreeItem " + treeItem.toJson().toString());
//print(" -- TreeItem " + treeItem.toJson().toString() + " active " + treeItem.active.toString());
if (treeItem.active == true) {
String treeName = isEnglish ? treeItem.name : treeItem.nameTranslation;
String assetImage = 'asset/menu/' + treeItem.imageUrl.substring(7);
@ -74,7 +76,12 @@ class WorkoutTreeRepository {
isEndurance = isParentEndurance(treeItem.parentId);
}
final WorkoutMenuTree menuItem = WorkoutMenuTree(
bool isRunning = treeItem.name == "Cardio" ? true : false;
if (isRunning == false && treeItem.parentId != 0) {
isRunning = isParentRunning(treeItem.parentId);
}
WorkoutMenuTree menuItem = WorkoutMenuTree(
treeItem.treeId,
treeItem.parentId,
treeName,
@ -87,32 +94,38 @@ class WorkoutTreeRepository {
false,
is1RM,
isEndurance,
isRunning,
treeItem.name,
);
menuItem = this.setWorkoutTypes(menuItem, treeItem);
this.tree[treeItem.name + "_" + treeItem.parentId.toString()] = menuItem;
//print("WorkoutMenuTree item " + menuItem.toJson().toString());
}
});
exerciseTypes.forEach((exerciseType) {
if (!(exerciseType.imageUrl.isEmpty || exerciseType.name.isEmpty || exerciseType.nameTranslation.isEmpty)) {
if (!(exerciseType.imageUrl.isEmpty || exerciseType.name.isEmpty || exerciseType.nameTranslation.isEmpty) &&
exerciseType.active == true) {
String exerciseTypeName = isEnglish ? exerciseType.name : exerciseType.nameTranslation;
String assetImage = 'asset/menu/' + exerciseType.imageUrl.substring(7);
if (exerciseType.parents.isNotEmpty) {
exerciseType.parents.forEach((parentId) {
bool is1RM = this.isParent1RM(parentId);
bool isEndurance = this.isParentEndurance(parentId);
exerciseType.is1RM = is1RM;
exerciseType.isEndurance = isEndurance;
if (is1RM) exerciseType.setAbility(ExerciseAbility.oneRepMax);
if (isEndurance) exerciseType.setAbility(ExerciseAbility.endurance);
bool isRunning = this.isParentRunning(parentId);
if (isRunning) exerciseType.setAbility(ExerciseAbility.running);
WorkoutMenuTree menuItem = WorkoutMenuTree(exerciseType.exerciseTypeId, parentId, exerciseTypeName, assetImage, Colors.white,
24, true, exerciseType.exerciseTypeId, exerciseType, exerciseType.base, is1RM, isEndurance, exerciseType.name);
24, true, exerciseType.exerciseTypeId, exerciseType, exerciseType.base, is1RM, isEndurance, isRunning, exerciseType.name);
this.tree[exerciseType.name] = menuItem;
//print("WorkoutMenuTree item " + menuItem.toJson().toString());
/*print("ExerciseType in Menu item " +
print("WorkoutMenuTree item " + menuItem.toJson().toString());
print("ExerciseType in Menu item " +
exerciseType.toJson().toString() +
" is1RM: " +
is1RM.toString() +
" isEndurance: " +
isEndurance.toString());*/
isEndurance.toString());
});
} else {
//print("No Parents " + exerciseType.toJson().toString());
@ -127,6 +140,39 @@ class WorkoutTreeRepository {
exerciseRepository.getBaseExerciseFinishedPercent();
}
WorkoutMenuTree setWorkoutTypes(WorkoutMenuTree menu, ExerciseTree treeItem) {
WorkoutType.values.forEach((workoutType) {
if (workoutType.equalsString(treeItem.name) || existWorkoutTypeInTree(workoutType)) {
menu.workoutTypes.add(workoutType);
}
});
return menu;
}
bool existWorkoutTypeInTree(WorkoutType workoutType) {
bool exists = false;
this.tree.forEach((key, treeItem) {
if (workoutType.equalsString(treeItem.name)) {
exists = true;
}
});
return exists;
}
bool isParentRunning(int treeId) {
bool isTreeItemRunning = false;
this.tree.forEach((key, value) {
WorkoutMenuTree treeItem = value as WorkoutMenuTree;
if (treeItem.id == treeId) {
isTreeItemRunning = isTreeItemRunning || treeItem.isRunning;
//print (treeItem.name + " 1RM " + treeItem.is1RM.toString() );
}
});
return isTreeItemRunning;
}
bool isParent1RM(int treeId) {
bool isTreeItem1RM = false;

View File

@ -35,7 +35,7 @@ class ExerciseTreeApi {
if (index > 0) {
ExerciseTree newElement = element.copy(parent.exerciseTreeParentId);
exerciseTree.add(newElement);
print("ExerciseTree " + newElement.toJson().toString());
//print("ExerciseTree " + newElement.toJson().toString());
} else {
element.parentId = parent.exerciseTreeParentId;
exerciseTree[treeIndex].parentId = parent.exerciseTreeParentId;

View File

@ -31,6 +31,7 @@ class Session {
await AppLocalizations.delegate.load(AppLanguage().appLocal);
print(" -- Session: fetch token..");
Cache().setServerAddress(_sharedPreferences);
Cache().getHardware(_sharedPreferences);
await _fetchToken(_sharedPreferences);
print(" -- FireBase init..");
await FirebaseApi().initializeFlutterFire();

View File

@ -3,7 +3,6 @@ import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/numberpicker.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/splash.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';

503
lib/view/evaluation.dart Normal file
View File

@ -0,0 +1,503 @@
import 'dart:collection';
import 'dart:ui';
import 'package:aitrainer_app/bloc/result/result_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/repository/exercise_result_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:aitrainer_app/model/result.dart';
// ignore: must_be_immutable
class EvaluationPage extends StatelessWidget with Trans {
@override
Widget build(BuildContext context) {
LinkedHashMap arguments = ModalRoute.of(context).settings.arguments;
ExerciseRepository exerciseRepository;
// ignore: close_sinks
if (arguments != null) {
exerciseRepository = arguments['exerciseRepository'];
} else {
exerciseRepository = ExerciseRepository();
}
ResultType resultType = ResultType.none;
String imageUrl = "";
if (Cache().userLoggedIn.sex == "m") {
resultType = ResultType.man;
imageUrl = 'asset/image/WT_Results_for_men.png';
} else {
resultType = ResultType.man;
imageUrl = 'asset/image/WT_Results_for_female.png';
}
if (exerciseRepository.exerciseType.getAbility().equalsTo(ExerciseAbility.running)) {
resultType = ResultType.running;
imageUrl = 'asset/image/WT_Results_for_runners.png';
}
print("ResultType: " + resultType.toString());
setContext(context);
return Scaffold(
appBar: AppBarMin(
back: true,
),
body: Container(
height: double.infinity,
width: double.infinity,
alignment: Alignment.center,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(imageUrl),
fit: BoxFit.cover,
alignment: Alignment.topCenter,
),
),
child: BlocProvider(
create: (context) =>
ResultBloc(resultRepository: ExerciseResultRepository(resultType: resultType), exerciseRepository: exerciseRepository)
..add(ResultLoad()),
child: BlocConsumer<ResultBloc, ResultState>(listener: (context, state) {
if (state is ResultError) {
Scaffold.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.error, style: TextStyle(color: Colors.white))));
} else if (state is ResultLoading) {
Scaffold.of(context).showSnackBar(SnackBar(
duration: Duration(milliseconds: 100),
backgroundColor: Colors.transparent,
content: Container(child: Center(child: CircularProgressIndicator()))));
}
}, builder: (context, state) {
final resultBloc = BlocProvider.of<ResultBloc>(context);
return getEvaluationWidgets(resultBloc);
}))),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 0));
}
Widget getEvaluationWidgets(ResultBloc resultBloc) {
String exerciseName = AppLanguage().appLocal == Locale("en")
? resultBloc.exerciseRepository.exerciseType.name
: resultBloc.exerciseRepository.exerciseType.nameTranslation;
return Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: CustomScrollView(scrollDirection: Axis.vertical, slivers: [
SliverAppBar(
pinned: true,
backgroundColor: Colors.transparent,
expandedHeight: 50.0,
automaticallyImplyLeading: false,
flexibleSpace: FlexibleSpaceBar(
title: Text(exerciseName,
textAlign: TextAlign.center,
maxLines: 3,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 24,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
),
),
SliverList(
delegate: SliverChildListDelegate([
Text(DateFormat('y-M-d HH:mm', AppLanguage().appLocal.toString()).format(resultBloc.exerciseRepository.start),
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
Divider(color: Colors.transparent),
Divider(color: Colors.transparent),
Text(t("Summary of your test"),
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.yellow[300],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
]),
),
getResultSummary(resultBloc),
getSuggestionTitle(resultBloc),
getSuggestion(resultBloc),
emptySliver(),
getResultTitle(resultBloc),
getResults(resultBloc),
]));
}
Widget getSuggestionTitle(ResultBloc resultBloc) {
if (resultBloc.exerciseRepository.exerciseType.unitQuantityUnit != null) {
return SliverList(
delegate: SliverChildListDelegate(
[
Divider(color: Colors.transparent),
Divider(color: Colors.transparent),
Text(t("Suggestions based on your test"),
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.yellow[300],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
],
),
);
} else
return emptySliver();
}
Widget getResultTitle(ResultBloc resultBloc) {
return SliverList(
delegate: SliverChildListDelegate(
[
Divider(color: Colors.transparent),
Divider(color: Colors.transparent),
Text(t("Health Data Summary"),
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.yellow[300],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
Divider(),
],
),
);
}
Widget getSuggestion(ResultBloc resultBloc) {
if (resultBloc.exerciseRepository.exerciseType.unitQuantityUnit != null) {
return SliverList(
delegate: SliverChildListDelegate(
[
getSuggestionWidget(resultBloc, "Hypertrophy", "asset/image/pict_hypertrophy.png", "3x10-12", 0.9, "2"),
Divider(color: Colors.transparent),
getSuggestionWidget(resultBloc, "Gain Strength", "asset/image/pict_weight_volumen_tonna.png", "3x10-12", 0.75, "3-5"),
Divider(color: Colors.transparent),
getSuggestionWidget(resultBloc, "Endurance", "asset/image/pict_reps_volumen_db.png", "4x25-35", 0.50, "3"),
],
),
);
} else
return emptySliver();
}
Widget emptySliver({int count = 1}) {
return SliverList(
delegate: SliverChildListDelegate(
[
Container(),
Divider(color: Colors.transparent),
],
),
);
}
Widget getSuggestionWidget(ResultBloc resultBloc, String title, String picture, String repeats, double percent, String restTime) {
String unitQuantityUnit = resultBloc.exerciseRepository.exerciseType.unitQuantityUnit == null
? ""
: resultBloc.exerciseRepository.exerciseType.unitQuantityUnit;
return Column(
children: [
Text(t(title),
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 30,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
Row(children: [
Image.asset(
picture,
height: 80,
),
SizedBox(
width: 10,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(repeats + " " + t("repeats"),
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 18,
color: Colors.orange,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
))
],
),
Row(
children: [
Text(t("Weight") + ": " + resultBloc.calculate1RM(percent: percent).toStringAsFixed(0) + " " + unitQuantityUnit,
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 18,
color: Colors.orange,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
],
),
Row(
children: [
Text(t("Rest time") + ": " + restTime + " " + t("minutes"),
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 18,
color: Colors.orange,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
],
),
],
)
]),
],
);
}
Widget getSummary(ResultBloc bloc) {
int index = 0;
List<Text> resultList = List();
bloc.exerciseRepository.actualExerciseList.forEach((exercise) {
final String unit = t(bloc.exerciseRepository.exerciseType.unit);
String exerciseElement = "";
final String exerciseRepeats = exercise.quantity.toStringAsFixed(0);
final String exerciseUnitQuantity = exercise.unitQuantity != null ? "x" + exercise.unitQuantity.toStringAsFixed(0) : "";
if (index == 0) {
exerciseElement = t("Test") + ": ";
} else if (index == 1) {
exerciseElement = t("1st Control") + ": ";
} else if (index == 2) {
exerciseElement = t("2nd Control") + ": ";
} else if (index == 3) {
exerciseElement = t("3rd Control") + ": ";
}
index++;
resultList.add(
Text(exerciseElement + exerciseRepeats + exerciseUnitQuantity + " " + unit,
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.inter(
fontSize: 18,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
);
});
return Column(children: resultList);
}
Widget getResultSummary(ResultBloc resultBloc) {
return SliverList(
delegate: SliverChildListDelegate(
[Divider(color: Colors.transparent), getSummary(resultBloc)],
),
);
}
Widget getResults(ResultBloc resultBloc) {
return SliverGrid(
delegate: SliverChildListDelegate(
getResultData(resultBloc),
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
childAspectRatio: 1.1,
),
);
}
List<Widget> getResultData(ResultBloc resultBloc) {
List<Widget> data = List();
resultBloc.resultRepository.getResults().forEach((element) {
data.add(getResultWidget(element));
});
return data;
}
Widget getResultWidget(ResultExt element) {
bool hasHardware = Cache().hasHardware;
bool blur = (!hasHardware && element.isHardware());
/* print("Blur: " +
element.getDescription() +
": " +
blur.toString() +
" hasHardware:" +
hasHardware.toString() +
" isHw: " +
element.isHardware().toString()); */
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
blur
? Stack(children: [
Image.asset(
element.getImage(),
height: 80,
//color: Colors.white12,
),
Image.asset(
element.getImage(),
height: 80,
color: Colors.black54,
),
])
: Image.asset(
element.getImage(),
height: 80,
),
SizedBox(
width: 10,
),
Text(
element.data,
style: GoogleFonts.archivoBlack(fontSize: 28, color: blur ? Colors.white30 : Colors.white),
),
Text(
t(element.getDescription()),
style: GoogleFonts.archivoBlack(fontSize: 14, color: blur ? Colors.white30 : Colors.white),
textAlign: TextAlign.left,
),
],
);
}
}

View File

@ -2,16 +2,17 @@ import 'dart:collection';
import 'package:aitrainer_app/bloc/exercise_control/exercise_control_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart';
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.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/number_picker.dart';
import 'package:aitrainer_app/widgets/splash.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:aitrainer_app/library/numberpicker.dart';
import 'package:google_fonts/google_fonts.dart';
class ExerciseControlPage extends StatefulWidget {
@ -32,16 +33,16 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
..add(ExerciseControlLoad()),
child: BlocConsumer<ExerciseControlBloc, ExerciseControlState>(listener: (context, state) {
if (state is ExerciseControlError) {
//LoadingDialog.hide(context);
Scaffold.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is ExerciseControlLoading) {
//LoadingDialog.show(context);
return LoadingDialog();
}
}, builder: (context, state) {
final exerciseBloc = BlocProvider.of<ExerciseControlBloc>(context);
if (state is ExerciseControlReady) {
//LoadingDialog.hide(context);
if (state is ExerciseControlLoading) {
return LoadingDialog();
} else if (state is ExerciseControlReady) {
return getControlForm(exerciseBloc);
} else {
return getControlForm(exerciseBloc);
@ -53,49 +54,80 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
String exerciseName = AppLanguage().appLocal == Locale("en")
? exerciseBloc.exerciseRepository.exerciseType.name
: exerciseBloc.exerciseRepository.exerciseType.nameTranslation;
return Form(
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBarNav(depth: 1),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
height: double.infinity,
width: double.infinity,
alignment: Alignment.center,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.png'),
fit: BoxFit.fill,
alignment: Alignment.center,
image: Cache().userLoggedIn.sex == "m"
? AssetImage("asset/image/WT_Results_for_men.png")
: AssetImage("asset/image/WT_Results_for_female.png"),
fit: BoxFit.cover,
alignment: Alignment.topCenter,
),
),
child: Container(
padding: const EdgeInsets.only(top: 25, left: 25, right: 25),
padding: const EdgeInsets.only(top: 10, left: 25, right: 25),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
controller: ScrollController(
initialScrollOffset: exerciseBloc.scrollOffset,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
exerciseName,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.orange),
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
overflow: TextOverflow.fade,
maxLines: 1,
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
),
FlatButton(
Divider(
color: Colors.transparent,
),
Divider(
color: Colors.transparent,
),
Divider(
color: Colors.transparent,
),
/* FlatButton(
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Icon(
Icons.info,
color: Colors.yellow[300],
color: Colors.yellow[50],
),
Flexible(
child: Text(t("Why do you need Exercise Control?"),
style: TextStyle(color: Colors.yellow[300], fontWeight: FontWeight.normal, fontSize: 14)),
style: TextStyle(color: Colors.yellow[50], fontWeight: FontWeight.normal, fontSize: 14)),
),
Icon(
Icons.arrow_forward_ios,
color: Colors.yellow[300],
color: Colors.yellow[50],
),
]),
textColor: Colors.blueAccent,
@ -103,20 +135,21 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
onPressed: () => {
//Navigator.of(context).pushNamed('exerciseTypeDescription', arguments: exerciseBloc.exerciseRepository),
},
),
), */
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(t("Your 1RM:"),
style: GoogleFonts.inter(
color: Colors.yellow[300],
fontSize: 18,
)),
Text(
" " +
exerciseBloc.initialRM.toStringAsFixed(0) +
" " +
exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit,
style: GoogleFonts.inter(color: Colors.yellow[300], fontWeight: FontWeight.bold),
style: GoogleFonts.inter(color: Colors.yellow[300], fontSize: 18, fontWeight: FontWeight.bold),
),
],
),
@ -134,7 +167,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
}
Widget numberPickForm(ExerciseControlBloc exerciseBloc, int step) {
String strTimes = step == 2 ? exerciseBloc.origQuantity.toString() : "max.";
String strTimes = step == 2 ? exerciseBloc.origQuantity.toStringAsFixed(0) : "max.";
String textInstruction = "";
textInstruction = t("Please repeat with ") +
exerciseBloc.unitQuantity.toStringAsFixed(0) +
@ -149,44 +182,46 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
);
String title = step.toString() + ". " + t("Control Exercise:");
LinkedHashMap args = LinkedHashMap();
List<Widget> listWidgets = [
Text(
title,
style: GoogleFonts.inter(color: Colors.yellow[300], fontWeight: FontWeight.bold),
style: GoogleFonts.inter(color: Colors.yellow[300], fontSize: 18, fontWeight: FontWeight.bold),
),
Text(
textInstruction,
style: GoogleFonts.inter(color: Colors.yellow[300], fontSize: 12),
style: GoogleFonts.inter(color: Colors.yellow[300], fontSize: 16),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
NumberPicker.horizontal(
highlightSelectedValue: step == exerciseBloc.step,
initialValue: exerciseBloc.quantity.toInt(),
NumberPickerWidget(
minValue: 0,
maxValue: 200,
step: 1,
onChanged: (value) => {exerciseBloc.add(ExerciseControlQuantityChange(quantity: value.toDouble(), step: step))},
listViewHeight: 80,
textStyleHighlighted: GoogleFonts.archivoBlack(color: Colors.orange[300], fontSize: 24),
//decoration: _decoration,
),
initalValue: exerciseBloc.quantity.toInt(),
unit: t("reps"),
color: Colors.yellow[50],
onChange: (value) => {exerciseBloc.add(ExerciseControlQuantityChange(quantity: value.toDouble(), step: step))}),
FlatButton(
padding: EdgeInsets.all(0),
textColor: Colors.white,
//color: step == exerciseBloc.step ? Colors.orange : Colors.black26,
focusColor: Colors.blueAccent,
onPressed: () => {
exerciseBloc.add(ExerciseControlSubmit(step: step)),
if (step == 3) {confirmationDialog(exerciseBloc)}
if (step == 3)
{
//confirmationDialog(exerciseBloc)
Navigator.of(context).pop(),
args['exerciseRepository'] = exerciseBloc.exerciseRepository,
Navigator.of(context).pushNamed('evaluationPage', arguments: args)
}
},
child: step == exerciseBloc.step
? Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_a.png', width: 140, height: 60),
Image.asset('asset/icon/gomb_orange_c.png', width: 140, height: 60),
Text(
t("Save"),
style: TextStyle(fontSize: 16, color: Colors.white),
@ -206,6 +241,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
void confirmationDialog(ExerciseControlBloc bloc) {
String unit = t(bloc.exerciseRepository.exerciseType.unit);
LinkedHashMap args = LinkedHashMap();
showCupertinoDialog(
useRootNavigator: true,
@ -235,7 +271,11 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
actions: [
FlatButton(
child: Text(t("OK")),
onPressed: () => {Navigator.of(context).pop(), Navigator.of(context).pop()},
onPressed: () => {
Navigator.of(context).pop(),
args['exerciseRepository'] = bloc.exerciseRepository,
Navigator.of(context).pushNamed('evaluationPage', arguments: args)
},
)
],
));

View File

@ -241,11 +241,11 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
style: (TextStyle(color: Colors.blue)),
),
Text(
exercise.quantity.toStringAsFixed(0) +
"x" +
exercise.unitQuantity.toStringAsFixed(0) +
" " +
exerciseType.unitQuantityUnit,
exercise.quantity.toStringAsFixed(0) + "x" + exercise.unitQuantity.toStringAsFixed(0) + " ",
//+
//exerciseType.unitQuantityUnit == null
// ? ""
// : exerciseType.unitQuantityUnit,
style: (TextStyle(color: Colors.deepOrange)),
),
Text(

View File

@ -2,8 +2,10 @@ import 'dart:collection';
import 'package:aitrainer_app/bloc/exercise_new/exercise_new_bloc.dart';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
@ -19,6 +21,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:stop_watch_timer/stop_watch_timer.dart';
class ExerciseNewPage extends StatefulWidget {
_ExerciseNewPageState createState() => _ExerciseNewPageState();
@ -132,15 +135,20 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans {
return SizeWidget(exerciseBloc: exerciseBloc);
}
bool isSecond = false;
String exerciseTask = "";
if (exerciseBloc.exerciseRepository.exerciseType.is1RM && menuBloc.ability.toString() == ExerciseAbility.oneRepMax.toString()) {
if (exerciseBloc.exerciseRepository.exerciseType.unit != "second") {
if (exerciseBloc.exerciseRepository.exerciseType.is1RM() && menuBloc.ability.toString() == ExerciseAbility.oneRepMax.toString()) {
exerciseTask = "Please take a relative bigger weight and repeat 12-20 times";
exerciseBloc.quantity = 12;
} else if (exerciseBloc.exerciseRepository.exerciseType.isEndurance &&
} else if (exerciseBloc.exerciseRepository.exerciseType.isEndurance() &&
menuBloc.ability.toString() == ExerciseAbility.endurance.toString()) {
exerciseTask = "Please take a medium weight and repeat 20-30 times";
exerciseBloc.quantity = 20;
}
} else {
isSecond = true;
}
return Form(
child: Scaffold(
@ -159,20 +167,34 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans {
child: KeyboardActions(
config: _buildConfig(context),
child: Container(
padding: const EdgeInsets.only(top: 5, left: 55, right: 55),
padding: const EdgeInsets.only(top: 25, left: 55, right: 55),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(t('Save Exercise'), style: TextStyle(fontSize: 14, color: Colors.blue[200])),
Divider(),
Text(
exerciseName,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.orange),
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
fontSize: 24,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
overflow: TextOverflow.fade,
maxLines: 2,
maxLines: 4,
softWrap: true,
textAlign: TextAlign.center,
),
@ -235,7 +257,7 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans {
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_a.png', width: 140, height: 60),
Image.asset('asset/icon/gomb_orange_c.png', width: 140, height: 60),
Text(
t("Save"),
style: TextStyle(fontSize: 16, color: Colors.white),
@ -280,6 +302,80 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans {
Column columnQuantity(ExerciseNewBloc bloc) {
if (bloc.exerciseRepository.exerciseType.unit == "second") {
return Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
Padding(
padding: const EdgeInsets.only(bottom: 0),
child: StreamBuilder<int>(
stream: bloc.stopWatchTimer.rawTime,
initialData: bloc.stopWatchTimer.rawTime.value,
builder: (context, snap) {
final value = snap.data;
final displayTime = StopWatchTimer.getDisplayTime(value, hours: false);
return Column(children: <Widget>[
Padding(
padding: const EdgeInsets.all(8),
child: Text(
displayTime,
style: const TextStyle(fontSize: 40, fontFamily: 'Helvetica', fontWeight: FontWeight.bold, color: Colors.white),
),
),
]);
})),
Padding(
padding: const EdgeInsets.all(2),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: IconButton(
padding: const EdgeInsets.all(2),
color: Colors.white70,
//shape: const StadiumBorder(),
onPressed: () async {
bloc.stopWatchTimer.onExecute.add(StopWatchExecute.start);
},
icon: Icon(CustomIcon.play_1),
iconSize: 40,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: IconButton(
padding: const EdgeInsets.all(2),
iconSize: 40,
color: Colors.white70,
//shape: const StadiumBorder(),
onPressed: () async {
bloc.stopWatchTimer.onExecute.add(StopWatchExecute.stop);
},
icon: Icon(CustomIcon.stop),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: IconButton(
padding: const EdgeInsets.all(2),
iconSize: 40,
color: Colors.white70,
onPressed: () async {
bloc.stopWatchTimer.onExecute.add(StopWatchExecute.reset);
},
icon: Icon(CustomIcon.creative_commons_zero),
),
),
],
),
),
],
),
),
Divider(),
Divider(),
Text("Or type the time manually:", style: GoogleFonts.inter(color: Colors.white)),
TimePickerWidget(
onChange: (value) => {bloc.add(ExerciseNewQuantityChange(quantity: value))},
)
@ -360,18 +456,26 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans {
child: Text(t("Yes")),
onPressed: () => {
bloc.exerciseRepository.setCustomer(Cache().userLoggedIn),
bloc.exerciseRepository.addExercise(),
bloc.add(ExerciseNewSubmit()),
Navigator.pop(context),
Navigator.pop(context),
if (bloc.exerciseRepository.exerciseType.is1RM && menuBloc.ability.toString() == ExerciseAbility.oneRepMax.toString())
print("Ability " +
menuBloc.ability.toString() +
" exerciseType 1rm " +
bloc.exerciseRepository.exerciseType.is1RM().toString()),
if (bloc.exerciseRepository.exerciseType.unitQuantityUnit == null)
{
args['exerciseRepository'] = bloc.exerciseRepository,
Navigator.of(context).pushNamed('evaluationPage', arguments: args)
}
else if (menuBloc.ability.equalsTo(ExerciseAbility.oneRepMax))
{
args['exerciseRepository'] = bloc.exerciseRepository,
args['percent'] = 0.75,
args['readonly'] = false,
Navigator.of(context).pushNamed('exerciseControlPage', arguments: args)
}
else if (bloc.exerciseRepository.exerciseType.isEndurance &&
menuBloc.ability.toString() == ExerciseAbility.endurance.toString())
else if (menuBloc.ability.equalsTo(ExerciseAbility.endurance))
{
args['exerciseRepository'] = bloc.exerciseRepository,
args['percent'] = 0.50,

View File

@ -7,7 +7,6 @@ import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/splash.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@ -161,7 +160,7 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
Text(
exerciseName,
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(fontSize: 18, color: Colors.deepOrange),
style: GoogleFonts.archivoBlack(fontSize: 18, color: Colors.yellow[200]),
overflow: TextOverflow.fade,
maxLines: 3,
softWrap: true,

View File

@ -9,7 +9,6 @@ import 'package:aitrainer_app/util/trans.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';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

View File

@ -1,5 +1,6 @@
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/util/trans.dart';
@ -36,20 +37,16 @@ class SettingsPage extends StatelessWidget with Trans {
if (state is SettingsError) {
} else if (state is SettingsReady) {
menuBloc.add(MenuRecreateTree());
} else if (state is SettingsLoading) {
Scaffold.of(context).showSnackBar(SnackBar(
duration: Duration(milliseconds: 100),
backgroundColor: Colors.transparent,
content: Container(child: Center(child: CircularProgressIndicator()))));
}
},
// ignore: missing_return
builder: (context, state) {
if (state is SettingsLoading) {
//LoadingDialog.show(context);
} else if (state is SettingsInitial) {
return settingsUI(context, settingsBloc, menuBloc);
} else if (state is SettingsReady) {
//LoadingDialog.hide(context);
return settingsUI(context, settingsBloc, menuBloc);
} else {
return Container();
}
}),
),
),
@ -72,11 +69,12 @@ class SettingsPage extends StatelessWidget with Trans {
onChanged: (String lang) => {
settingsBloc.add(SettingsChangeLanguage(language: lang)),
})),
getServer(),
getServer(settingsBloc),
getDevice(settingsBloc),
]);
}
ListTile getServer() {
ListTile getServer(SettingsBloc settingsBloc) {
if (Cache().userLoggedIn.admin != 1) {
return ListTile(
title: Container(),
@ -100,7 +98,29 @@ class SettingsPage extends StatelessWidget with Trans {
inactiveFgColor: Colors.grey[900],
labels: [t('Live-Server'), t('Test-Server')],
onToggle: (index) {
Cache().setServer(index == 0);
//Cache().setServer(index == 0);
settingsBloc.add(SettingsSetServer(live: index == 0));
},
),
);
}
ListTile getDevice(SettingsBloc settingsBloc) {
return ListTile(
leading: Icon(CustomIcon.cog),
subtitle: Text("Do you have Smart watch, or any device which collects the fit/health data?"),
title: ToggleSwitch(
minWidth: 120.0,
minHeight: 30.0,
fontSize: 14.0,
initialLabelIndex: Cache().hasHardware ? 0 : 1,
activeBgColor: Colors.indigo,
activeFgColor: Colors.white,
inactiveBgColor: Colors.white60,
inactiveFgColor: Colors.grey[900],
labels: [t('Yes'), t('No')],
onToggle: (index) {
settingsBloc.add(SettingsSetHardware(hasHardware: index == 0));
},
),
);

View File

@ -5,7 +5,8 @@ import 'package:flutter/material.dart';
class LoadingScreenMain extends StatelessWidget {
@override
Widget build(BuildContext context) {
Image _backgroundImage = Image.asset('asset/image/WT01_loading_layers.png',
final Image _backgroundImage = Image.asset(
'asset/image/WT01_loading_layers.png',
fit: BoxFit.cover,
height: double.infinity,
width: double.infinity,
@ -23,13 +24,14 @@ class LoadingScreenMain extends StatelessWidget {
new Container(
decoration: BoxDecoration(color: Colors.white),
),
/// Render the background image
new Container(
child: SafeArea(
bottom: false,
child: _backgroundImage,
)
),
)),
/// Render the Title widget, loader and messages below each other
new Column(
mainAxisAlignment: MainAxisAlignment.center,
@ -43,7 +45,6 @@ class LoadingScreenMain extends StatelessWidget {
new Padding(
padding: const EdgeInsets.only(top: 30.0),
),
],
)),
),
@ -54,8 +55,7 @@ class LoadingScreenMain extends StatelessWidget {
children: <Widget>[
/// Loader Animation Widget
CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(
Colors.lightGreenAccent),
valueColor: new AlwaysStoppedAnimation<Color>(Colors.lightGreenAccent),
),
Padding(
padding: const EdgeInsets.only(top: 20.0),

View File

@ -0,0 +1,71 @@
import 'package:aitrainer_app/util/trans.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class NumberPickerWidget extends StatefulWidget {
final Function(double) onChange;
final int minValue;
final int maxValue;
final int initalValue;
final String unit;
final Color color;
const NumberPickerWidget({Key key, this.minValue, this.maxValue, this.initalValue, this.unit, this.color, this.onChange})
: super(key: key);
@override
_NumberPickerWidgetState createState() => _NumberPickerWidgetState();
}
class _NumberPickerWidgetState extends State<NumberPickerWidget> with Trans {
Widget durationPicker({bool inSeconds = false, bool inHundredths = false}) {
double value = 0;
return CupertinoPicker(
scrollController: FixedExtentScrollController(initialItem: widget.initalValue),
backgroundColor: Colors.transparent,
onSelectedItemChanged: (x) {
currentData = x.toDouble();
value = x.toDouble();
//print("sec" + seconds.toStringAsFixed(2));
setState(() {});
widget.onChange(value);
},
children: List.generate(widget.maxValue, (index) => Text('$index ' + widget.unit, style: TextStyle(color: widget.color))),
itemExtent: 40,
);
}
double currentData = 0;
@override
Widget build(BuildContext context) {
setContext(context);
return Container(
//color: Colors.white24,
width: MediaQuery.of(context).size.width * .45,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color: Colors.transparent,
width: MediaQuery.of(context).size.width * .3,
child: Center(
child: Container(
color: Colors.transparent,
width: MediaQuery.of(context).size.width * 0.95,
height: MediaQuery.of(context).size.height * 0.25,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(child: durationPicker()),
],
)),
),
),
],
),
),
);
}
}

View File

@ -211,6 +211,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.10"
device_info:
dependency: transitive
description:
name: device_info
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2+10"
device_info_platform_interface:
dependency: transitive
description:
name: device_info_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
devicelocale:
dependency: "direct main"
description:
@ -430,6 +444,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
health:
dependency: "direct main"
description:
name: health
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.9"
http:
dependency: "direct dev"
description:
@ -869,6 +890,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0-nullsafety.1"
stop_watch_timer:
dependency: "direct main"
description:
name: stop_watch_timer
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.0+1"
stream_channel:
dependency: transitive
description:

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.2+36
version: 1.1.2+39
environment:
sdk: ">=2.10.0 <3.0.0"
@ -42,7 +42,9 @@ dependencies:
keyboard_actions: ^3.3.1+1
dropdown_search: ^0.4.8
badges: ^1.1.4
#health: ^2.0.9
health: ^2.0.9
stop_watch_timer: ^0.6.0+1
#geolocator: ^6.1.13
firebase_core: ^0.5.2
@ -97,6 +99,7 @@ flutter:
assets:
- asset/icon/gomb_kek_a-2.png
- asset/icon/gomb_orange_a.png
- asset/icon/gomb_orange_c.png
- asset/icon/gomb_pink_a.png
- asset/icon/gomb_pink_b.png
- asset/icon/gomb_zold_b-1.png
@ -116,6 +119,9 @@ flutter:
- asset/image/Gain_muscle.png
- asset/image/WT_weight_loss.png
- asset/image/WT_welcome.png
- asset/image/WT_Results_for_runners.png
- asset/image/WT_Results_for_female.png
- asset/image/WT_Results_for_men.png
- asset/image/login_fb.png
- asset/image/lock.png
- asset/image/Congrats_N1.jpg
@ -157,6 +163,19 @@ flutter:
- asset/image/equipment_gym_place.jpg
- asset/image/equipment_street_place.jpg
- asset/image/haken.png
- asset/image/pict_calorie.png
- asset/image/pict_development_by_bodypart_percent.png
- asset/image/pict_distance_m.png
- asset/image/pict_fatburn_percent.png
- asset/image/pict_hravg_bpm.png
- asset/image/pict_hrmin_bpm.png
- asset/image/pict_hrmax_bpm.png
- asset/image/pict_maxspeed_kmh.png
- asset/image/pict_reps_volumen_db.png
- asset/image/pict_steps.png
- asset/image/pict_time_h.png
- asset/image/pict_hypertrophy.png
- asset/image/pict_weight_volumen_tonna.png
- asset/menu/1.cardio.png
- asset/menu/1.1.aerob.png
- asset/menu/1.2.anaerob.png

21
test/result_test.dart Normal file
View File

@ -0,0 +1,21 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/result.dart';
import 'package:test/test.dart';
main() {
setUp(() {
Cache().setTestBaseUrl();
});
group('Result', () {
test('test ResultExt constructor', () async {
final ResultExt resultExt = ResultExt(itemString: "Calorie");
expect(resultExt.getImage(), "asset/image/pic_calorie.png");
expect(resultExt.getDescription(), "Calorie");
expect(resultExt.item.equals(ResultItem.calorie), true);
expect(resultExt.equals(ResultItem.calorie), true);
expect(resultExt.equalsString("Calorie"), true);
});
});
}