WT1.1.18+2 Training Plan days, skip

This commit is contained in:
bossanyit 2021-05-30 15:29:26 +02:00
parent d388228caa
commit 48804c50f0
19 changed files with 453 additions and 101 deletions

View File

@ -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 = (

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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