WT1.1.18+2 Training Plan days, skip
This commit is contained in:
parent
d388228caa
commit
48804c50f0
@ -388,7 +388,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 2;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@ -531,7 +531,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 2;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@ -566,7 +566,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 2;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
@ -131,6 +131,9 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
|
|||||||
case "Test Center":
|
case "Test Center":
|
||||||
ability = ExerciseAbility.mini_test_set;
|
ability = ExerciseAbility.mini_test_set;
|
||||||
break;
|
break;
|
||||||
|
case "Training Plans":
|
||||||
|
ability = ExerciseAbility.training;
|
||||||
|
break;
|
||||||
case "My Body":
|
case "My Body":
|
||||||
ability = ExerciseAbility.none;
|
ability = ExerciseAbility.none;
|
||||||
break;
|
break;
|
||||||
|
@ -4,13 +4,11 @@ import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
|||||||
import 'package:aitrainer_app/model/cache.dart';
|
import 'package:aitrainer_app/model/cache.dart';
|
||||||
import 'package:aitrainer_app/model/customer_training_plan.dart';
|
import 'package:aitrainer_app/model/customer_training_plan.dart';
|
||||||
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
|
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
|
||||||
import 'package:aitrainer_app/model/customer_training_plan_exercise.dart';
|
|
||||||
import 'package:aitrainer_app/model/exercise.dart';
|
import 'package:aitrainer_app/model/exercise.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
||||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||||
import 'package:aitrainer_app/repository/training_plan_repository.dart';
|
import 'package:aitrainer_app/repository/training_plan_repository.dart';
|
||||||
import 'package:aitrainer_app/service/exercise_service.dart';
|
import 'package:aitrainer_app/service/exercise_service.dart';
|
||||||
import 'package:aitrainer_app/service/training_plan_service.dart';
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
@ -22,19 +20,21 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
|
|||||||
final MenuBloc menuBloc;
|
final MenuBloc menuBloc;
|
||||||
TrainingPlanBloc({required this.trainingPlanRepository, required this.menuBloc}) : super(TrainingPlanInitial());
|
TrainingPlanBloc({required this.trainingPlanRepository, required this.menuBloc}) : super(TrainingPlanInitial());
|
||||||
|
|
||||||
CustomerTrainingPlan? myPlan;
|
CustomerTrainingPlan? _myPlan;
|
||||||
bool started = false;
|
bool started = false;
|
||||||
|
final List<String> dayNames = [];
|
||||||
|
|
||||||
CustomerTrainingPlan? getMyPlan() => this.myPlan;
|
CustomerTrainingPlan? getMyPlan() => this._myPlan;
|
||||||
setMyPlan(CustomerTrainingPlan myPlan) => this.myPlan = myPlan;
|
setMyPlan(CustomerTrainingPlan? myPlan) => this._myPlan = myPlan;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<TrainingPlanState> mapEventToState(TrainingPlanEvent event) async* {
|
Stream<TrainingPlanState> mapEventToState(TrainingPlanEvent event) async* {
|
||||||
try {
|
try {
|
||||||
if (event is TrainingPlanActivate) {
|
if (event is TrainingPlanActivate) {
|
||||||
yield TrainingPlanLoading();
|
yield TrainingPlanLoading();
|
||||||
myPlan = await trainingPlanRepository.activateTrainingPlan(event.trainingPlanId);
|
_myPlan = await trainingPlanRepository.activateTrainingPlan(event.trainingPlanId);
|
||||||
Cache().myTrainingPlan = myPlan;
|
this.activateDays();
|
||||||
|
Cache().myTrainingPlan = _myPlan;
|
||||||
await Cache().saveMyTrainingPlan();
|
await Cache().saveMyTrainingPlan();
|
||||||
yield TrainingPlanFinished();
|
yield TrainingPlanFinished();
|
||||||
} else if (event is TrainingPlanWeightChange) {
|
} else if (event is TrainingPlanWeightChange) {
|
||||||
@ -66,13 +66,19 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
|
|||||||
event.detail.state = ExercisePlanDetailState.inProgress;
|
event.detail.state = ExercisePlanDetailState.inProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
exercise.trainingPlanDetailsId = myPlan!.trainingPlanId;
|
exercise.trainingPlanDetailsId = _myPlan!.trainingPlanId;
|
||||||
|
|
||||||
// save Exercise
|
// save Exercise
|
||||||
await ExerciseApi().addExercise(exercise);
|
await ExerciseApi().addExercise(exercise);
|
||||||
Cache().addExercise(exercise);
|
Cache().addExercise(exercise);
|
||||||
|
|
||||||
Cache().myTrainingPlan = myPlan;
|
Cache().myTrainingPlan = _myPlan;
|
||||||
|
await Cache().saveMyTrainingPlan();
|
||||||
|
yield TrainingPlanReady();
|
||||||
|
} else if (event is TrainingPlanSkipExercise) {
|
||||||
|
yield TrainingPlanLoading();
|
||||||
|
event.detail.state = ExercisePlanDetailState.skipped;
|
||||||
|
Cache().myTrainingPlan = _myPlan;
|
||||||
await Cache().saveMyTrainingPlan();
|
await Cache().saveMyTrainingPlan();
|
||||||
yield TrainingPlanReady();
|
yield TrainingPlanReady();
|
||||||
}
|
}
|
||||||
@ -81,13 +87,41 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void activateDays() {
|
||||||
|
if (_myPlan == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dayNames.clear();
|
||||||
|
_myPlan!.days.clear();
|
||||||
|
String dayName = ".";
|
||||||
|
_myPlan!.details.forEach((element) {
|
||||||
|
if (element.day != null && element.day != dayName) {
|
||||||
|
dayNames.add(element.day!);
|
||||||
|
dayName = element.day!;
|
||||||
|
}
|
||||||
|
if (_myPlan!.days[dayName] == null) {
|
||||||
|
if (dayName == ".") {
|
||||||
|
dayName = "";
|
||||||
|
}
|
||||||
|
_myPlan!.days[dayName] = [];
|
||||||
|
}
|
||||||
|
_myPlan!.days[dayName]!.add(element);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dayNames.length == 0) {
|
||||||
|
dayNames.add("");
|
||||||
|
_myPlan!.days[""] = [];
|
||||||
|
_myPlan!.days[""]!.addAll(_myPlan!.details);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CustomerTrainingPlanDetails? getTrainingPlanDetail(int trainingPlanDetailsId) {
|
CustomerTrainingPlanDetails? getTrainingPlanDetail(int trainingPlanDetailsId) {
|
||||||
CustomerTrainingPlanDetails? detail;
|
CustomerTrainingPlanDetails? detail;
|
||||||
if (myPlan == null || myPlan!.details.isEmpty) {
|
if (_myPlan == null || _myPlan!.details.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final det in this.myPlan!.details) {
|
for (final det in this._myPlan!.details) {
|
||||||
if (det.customerTrainingPlanDetailsId == trainingPlanDetailsId) {
|
if (det.customerTrainingPlanDetailsId == trainingPlanDetailsId) {
|
||||||
detail = det;
|
detail = det;
|
||||||
break;
|
break;
|
||||||
@ -118,21 +152,21 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CustomerTrainingPlanDetails? getNext() {
|
CustomerTrainingPlanDetails? getNext() {
|
||||||
if (myPlan == null || myPlan!.details.isEmpty) {
|
if (_myPlan == null || _myPlan!.details.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomerTrainingPlanDetails? next;
|
CustomerTrainingPlanDetails? next;
|
||||||
int minStep = 99;
|
int minStep = 99;
|
||||||
for (final detail in this.myPlan!.details) {
|
for (final detail in this._myPlan!.details) {
|
||||||
if (!detail.state.equalsTo(ExercisePlanDetailState.finished)) {
|
if (!detail.state.equalsTo(ExercisePlanDetailState.finished)) {
|
||||||
if (detail.exercises.isEmpty) {
|
if (detail.exercises.isEmpty && !detail.state.equalsTo(ExercisePlanDetailState.skipped)) {
|
||||||
next = detail;
|
next = detail;
|
||||||
minStep = 1;
|
minStep = 1;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
final int step = detail.exercises.length;
|
final int step = detail.exercises.length;
|
||||||
if (step < minStep) {
|
if (step < minStep && !detail.state.equalsTo(ExercisePlanDetailState.skipped)) {
|
||||||
next = detail;
|
next = detail;
|
||||||
minStep = step;
|
minStep = step;
|
||||||
if (detail.parallel != true) {
|
if (detail.parallel != true) {
|
||||||
@ -142,19 +176,41 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
print("Next detail $next");
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isStarted() {
|
bool isStarted() {
|
||||||
if (myPlan == null || myPlan!.details.isEmpty) {
|
if (_myPlan == null || _myPlan!.details.isEmpty) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myPlan!.details[0].state == ExercisePlanDetailState.start) {
|
if (_myPlan!.details[0].state == ExercisePlanDetailState.start) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double getOffset() {
|
||||||
|
double offset = 5;
|
||||||
|
if (_myPlan == null) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
int indexInProgress = 0;
|
||||||
|
int indexInStart = 0;
|
||||||
|
for (var detail in _myPlan!.details) {
|
||||||
|
if (detail.state == ExercisePlanDetailState.inProgress) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (detail.state == ExercisePlanDetailState.start) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indexInStart++;
|
||||||
|
indexInProgress++;
|
||||||
|
}
|
||||||
|
int index = indexInStart > indexInProgress ? indexInStart : indexInProgress;
|
||||||
|
offset = index * 80;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,5 +50,9 @@ class TrainingPlanFinishTraining extends TrainingPlanEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TrainingPlanSkipExercise extends TrainingPlanEvent {
|
class TrainingPlanSkipExercise extends TrainingPlanEvent {
|
||||||
const TrainingPlanSkipExercise();
|
final CustomerTrainingPlanDetails detail;
|
||||||
|
const TrainingPlanSkipExercise({required this.detail});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [detail];
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@ class TutorialBloc extends Bloc<TutorialEvent, TutorialState> with Logging {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
if (Cache().tutorials != null) {
|
if (Cache().tutorials != null) {
|
||||||
print("Actual step: $step");
|
|
||||||
final List<Tutorial> tutorials = Cache().tutorials!;
|
final List<Tutorial> tutorials = Cache().tutorials!;
|
||||||
tutorials.forEach((element) {
|
tutorials.forEach((element) {
|
||||||
final String realTutorialName = tutorialName.replaceFirst("tutorial", "").toLowerCase();
|
final String realTutorialName = tutorialName.replaceFirst("tutorial", "").toLowerCase();
|
||||||
@ -64,7 +63,7 @@ class TutorialBloc extends Bloc<TutorialEvent, TutorialState> with Logging {
|
|||||||
actualText = tutorial!.steps![step].tutorialTextTranslation;
|
actualText = tutorial!.steps![step].tutorialTextTranslation;
|
||||||
|
|
||||||
this.actualCheck = tutorial!.steps![step].checkText;
|
this.actualCheck = tutorial!.steps![step].checkText;
|
||||||
print("Step: $step, text: $actualCheck");
|
|
||||||
this.checks = [];
|
this.checks = [];
|
||||||
|
|
||||||
if (this.actualCheck != null) {
|
if (this.actualCheck != null) {
|
||||||
@ -91,7 +90,6 @@ class TutorialBloc extends Bloc<TutorialEvent, TutorialState> with Logging {
|
|||||||
}
|
}
|
||||||
bool? isActivityDone = Cache().activitiesDone[activityDone.toStr()];
|
bool? isActivityDone = Cache().activitiesDone[activityDone.toStr()];
|
||||||
|
|
||||||
log("$tutorialName isActivityDone? $isActivityDone");
|
|
||||||
if (isActivityDone == null || isActivityDone == true) {
|
if (isActivityDone == null || isActivityDone == true) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -238,10 +238,15 @@ class Cache with Logging {
|
|||||||
if (savedTrainingPlanJson == null) {
|
if (savedTrainingPlanJson == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//String jsonPlan = savedTrainingPlanJson.replaceAllMapped(RegExp(r'[a-zA-Z]+\:'), (Match m) => "\"${m[0]}\"");
|
||||||
final Map<String, dynamic> map = JsonDecoder().convert(savedTrainingPlanJson);
|
Map<String, dynamic> map;
|
||||||
print("Training plan: $savedTrainingPlanJson");
|
try {
|
||||||
this.myTrainingPlan = CustomerTrainingPlan.fromJsonWithDetails(map);
|
map = JsonDecoder().convert(savedTrainingPlanJson);
|
||||||
|
print("Training plan: $savedTrainingPlanJson");
|
||||||
|
this.myTrainingPlan = CustomerTrainingPlan.fromJsonWithDetails(map);
|
||||||
|
} on Exception catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteActiveExercisePlan() async {
|
Future<void> deleteActiveExercisePlan() async {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'dart:collection';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
@ -17,6 +18,8 @@ class CustomerTrainingPlan {
|
|||||||
|
|
||||||
List<CustomerTrainingPlanDetails> details = [];
|
List<CustomerTrainingPlanDetails> details = [];
|
||||||
|
|
||||||
|
HashMap<String, List<CustomerTrainingPlanDetails>> days = HashMap();
|
||||||
|
|
||||||
CustomerTrainingPlan.fromJson(Map json) {
|
CustomerTrainingPlan.fromJson(Map json) {
|
||||||
this.customerTrainingPlanId = json['customerTrainingPlanId'];
|
this.customerTrainingPlanId = json['customerTrainingPlanId'];
|
||||||
this.customerId = json['customerId'];
|
this.customerId = json['customerId'];
|
||||||
@ -38,12 +41,17 @@ class CustomerTrainingPlan {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final String details = json['details'];
|
final String details = json['details'];
|
||||||
String jsonDetails = details.replaceAllMapped(
|
String jsonDetails = details.replaceAllMapped(RegExp(r'([a-zA-Z]+)\:'), (Match m) => "\"${m[1]}\":");
|
||||||
RegExp(r'([a-zA-Z]+|[0-9]{4}\-[0-9]{2}\-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})'), (Match m) => "\"${m[0]}\"");
|
jsonDetails = jsonDetails.replaceAllMapped(RegExp(r'\: ([a-zA-Z /]+)'), (Match m) => ":\"${m[1]}\"");
|
||||||
|
|
||||||
jsonDetails = jsonDetails.replaceAll(r'\"null\"', 'null');
|
jsonDetails =
|
||||||
jsonDetails = jsonDetails.replaceAll(r'\"false\"', 'false');
|
jsonDetails.replaceAllMapped(RegExp(r'([0-9]{4}\-[0-9]{2}\-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})'), (Match m) => "\"${m[0]}\"");
|
||||||
jsonDetails = jsonDetails.replaceAll(r'\"true\"', 'true');
|
|
||||||
|
// jsonDetails = jsonDetails.replaceAll(r'\"null\"', 'null');
|
||||||
|
// jsonDetails = jsonDetails.replaceAll(r'\"false\"', 'false');
|
||||||
|
// jsonDetails = jsonDetails.replaceAll(r'\"true\"', 'true');
|
||||||
|
|
||||||
|
print("detail: $jsonDetails");
|
||||||
|
|
||||||
Iterable iterable = jsonDecode(jsonDetails);
|
Iterable iterable = jsonDecode(jsonDetails);
|
||||||
this.details = iterable.map((detail) => CustomerTrainingPlanDetails.fromJsonWithExerciseList(detail)).toList();
|
this.details = iterable.map((detail) => CustomerTrainingPlanDetails.fromJsonWithExerciseList(detail)).toList();
|
||||||
@ -66,7 +74,7 @@ class CustomerTrainingPlan {
|
|||||||
"customerTrainingPlanId": this.customerTrainingPlanId,
|
"customerTrainingPlanId": this.customerTrainingPlanId,
|
||||||
"customerId": this.customerId,
|
"customerId": this.customerId,
|
||||||
"trainingPlanId": this.trainingPlanId,
|
"trainingPlanId": this.trainingPlanId,
|
||||||
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!),
|
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd!).toString(),
|
||||||
"name": this.name,
|
"name": this.name,
|
||||||
"active": this.active,
|
"active": this.active,
|
||||||
"status": this.status,
|
"status": this.status,
|
||||||
|
@ -51,7 +51,7 @@ class CustomerTrainingPlanDetails {
|
|||||||
: json['customerTrainingPlanDetailsId'];
|
: json['customerTrainingPlanDetailsId'];
|
||||||
this.exerciseTypeId = json['exerciseTypeId'];
|
this.exerciseTypeId = json['exerciseTypeId'];
|
||||||
this.set = json['set'];
|
this.set = json['set'];
|
||||||
this.repeats = json['repeats'];
|
this.repeats = json['repeats'] == "null" ? -1 : json['repeats'];
|
||||||
this.weight = json['weight'];
|
this.weight = json['weight'];
|
||||||
this.restingTime = json['restingTime'];
|
this.restingTime = json['restingTime'];
|
||||||
this.parallel = json['parallel'] == "false"
|
this.parallel = json['parallel'] == "false"
|
||||||
@ -59,7 +59,10 @@ class CustomerTrainingPlanDetails {
|
|||||||
: json['parallel'] == "true"
|
: json['parallel'] == "true"
|
||||||
? true
|
? true
|
||||||
: null;
|
: null;
|
||||||
this.day = json['day'];
|
this.day = json['day'].toString();
|
||||||
|
if (this.day == null || this.day == "null") {
|
||||||
|
this.day = "";
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Iterable iterable = json['exercises'];
|
Iterable iterable = json['exercises'];
|
||||||
this.exercises = iterable.map((exercise) => Exercise.fromJson(exercise)).toList();
|
this.exercises = iterable.map((exercise) => Exercise.fromJson(exercise)).toList();
|
||||||
@ -67,13 +70,16 @@ class CustomerTrainingPlanDetails {
|
|||||||
print("JsonDecode error " + e.toString());
|
print("JsonDecode error " + e.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exercises.length >= this.set!) {
|
if (json['state'] == ExercisePlanDetailState.finished.toStr()) {
|
||||||
this.state = ExercisePlanDetailState.finished;
|
this.state = ExercisePlanDetailState.finished;
|
||||||
} else if (exercises.length > 0) {
|
} else if (json['state'] == ExercisePlanDetailState.inProgress.toStr()) {
|
||||||
this.state = ExercisePlanDetailState.inProgress;
|
this.state = ExercisePlanDetailState.inProgress;
|
||||||
|
} else if (json['state'] == ExercisePlanDetailState.skipped.toStr()) {
|
||||||
|
this.state = ExercisePlanDetailState.skipped;
|
||||||
} else {
|
} else {
|
||||||
this.state = ExercisePlanDetailState.start;
|
this.state = ExercisePlanDetailState.start;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.exerciseType = Cache().getExerciseTypeById(exerciseTypeId!);
|
this.exerciseType = Cache().getExerciseTypeById(exerciseTypeId!);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +98,7 @@ class CustomerTrainingPlanDetails {
|
|||||||
|
|
||||||
Map<String, dynamic> toJsonWithExercises() {
|
Map<String, dynamic> toJsonWithExercises() {
|
||||||
final Map<String, dynamic> jsonMap = {
|
final Map<String, dynamic> jsonMap = {
|
||||||
"customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId,
|
//"customerTrainingPlanDetailsId": this.customerTrainingPlanDetailsId,
|
||||||
"exerciseTypeId": this.exerciseTypeId,
|
"exerciseTypeId": this.exerciseTypeId,
|
||||||
"set": this.set,
|
"set": this.set,
|
||||||
"repeats": this.repeats,
|
"repeats": this.repeats,
|
||||||
@ -100,6 +106,7 @@ class CustomerTrainingPlanDetails {
|
|||||||
"restingTime": this.restingTime,
|
"restingTime": this.restingTime,
|
||||||
"parallel": this.parallel,
|
"parallel": this.parallel,
|
||||||
'exercises': exercises.isEmpty ? [].toString() : exercises.map((exercise) => exercise.toJson()).toList().toString(),
|
'exercises': exercises.isEmpty ? [].toString() : exercises.map((exercise) => exercise.toJson()).toList().toString(),
|
||||||
|
'state': this.state.toStr(),
|
||||||
};
|
};
|
||||||
if (this.day != null && this.day!.isNotEmpty) {
|
if (this.day != null && this.day!.isNotEmpty) {
|
||||||
jsonMap["day"] = this.day;
|
jsonMap["day"] = this.day;
|
||||||
@ -110,5 +117,5 @@ class CustomerTrainingPlanDetails {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => this.toJson().toString();
|
String toString() => this.toJsonWithExercises().toString();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
enum ExerciseAbility { oneRepMax, endurance, running, mini_test_set, paralell_test, none }
|
enum ExerciseAbility { oneRepMax, endurance, running, mini_test_set, paralell_test, training, none }
|
||||||
|
|
||||||
extension ExerciseAbilityExt on ExerciseAbility {
|
extension ExerciseAbilityExt on ExerciseAbility {
|
||||||
String enumToString() => this.toString().split(".").last;
|
String enumToString() => this.toString().split(".").last;
|
||||||
@ -16,6 +16,8 @@ extension ExerciseAbilityExt on ExerciseAbility {
|
|||||||
return "Compact Test";
|
return "Compact Test";
|
||||||
case ExerciseAbility.paralell_test:
|
case ExerciseAbility.paralell_test:
|
||||||
return "Custom Test";
|
return "Custom Test";
|
||||||
|
case ExerciseAbility.training:
|
||||||
|
return "Training";
|
||||||
default:
|
default:
|
||||||
return "Compact Test";
|
return "Compact Test";
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@ import 'dart:convert';
|
|||||||
import 'package:aitrainer_app/model/exercise.dart';
|
import 'package:aitrainer_app/model/exercise.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_type.dart';
|
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||||
|
|
||||||
enum ExercisePlanDetailState { start, inProgress, finished }
|
enum ExercisePlanDetailState { start, inProgress, skipped, finished }
|
||||||
|
|
||||||
extension ExericisePlanDetailStateExt on ExercisePlanDetailState {
|
extension ExericisePlanDetailStateExt on ExercisePlanDetailState {
|
||||||
bool equalsTo(ExercisePlanDetailState state) => this.toString() == state.toString();
|
bool equalsTo(ExercisePlanDetailState state) => this.toString() == state.toString();
|
||||||
bool equalsStringTo(String state) => this.toString() == state;
|
bool equalsStringTo(String state) => this.toString() == state;
|
||||||
|
String toStr() => this.toString().split(".").last;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExercisePlanDetail {
|
class ExercisePlanDetail {
|
||||||
|
@ -40,9 +40,26 @@ class WorkoutMenuTree {
|
|||||||
late String parentName;
|
late String parentName;
|
||||||
late String parentNameEnglish;
|
late String parentNameEnglish;
|
||||||
late int sort;
|
late int sort;
|
||||||
|
late String internalName;
|
||||||
|
|
||||||
WorkoutMenuTree(this.id, this.parent, this.name, this.imageName, this.color, this.fontSize, this.child, this.exerciseTypeId,
|
WorkoutMenuTree(
|
||||||
this.exerciseType, this.base, this.is1RM, this.isRunning, this.nameEnglish, this.parentName, this.parentNameEnglish, this.sort);
|
this.id,
|
||||||
|
this.parent,
|
||||||
|
this.name,
|
||||||
|
this.imageName,
|
||||||
|
this.color,
|
||||||
|
this.fontSize,
|
||||||
|
this.child,
|
||||||
|
this.exerciseTypeId,
|
||||||
|
this.exerciseType,
|
||||||
|
this.base,
|
||||||
|
this.is1RM,
|
||||||
|
this.isRunning,
|
||||||
|
this.nameEnglish,
|
||||||
|
this.parentName,
|
||||||
|
this.parentNameEnglish,
|
||||||
|
this.sort,
|
||||||
|
this.internalName);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
|
@ -38,12 +38,10 @@ class WorkoutTreeRepository with Logging {
|
|||||||
exerciseTree.sort((a, b) => a.sort!.compareTo(b.sort!));
|
exerciseTree.sort((a, b) => a.sort!.compareTo(b.sort!));
|
||||||
|
|
||||||
exerciseTree.forEach((treeItem) async {
|
exerciseTree.forEach((treeItem) async {
|
||||||
//log(" -- TreeItem " + treeItem.toJson().toString() + " active " + treeItem.active.toString());
|
|
||||||
if (treeItem.active == true) {
|
if (treeItem.active == true) {
|
||||||
String treeName = isEnglish! ? treeItem.name : treeItem.nameTranslation;
|
String treeName = isEnglish! ? treeItem.name : treeItem.nameTranslation;
|
||||||
|
|
||||||
bool is1RM =
|
bool is1RM = treeItem.internalName != null && treeItem.internalName!.contains("one_rep_max") ? true : false;
|
||||||
treeItem.name.contains("Muscle") || treeItem.name.contains("Shape") || treeItem.name.contains("Strength") ? true : false;
|
|
||||||
if (!is1RM) {
|
if (!is1RM) {
|
||||||
is1RM = this.isParent1RM(treeItem.parentId);
|
is1RM = this.isParent1RM(treeItem.parentId);
|
||||||
}
|
}
|
||||||
@ -69,7 +67,8 @@ class WorkoutTreeRepository with Logging {
|
|||||||
treeItem.name,
|
treeItem.name,
|
||||||
parent != null ? parent.name : "",
|
parent != null ? parent.name : "",
|
||||||
parent != null ? parent.nameEnglish : "",
|
parent != null ? parent.nameEnglish : "",
|
||||||
treeItem.sort!);
|
treeItem.sort!,
|
||||||
|
treeItem.internalName != null ? treeItem.internalName! : "");
|
||||||
menuItem = this.setWorkoutTypes(menuItem, treeItem);
|
menuItem = this.setWorkoutTypes(menuItem, treeItem);
|
||||||
this.tree[treeItem.name + "_" + treeItem.parentId.toString()] = menuItem;
|
this.tree[treeItem.name + "_" + treeItem.parentId.toString()] = menuItem;
|
||||||
//log("WorkoutMenuTree item ${menuItem.toJson()}");
|
//log("WorkoutMenuTree item ${menuItem.toJson()}");
|
||||||
@ -110,7 +109,8 @@ class WorkoutTreeRepository with Logging {
|
|||||||
exerciseType.name,
|
exerciseType.name,
|
||||||
parent != null ? parent.name : "",
|
parent != null ? parent.name : "",
|
||||||
parent != null ? parent.nameEnglish : "",
|
parent != null ? parent.nameEnglish : "",
|
||||||
0);
|
0,
|
||||||
|
"");
|
||||||
this.tree[exerciseType.name] = menuItem;
|
this.tree[exerciseType.name] = menuItem;
|
||||||
if (isRunning || is1RM) {
|
if (isRunning || is1RM) {
|
||||||
menuAsExercise.add(menuItem);
|
menuAsExercise.add(menuItem);
|
||||||
|
@ -234,7 +234,7 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
|
|||||||
onPrimary: Colors.white,
|
onPrimary: Colors.white,
|
||||||
primary: Colors.orange,
|
primary: Colors.orange,
|
||||||
),
|
),
|
||||||
child: Text(t("Activate")),
|
child: Text(t("Start")),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (Cache().myTrainingPlan != null) {
|
if (Cache().myTrainingPlan != null) {
|
||||||
showCupertinoDialog(
|
showCupertinoDialog(
|
||||||
|
@ -4,11 +4,14 @@ import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
|
|||||||
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||||
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
|
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
||||||
|
import 'package:aitrainer_app/util/app_localization.dart';
|
||||||
import 'package:aitrainer_app/util/trans.dart';
|
import 'package:aitrainer_app/util/trans.dart';
|
||||||
import 'package:aitrainer_app/widgets/app_bar.dart';
|
import 'package:aitrainer_app/widgets/app_bar.dart';
|
||||||
import 'package:aitrainer_app/widgets/dialog_common.dart';
|
import 'package:aitrainer_app/widgets/dialog_common.dart';
|
||||||
import 'package:aitrainer_app/widgets/menu_image.dart';
|
import 'package:aitrainer_app/widgets/menu_image.dart';
|
||||||
|
import 'package:extended_tabs/extended_tabs.dart';
|
||||||
import 'package:ezanimation/ezanimation.dart';
|
import 'package:ezanimation/ezanimation.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
@ -16,10 +19,19 @@ import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
|
|||||||
import 'package:timeline_tile/timeline_tile.dart';
|
import 'package:timeline_tile/timeline_tile.dart';
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class TrainingPlanExecutePage extends StatelessWidget with Trans {
|
class TrainingPlanExecutePage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_TrainingPlanExecutePageState createState() => _TrainingPlanExecutePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TrainingPlanExecutePageState extends State<TrainingPlanExecutePage> with Trans {
|
||||||
|
final scrollController = ScrollController();
|
||||||
|
TrainingPlanBloc? bloc;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
|
bloc = BlocProvider.of<TrainingPlanBloc>(context);
|
||||||
|
bloc!.activateDays();
|
||||||
setContext(context);
|
setContext(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBarNav(depth: 0),
|
appBar: AppBarNav(depth: 0),
|
||||||
@ -39,7 +51,7 @@ class TrainingPlanExecutePage extends StatelessWidget with Trans {
|
|||||||
} else if (state is TrainingPlanFinished) {}
|
} else if (state is TrainingPlanFinished) {}
|
||||||
}, builder: (context, state) {
|
}, builder: (context, state) {
|
||||||
return ModalProgressHUD(
|
return ModalProgressHUD(
|
||||||
child: getExercises(bloc),
|
child: ExerciseTabs(bloc: bloc!),
|
||||||
inAsyncCall: state is TrainingPlanLoading,
|
inAsyncCall: state is TrainingPlanLoading,
|
||||||
opacity: 0.5,
|
opacity: 0.5,
|
||||||
color: Colors.black54,
|
color: Colors.black54,
|
||||||
@ -48,7 +60,9 @@ class TrainingPlanExecutePage extends StatelessWidget with Trans {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton.extended(
|
floatingActionButton: FloatingActionButton.extended(
|
||||||
onPressed: () => bloc.getNext() != null ? executeExercise(bloc, bloc.getNext()!) : Navigator.of(context).pushNamed('home'),
|
onPressed: () => bloc!.getNext() != null
|
||||||
|
? _ExerciseListState.executeExercise(bloc!, bloc!.getNext()!, context)
|
||||||
|
: Navigator.of(context).pushNamed('home'),
|
||||||
backgroundColor: Colors.orange[800],
|
backgroundColor: Colors.orange[800],
|
||||||
icon: Icon(CustomIcon.weight_hanging),
|
icon: Icon(CustomIcon.weight_hanging),
|
||||||
label: Text(
|
label: Text(
|
||||||
@ -58,10 +72,171 @@ class TrainingPlanExecutePage extends StatelessWidget with Trans {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget getExercises(TrainingPlanBloc bloc) {
|
class ExerciseTabs extends StatefulWidget {
|
||||||
return CustomScrollView(slivers: [
|
final TrainingPlanBloc bloc;
|
||||||
SliverList(delegate: SliverChildListDelegate(getTiles(bloc))),
|
ExerciseTabs({required this.bloc});
|
||||||
|
@override
|
||||||
|
_ExerciseTabs createState() => _ExerciseTabs();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ExerciseTabs extends State<ExerciseTabs> with TickerProviderStateMixin {
|
||||||
|
late TabController tabController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
tabController = TabController(length: widget.bloc.dayNames.length, vsync: this);
|
||||||
|
tabController.animateTo(0, duration: Duration(milliseconds: 300));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
tabController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return getTabs(widget.bloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getTabs(TrainingPlanBloc bloc) {
|
||||||
|
return Column(children: [
|
||||||
|
ExtendedTabBar(
|
||||||
|
tabs: getTabNames(),
|
||||||
|
controller: tabController,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ExtendedTabBarView(
|
||||||
|
children: getExerciseLists(),
|
||||||
|
controller: tabController,
|
||||||
|
|
||||||
|
/// if link is true and current tabbarview over scroll,
|
||||||
|
/// it will check and scroll ancestor or child tabbarView.
|
||||||
|
link: true,
|
||||||
|
|
||||||
|
/// cache page count
|
||||||
|
/// default is 0.
|
||||||
|
/// if cacheExtent is 1, it has two pages in cache
|
||||||
|
/// null is infinity, it will cache all pages
|
||||||
|
cacheExtent: 0,
|
||||||
|
)),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Tab> getTabNames() {
|
||||||
|
List<Tab> tabs = [];
|
||||||
|
widget.bloc.dayNames.forEach((element) {
|
||||||
|
final Widget widget = RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
style: GoogleFonts.inter(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: AppLocalizations.of(context)!.translate("Training Day") + ": \n",
|
||||||
|
style: GoogleFonts.inter(
|
||||||
|
fontSize: 14,
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
TextSpan(
|
||||||
|
text: element,
|
||||||
|
style: GoogleFonts.inter(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.yellow[400],
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
]));
|
||||||
|
|
||||||
|
tabs.add(Tab(child: widget));
|
||||||
|
});
|
||||||
|
return tabs;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> getExerciseLists() {
|
||||||
|
List<Widget> list = [];
|
||||||
|
widget.bloc.dayNames.forEach((element) {
|
||||||
|
list.add(ExerciseList(bloc: widget.bloc, dayName: element));
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExerciseList extends StatefulWidget {
|
||||||
|
final TrainingPlanBloc bloc;
|
||||||
|
final String dayName;
|
||||||
|
ExerciseList({required this.bloc, required this.dayName});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ExerciseListState createState() => _ExerciseListState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ExerciseListState extends State<ExerciseList> with Trans {
|
||||||
|
final scrollController = ScrollController();
|
||||||
|
double offset = 5;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
WidgetsBinding.instance!.addPostFrameCallback((_) {
|
||||||
|
animate();
|
||||||
|
});
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(ExerciseList page) {
|
||||||
|
super.didUpdateWidget(page);
|
||||||
|
WidgetsBinding.instance!.addPostFrameCallback((_) {
|
||||||
|
animate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void animate() {
|
||||||
|
offset = widget.bloc.getOffset();
|
||||||
|
if (scrollController.hasClients) {
|
||||||
|
scrollController.animateTo(offset, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
setContext(context);
|
||||||
|
return CustomScrollView(controller: scrollController, slivers: [
|
||||||
|
SliverList(delegate: SliverChildListDelegate(getTiles(widget.bloc))),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +244,7 @@ class TrainingPlanExecutePage extends StatelessWidget with Trans {
|
|||||||
List<Widget> tiles = [];
|
List<Widget> tiles = [];
|
||||||
tiles.add(getStartTile(bloc));
|
tiles.add(getStartTile(bloc));
|
||||||
tiles.addAll(getExerciseTiles(bloc, context));
|
tiles.addAll(getExerciseTiles(bloc, context));
|
||||||
if (bloc.myPlan != null) tiles.add(getEndTile());
|
if (bloc.getMyPlan() != null) tiles.add(getEndTile());
|
||||||
return tiles;
|
return tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,11 +252,12 @@ class TrainingPlanExecutePage extends StatelessWidget with Trans {
|
|||||||
String startText = "";
|
String startText = "";
|
||||||
String explainingText = "";
|
String explainingText = "";
|
||||||
if (null == bloc.getMyPlan()) {
|
if (null == bloc.getMyPlan()) {
|
||||||
startText = "No Active Training Plan";
|
startText = t("No Active Training Plan");
|
||||||
explainingText = "Please select one in the Training menu, or create your custom plan";
|
explainingText = t("Please select one in the Training menu, or create your custom plan");
|
||||||
} else {
|
} else {
|
||||||
startText = bloc.isStarted() ? "Continue your training" : "Start your training";
|
startText = bloc.isStarted() ? t("Continue your training") : t("Start your training");
|
||||||
explainingText = bloc.getMyPlan()!.name != null ? bloc.getMyPlan()!.name! : "";
|
explainingText = bloc.getMyPlan()!.name != null ? bloc.getMyPlan()!.name! : "";
|
||||||
|
print(" *** Plan NAME ${bloc.getMyPlan()!.name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return TimelineTile(
|
return TimelineTile(
|
||||||
@ -212,10 +388,14 @@ class TrainingPlanExecutePage extends StatelessWidget with Trans {
|
|||||||
|
|
||||||
List<Widget> getExerciseTiles(TrainingPlanBloc bloc, BuildContext context) {
|
List<Widget> getExerciseTiles(TrainingPlanBloc bloc, BuildContext context) {
|
||||||
List<Widget> tiles = [];
|
List<Widget> tiles = [];
|
||||||
if (bloc.myPlan != null && bloc.myPlan!.details.isNotEmpty) {
|
if (bloc.getMyPlan() != null &&
|
||||||
bloc.myPlan!.details.forEach((element) {
|
bloc.getMyPlan()!.details.isNotEmpty &&
|
||||||
|
bloc.getMyPlan()!.days[widget.dayName] != null &&
|
||||||
|
bloc.getMyPlan()!.days[widget.dayName]!.isNotEmpty) {
|
||||||
|
bloc.getMyPlan()!.days[widget.dayName]!.forEach((element) {
|
||||||
|
//bloc.getMyPlan()!.details.forEach((element) {
|
||||||
tiles.add(GestureDetector(
|
tiles.add(GestureDetector(
|
||||||
onTap: () => {},
|
onTap: () => bloc.getNext() != null ? executeExercise(bloc, bloc.getNext()!, context) : Navigator.of(context).pushNamed('home'),
|
||||||
child: ExerciseTile(
|
child: ExerciseTile(
|
||||||
bloc: bloc,
|
bloc: bloc,
|
||||||
detail: element,
|
detail: element,
|
||||||
@ -226,7 +406,7 @@ class TrainingPlanExecutePage extends StatelessWidget with Trans {
|
|||||||
return tiles;
|
return tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
void executeExercise(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail) {
|
static void executeExercise(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail, BuildContext context) {
|
||||||
CustomerTrainingPlanDetails? next = bloc.getNext();
|
CustomerTrainingPlanDetails? next = bloc.getNext();
|
||||||
|
|
||||||
if (next != null) {
|
if (next != null) {
|
||||||
@ -234,9 +414,10 @@ class TrainingPlanExecutePage extends StatelessWidget with Trans {
|
|||||||
String description = "";
|
String description = "";
|
||||||
String description2 = "";
|
String description2 = "";
|
||||||
if (next.exerciseTypeId != detail.exerciseTypeId) {
|
if (next.exerciseTypeId != detail.exerciseTypeId) {
|
||||||
title = t("Stop!");
|
title = AppLocalizations.of(context)!.translate("Stop!");
|
||||||
description = t("Please continue with the next exercise in the queue:") + next.exerciseType!.nameTranslation;
|
description = AppLocalizations.of(context)!.translate("Please continue with the next exercise in the queue:") +
|
||||||
description2 = t("Or, you can redifine this exercise queue in the Compact Test menu");
|
next.exerciseType!.nameTranslation;
|
||||||
|
description2 = AppLocalizations.of(context)!.translate("Or, you can redifine this exercise queue in the Compact Test menu");
|
||||||
} else {
|
} else {
|
||||||
final HashMap args = HashMap();
|
final HashMap args = HashMap();
|
||||||
args['exerciseType'] = next.exerciseType;
|
args['exerciseType'] = next.exerciseType;
|
||||||
@ -264,8 +445,7 @@ class TrainingPlanExecutePage extends StatelessWidget with Trans {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
class ExerciseTile extends StatefulWidget {
|
||||||
class ExerciseTile extends StatefulWidget with Trans {
|
|
||||||
final TrainingPlanBloc bloc;
|
final TrainingPlanBloc bloc;
|
||||||
final CustomerTrainingPlanDetails detail;
|
final CustomerTrainingPlanDetails detail;
|
||||||
|
|
||||||
@ -323,6 +503,16 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
|
|||||||
size: 40,
|
size: 40,
|
||||||
color: Colors.green,
|
color: Colors.green,
|
||||||
)));
|
)));
|
||||||
|
} else if (state.equalsTo(ExercisePlanDetailState.skipped)) {
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(24.0),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: Icon(
|
||||||
|
CustomIcon.stop_1,
|
||||||
|
size: 40,
|
||||||
|
color: Colors.grey,
|
||||||
|
)));
|
||||||
} else {
|
} else {
|
||||||
return Image.asset(
|
return Image.asset(
|
||||||
"asset/image/pict_reps_volumen_db.png",
|
"asset/image/pict_reps_volumen_db.png",
|
||||||
@ -334,7 +524,7 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
setContext(context);
|
setContext(context);
|
||||||
final ExercisePlanDetailState state = widget.detail.state;
|
final ExercisePlanDetailState state = widget.detail.state;
|
||||||
final bool done = state.equalsTo(ExercisePlanDetailState.finished);
|
final bool done = state.equalsTo(ExercisePlanDetailState.finished) || state.equalsTo(ExercisePlanDetailState.skipped);
|
||||||
final String countSerie = widget.detail.set.toString();
|
final String countSerie = widget.detail.set.toString();
|
||||||
final String step = (widget.detail.exercises.length).toString();
|
final String step = (widget.detail.exercises.length).toString();
|
||||||
String weight = widget.detail.weight!.toStringAsFixed(1);
|
String weight = widget.detail.weight!.toStringAsFixed(1);
|
||||||
@ -363,16 +553,38 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
|
|||||||
height: 40,
|
height: 40,
|
||||||
indicator: getIndicator(state),
|
indicator: getIndicator(state),
|
||||||
),
|
),
|
||||||
|
startChild: Container(
|
||||||
|
child: Column(children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 55,
|
||||||
|
),
|
||||||
|
done
|
||||||
|
? Offstage()
|
||||||
|
: IconButton(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
icon: Icon(
|
||||||
|
Icons.skip_next_sharp,
|
||||||
|
size: 30,
|
||||||
|
color: Colors.orange[300],
|
||||||
|
),
|
||||||
|
onPressed: () => skip()),
|
||||||
|
]),
|
||||||
|
),
|
||||||
endChild: Container(
|
endChild: Container(
|
||||||
padding: EdgeInsets.only(left: 10),
|
padding: EdgeInsets.only(left: 10),
|
||||||
child: Row(children: [
|
child: Row(children: [
|
||||||
Container(
|
Container(
|
||||||
width: 120,
|
width: 120,
|
||||||
height: 80,
|
height: 80,
|
||||||
child: MenuImage(
|
child: MenuImage(
|
||||||
imageName: widget.bloc.getActualImageName(widget.detail.exerciseType!.exerciseTypeId),
|
imageName: widget.bloc.getActualImageName(widget.detail.exerciseType!.exerciseTypeId),
|
||||||
workoutTreeId: widget.bloc.getActualWorkoutTreeId(widget.detail.exerciseType!.exerciseTypeId)!,
|
workoutTreeId: widget.bloc.getActualWorkoutTreeId(widget.detail.exerciseType!.exerciseTypeId)!,
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 10,
|
width: 10,
|
||||||
),
|
),
|
||||||
@ -507,4 +719,30 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void skip() {
|
||||||
|
showCupertinoDialog(
|
||||||
|
useRootNavigator: true,
|
||||||
|
context: context,
|
||||||
|
builder: (_) => CupertinoAlertDialog(
|
||||||
|
title: Text(t("You want to skip really this exercise?")),
|
||||||
|
content: Column(children: [
|
||||||
|
Divider(),
|
||||||
|
]),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
child: Text(t("No")),
|
||||||
|
onPressed: () => {
|
||||||
|
Navigator.pop(context),
|
||||||
|
}),
|
||||||
|
TextButton(
|
||||||
|
child: Text(t("Yes")),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
widget.bloc.add(TrainingPlanSkipExercise(detail: widget.detail));
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import 'package:aitrainer_app/model/exercise_type.dart';
|
|||||||
|
|
||||||
import 'package:aitrainer_app/util/trans.dart';
|
import 'package:aitrainer_app/util/trans.dart';
|
||||||
import 'package:aitrainer_app/widgets/app_bar.dart';
|
import 'package:aitrainer_app/widgets/app_bar.dart';
|
||||||
import 'package:aitrainer_app/widgets/bottom_bar_multiple_exercises.dart';
|
|
||||||
import 'package:aitrainer_app/widgets/exercise_save.dart';
|
import 'package:aitrainer_app/widgets/exercise_save.dart';
|
||||||
import 'package:aitrainer_app/widgets/number_picker.dart';
|
import 'package:aitrainer_app/widgets/number_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -25,7 +24,6 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final HashMap args = ModalRoute.of(context)!.settings.arguments as HashMap;
|
final HashMap args = ModalRoute.of(context)!.settings.arguments as HashMap;
|
||||||
final ExerciseType exerciseType = args['exerciseType'];
|
|
||||||
final CustomerTrainingPlanDetails detail = args['customerTrainingPlanDetails'];
|
final CustomerTrainingPlanDetails detail = args['customerTrainingPlanDetails'];
|
||||||
// ignore: close_sinks
|
// ignore: close_sinks
|
||||||
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
|
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
|
||||||
@ -73,10 +71,6 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
|
|||||||
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
|
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
/* bottomNavigationBar: BottomBarMultipleExercises(
|
|
||||||
//isSet: executeBloc.miniTestSet == true,
|
|
||||||
exerciseTypeId: exerciseType.exerciseTypeId,
|
|
||||||
), */
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,6 +92,8 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
|
|||||||
hasUnitQuantity: detail.exerciseType!.unitQuantityUnit != null,
|
hasUnitQuantity: detail.exerciseType!.unitQuantityUnit != null,
|
||||||
weight: detail.weight == -1 ? 30 : detail.weight,
|
weight: detail.weight == -1 ? 30 : detail.weight,
|
||||||
repeats: detail.repeats == -1 ? 12 : detail.repeats,
|
repeats: detail.repeats == -1 ? 12 : detail.repeats,
|
||||||
|
set: detail.set,
|
||||||
|
exerciseNr: detail.exercises.length + 1,
|
||||||
onUnitQuantityChanged: (value) => bloc.add(TrainingPlanWeightChange(weight: value, detail: detail)),
|
onUnitQuantityChanged: (value) => bloc.add(TrainingPlanWeightChange(weight: value, detail: detail)),
|
||||||
onQuantityChanged: (value) => bloc.add(TrainingPlanRepeatsChange(repeats: value.toInt(), detail: detail)),
|
onQuantityChanged: (value) => bloc.add(TrainingPlanRepeatsChange(repeats: value.toInt(), detail: detail)),
|
||||||
exerciseTypeId: detail.exerciseType!.exerciseTypeId,
|
exerciseTypeId: detail.exerciseType!.exerciseTypeId,
|
||||||
|
@ -24,21 +24,24 @@ class ExerciseSave extends StatefulWidget {
|
|||||||
final int exerciseTypeId;
|
final int exerciseTypeId;
|
||||||
final double? weight;
|
final double? weight;
|
||||||
final int? repeats;
|
final int? repeats;
|
||||||
|
final int? set;
|
||||||
|
final int? exerciseNr;
|
||||||
|
|
||||||
ExerciseSave({
|
ExerciseSave(
|
||||||
required this.onQuantityChanged,
|
{required this.onQuantityChanged,
|
||||||
this.onUnitQuantityChanged,
|
this.onUnitQuantityChanged,
|
||||||
this.onSubmit,
|
this.onSubmit,
|
||||||
required this.hasUnitQuantity,
|
required this.hasUnitQuantity,
|
||||||
this.unitQuantityUnit,
|
this.unitQuantityUnit,
|
||||||
required this.unit,
|
required this.unit,
|
||||||
required this.exerciseName,
|
required this.exerciseName,
|
||||||
required this.exerciseDescription,
|
required this.exerciseDescription,
|
||||||
required this.exerciseTask,
|
required this.exerciseTask,
|
||||||
required this.exerciseTypeId,
|
required this.exerciseTypeId,
|
||||||
this.weight,
|
this.weight,
|
||||||
this.repeats,
|
this.repeats,
|
||||||
});
|
this.set,
|
||||||
|
this.exerciseNr});
|
||||||
@override
|
@override
|
||||||
_ExerciseSaveState createState() => _ExerciseSaveState();
|
_ExerciseSaveState createState() => _ExerciseSaveState();
|
||||||
}
|
}
|
||||||
@ -230,7 +233,9 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
|||||||
),
|
),
|
||||||
widget.hasUnitQuantity
|
widget.hasUnitQuantity
|
||||||
? Text(
|
? Text(
|
||||||
t("Step") + ": " + "1/4",
|
widget.set == null || widget.exerciseNr == null
|
||||||
|
? t("Step") + ": " + "1/4"
|
||||||
|
: t("Step") + ": " + "${widget.exerciseNr}/${widget.set}",
|
||||||
style: GoogleFonts.inter(
|
style: GoogleFonts.inter(
|
||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
|
@ -79,7 +79,6 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
}
|
}
|
||||||
if (!tutorialBloc.isTutorialDone()) {
|
if (!tutorialBloc.isTutorialDone()) {
|
||||||
if (tutorialBloc.isActive == false && tutorialBloc.canActivate) {
|
if (tutorialBloc.isActive == false && tutorialBloc.canActivate) {
|
||||||
print("Activate tutorial");
|
|
||||||
tutorialBloc.canActivate = true;
|
tutorialBloc.canActivate = true;
|
||||||
tutorialBloc.isActive = true;
|
tutorialBloc.isActive = true;
|
||||||
tutorialBloc.menuBloc = menuBloc;
|
tutorialBloc.menuBloc = menuBloc;
|
||||||
@ -328,7 +327,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
if (Cache().myTrainingPlan != null) {
|
if (Cache().myTrainingPlan != null) {
|
||||||
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
|
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
|
||||||
bloc.myPlan = Cache().myTrainingPlan;
|
bloc.setMyPlan(Cache().myTrainingPlan);
|
||||||
Navigator.of(context).pushNamed("myTrainingPlanExecute");
|
Navigator.of(context).pushNamed("myTrainingPlanExecute");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -411,6 +410,11 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
args['templateName'] = workoutTree.nameEnglish;
|
args['templateName'] = workoutTree.nameEnglish;
|
||||||
args['templateNameTranslation'] = workoutTree.name;
|
args['templateNameTranslation'] = workoutTree.name;
|
||||||
Navigator.of(context).pushNamed('testSetEdit', arguments: args);
|
Navigator.of(context).pushNamed('testSetEdit', arguments: args);
|
||||||
|
} else if (menuBloc.ability != null && ExerciseAbility.training.equalsTo(menuBloc.ability!) && workoutTree.parent != 0) {
|
||||||
|
HashMap<String, dynamic> args = HashMap();
|
||||||
|
print("menu ${workoutTree.internalName}");
|
||||||
|
args['parentName'] = workoutTree.internalName;
|
||||||
|
Navigator.of(context).pushNamed("myTrainingPlanActivate", arguments: args);
|
||||||
}
|
}
|
||||||
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
|
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
|
||||||
} else {
|
} else {
|
||||||
|
@ -274,6 +274,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.2"
|
||||||
|
extended_tabs:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: extended_tabs
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
ezanimation:
|
ezanimation:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -58,6 +58,7 @@ dependencies:
|
|||||||
flutter_app_badger: ^1.2.0
|
flutter_app_badger: ^1.2.0
|
||||||
#super_tooltip: ^1.0.1
|
#super_tooltip: ^1.0.1
|
||||||
url_launcher: ^6.0.3
|
url_launcher: ^6.0.3
|
||||||
|
extended_tabs: ^2.2.0
|
||||||
|
|
||||||
firebase_core: ^1.2.0
|
firebase_core: ^1.2.0
|
||||||
firebase_analytics: ^8.1.0
|
firebase_analytics: ^8.1.0
|
||||||
|
Loading…
Reference in New Issue
Block a user