WT1.1.10+1 Compact Test Edit
This commit is contained in:
parent
9c84714822
commit
2e0d7fc37d
BIN
asset/menu/machine_test.jpg
Normal file
BIN
asset/menu/machine_test.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
BIN
asset/menu/own_body.jpg
Normal file
BIN
asset/menu/own_body.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 143 KiB |
BIN
asset/menu/test_center.jpg
Normal file
BIN
asset/menu/test_center.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 80 KiB |
BIN
asset/menu/under_body.jpg
Normal file
BIN
asset/menu/under_body.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 109 KiB |
BIN
asset/menu/upper_body.jpg
Normal file
BIN
asset/menu/upper_body.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 164 KiB |
BIN
asset/menu/weight_test.jpg
Normal file
BIN
asset/menu/weight_test.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 142 KiB |
@ -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 = 5;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@ -405,7 +405,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.1.7;
|
MARKETING_VERSION = 1.1.10;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@ -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 = 5;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@ -548,7 +548,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.1.7;
|
MARKETING_VERSION = 1.1.10;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@ -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 = 5;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
DEVELOPMENT_TEAM = SFJJBDCU6Z;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@ -583,7 +583,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"$(PROJECT_DIR)/Flutter",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.1.7;
|
MARKETING_VERSION = 1.1.10;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
@ -173,6 +173,11 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> with Trans, Logging {
|
|||||||
ability = ExerciseAbility.endurance;
|
ability = ExerciseAbility.endurance;
|
||||||
break;
|
break;
|
||||||
case "Cardio":
|
case "Cardio":
|
||||||
|
ability = ExerciseAbility.running;
|
||||||
|
break;
|
||||||
|
case "Test Center":
|
||||||
|
ability = ExerciseAbility.mini_test;
|
||||||
|
break;
|
||||||
case "My Body":
|
case "My Body":
|
||||||
ability = ExerciseAbility.none;
|
ability = ExerciseAbility.none;
|
||||||
break;
|
break;
|
||||||
|
83
lib/bloc/test_set_edit/test_set_edit_bloc.dart
Normal file
83
lib/bloc/test_set_edit/test_set_edit_bloc.dart
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
|
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||||
|
import 'package:aitrainer_app/model/cache.dart';
|
||||||
|
import 'package:aitrainer_app/model/exercise_ability.dart';
|
||||||
|
import 'package:aitrainer_app/model/exercise_plan.dart';
|
||||||
|
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
||||||
|
import 'package:aitrainer_app/model/exercise_plan_template.dart';
|
||||||
|
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||||
|
import 'package:aitrainer_app/repository/workout_tree_repository.dart';
|
||||||
|
import 'package:aitrainer_app/service/exercise_plan_service.dart';
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
part 'test_set_edit_event.dart';
|
||||||
|
part 'test_set_edit_state.dart';
|
||||||
|
|
||||||
|
class TestSetEditBloc extends Bloc<TestSetEditEvent, TestSetEditState> {
|
||||||
|
final String templateName;
|
||||||
|
final WorkoutTreeRepository workoutTreeRepository;
|
||||||
|
final MenuBloc menuBloc;
|
||||||
|
final List<ExerciseType> _exerciseTypes = List();
|
||||||
|
final HashMap<int, ExerciseType> _exercisePlanDetails = HashMap();
|
||||||
|
|
||||||
|
TestSetEditBloc({this.templateName, this.workoutTreeRepository, this.menuBloc}) : super(TestSetEditInitial()) {
|
||||||
|
if (Cache().exercisePlanTemplates.isNotEmpty) {
|
||||||
|
Cache().exercisePlanTemplates.forEach((element) {
|
||||||
|
final ExercisePlanTemplate template = element as ExercisePlanTemplate;
|
||||||
|
if (template.name == templateName) {
|
||||||
|
template.exerciseTypes.forEach((id) {
|
||||||
|
final ExerciseType exerciseType = Cache().getExerciseTypeById(id);
|
||||||
|
_exerciseTypes.add(exerciseType);
|
||||||
|
_exercisePlanDetails[exerciseType.exerciseTypeId] = exerciseType;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<TestSetEditState> mapEventToState(TestSetEditEvent event) async* {
|
||||||
|
try {
|
||||||
|
if (event is TestSetEditChangeExerciseType) {
|
||||||
|
final List<ExerciseType> alternatives = workoutTreeRepository.getExerciseTypeAlternatives(event.exerciseTypeId);
|
||||||
|
final ExerciseType exerciseType = Cache().getExerciseTypeById(event.exerciseTypeId);
|
||||||
|
if (event.index > alternatives.length) {
|
||||||
|
/// skip
|
||||||
|
_exercisePlanDetails[exerciseType.exerciseTypeId] = null;
|
||||||
|
} else if (event.index == 0) {
|
||||||
|
_exercisePlanDetails[exerciseType.exerciseTypeId] = exerciseType;
|
||||||
|
} else {
|
||||||
|
final changedExerciseType = alternatives[event.index - 1];
|
||||||
|
_exercisePlanDetails[exerciseType.exerciseTypeId] = changedExerciseType;
|
||||||
|
}
|
||||||
|
} else if (event is TestSetEditSubmit) {
|
||||||
|
yield TestSetEditLoading();
|
||||||
|
ExercisePlan exercisePlan = ExercisePlan(templateName, Cache().userLoggedIn.customerId);
|
||||||
|
exercisePlan.private = true;
|
||||||
|
exercisePlan.type = ExerciseAbility.mini_test.toString();
|
||||||
|
exercisePlan.dateAdd = DateTime.now();
|
||||||
|
ExercisePlan savedExercisePlan = await ExercisePlanApi().saveExercisePlan(exercisePlan);
|
||||||
|
|
||||||
|
List<ExercisePlanDetail> details = List();
|
||||||
|
for (var entry in _exercisePlanDetails.entries) {
|
||||||
|
if (entry.value != null) {
|
||||||
|
ExercisePlanDetail exercisePlanDetail = ExercisePlanDetail(entry.value.exerciseTypeId);
|
||||||
|
exercisePlanDetail.exercisePlanId = savedExercisePlan.exercisePlanId;
|
||||||
|
exercisePlanDetail.serie = 1;
|
||||||
|
ExercisePlanDetail savedDetail = await ExercisePlanApi().saveExercisePlanDetail(exercisePlanDetail);
|
||||||
|
details.add(savedDetail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Cache().saveActiveExercisePlan(exercisePlan, details);
|
||||||
|
yield TestSetEditSaved();
|
||||||
|
}
|
||||||
|
} on Exception catch (e) {
|
||||||
|
yield TestSetEditError(message: e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List get exerciseTypes => this._exerciseTypes;
|
||||||
|
}
|
33
lib/bloc/test_set_edit/test_set_edit_event.dart
Normal file
33
lib/bloc/test_set_edit/test_set_edit_event.dart
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
part of 'test_set_edit_bloc.dart';
|
||||||
|
|
||||||
|
abstract class TestSetEditEvent extends Equatable {
|
||||||
|
const TestSetEditEvent();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSetEditLoad extends TestSetEditEvent {
|
||||||
|
const TestSetEditLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSetEditChangeExerciseType extends TestSetEditEvent {
|
||||||
|
final int index;
|
||||||
|
final int exerciseTypeId;
|
||||||
|
const TestSetEditChangeExerciseType({this.index, this.exerciseTypeId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [index, exerciseTypeId];
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSetEditSkipExerciseType extends TestSetEditEvent {
|
||||||
|
final int exerciseTypeId;
|
||||||
|
const TestSetEditSkipExerciseType({this.exerciseTypeId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [exerciseTypeId];
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSetEditSubmit extends TestSetEditEvent {
|
||||||
|
const TestSetEditSubmit();
|
||||||
|
}
|
32
lib/bloc/test_set_edit/test_set_edit_state.dart
Normal file
32
lib/bloc/test_set_edit/test_set_edit_state.dart
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
part of 'test_set_edit_bloc.dart';
|
||||||
|
|
||||||
|
abstract class TestSetEditState extends Equatable {
|
||||||
|
const TestSetEditState();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSetEditInitial extends TestSetEditState {
|
||||||
|
const TestSetEditInitial();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSetEditReady extends TestSetEditState {
|
||||||
|
const TestSetEditReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSetEditSaved extends TestSetEditState {
|
||||||
|
const TestSetEditSaved();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSetEditLoading extends TestSetEditState {
|
||||||
|
const TestSetEditLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSetEditError extends TestSetEditState {
|
||||||
|
final String message;
|
||||||
|
const TestSetEditError({this.message});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [message];
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
import 'dart:convert';
|
||||||
import 'package:aitrainer_app/model/customer.dart';
|
import 'package:aitrainer_app/model/customer.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_plan.dart';
|
import 'package:aitrainer_app/model/exercise_plan.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
||||||
|
import 'package:aitrainer_app/model/exercise_plan_template.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_tree.dart';
|
import 'package:aitrainer_app/model/exercise_tree.dart';
|
||||||
import 'package:aitrainer_app/model/exercise.dart';
|
import 'package:aitrainer_app/model/exercise.dart';
|
||||||
import 'package:aitrainer_app/model/model_change.dart';
|
import 'package:aitrainer_app/model/model_change.dart';
|
||||||
@ -63,6 +65,8 @@ class Cache with Logging {
|
|||||||
static final String hardwareKey = 'hardware';
|
static final String hardwareKey = 'hardware';
|
||||||
static final String loginTypeKey = 'login_type';
|
static final String loginTypeKey = 'login_type';
|
||||||
static final String timerDisplayKey = 'timer_display';
|
static final String timerDisplayKey = 'timer_display';
|
||||||
|
static final String activeExercisePlanKey = 'active_exercise_plan';
|
||||||
|
static final String activeExercisePlanDetailsKey = 'active_exercise_details_plan';
|
||||||
|
|
||||||
static String baseUrl = 'http://aitrainer.info:8888/api/';
|
static String baseUrl = 'http://aitrainer.info:8888/api/';
|
||||||
static final String mediaUrl = 'https://aitrainer.info:4343/media/';
|
static final String mediaUrl = 'https://aitrainer.info:4343/media/';
|
||||||
@ -89,6 +93,10 @@ class Cache with Logging {
|
|||||||
List<wt_product.Product> _products;
|
List<wt_product.Product> _products;
|
||||||
List<Purchase> _purchases = List();
|
List<Purchase> _purchases = List();
|
||||||
List<ProductTest> _productTests;
|
List<ProductTest> _productTests;
|
||||||
|
List<ExercisePlanTemplate> _exercisePlanTemplates = List();
|
||||||
|
|
||||||
|
ExercisePlan activeExercisePlan;
|
||||||
|
List<ExercisePlanDetail> activeExercisePlanDetails;
|
||||||
|
|
||||||
List<ExerciseDevice> _devices;
|
List<ExerciseDevice> _devices;
|
||||||
List<CustomerExerciseDevice> _customerDevices;
|
List<CustomerExerciseDevice> _customerDevices;
|
||||||
@ -132,6 +140,38 @@ class Cache with Logging {
|
|||||||
return this.authToken;
|
return this.authToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> saveActiveExercisePlan(ExercisePlan exercisePlan, List<ExercisePlanDetail> exercisePlanDetails) async {
|
||||||
|
this.activeExercisePlan = exercisePlan;
|
||||||
|
this.activeExercisePlanDetails = exercisePlanDetails;
|
||||||
|
String exercisePlanJson = JsonEncoder().convert(exercisePlan.toJson());
|
||||||
|
String detailsJson = jsonEncode(exercisePlanDetails);
|
||||||
|
|
||||||
|
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
|
SharedPreferences sharedPreferences;
|
||||||
|
sharedPreferences = await prefs;
|
||||||
|
|
||||||
|
sharedPreferences.setString(Cache.activeExercisePlanKey, exercisePlanJson);
|
||||||
|
sharedPreferences.setString(Cache.activeExercisePlanDetailsKey, detailsJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getActiveExercisePlan() async {
|
||||||
|
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
|
SharedPreferences sharedPreferences;
|
||||||
|
sharedPreferences = await prefs;
|
||||||
|
|
||||||
|
String exercisePlanJson = sharedPreferences.getString(Cache.activeExercisePlanKey);
|
||||||
|
if (exercisePlanJson != null) {
|
||||||
|
final Map<String, dynamic> map = JsonDecoder().convert(exercisePlanJson);
|
||||||
|
this.activeExercisePlan = ExercisePlan.fromJson(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
String detailsJson = sharedPreferences.getString(Cache.activeExercisePlanDetailsKey);
|
||||||
|
if (detailsJson != null) {
|
||||||
|
Iterable json = jsonDecode(detailsJson);
|
||||||
|
this.activeExercisePlanDetails = json.map((details) => ExercisePlanDetail.fromJson(details)).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> setServer(bool live) async {
|
Future<void> setServer(bool live) async {
|
||||||
if (this.testEnvironment == "1") {
|
if (this.testEnvironment == "1") {
|
||||||
liveServer = false;
|
liveServer = false;
|
||||||
@ -146,7 +186,6 @@ class Cache with Logging {
|
|||||||
|
|
||||||
void getHardware(SharedPreferences prefs) {
|
void getHardware(SharedPreferences prefs) {
|
||||||
final bool hasHardware = prefs.getBool(Cache.hardwareKey);
|
final bool hasHardware = prefs.getBool(Cache.hardwareKey);
|
||||||
//log("Has Hardware: " + hasHardware.toString());
|
|
||||||
this.hasHardware = hasHardware;
|
this.hasHardware = hasHardware;
|
||||||
if (hasHardware == null) {
|
if (hasHardware == null) {
|
||||||
this.hasHardware = false;
|
this.hasHardware = false;
|
||||||
@ -301,9 +340,7 @@ class Cache with Logging {
|
|||||||
this._exerciseTree = exerciseTree;
|
this._exerciseTree = exerciseTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setExercises(List<Exercise> exercises) {
|
void setExercises(List<Exercise> exercises) => this._exercises = exercises;
|
||||||
this._exercises = exercises;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setExercisesTrainee(List<Exercise> exercises) {
|
void setExercisesTrainee(List<Exercise> exercises) {
|
||||||
this._exercisesTrainee = exercises;
|
this._exercisesTrainee = exercises;
|
||||||
@ -485,10 +522,10 @@ class Cache with Logging {
|
|||||||
Future<void> initCustomer(int customerId) async {
|
Future<void> initCustomer(int customerId) async {
|
||||||
log(" *** initCustomer");
|
log(" *** initCustomer");
|
||||||
await PackageApi().getCustomerPackage(customerId);
|
await PackageApi().getCustomerPackage(customerId);
|
||||||
|
|
||||||
Flurry.setUserId(customerId.toString());
|
Flurry.setUserId(customerId.toString());
|
||||||
|
|
||||||
await setLoginTypeFromPrefs();
|
await setLoginTypeFromPrefs();
|
||||||
|
await getActiveExercisePlan();
|
||||||
Cache().startPage = "home";
|
Cache().startPage = "home";
|
||||||
Track().track(TrackingEvent.enter);
|
Track().track(TrackingEvent.enter);
|
||||||
}
|
}
|
||||||
@ -498,4 +535,7 @@ class Cache with Logging {
|
|||||||
|
|
||||||
LoginType getLoginType() => loginType;
|
LoginType getLoginType() => loginType;
|
||||||
void setLoginType(LoginType type) => this.loginType = type;
|
void setLoginType(LoginType type) => this.loginType = type;
|
||||||
|
|
||||||
|
List get exercisePlanTemplates => this._exercisePlanTemplates;
|
||||||
|
setExercisePlanTemplates(value) => this._exercisePlanTemplates = value;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
enum ExerciseAbility { oneRepMax, endurance, running, none }
|
enum ExerciseAbility { oneRepMax, endurance, running, mini_test, none }
|
||||||
|
|
||||||
extension ExerciseAbilityExt on ExerciseAbility {
|
extension ExerciseAbilityExt on ExerciseAbility {
|
||||||
bool equalsTo(ExerciseAbility ability) => this.toString() == ability.toString();
|
bool equalsTo(ExerciseAbility ability) => this.toString() == ability.toString();
|
||||||
|
@ -8,6 +8,8 @@ class ExercisePlan {
|
|||||||
bool private;
|
bool private;
|
||||||
DateTime dateAdd;
|
DateTime dateAdd;
|
||||||
DateTime dateUpd;
|
DateTime dateUpd;
|
||||||
|
String type;
|
||||||
|
int exercisePlanTemplateId;
|
||||||
|
|
||||||
ExercisePlan(String name, int customerId) {
|
ExercisePlan(String name, int customerId) {
|
||||||
this.customerId = customerId;
|
this.customerId = customerId;
|
||||||
@ -23,6 +25,8 @@ class ExercisePlan {
|
|||||||
this.description = json['description'];
|
this.description = json['description'];
|
||||||
this.dateAdd = json['dateAdd'] == null ? null : DateTime.parse(json['dateAdd']);
|
this.dateAdd = json['dateAdd'] == null ? null : DateTime.parse(json['dateAdd']);
|
||||||
this.dateUpd = json['dateUpd'] == null ? null : DateTime.parse(json['dateUpd']);
|
this.dateUpd = json['dateUpd'] == null ? null : DateTime.parse(json['dateUpd']);
|
||||||
|
this.type = json['type'];
|
||||||
|
this.exercisePlanTemplateId = json['exercisePlanTemplateId'];
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
@ -40,6 +44,8 @@ class ExercisePlan {
|
|||||||
"private": private,
|
"private": private,
|
||||||
"dateAdd": formattedDateAdd,
|
"dateAdd": formattedDateAdd,
|
||||||
"dateUpd": formattedDateUpd,
|
"dateUpd": formattedDateUpd,
|
||||||
|
"type": type,
|
||||||
|
"exercisePlanTemplateId": exercisePlanTemplateId
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
@ -50,6 +56,8 @@ class ExercisePlan {
|
|||||||
"private": private,
|
"private": private,
|
||||||
"dateAdd": formattedDateAdd,
|
"dateAdd": formattedDateAdd,
|
||||||
"dateUpd": formattedDateUpd,
|
"dateUpd": formattedDateUpd,
|
||||||
|
"type": type,
|
||||||
|
"exercisePlanTemplateId": exercisePlanTemplateId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
37
lib/model/exercise_plan_template.dart
Normal file
37
lib/model/exercise_plan_template.dart
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
class ExercisePlanTemplate {
|
||||||
|
int exercisePlanTemplateId;
|
||||||
|
String name;
|
||||||
|
String description;
|
||||||
|
String templateType;
|
||||||
|
String nameTranslation;
|
||||||
|
String descriptionTranslation;
|
||||||
|
List<int> exerciseTypes = List();
|
||||||
|
|
||||||
|
ExercisePlanTemplate.fromJson(Map json) {
|
||||||
|
this.exercisePlanTemplateId = json['exercisePlanId'];
|
||||||
|
this.name = json['name'];
|
||||||
|
this.description = json['description'];
|
||||||
|
this.templateType = json['templateType'];
|
||||||
|
this.nameTranslation = json['translations'] != null && (json['translations']).length > 0 ? json['translations'][0]['name'] : this.name;
|
||||||
|
this.descriptionTranslation =
|
||||||
|
json['translations'] != null && (json['translations']).length > 0 ? json['translations'][0]['description'] : this.description;
|
||||||
|
if (json['details'] != null && (json['details']).length > 0) {
|
||||||
|
List details = json['details'];
|
||||||
|
details.forEach((element) {
|
||||||
|
exerciseTypes.add(element['exerciseTypeId']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
"exercisePlanTemplateId": exercisePlanTemplateId,
|
||||||
|
"name": name,
|
||||||
|
"description": "description",
|
||||||
|
"templateType": templateType,
|
||||||
|
"nameTranslation": nameTranslation,
|
||||||
|
"descriptionTranslation": descriptionTranslation,
|
||||||
|
"exerciseTypes": exerciseTypes.toString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ class ExerciseTree {
|
|||||||
String imageUrl;
|
String imageUrl;
|
||||||
bool active;
|
bool active;
|
||||||
String nameTranslation;
|
String nameTranslation;
|
||||||
|
int sort;
|
||||||
|
|
||||||
ExerciseTree();
|
ExerciseTree();
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ class ExerciseTree {
|
|||||||
"imageUrl": imageUrl,
|
"imageUrl": imageUrl,
|
||||||
"active": active.toString(),
|
"active": active.toString(),
|
||||||
"nameTranslation": nameTranslation,
|
"nameTranslation": nameTranslation,
|
||||||
|
"sort": sort,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,6 +40,7 @@ class ExerciseTree {
|
|||||||
newTree.parentId = parentId;
|
newTree.parentId = parentId;
|
||||||
}
|
}
|
||||||
newTree.active = this.active;
|
newTree.active = this.active;
|
||||||
|
newTree.sort = this.sort;
|
||||||
|
|
||||||
return newTree;
|
return newTree;
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,12 @@ class ExerciseTreeParents {
|
|||||||
int exerciseTreeParentsId;
|
int exerciseTreeParentsId;
|
||||||
int exerciseTreeParentId;
|
int exerciseTreeParentId;
|
||||||
int exerciseTreeChildId;
|
int exerciseTreeChildId;
|
||||||
|
int sort;
|
||||||
|
|
||||||
ExerciseTreeParents.fromJson(Map json) {
|
ExerciseTreeParents.fromJson(Map json) {
|
||||||
this.exerciseTreeParentsId = json['exerciseTreeParentsId'];
|
this.exerciseTreeParentsId = json['exerciseTreeParentsId'];
|
||||||
this.exerciseTreeParentId = json['exerciseTreeParentId'];
|
this.exerciseTreeParentId = json['exerciseTreeParentId'];
|
||||||
this.exerciseTreeChildId = json['exerciseTreeChildId'];
|
this.exerciseTreeChildId = json['exerciseTreeChildId'];
|
||||||
|
this.sort = json['sort'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ class ExerciseType {
|
|||||||
String descriptionTranslation = "";
|
String descriptionTranslation = "";
|
||||||
List<int> devices = List();
|
List<int> devices = List();
|
||||||
List<int> parents = List();
|
List<int> parents = List();
|
||||||
|
List<int> alternatives = List();
|
||||||
|
|
||||||
ExerciseAbility ability;
|
ExerciseAbility ability;
|
||||||
|
|
||||||
@ -55,6 +56,14 @@ class ExerciseType {
|
|||||||
this.parents.add(parent['exerciseTreeId']);
|
this.parents.add(parent['exerciseTreeId']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (json['alternatives'].length > 0) {
|
||||||
|
final List jsonAlternatives = json['alternatives'];
|
||||||
|
|
||||||
|
jsonAlternatives.forEach((alternative) {
|
||||||
|
this.alternatives.add(alternative['exerciseTypeChildId']);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
|
@ -40,6 +40,7 @@ class WorkoutMenuTree {
|
|||||||
String nameEnglish;
|
String nameEnglish;
|
||||||
String parentName;
|
String parentName;
|
||||||
String parentNameEnglish;
|
String parentNameEnglish;
|
||||||
|
int sort;
|
||||||
|
|
||||||
WorkoutMenuTree(
|
WorkoutMenuTree(
|
||||||
this.id,
|
this.id,
|
||||||
@ -57,7 +58,8 @@ class WorkoutMenuTree {
|
|||||||
this.isRunning,
|
this.isRunning,
|
||||||
this.nameEnglish,
|
this.nameEnglish,
|
||||||
this.parentName,
|
this.parentName,
|
||||||
this.parentNameEnglish);
|
this.parentNameEnglish,
|
||||||
|
this.sort);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
@ -73,6 +75,7 @@ class WorkoutMenuTree {
|
|||||||
"is1RM": is1RM.toString(),
|
"is1RM": is1RM.toString(),
|
||||||
"isEndurance": isEndurance.toString(),
|
"isEndurance": isEndurance.toString(),
|
||||||
"isRunning": isRunning.toString(),
|
"isRunning": isRunning.toString(),
|
||||||
|
"sort": sort,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,8 @@ class WorkoutTreeRepository with Logging {
|
|||||||
isRunning,
|
isRunning,
|
||||||
treeItem.name,
|
treeItem.name,
|
||||||
parent != null ? parent.name : "",
|
parent != null ? parent.name : "",
|
||||||
parent != null ? parent.nameEnglish : "");
|
parent != null ? parent.nameEnglish : "",
|
||||||
|
treeItem.sort);
|
||||||
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().toString());
|
//log("WorkoutMenuTree item " + menuItem.toJson().toString());
|
||||||
@ -141,7 +142,8 @@ class WorkoutTreeRepository with Logging {
|
|||||||
isRunning,
|
isRunning,
|
||||||
exerciseType.name,
|
exerciseType.name,
|
||||||
parent != null ? parent.name : "",
|
parent != null ? parent.name : "",
|
||||||
parent != null ? parent.nameEnglish : "");
|
parent != null ? parent.nameEnglish : "",
|
||||||
|
0);
|
||||||
this.tree[exerciseType.name] = menuItem;
|
this.tree[exerciseType.name] = menuItem;
|
||||||
menuAsExercise.add(menuItem);
|
menuAsExercise.add(menuItem);
|
||||||
//log("WorkoutMenuTree item " + menuItem.toJson().toString());
|
//log("WorkoutMenuTree item " + menuItem.toJson().toString());
|
||||||
@ -283,6 +285,56 @@ class WorkoutTreeRepository with Logging {
|
|||||||
return parentItem;
|
return parentItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WorkoutMenuTree getMenuItemByExerciseTypeId(int exerciseTypeId) {
|
||||||
|
WorkoutMenuTree menuItem;
|
||||||
|
this.menuAsExercise.forEach((element) {
|
||||||
|
if (element.exerciseTypeId == exerciseTypeId) {
|
||||||
|
menuItem = element;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return menuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<WorkoutMenuTree> getWorkoutTreeAlternatives(WorkoutMenuTree workoutMenuTree) {
|
||||||
|
if (workoutMenuTree == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (workoutMenuTree.exerciseType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final List<ExerciseType> alternatives = this.getExerciseTypeAlternatives(workoutMenuTree.exerciseTypeId);
|
||||||
|
if (alternatives == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<WorkoutMenuTree> list = List();
|
||||||
|
list.add(workoutMenuTree);
|
||||||
|
alternatives.forEach((element) {
|
||||||
|
final WorkoutMenuTree alternativeMenuItem = this.getMenuItemByExerciseTypeId(element.exerciseTypeId);
|
||||||
|
list.add(alternativeMenuItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ExerciseType> getExerciseTypeAlternatives(int exerciseTypeId) {
|
||||||
|
if (exerciseTypeId == null || exerciseTypeId <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<ExerciseType> list = List();
|
||||||
|
Cache().getExerciseTypes().forEach((exerciseType) {
|
||||||
|
if (exerciseType.alternatives.isNotEmpty) {
|
||||||
|
exerciseType.alternatives.forEach((childId) {
|
||||||
|
if (childId == exerciseTypeId) {
|
||||||
|
list.add(exerciseType);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
void sortByMuscleType() {
|
void sortByMuscleType() {
|
||||||
sortedTree = SplayTreeMap<String, List<WorkoutMenuTree>>();
|
sortedTree = SplayTreeMap<String, List<WorkoutMenuTree>>();
|
||||||
tree.forEach((key, value) {
|
tree.forEach((key, value) {
|
||||||
|
@ -56,18 +56,16 @@ class ExerciseTreeApi with Logging {
|
|||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
ExerciseTree newElement = element.copy(parent.exerciseTreeParentId);
|
ExerciseTree newElement = element.copy(parent.exerciseTreeParentId);
|
||||||
exerciseTree.add(newElement);
|
exerciseTree.add(newElement);
|
||||||
//print("ExerciseTree " + newElement.toJson().toString());
|
|
||||||
} else {
|
} else {
|
||||||
element.parentId = parent.exerciseTreeParentId;
|
element.parentId = parent.exerciseTreeParentId;
|
||||||
|
element.sort = parent.sort;
|
||||||
exerciseTree[treeIndex].parentId = parent.exerciseTreeParentId;
|
exerciseTree[treeIndex].parentId = parent.exerciseTreeParentId;
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//print("ExerciseTree " + element.toJson().toString());
|
|
||||||
treeIndex++;
|
treeIndex++;
|
||||||
});
|
});
|
||||||
|
|
||||||
return exerciseTree;
|
return exerciseTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import 'package:aitrainer_app/model/customer_exercise_device.dart';
|
|||||||
import 'package:aitrainer_app/model/customer_property.dart';
|
import 'package:aitrainer_app/model/customer_property.dart';
|
||||||
import 'package:aitrainer_app/model/exercise.dart';
|
import 'package:aitrainer_app/model/exercise.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_device.dart';
|
import 'package:aitrainer_app/model/exercise_device.dart';
|
||||||
|
import 'package:aitrainer_app/model/exercise_plan_template.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_result.dart';
|
import 'package:aitrainer_app/model/exercise_result.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_tree.dart';
|
import 'package:aitrainer_app/model/exercise_tree.dart';
|
||||||
import 'package:aitrainer_app/model/exercise_tree_parents.dart';
|
import 'package:aitrainer_app/model/exercise_tree_parents.dart';
|
||||||
@ -53,6 +54,10 @@ class PackageApi {
|
|||||||
Cache().setExerciseTypes(exerciseTypes);
|
Cache().setExerciseTypes(exerciseTypes);
|
||||||
}
|
}
|
||||||
} else if (headRecord[0] == "ExerciseAbility") {
|
} else if (headRecord[0] == "ExerciseAbility") {
|
||||||
|
} else if (headRecord[0] == "ExercisePlanTemplate") {
|
||||||
|
final List<ExercisePlanTemplate> exercisePlanTemplates =
|
||||||
|
json.map((exercisePlanTemplate) => ExercisePlanTemplate.fromJson(exercisePlanTemplate)).toList();
|
||||||
|
Cache().setExercisePlanTemplates(exercisePlanTemplates);
|
||||||
} else if (headRecord[0] == "ExerciseTreeParents") {
|
} else if (headRecord[0] == "ExerciseTreeParents") {
|
||||||
exerciseTreeParents = json.map((exerciseTreeParent) => ExerciseTreeParents.fromJson(exerciseTreeParent)).toList();
|
exerciseTreeParents = json.map((exerciseTreeParent) => ExerciseTreeParents.fromJson(exerciseTreeParent)).toList();
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,257 @@
|
|||||||
import 'package:aitrainer_app/widgets/app_bar.dart';
|
import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class TestSetEdit extends StatelessWidget {
|
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||||
|
import 'package:aitrainer_app/bloc/test_set_edit/test_set_edit_bloc.dart';
|
||||||
|
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||||
|
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||||
|
import 'package:aitrainer_app/util/trans.dart';
|
||||||
|
import 'package:aitrainer_app/widgets/app_bar.dart';
|
||||||
|
import 'package:aitrainer_app/widgets/dialog_common.dart';
|
||||||
|
import 'package:carousel_slider/carousel_slider.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:modal_progress_hud/modal_progress_hud.dart';
|
||||||
|
import 'package:transparent_image/transparent_image.dart';
|
||||||
|
import 'package:aitrainer_app/library/image_cache.dart' as wt;
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
|
class TestSetEdit extends StatelessWidget with Trans {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final String templateName = ModalRoute.of(context).settings.arguments;
|
||||||
|
// ignore: close_sinks
|
||||||
|
final MenuBloc menuBloc = BlocProvider.of<MenuBloc>(context);
|
||||||
|
TestSetEditBloc bloc;
|
||||||
|
|
||||||
|
setContext(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBarNav(depth: 1),
|
appBar: AppBarNav(depth: 1),
|
||||||
body: Container(
|
body: Container(
|
||||||
padding: EdgeInsets.all(20),
|
padding: EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: AssetImage('asset/image/WT_black_background.jpg'),
|
image: AssetImage('asset/image/WT_black_background.jpg'),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
child: Text("H")));
|
),
|
||||||
|
child: BlocProvider(
|
||||||
|
create: (context) =>
|
||||||
|
TestSetEditBloc(templateName: templateName, workoutTreeRepository: menuBloc.menuTreeRepository, menuBloc: menuBloc),
|
||||||
|
child: BlocConsumer<TestSetEditBloc, TestSetEditState>(listener: (context, state) {
|
||||||
|
if (state is TestSetEditError) {
|
||||||
|
Scaffold.of(context).showSnackBar(
|
||||||
|
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
|
||||||
|
} else if (state is TestSetEditSaved) {
|
||||||
|
Navigator.of(context).pushNamed("home");
|
||||||
|
}
|
||||||
|
}, builder: (context, state) {
|
||||||
|
bloc = BlocProvider.of<TestSetEditBloc>(context);
|
||||||
|
return ModalProgressHUD(
|
||||||
|
child: getTestSetWidget(bloc, templateName),
|
||||||
|
inAsyncCall: state is TestSetEditLoading,
|
||||||
|
opacity: 0.5,
|
||||||
|
color: Colors.black54,
|
||||||
|
progressIndicator: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
}))),
|
||||||
|
floatingActionButton: FloatingActionButton.extended(
|
||||||
|
onPressed: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return DialogCommon(
|
||||||
|
title: "Start!",
|
||||||
|
descriptions: "GO",
|
||||||
|
text: "OK",
|
||||||
|
onTap: () => {
|
||||||
|
Navigator.of(context).pop(),
|
||||||
|
if (bloc != null)
|
||||||
|
{
|
||||||
|
bloc.add(TestSetEditSubmit()),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCancel: () => {Navigator.of(context).pop()},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
backgroundColor: Colors.orange[800],
|
||||||
|
icon: Icon(CustomIcon.clock),
|
||||||
|
label: Text(
|
||||||
|
"Start training",
|
||||||
|
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getTestSetWidget(TestSetEditBloc bloc, String templateName) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(left: 10, right: 10),
|
||||||
|
child: CustomScrollView(scrollDirection: Axis.vertical, slivers: [
|
||||||
|
SliverAppBar(
|
||||||
|
toolbarHeight: 135,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
title: Column(mainAxisAlignment: MainAxisAlignment.start, children: [
|
||||||
|
RichText(
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
text: TextSpan(
|
||||||
|
style: GoogleFonts.archivoBlack(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
TextSpan(text: t("Edit Your Training Test Set"), style: GoogleFonts.inter(color: Colors.white, fontSize: 18)),
|
||||||
|
TextSpan(text: "\n", style: GoogleFonts.inter(color: Colors.white, fontSize: 18)),
|
||||||
|
TextSpan(text: t(templateName), style: GoogleFonts.archivoBlack(color: Colors.yellow[300], fontSize: 18)),
|
||||||
|
])),
|
||||||
|
Divider(
|
||||||
|
color: Colors.transparent,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return DialogCommon(
|
||||||
|
title: "Own Body",
|
||||||
|
descriptions: t("execute these exercises with maximum repeats. Leave at least 3 min rest time between time"),
|
||||||
|
text: "OK",
|
||||||
|
onTap: () => {Navigator.of(context).pop()},
|
||||||
|
onCancel: () => {Navigator.of(context).pop()},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
child: Icon(
|
||||||
|
CustomIcon.question_circle,
|
||||||
|
color: Colors.orange[400],
|
||||||
|
size: 40,
|
||||||
|
)),
|
||||||
|
]),
|
||||||
|
centerTitle: true,
|
||||||
|
),
|
||||||
|
SliverList(delegate: SliverChildListDelegate(getExerciseTypeWidgets(bloc))),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> imageSliders(List<WorkoutMenuTree> alternatives, MenuBloc menuBloc) {
|
||||||
|
final List<Widget> list = List();
|
||||||
|
alternatives.forEach((element) {
|
||||||
|
list.add(getImageStack(element, menuBloc));
|
||||||
|
});
|
||||||
|
list.add(Container(
|
||||||
|
padding: EdgeInsets.only(top: 25, bottom: 25),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(24.0),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.red[600],
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
"X",
|
||||||
|
style: GoogleFonts.archivoBlack(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 80,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)))));
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stack getImageStack(WorkoutMenuTree element, MenuBloc menuBloc) {
|
||||||
|
print(element.toJson());
|
||||||
|
return Stack(alignment: Alignment.bottomLeft, children: [
|
||||||
|
_getButtonImage(element, menuBloc),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.only(left: 15, bottom: 15, right: 15),
|
||||||
|
child: Text(
|
||||||
|
element.name,
|
||||||
|
maxLines: 4,
|
||||||
|
style: GoogleFonts.archivoBlack(color: element.color, fontSize: 16, height: 1.1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> getExerciseTypeWidgets(TestSetEditBloc bloc) {
|
||||||
|
final List<Widget> widgets = List();
|
||||||
|
bloc.exerciseTypes.forEach((element) {
|
||||||
|
final WorkoutMenuTree workoutTree = bloc.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(element.exerciseTypeId);
|
||||||
|
|
||||||
|
final List<WorkoutMenuTree> alternativeMenuItems = bloc.menuBloc.menuTreeRepository.getWorkoutTreeAlternatives(workoutTree);
|
||||||
|
if (workoutTree != null && alternativeMenuItems != null) {
|
||||||
|
final Widget widget = CarouselSlider(
|
||||||
|
options: CarouselOptions(
|
||||||
|
viewportFraction: 0.80,
|
||||||
|
reverse: false,
|
||||||
|
enableInfiniteScroll: false,
|
||||||
|
autoPlay: false,
|
||||||
|
aspectRatio: 2,
|
||||||
|
enlargeCenterPage: true,
|
||||||
|
onPageChanged: (index, reason) =>
|
||||||
|
bloc.add(TestSetEditChangeExerciseType(index: index, exerciseTypeId: element.exerciseTypeId)),
|
||||||
|
enlargeStrategy: CenterPageEnlargeStrategy.scale),
|
||||||
|
items: imageSliders(alternativeMenuItems, bloc.menuBloc),
|
||||||
|
);
|
||||||
|
widgets.add(widget);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return widgets;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _getButtonImage(WorkoutMenuTree workoutTree, MenuBloc menuBloc) {
|
||||||
|
if (workoutTree == null) {
|
||||||
|
return Offstage();
|
||||||
|
}
|
||||||
|
String imageString = menuBloc.getImage(workoutTree.id, workoutTree.imageName);
|
||||||
|
Widget widget;
|
||||||
|
if (imageString != null) {
|
||||||
|
widget = ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(24.0),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: FadeInImage(
|
||||||
|
fadeInDuration: Duration(milliseconds: 100),
|
||||||
|
image: MemoryImage(base64Decode(imageString)),
|
||||||
|
placeholder: MemoryImage(kTransparentImage),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
if (workoutTree.imageName.contains("https")) {
|
||||||
|
if (!wt.ImageCache().existsImageInMap(workoutTree.id, workoutTree.imageName)) {
|
||||||
|
widget = ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(24.0),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: FadeInImage(
|
||||||
|
fadeInDuration: Duration(milliseconds: 500),
|
||||||
|
image: NetworkImage(workoutTree.imageName),
|
||||||
|
placeholder: MemoryImage(kTransparentImage),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
widget = ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(24.0),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Image.asset(workoutTree.imageName),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return widget;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import 'package:aitrainer_app/service/logging.dart';
|
|||||||
import 'package:aitrainer_app/util/trans.dart';
|
import 'package:aitrainer_app/util/trans.dart';
|
||||||
import 'package:aitrainer_app/widgets/dialog_common.dart';
|
import 'package:aitrainer_app/widgets/dialog_common.dart';
|
||||||
import 'package:badges/badges.dart';
|
import 'package:badges/badges.dart';
|
||||||
|
import 'package:ezanimation/ezanimation.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/painting.dart';
|
import 'package:flutter/painting.dart';
|
||||||
@ -24,7 +25,6 @@ import 'package:transparent_image/transparent_image.dart';
|
|||||||
import 'package:aitrainer_app/library/image_cache.dart' as wt;
|
import 'package:aitrainer_app/library/image_cache.dart' as wt;
|
||||||
|
|
||||||
import 'dialog_html.dart';
|
import 'dialog_html.dart';
|
||||||
import 'menu_info_widget.dart';
|
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class MenuPageWidget extends StatefulWidget {
|
class MenuPageWidget extends StatefulWidget {
|
||||||
@ -39,14 +39,24 @@ class MenuPageWidget extends StatefulWidget {
|
|||||||
class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||||
final double baseWidth = 312;
|
final double baseWidth = 312;
|
||||||
final double baseHeight = 675.2;
|
final double baseHeight = 675.2;
|
||||||
bool isFirst = true;
|
|
||||||
bool wait = false;
|
|
||||||
MenuBloc menuBloc;
|
MenuBloc menuBloc;
|
||||||
final scrollController = ScrollController();
|
final scrollController = ScrollController();
|
||||||
|
final bool activeExercisePlan = Cache().activeExercisePlan != null;
|
||||||
|
final EzAnimation animation = EzAnimation(35.0, 10.0, Duration(seconds: 2), reverseCurve: Curves.linear);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
isFirst = true;
|
if (activeExercisePlan) {
|
||||||
|
animation.start();
|
||||||
|
animation.addStatusListener((status) {
|
||||||
|
if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) {
|
||||||
|
animation.reverse();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
animation.addListener(() {
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// We require the initializers to run after the loading screen is rendered
|
/// We require the initializers to run after the loading screen is rendered
|
||||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||||
@ -88,7 +98,8 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
padding: EdgeInsets.only(top: 15.0),
|
padding: EdgeInsets.only(top: 15.0),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Stack(alignment: Alignment.bottomLeft, children: [
|
child: Stack(alignment: Alignment.bottomLeft, children: [
|
||||||
Text(t("All Exercises has been filtered out"), style: GoogleFonts.inter(color: Colors.white)),
|
Text(AppLocalizations.of(context).translate("All Exercises has been filtered out"),
|
||||||
|
style: GoogleFonts.inter(color: Colors.white)),
|
||||||
]))));
|
]))));
|
||||||
} else {
|
} else {
|
||||||
menuBloc.getFilteredBranch(menuBloc.parent).forEach((treeName, value) {
|
menuBloc.getFilteredBranch(menuBloc.parent).forEach((treeName, value) {
|
||||||
@ -103,7 +114,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
animationType: BadgeAnimationType.slide,
|
animationType: BadgeAnimationType.slide,
|
||||||
badgeColor: Colors.orange[800],
|
badgeColor: Colors.orange[800],
|
||||||
showBadge: workoutTree.base,
|
showBadge: workoutTree.base,
|
||||||
badgeContent: Text(t("base"),
|
badgeContent: Text(AppLocalizations.of(context).translate("base"),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@ -120,7 +131,9 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return DialogHTML(
|
return DialogHTML(
|
||||||
title: workoutTree.name,
|
title: workoutTree.name,
|
||||||
htmlData: workoutTree.nameEnglish == "Endurance" ? t("Endurance_desc") : t("OneRepMax_desc"),
|
htmlData: workoutTree.nameEnglish == "Endurance"
|
||||||
|
? AppLocalizations.of(context).translate("Endurance_desc")
|
||||||
|
: AppLocalizations.of(context).translate("OneRepMax_desc"),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -171,7 +184,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
delegate: SliverChildListDelegate([
|
delegate: SliverChildListDelegate([
|
||||||
Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [
|
Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [
|
||||||
Text(
|
Text(
|
||||||
t("Equipment Filter"),
|
AppLocalizations.of(context).translate("Equipment Filter"),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: GoogleFonts.archivoBlack(
|
style: GoogleFonts.archivoBlack(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
@ -241,6 +254,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
menuBloc.setMenuInfo();
|
menuBloc.setMenuInfo();
|
||||||
|
|
||||||
SliverAppBar sliverAppBar = SliverAppBar(
|
SliverAppBar sliverAppBar = SliverAppBar(
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
title: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
|
title: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@ -283,6 +297,35 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
activeExercisePlan
|
||||||
|
? GestureDetector(
|
||||||
|
onTap: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return DialogCommon(
|
||||||
|
title: t("You have an acive Compact Test"),
|
||||||
|
descriptions: t("Press OK to continue!"),
|
||||||
|
text: "OK",
|
||||||
|
onTap: () => {
|
||||||
|
Navigator.of(context).pop(),
|
||||||
|
},
|
||||||
|
onCancel: () => {
|
||||||
|
Navigator.of(context).pop(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
child: AnimatedBuilder(
|
||||||
|
animation: animation,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
return Center(
|
||||||
|
child: Container(
|
||||||
|
width: animation.value,
|
||||||
|
height: animation.value,
|
||||||
|
child: Image.asset("asset/image/pict_reps_volumen_db.png"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}))
|
||||||
|
: Offstage(),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 10,
|
width: 10,
|
||||||
),
|
),
|
||||||
@ -292,6 +335,9 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
|||||||
|
|
||||||
void menuClick(WorkoutMenuTree workoutTree, MenuBloc menuBloc, BuildContext context) {
|
void menuClick(WorkoutMenuTree workoutTree, MenuBloc menuBloc, BuildContext context) {
|
||||||
if (workoutTree.child == false) {
|
if (workoutTree.child == false) {
|
||||||
|
if (ExerciseAbility.mini_test.equalsTo(menuBloc.ability) && workoutTree.parent != 0) {
|
||||||
|
Navigator.of(context).pushNamed('testSetEdit', arguments: workoutTree.nameEnglish);
|
||||||
|
}
|
||||||
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
|
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
|
||||||
} else {
|
} else {
|
||||||
menuBloc.add(MenuClickExercise(exerciseTypeId: workoutTree.id));
|
menuBloc.add(MenuClickExercise(exerciseTypeId: workoutTree.id));
|
||||||
|
14
pubspec.lock
14
pubspec.lock
@ -141,6 +141,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.1.0"
|
version: "7.1.0"
|
||||||
|
carousel_slider:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: carousel_slider
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -274,6 +281,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.5"
|
version: "1.2.5"
|
||||||
|
ezanimation:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: ezanimation
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.1"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
11
pubspec.yaml
11
pubspec.yaml
@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
version: 1.1.9+59
|
version: 1.1.10+60
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.7.0 <3.0.0"
|
sdk: ">=2.7.0 <3.0.0"
|
||||||
@ -54,6 +54,7 @@ dependencies:
|
|||||||
liquid_progress_indicator: ^0.3.2
|
liquid_progress_indicator: ^0.3.2
|
||||||
dropdown_search: ^0.4.9
|
dropdown_search: ^0.4.9
|
||||||
audioplayer: ^0.8.1
|
audioplayer: ^0.8.1
|
||||||
|
ezanimation: ^0.4.1
|
||||||
|
|
||||||
|
|
||||||
firebase_core: ^0.5.0
|
firebase_core: ^0.5.0
|
||||||
@ -66,6 +67,7 @@ dependencies:
|
|||||||
crypto: ^2.1.5
|
crypto: ^2.1.5
|
||||||
transparent_image: ^1.0.0
|
transparent_image: ^1.0.0
|
||||||
#auto_animated: ^2.1.0
|
#auto_animated: ^2.1.0
|
||||||
|
carousel_slider: ^3.0.0
|
||||||
|
|
||||||
flurry: ^0.0.7
|
flurry: ^0.0.7
|
||||||
|
|
||||||
@ -299,10 +301,12 @@ flutter:
|
|||||||
- asset/menu/lying_scissors.jpg
|
- asset/menu/lying_scissors.jpg
|
||||||
- asset/menu/lying_triceps_extension.jpg
|
- asset/menu/lying_triceps_extension.jpg
|
||||||
- asset/menu/machine_shoulder_press.jpg
|
- asset/menu/machine_shoulder_press.jpg
|
||||||
|
- asset/menu/machine_test.jpg
|
||||||
- asset/menu/oblique_crunch.jpg
|
- asset/menu/oblique_crunch.jpg
|
||||||
- asset/menu/olympic_squat.jpg
|
- asset/menu/olympic_squat.jpg
|
||||||
- asset/menu/one_arm_row.jpg
|
- asset/menu/one_arm_row.jpg
|
||||||
- asset/menu/overhead_dumbbell_triceps_extension.jpg
|
- asset/menu/overhead_dumbbell_triceps_extension.jpg
|
||||||
|
- asset/menu/own_body.jpg
|
||||||
- asset/menu/peck_deck_flyes.jpg
|
- asset/menu/peck_deck_flyes.jpg
|
||||||
- asset/menu/plank.jpg
|
- asset/menu/plank.jpg
|
||||||
- asset/menu/pull_up.jpg
|
- asset/menu/pull_up.jpg
|
||||||
@ -348,16 +352,21 @@ flutter:
|
|||||||
- asset/menu/stiff_legged_deadlift.jpg
|
- asset/menu/stiff_legged_deadlift.jpg
|
||||||
- asset/menu/straight-arm_rope_pull-down.jpg
|
- asset/menu/straight-arm_rope_pull-down.jpg
|
||||||
- asset/menu/t_bar_rows.jpg
|
- asset/menu/t_bar_rows.jpg
|
||||||
|
- asset/menu/test_center.jpg
|
||||||
- asset/menu/thigh_adductor.jpg
|
- asset/menu/thigh_adductor.jpg
|
||||||
- asset/menu/triceps_extension_on_cable_with_rope.jpg
|
- asset/menu/triceps_extension_on_cable_with_rope.jpg
|
||||||
- asset/menu/triceps_kickback.jpg
|
- asset/menu/triceps_kickback.jpg
|
||||||
- asset/menu/triceps_pushdown.jpg
|
- asset/menu/triceps_pushdown.jpg
|
||||||
- asset/menu/twisted_crunches.jpg
|
- asset/menu/twisted_crunches.jpg
|
||||||
|
- asset/menu/under_body.jpg
|
||||||
|
- asset/menu/upper_body.jpg
|
||||||
- asset/menu/v_ups.jpg
|
- asset/menu/v_ups.jpg
|
||||||
- asset/menu/wall_sit.jpg
|
- asset/menu/wall_sit.jpg
|
||||||
|
- asset/menu/weight_test.jpg
|
||||||
- asset/menu/weighted_bench_dip.jpg
|
- asset/menu/weighted_bench_dip.jpg
|
||||||
- asset/menu/wide_grip_behind_the_neck_pull_ups.jpg
|
- asset/menu/wide_grip_behind_the_neck_pull_ups.jpg
|
||||||
- asset/menu/wide_grip_front_lat_pulldown.jpg
|
- asset/menu/wide_grip_front_lat_pulldown.jpg
|
||||||
|
|
||||||
- asset/wine-glass.mp3
|
- asset/wine-glass.mp3
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user