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;
try {
map = JsonDecoder().convert(savedTrainingPlanJson);
print("Training plan: $savedTrainingPlanJson"); print("Training plan: $savedTrainingPlanJson");
this.myTrainingPlan = CustomerTrainingPlan.fromJsonWithDetails(map); 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,6 +553,27 @@ 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: [
@ -372,7 +583,8 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
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,9 +24,11 @@ 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,
@ -38,7 +40,8 @@ class ExerciseSave extends StatefulWidget {
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