From 85ce68a9b8a32e3d59421d589d0cb38b2da33a43 Mon Sep 17 00:00:00 2001 From: bossanyit Date: Tue, 8 Dec 2020 17:05:55 +0100 Subject: [PATCH] =?UTF-8?q?WT=201.1.0+35=20Design,=20Men=C3=BC=20filter,?= =?UTF-8?q?=20Test=20Server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- i18n/en.json | 9 +- i18n/hu.json | 9 +- ios/Podfile.lock | 8 +- ios/Runner.xcodeproj/project.pbxproj | 6 +- lib/bloc/menu/menu_bloc.dart | 108 ++++++-- lib/bloc/menu/menu_event.dart | 4 + lib/model/cache.dart | 39 ++- lib/model/exercise_device.dart | 2 + lib/model/exercise_tree.dart | 33 ++- lib/model/exercise_tree_parents.dart | 11 + lib/model/exercise_type.dart | 58 ++++- lib/model/exercise_type_device.dart | 11 + lib/model/workout_menu_tree.dart | 11 +- .../exercise_device_repository.dart | 30 +++ lib/repository/workout_tree_repository.dart | 101 ++++++-- lib/service/api.dart | 1 + lib/service/exercise_tree_service.dart | 51 +++- lib/service/exercisetype_service.dart | 21 +- lib/util/session.dart | 20 +- lib/view/exercise_new_page.dart | 42 +++- lib/view/settings.dart | 66 +++-- lib/widgets/app_bar.dart | 141 ++++++----- lib/widgets/app_bar_min.dart | 39 ++- lib/widgets/menu_info_widget.dart | 24 +- lib/widgets/menu_page_widget.dart | 230 +++++++++++++----- pubspec.yaml | 2 +- 26 files changed, 821 insertions(+), 256 deletions(-) create mode 100644 lib/model/exercise_tree_parents.dart create mode 100644 lib/model/exercise_type_device.dart diff --git a/i18n/en.json b/i18n/en.json index b16ca34..911f212 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -228,5 +228,12 @@ "select your equipments by tapping":"select your equipments by tapping", "Available Equipments":"Available Equipments", "select your places by tapping":"select your places by tapping", - "Available Training Places":"Available Training Places" + "Available Training Places":"Available Training Places", + "Please take a relative bigger weight and repeat 12-30 times":"Please take a relative bigger weight and repeat 12-30 times", + "Please take a medium weight and repeat 20-30 times":"Please take a medium weight and repeat 20-30 times", + "Equipment Filter":"Equipment Filter", + "Live-Server":"Live-Server", + "Test-Server":"Test-Server", + "All Exercises has been filtered out":"All Exercises has been filtered out", + "base":"base" } \ No newline at end of file diff --git a/i18n/hu.json b/i18n/hu.json index 3bcd0a5..82e41c8 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -229,5 +229,12 @@ "select your equipments by tapping":"válaszd ki az eszközeidet, kattints a képre", "Available Equipments":"Elérhető eszközök", "select your places by tapping":"kattints az edzéshelyszínre", - "Available Training Places":"Elérhető edzéshelyszínek" + "Available Training Places":"Elérhető edzéshelyszínek", + "Please take a relative bigger weight and repeat 12-20 times":"Vegyél egy relatív nagyobb súlyt és végezz el 12-20 ismétlést", + "Please take a medium weight and repeat 20-30 times": "Vegyél egy közepes súlyt és végezz el 20-30 ismétlést", + "Equipment Filter":"Eszköz szűrő", + "Live-Server":"Live-Server", + "Test-Server":"Test-Server", + "All Exercises has been filtered out":"Az összes gyakorlatot kiszűrted", + "base":"alap" } \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index da436c1..3451587 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -9,12 +9,12 @@ PODS: - Firebase/Messaging (6.33.0): - Firebase/CoreOnly - FirebaseMessaging (~> 4.7.0) - - firebase_auth (0.18.3): + - firebase_auth (0.18.3-1): - Firebase/Auth (~> 6.33.0) - Firebase/CoreOnly (~> 6.33.0) - firebase_core - Flutter - - firebase_core (0.5.2): + - firebase_core (0.5.2-1): - Firebase/CoreOnly (~> 6.33.0) - Flutter - firebase_messaging (7.0.3): @@ -154,8 +154,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: devicelocale: feebbe5e7a30adb8c4f83185de1b50ff19b44f00 Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 - firebase_auth: 240419f6b00dea39c60a2a9c4379c16c4a4b02fb - firebase_core: 350ba329d1641211bc6183a3236893cafdacfea7 + firebase_auth: cb33b01b51904969161403bbcb20036519f0c578 + firebase_core: 7423d688a1c6f2f2d859d64ae26991be39989781 firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 FirebaseAuth: c92d49ada7948d1a23466e3db17bc4c2039dddc3 FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 830febb..cf4ead3 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -362,7 +362,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 34; + CURRENT_PROJECT_VERSION = 36; DEVELOPMENT_TEAM = SFJJBDCU6Z; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -505,7 +505,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 34; + CURRENT_PROJECT_VERSION = 36; DEVELOPMENT_TEAM = SFJJBDCU6Z; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -540,7 +540,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 34; + CURRENT_PROJECT_VERSION = 36; DEVELOPMENT_TEAM = SFJJBDCU6Z; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( diff --git a/lib/bloc/menu/menu_bloc.dart b/lib/bloc/menu/menu_bloc.dart index 1c6eb79..a3a5bf5 100644 --- a/lib/bloc/menu/menu_bloc.dart +++ b/lib/bloc/menu/menu_bloc.dart @@ -1,7 +1,9 @@ import 'dart:async'; +import 'dart:collection'; import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/workout_menu_tree.dart'; +import 'package:aitrainer_app/repository/exercise_device_repository.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/repository/workout_tree_repository.dart'; import 'package:aitrainer_app/util/trans.dart'; @@ -13,11 +15,15 @@ import 'package:meta/meta.dart'; part 'menu_event.dart'; part 'menu_state.dart'; +enum ExerciseAbility { oneRepMax, endurance, none } + class MenuBloc extends Bloc with Trans { final WorkoutTreeRepository menuTreeRepository; final ExerciseRepository exerciseRepository = ExerciseRepository(); + ExerciseDeviceRepository exerciseDeviceRepository = ExerciseDeviceRepository(); int parent; WorkoutMenuTree workoutItem; + List listFilterDevice = List(); String infoTitle = ""; String infoText = ""; @@ -29,41 +35,47 @@ class MenuBloc extends Bloc with Trans { BuildContext context; + ExerciseAbility ability; + MenuBloc({this.menuTreeRepository}) : super(MenuInitial()) { parent = 0; } void setMenuInfo() { double percent = Cache().getPercentExercises(); - if ( percent == -1 ) { + if (percent == -1) { exerciseRepository.getBaseExerciseFinishedPercent(); percent = Cache().getPercentExercises(); } - if ( context == null ) return; + if (context == null) return; percent = percent * 100; print("Percent " + percent.toString()); - if ( percent == -1 || percent == 0) { + if (percent == -1 || percent == 0) { infoTitle = t("Greetings!"); - infoText = t("The purpose is to measure you physical condition") + " " + t("The suggested order of the exercises: chest - biceps - triceps - back - shoulders - core - tigh - calf."); + infoText = t("The purpose is to measure you physical condition") + + " " + + t("The suggested order of the exercises: chest - biceps - triceps - back - shoulders - core - tigh - calf."); infoText2 = t("I suggest begin your tests with a"); infoText3 = t("Go to the menu Strength - One Rep Max - Chest, and select your favourite exercise."); infoLink = t("Bring me there"); - } else if ( percent > 0 && percent < 20) { + } else if (percent > 0 && percent < 20) { infoTitle = t("Nice! This is a good start"); - } else if ( percent > 20 && percent < 40) { + } else if (percent > 20 && percent < 40) { infoTitle = t("Go on!") + " " + t("You are on track"); - } else if ( percent > 60 && percent < 80) { + } else if (percent > 60 && percent < 80) { infoTitle = t("Persistence!") + " " + t("Not so much left"); - } else if ( percent > 80 && percent < 100) { + } else if (percent > 80 && percent < 100) { infoTitle = t("Almost!") + " " + t("You have only 1-2 exercise left to finish!"); } menuTreeRepository.sortByMuscleType(); missingTreeName = exerciseRepository.nextMissingBaseExercise(menuTreeRepository.sortedTree); - print("Missing " + missingTreeName); - if ( percent > 0) { - infoText = t("Please continue your tests with a") + " '" + missingTreeName + "' " + t("exercise!"); - infoLink = t("Bring me there"); + //print("Missing " + missingTreeName); + if (missingTreeName != null) { + if (percent > 0) { + infoText = t("Please continue your tests with a") + " '" + missingTreeName + "' " + t("exercise!"); + infoLink = t("Bring me there"); + } } } @@ -76,10 +88,14 @@ class MenuBloc extends Bloc with Trans { MenuEvent event, ) async* { try { - if ( event is MenuCreate ) { + if (event is MenuCreate) { yield MenuLoading(); - await menuTreeRepository.createTree(); + //await menuTreeRepository.createTree(); setMenuInfo(); + exerciseDeviceRepository.setDevices(Cache().getDevices()); + exerciseDeviceRepository.getGymDevices().forEach((element) { + listFilterDevice.add(element.exerciseDeviceId); + }); yield MenuReady(); } else if (event is MenuRecreateTree) { // ie. at language changes @@ -90,6 +106,7 @@ class MenuBloc extends Bloc with Trans { yield MenuLoading(); parent = event.parent; workoutItem = event.item; + setAbility(workoutItem.nameEnglish); //print("menuitem " + workoutItem.id.toString() + " parent "+workoutItem.parent.toString()); menuTreeRepository.getBranch(event.parent); yield MenuReady(); @@ -98,27 +115,84 @@ class MenuBloc extends Bloc with Trans { // get parent menus or exercises parent = event.parent; workoutItem = menuTreeRepository.getParentItem(parent); - if ( workoutItem != null) { + + if (workoutItem != null) { //print("UP menuitem " + workoutItem.id.toString() + " parent " + workoutItem.parent.toString()); menuTreeRepository.getBranch(workoutItem.parent); + setAbility(workoutItem.nameEnglish); } yield MenuReady(); } else if (event is MenuTreeJump) { yield MenuLoading(); parent = event.parent; workoutItem = menuTreeRepository.getParentItem(parent); - if ( workoutItem != null) { + + if (workoutItem != null) { //print("JUMP menuitem " + workoutItem.id.toString() + " parent " + workoutItem.parent.toString()); menuTreeRepository.getBranch(workoutItem.parent); + setAbility(workoutItem.nameEnglish); } yield MenuReady(); } else if (event is MenuClickExercise) { yield MenuLoading(); // get exercise page yield MenuReady(); + } else if (event is MenuFilterExerciseType) { + yield MenuLoading(); + final int deviceId = event.deviceId; + print("Defilter " + deviceId.toString()); + if (selectedDevice(deviceId)) { + listFilterDevice.remove(deviceId); + } else { + listFilterDevice.add(deviceId); + } + yield MenuReady(); } - } on Exception catch(ex) { + } on Exception catch (ex) { yield MenuError(message: ex.toString()); } } + + void setAbility(String name) { + switch (name) { + case "One Rep Max": + ability = ExerciseAbility.oneRepMax; + break; + case "Endurance": + ability = ExerciseAbility.endurance; + break; + case "Cardio": + case "Body Compositions": + ability = ExerciseAbility.none; + break; + } + print("Ability: " + ability.toString() + " name:" + name); + } + + bool selectedDevice(int deviceId) { + return listFilterDevice.contains(deviceId); + } + + LinkedHashMap getFilteredBranch(int parent) { + if (parent == null) return LinkedHashMap(); + + LinkedHashMap branch = menuTreeRepository.getBranch(parent); + if (!menuTreeRepository.isChild(parent) || ability.toString() == ExerciseAbility.none.toString()) { + return branch; + } + LinkedHashMap filtered = LinkedHashMap(); + + branch.forEach((key, value) { + final WorkoutMenuTree elem = value; + if (elem.exerciseType != null) { + for (int i = 0; i < elem.exerciseType.devices.length; i++) { + if (listFilterDevice.contains(elem.exerciseType.devices[i])) { + filtered[elem.name] = elem; + } + } + } + }); + + return filtered; + } } diff --git a/lib/bloc/menu/menu_event.dart b/lib/bloc/menu/menu_event.dart index c21cf9b..6c45322 100644 --- a/lib/bloc/menu/menu_event.dart +++ b/lib/bloc/menu/menu_event.dart @@ -53,3 +53,7 @@ class MenuRecreateTree extends MenuEvent { const MenuRecreateTree(); } +class MenuFilterExerciseType extends MenuEvent { + final int deviceId; + const MenuFilterExerciseType({this.deviceId}); +} diff --git a/lib/model/cache.dart b/lib/model/cache.dart index 9c1efba..df961a5 100644 --- a/lib/model/cache.dart +++ b/lib/model/cache.dart @@ -10,6 +10,7 @@ import 'package:aitrainer_app/model/workout_menu_tree.dart'; import 'package:aitrainer_app/repository/customer_repository.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/service/customer_exercise_device_service.dart'; +import 'package:aitrainer_app/service/exercise_device_service.dart'; import 'package:aitrainer_app/service/exercise_tree_service.dart'; import 'package:aitrainer_app/service/exercisetype_service.dart'; import 'package:aitrainer_app/util/env.dart'; @@ -53,6 +54,7 @@ class Cache { static final String isRegisteredKey = 'is_registered'; static final String isLoggedInKey = 'is_logged_in'; static final String langKey = 'lang'; + static final String serverKey = 'live'; static String baseUrl = 'http://aitrainer.info:8888/api/'; static final String mediaUrl = 'https://aitrainer.info:4343/media/'; @@ -88,6 +90,8 @@ class Cache { List deviceLanguages; String startPage; + String testEnvironment; + bool liveServer = true; factory Cache() { return _singleton; @@ -95,8 +99,10 @@ class Cache { Cache._internal() { String testEnv = EnvironmentConfig.test_env; + this.testEnvironment = testEnv; if (testEnv == "1") { baseUrl = 'http://aitrainer.app:8899/api/'; + liveServer = false; } } @@ -108,6 +114,33 @@ class Cache { return this.authToken; } + void setServer(bool live) async { + if (this.testEnvironment == "1") { + liveServer = false; + live = false; + } + Future prefs = SharedPreferences.getInstance(); + SharedPreferences sharedPreferences; + sharedPreferences = await prefs; + liveServer = live; + print("Set Live servier. live? " + live.toString() + " env? " + this.testEnvironment); + sharedPreferences.setBool(Cache.serverKey, live); + } + + void setServerAddress(SharedPreferences prefs) { + if (this.testEnvironment == "1") { + return; + } + final bool live = prefs.getBool(Cache.serverKey); + if (live == null) { + return; + } + liveServer = live; + if (live) { + baseUrl = 'http://aitrainer.info:8888/api/'; + } + } + static String getToken(SharedPreferences prefs) { return prefs.getString(authTokenKey); } @@ -163,27 +196,29 @@ class Cache { ExerciseRepository exerciseRepository = ExerciseRepository(); if (type == SharePrefsChange.registration) { Cache().startPage = "home"; + Flurry.setUserId(customerId.toString()); sharedPreferences.setInt(Cache.customerIdKey, customerId); sharedPreferences.setBool(Cache.isRegisteredKey, true); sharedPreferences.setBool(Cache.isLoggedInKey, true); sharedPreferences.setString(Cache.firebaseUidKey, firebaseUid); await ExerciseTypeApi().getExerciseTypes(); await ExerciseTreeApi().getExerciseTree(); + await ExerciseDeviceApi().getDevices(); final customerDevices = await CustomerExerciseDeviceApi().getDevices(customerId); Cache().setCustomerDevices(customerDevices); await exerciseRepository.getExercisesByCustomer(customerId); - Flurry.setUserId(customerId.toString()); } else if (type == SharePrefsChange.login) { + Flurry.setUserId(customerId.toString()); Cache().startPage = "home"; sharedPreferences.setInt(Cache.customerIdKey, customerId); sharedPreferences.setString(Cache.firebaseUidKey, firebaseUid); sharedPreferences.setBool(Cache.isLoggedInKey, true); await ExerciseTypeApi().getExerciseTypes(); await ExerciseTreeApi().getExerciseTree(); + await ExerciseDeviceApi().getDevices(); final customerDevices = await CustomerExerciseDeviceApi().getDevices(customerId); Cache().setCustomerDevices(customerDevices); await exerciseRepository.getExercisesByCustomer(customerId); - Flurry.setUserId(customerId.toString()); } else if (type == SharePrefsChange.logout) { sharedPreferences.setBool(Cache.isLoggedInKey, false); sharedPreferences.setInt(Cache.customerIdKey, 0); diff --git a/lib/model/exercise_device.dart b/lib/model/exercise_device.dart index 3693c76..f8317a1 100644 --- a/lib/model/exercise_device.dart +++ b/lib/model/exercise_device.dart @@ -7,6 +7,8 @@ class ExerciseDevice { int sort; bool place; + bool isGym; + ExerciseDevice.fromJson(Map json) { this.exerciseDeviceId = json['exerciseDeviceId']; this.name = json['name']; diff --git a/lib/model/exercise_tree.dart b/lib/model/exercise_tree.dart index 417190e..5523f14 100644 --- a/lib/model/exercise_tree.dart +++ b/lib/model/exercise_tree.dart @@ -6,15 +6,38 @@ class ExerciseTree { bool active; String nameTranslation; + ExerciseTree(); + ExerciseTree.fromJson(Map json) { this.treeId = json['treeId']; this.name = json['name']; - this.parentId = json['parentId']; + this.parentId = -1; this.imageUrl = json['imageUrl']; this.active = json['active']; - this.nameTranslation = - json['translations'] != null && (json['translations']).length > 0 - ? json['translations'][0]['name'] - : this.name; + this.nameTranslation = json['translations'] != null && (json['translations']).length > 0 ? json['translations'][0]['name'] : this.name; + } + + Map toJson() { + return { + "treeId": treeId, + "parentId": parentId, + "name": name, + "imageUrl": imageUrl, + "active": active.toString(), + "nameTranslation": nameTranslation, + }; + } + + ExerciseTree copy(int parentId) { + ExerciseTree newTree = ExerciseTree(); + newTree.treeId = this.treeId; + newTree.name = this.name; + newTree.imageUrl = this.imageUrl; + newTree.nameTranslation = this.nameTranslation; + if (parentId != -1) { + newTree.parentId = parentId; + } + + return newTree; } } diff --git a/lib/model/exercise_tree_parents.dart b/lib/model/exercise_tree_parents.dart new file mode 100644 index 0000000..b603003 --- /dev/null +++ b/lib/model/exercise_tree_parents.dart @@ -0,0 +1,11 @@ +class ExerciseTreeParents { + int exerciseTreeParentsId; + int exerciseTreeParentId; + int exerciseTreeChildId; + + ExerciseTreeParents.fromJson(Map json) { + this.exerciseTreeParentsId = json['exerciseTreeParentsId']; + this.exerciseTreeParentId = json['exerciseTreeParentId']; + this.exerciseTreeChildId = json['exerciseTreeChildId']; + } +} diff --git a/lib/model/exercise_type.dart b/lib/model/exercise_type.dart index 27890f0..eacf50c 100644 --- a/lib/model/exercise_type.dart +++ b/lib/model/exercise_type.dart @@ -2,7 +2,7 @@ import 'package:flutter/services.dart'; class ExerciseType { int exerciseTypeId; - int treeId; + //int treeId; String name; String description; BinaryCodec video; @@ -11,17 +11,20 @@ class ExerciseType { String unitQuantityUnit; bool active; bool base; - String imageUrl; - String nameTranslation; - String descriptionTranslation; + String imageUrl = ""; + String nameTranslation = ""; + String descriptionTranslation = ""; + List devices = List(); + List parents = List(); bool is1RM; + bool isEndurance; ExerciseType({this.name, this.description}); ExerciseType.fromJson(Map json) { this.exerciseTypeId = json['exerciseTypeId']; - this.treeId = json['treeId']; + //this.treeId = json['treeId']; this.name = json['name']; this.description = json['description']; this.unit = json['unit']; @@ -29,19 +32,42 @@ class ExerciseType { this.unitQuantityUnit = json['unitQuantityUnit']; this.active = json['active']; this.base = json['base']; - this.imageUrl = json['images'][0]['url']; - this.nameTranslation = json['translations'][0]['name']; - this.descriptionTranslation = json['translations'][0]['description']; + if (json['images'].length > 0) { + this.imageUrl = json['images'][0]['url']; + } + if (json['translations'].length > 0) { + this.nameTranslation = json['translations'][0]['name']; + this.descriptionTranslation = json['translations'][0]['description']; + } + + if (json['devices'].length > 0) { + final List jsonDevices = json['devices']; + + jsonDevices.forEach((device) { + this.devices.add(device['exerciseDeviceId']); + }); + } + + if (json['parents'].length > 0) { + final List jsonParents = json['parents']; + + jsonParents.forEach((parent) { + this.parents.add(parent['exerciseTreeId']); + }); + } + ; } - Map toJson() => - { + Map toJson() => { "name": name, "description": description, "unit": unit, "unitQuantity": unitQuantity, "unitQuantityUnit": unitQuantityUnit, - "active": active + "active": active, + "devices": this.devices.toString(), + "nameTranslation": this.nameTranslation, + "parents": this.parents.toString() }; void set1RM(bool is1RM) { @@ -51,4 +77,12 @@ class ExerciseType { bool get1RM() { return this.is1RM; } -} \ No newline at end of file + + void setEndurance(bool isEndurance) { + this.isEndurance = isEndurance; + } + + bool getEndurance() { + return this.isEndurance; + } +} diff --git a/lib/model/exercise_type_device.dart b/lib/model/exercise_type_device.dart new file mode 100644 index 0000000..d616819 --- /dev/null +++ b/lib/model/exercise_type_device.dart @@ -0,0 +1,11 @@ +class ExerciseTypeDevice { + int exerciseTypeDeviceId; + int exerciseDeviceId; + + ExerciseTypeDevice(); + + ExerciseTypeDevice.fromJson(Map json) { + this.exerciseTypeDeviceId = json['exerciseTypeDeviceId']; + this.exerciseDeviceId = json['exerciseDeviceId']; + } +} diff --git a/lib/model/workout_menu_tree.dart b/lib/model/workout_menu_tree.dart index a12ac6c..0f38d94 100644 --- a/lib/model/workout_menu_tree.dart +++ b/lib/model/workout_menu_tree.dart @@ -15,13 +15,14 @@ class WorkoutMenuTree { bool base; bool is1RM; + bool isEndurance; bool selected = false; bool executed = false; String exerciseDetail; String nameEnglish; - WorkoutMenuTree(this.id, this.parent, this.name, this.imageName, this.color, this.fontSize, this.child, - this.exerciseTypeId, this.exerciseType, this.base, this.is1RM, this.nameEnglish); + WorkoutMenuTree(this.id, this.parent, this.name, this.imageName, this.color, this.fontSize, this.child, this.exerciseTypeId, + this.exerciseType, this.base, this.is1RM, this.isEndurance, this.nameEnglish); Map toJson() { return { @@ -35,6 +36,12 @@ class WorkoutMenuTree { "exerciseTypeId": exerciseTypeId.toString(), "base": base.toString(), "is1RM": is1RM.toString(), + "isEndurance": isEndurance.toString(), }; } + + @override + String toString() { + return this.toJson().toString(); + } } diff --git a/lib/repository/exercise_device_repository.dart b/lib/repository/exercise_device_repository.dart index 2f052e1..9dfbc33 100644 --- a/lib/repository/exercise_device_repository.dart +++ b/lib/repository/exercise_device_repository.dart @@ -1,3 +1,4 @@ +import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/exercise_device.dart'; import 'package:aitrainer_app/service/exercise_device_service.dart'; @@ -8,8 +9,37 @@ class ExerciseDeviceRepository { return this._devices; } + void setDevices(List list) { + _devices = list; + } + Future> getDBDevices() async { this._devices = await ExerciseDeviceApi().getDevices(); return this._devices; } + + bool isGym(int deviceId) { + bool isGym = false; + _devices.forEach((element) { + isGym = isGymElement(element.name); + }); + return isGym; + } + + bool isGymElement(String name) { + return name == "Cable" || name == "Baar" || name == "Gym Machine" || name == "Dumbbells" || name == "Barbell"; + } + + List getGymDevices() { + final List gymDevices = List(); + if (_devices == null || _devices.isEmpty) { + _devices = Cache().getDevices(); + } + _devices.forEach((element) { + if (isGymElement(element.name)) { + gymDevices.add(element); + } + }); + return gymDevices; + } } diff --git a/lib/repository/workout_tree_repository.dart b/lib/repository/workout_tree_repository.dart index 009bf9d..9ec8b97 100644 --- a/lib/repository/workout_tree_repository.dart +++ b/lib/repository/workout_tree_repository.dart @@ -50,17 +50,31 @@ class WorkoutTreeRepository { List exerciseTree = Cache().getExerciseTree(); if (exerciseTree == null || exerciseTree.length == 0) { - await ExerciseTreeApi().getExerciseTree(); + exerciseTree = await ExerciseTreeApi().getExerciseTree(); + } + + List exerciseTypes = Cache().getExerciseTypes(); + if (exerciseTypes == null || exerciseTypes.length == 0) { + exerciseTypes = await ExerciseTypeApi().getExerciseTypes(); } exerciseTree.forEach((treeItem) async { + //print(" -- TreeItem " + treeItem.toJson().toString()); + String treeName = isEnglish ? treeItem.name : treeItem.nameTranslation; String assetImage = 'asset/menu/' + treeItem.imageUrl.substring(7); + bool is1RM = treeItem.name == 'One Rep Max' ? true : false; if (is1RM == false && treeItem.parentId != 0) { is1RM = isParent1RM(treeItem.parentId); } - this.tree[treeItem.name] = WorkoutMenuTree( + + bool isEndurance = treeItem.name == 'Endurance' ? true : false; + if (isEndurance == false && treeItem.parentId != 0) { + isEndurance = isParentEndurance(treeItem.parentId); + } + + final WorkoutMenuTree menuItem = WorkoutMenuTree( treeItem.treeId, treeItem.parentId, treeName, @@ -72,22 +86,40 @@ class WorkoutTreeRepository { null, false, is1RM, + isEndurance, treeItem.name, ); + this.tree[treeItem.name + "_" + treeItem.parentId.toString()] = menuItem; + //print("WorkoutMenuTree item " + menuItem.toJson().toString()); }); - List exerciseTypes = Cache().getExerciseTypes(); - if (exerciseTypes == null || exerciseTypes.length == 0) { - await ExerciseTypeApi().getExerciseTypes(); - } - exerciseTypes.forEach((exerciseType) { - String exerciseTypeName = isEnglish ? exerciseType.name : exerciseType.nameTranslation; - String assetImage = 'asset/menu/' + exerciseType.imageUrl.substring(7); - bool is1RM = this.isParent1RM(exerciseType.treeId); - exerciseType.is1RM = is1RM; - this.tree[exerciseType.name] = WorkoutMenuTree(exerciseType.exerciseTypeId, exerciseType.treeId, exerciseTypeName, assetImage, - Colors.white, 24, true, exerciseType.exerciseTypeId, exerciseType, exerciseType.base, is1RM, exerciseType.name); + if (!(exerciseType.imageUrl.isEmpty || exerciseType.name.isEmpty || exerciseType.nameTranslation.isEmpty)) { + String exerciseTypeName = isEnglish ? exerciseType.name : exerciseType.nameTranslation; + String assetImage = 'asset/menu/' + exerciseType.imageUrl.substring(7); + if (exerciseType.parents.isNotEmpty) { + exerciseType.parents.forEach((parentId) { + bool is1RM = this.isParent1RM(parentId); + bool isEndurance = this.isParentEndurance(parentId); + exerciseType.is1RM = is1RM; + exerciseType.isEndurance = isEndurance; + WorkoutMenuTree menuItem = WorkoutMenuTree(exerciseType.exerciseTypeId, parentId, exerciseTypeName, assetImage, Colors.white, + 24, true, exerciseType.exerciseTypeId, exerciseType, exerciseType.base, is1RM, isEndurance, exerciseType.name); + this.tree[exerciseType.name] = menuItem; + //print("WorkoutMenuTree item " + menuItem.toJson().toString()); + /*print("ExerciseType in Menu item " + + exerciseType.toJson().toString() + + " is1RM: " + + is1RM.toString() + + " isEndurance: " + + isEndurance.toString());*/ + }); + } else { + //print("No Parents " + exerciseType.toJson().toString()); + } + } else { + //print("ExerciseType missing data: " + exerciseType.exerciseTypeId.toString()); + } }); Cache().setWorkoutMenuTree(tree); @@ -101,7 +133,7 @@ class WorkoutTreeRepository { this.tree.forEach((key, value) { WorkoutMenuTree treeItem = value as WorkoutMenuTree; if (treeItem.id == treeId) { - isTreeItem1RM = treeItem.is1RM; + isTreeItem1RM = isTreeItem1RM || treeItem.is1RM; //print (treeItem.name + " 1RM " + treeItem.is1RM.toString() ); } }); @@ -109,8 +141,45 @@ class WorkoutTreeRepository { return isTreeItem1RM; } - LinkedHashMap getBranch(int parent) { - LinkedHashMap branch = LinkedHashMap(); + bool isParentEndurance(int treeId) { + bool isTreeItemEndurance = false; + + this.tree.forEach((key, value) { + WorkoutMenuTree treeItem = value as WorkoutMenuTree; + if (treeItem.id == treeId) { + isTreeItemEndurance = isTreeItemEndurance || treeItem.isEndurance; + //print(treeItem.id.toString() + " " + treeItem.name + " Endurance? " + treeItem.isEndurance.toString()); + } + }); + + return isTreeItemEndurance; + } + + bool isChild(int parentId) { + bool isChild = true; + + this.getBranch(parentId).forEach((key, value) { + WorkoutMenuTree workoutTree = value; + isChild = isChild && workoutTree.child; + }); + //print("Check child " + parentId.toString() + " child: " + isChild.toString()); + return isChild; + } + + bool isChildAndGym(int parentId) { + bool isChild = true; + bool isGym = true; + + this.getBranch(parentId).forEach((key, value) { + WorkoutMenuTree workoutTree = value; + isChild = isChild && workoutTree.child; + isGym = isGym && (workoutTree.is1RM || workoutTree.isEndurance); + }); + return isChild && isGym; + } + + LinkedHashMap getBranch(int parent, {bool filtering = false}) { + LinkedHashMap branch = LinkedHashMap(); tree.forEach((key, value) { WorkoutMenuTree workoutTree = value as WorkoutMenuTree; if (parent == workoutTree.parent) { diff --git a/lib/service/api.dart b/lib/service/api.dart index 665cda9..10c3ab1 100644 --- a/lib/service/api.dart +++ b/lib/service/api.dart @@ -7,6 +7,7 @@ import 'package:aitrainer_app/model/cache.dart'; class APIClient with Common { Future get(String endPoint, String param) async { final url = Cache.getBaseUrl() + endPoint + param; + print("-------- API get " + url); String authToken = Cache().getAuthToken(); if (authToken.length == 0) { var responseJson = await APIClient.authenticateUser(Cache.username, Cache.password); diff --git a/lib/service/exercise_tree_service.dart b/lib/service/exercise_tree_service.dart index 55df9ad..faf6d90 100644 --- a/lib/service/exercise_tree_service.dart +++ b/lib/service/exercise_tree_service.dart @@ -2,18 +2,61 @@ import 'dart:convert'; import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/exercise_tree.dart'; +import 'package:aitrainer_app/model/exercise_tree_parents.dart'; import 'api.dart'; class ExerciseTreeApi { final APIClient _client = new APIClient(); Future> getExerciseTree() async { - final body = await _client.get("exercise_tree", ""); - final Iterable json = jsonDecode(body); - final List exerciseTree = json.map((exerciseTree) => - ExerciseTree.fromJson(exerciseTree)).toList(); + final String body = await _client.get("exercise_tree", ""); + Iterable json = jsonDecode(body); + List exerciseTree = json.map((exerciseTree) => ExerciseTree.fromJson(exerciseTree)).toList(); + + exerciseTree = await getExerciseTreeParents(exerciseTree); + Cache().setExerciseTree(exerciseTree); return exerciseTree; } + Future> getExerciseTreeParents(List exerciseTree) async { + List copyList = this._copyList(exerciseTree); + + final String body = await _client.get("exercise_tree_parents", ""); + Iterable json = jsonDecode(body); + final List exerciseTreeParents = + json.map((exerciseTreeParent) => ExerciseTreeParents.fromJson(exerciseTreeParent)).toList(); + + int treeIndex = 0; + copyList.forEach((element) async { + int index = 0; + exerciseTreeParents.forEach((parent) { + if (parent.exerciseTreeChildId == element.treeId) { + if (index > 0) { + ExerciseTree newElement = element.copy(parent.exerciseTreeParentId); + exerciseTree.add(newElement); + print("ExerciseTree " + newElement.toJson().toString()); + } else { + element.parentId = parent.exerciseTreeParentId; + exerciseTree[treeIndex].parentId = parent.exerciseTreeParentId; + } + index++; + } + }); + print("ExerciseTree " + element.toJson().toString()); + treeIndex++; + }); + + return exerciseTree; + } + + List _copyList(List tree) { + final List copyList = List(); + tree.forEach((element) { + final ExerciseTree copy = element.copy(-1); + copyList.add(copy); + }); + + return copyList; + } } diff --git a/lib/service/exercisetype_service.dart b/lib/service/exercisetype_service.dart index 38273b6..ea24e1b 100644 --- a/lib/service/exercisetype_service.dart +++ b/lib/service/exercisetype_service.dart @@ -3,31 +3,26 @@ import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/exercise_type.dart'; import 'package:aitrainer_app/service/api.dart'; - class ExerciseTypeApi { - final APIClient _client=new APIClient(); + final APIClient _client = new APIClient(); Future> getExerciseTypes() async { - final body = await _client.get("exercise_type/active", ""); + final body = await _client.get("exercise_type", ""); final Iterable json = jsonDecode(body); - final List exerciseTypes = json.map( (exerciseType) => ExerciseType.fromJson(exerciseType) ).toList(); + final List exerciseTypes = json.map((exerciseType) => ExerciseType.fromJson(exerciseType)).toList(); Cache().setExerciseTypes(exerciseTypes); return exerciseTypes; } Future saveExerciseType(ExerciseType exerciseType) async { String body = JsonEncoder().convert(exerciseType.toJson()); - print(" ===== saving exerciseType id: " + exerciseType.exerciseTypeId.toString() + ":" + body ); - await _client.post( - "exercise_type/"+exerciseType.exerciseTypeId.toString(), - body); + print(" ===== saving exerciseType id: " + exerciseType.exerciseTypeId.toString() + ":" + body); + await _client.post("exercise_type/" + exerciseType.exerciseTypeId.toString(), body); } Future addExerciseType(ExerciseType exerciseType) async { String body = JsonEncoder().convert(exerciseType.toJson()); - print(" ===== add new exerciseType: " + body ); - await _client.post( - "exercise_type", - body); + print(" ===== add new exerciseType: " + body); + await _client.post("exercise_type", body); } -} \ No newline at end of file +} diff --git a/lib/util/session.dart b/lib/util/session.dart index 4938170..daf019a 100644 --- a/lib/util/session.dart +++ b/lib/util/session.dart @@ -30,6 +30,7 @@ class Session { await AppLanguage().getLocale(_sharedPreferences); await AppLocalizations.delegate.load(AppLanguage().appLocal); print(" -- Session: fetch token.."); + Cache().setServerAddress(_sharedPreferences); await _fetchToken(_sharedPreferences); print(" -- FireBase init.."); await FirebaseApi().initializeFlutterFire(); @@ -101,18 +102,17 @@ class Session { await CustomerApi().getCustomer(customerId); Cache().startPage = "home"; Flurry.setUserId(customerId.toString()); + await ExerciseTypeApi().getExerciseTypes(); + await ExerciseTreeApi().getExerciseTree(); + await ExerciseDeviceApi().getDevices(); + final customerDevices = await CustomerExerciseDeviceApi().getDevices(customerId); + Cache().setCustomerDevices(customerDevices); + if (customerId > 0) { + ExerciseRepository exerciseRepository = ExerciseRepository(); + await exerciseRepository.getExercisesByCustomer(customerId); + } } } - - await ExerciseTypeApi().getExerciseTypes(); - await ExerciseTreeApi().getExerciseTree(); - final customerDevices = await CustomerExerciseDeviceApi().getDevices(customerId); - Cache().setCustomerDevices(customerDevices); - if (customerId > 0) { - ExerciseRepository exerciseRepository = ExerciseRepository(); - await exerciseRepository.getExercisesByCustomer(customerId); - } - await ExerciseDeviceApi().getDevices(); print("--- Session finished"); } } diff --git a/lib/view/exercise_new_page.dart b/lib/view/exercise_new_page.dart index dec0d3a..7c6b2c6 100644 --- a/lib/view/exercise_new_page.dart +++ b/lib/view/exercise_new_page.dart @@ -12,7 +12,6 @@ import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/bmi_widget.dart'; import 'package:aitrainer_app/widgets/bmr_widget.dart'; import 'package:aitrainer_app/widgets/size_widget.dart'; -import 'package:aitrainer_app/widgets/splash.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -102,12 +101,12 @@ class _ExerciseNewPageState extends State with Trans { //LoadingDialog.hide(context); } final exerciseBloc = BlocProvider.of(context); - return getExerciseWidget(exerciseBloc, exerciseType); + return getExerciseWidget(exerciseBloc, exerciseType, menuBloc); }, )); } - Widget getExerciseWidget(ExerciseNewBloc exerciseBloc, ExerciseType exerciseType) { + Widget getExerciseWidget(ExerciseNewBloc exerciseBloc, ExerciseType exerciseType, MenuBloc menuBloc) { exerciseBloc.exerciseRepository.setExerciseType(exerciseType); final String exerciseName = AppLanguage().appLocal == Locale("en") ? exerciseBloc.exerciseRepository.exerciseType.name @@ -120,7 +119,7 @@ class _ExerciseNewPageState extends State with Trans { exerciseDescription = ""; } - print(exerciseBloc.exerciseRepository.exerciseType.name); + //print(exerciseBloc.exerciseRepository.exerciseType.name); if (exerciseBloc.exerciseRepository.exerciseType.name == "BMR") { return BMR(exerciseBloc: exerciseBloc); @@ -132,8 +131,17 @@ class _ExerciseNewPageState extends State with Trans { return SizeWidget(exerciseBloc: exerciseBloc); } + String exerciseTask = ""; + if (exerciseBloc.exerciseRepository.exerciseType.is1RM && menuBloc.ability.toString() == ExerciseAbility.oneRepMax.toString()) { + exerciseTask = "Please take a relative bigger weight and repeat 12-20 times"; + exerciseBloc.quantity = 12; + } else if (exerciseBloc.exerciseRepository.exerciseType.isEndurance && + menuBloc.ability.toString() == ExerciseAbility.endurance.toString()) { + exerciseTask = "Please take a medium weight and repeat 20-30 times"; + exerciseBloc.quantity = 20; + } + return Form( - //autovalidateMode: AutovalidateMode.disabled, child: Scaffold( resizeToAvoidBottomInset: true, appBar: AppBarNav(depth: 1), @@ -189,6 +197,21 @@ class _ExerciseNewPageState extends State with Trans { Divider( color: Colors.transparent, ), + Text( + t(exerciseTask), + style: GoogleFonts.inter( + fontSize: 14, + color: Colors.orange, + fontWeight: FontWeight.bold, + ), + maxLines: 3, + textAlign: TextAlign.center, + overflow: TextOverflow.fade, + softWrap: true, + ), + Divider( + color: Colors.transparent, + ), columnQuantityUnit(exerciseBloc), Divider( color: Colors.transparent, @@ -269,7 +292,7 @@ class _ExerciseNewPageState extends State with Trans { borderSide: BorderSide(color: Colors.black26, width: 0.4), ), ), - initialValue: "12", + initialValue: bloc.quantity.toStringAsFixed(0), keyboardType: TextInputType.number, textInputAction: TextInputAction.next, style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.orange[200]), @@ -340,6 +363,13 @@ class _ExerciseNewPageState extends State with Trans { args['readonly'] = false, Navigator.of(context).pushNamed('exerciseControlPage', arguments: args) } + else if (bloc.exerciseRepository.exerciseType.isEndurance) + { + args['exerciseRepository'] = bloc.exerciseRepository, + args['percent'] = 0.50, + args['readonly'] = false, + Navigator.of(context).pushNamed('exerciseControlPage', arguments: args) + } }, ) ], diff --git a/lib/view/settings.dart b/lib/view/settings.dart index 7d2da2c..18a3f50 100644 --- a/lib/view/settings.dart +++ b/lib/view/settings.dart @@ -1,38 +1,28 @@ import 'package:aitrainer_app/bloc/menu/menu_bloc.dart'; import 'package:aitrainer_app/bloc/settings/settings_bloc.dart'; import 'package:aitrainer_app/localization/app_language.dart'; -import 'package:aitrainer_app/localization/app_localization.dart'; +import 'package:aitrainer_app/model/cache.dart'; +import 'package:aitrainer_app/util/trans.dart'; +import 'package:aitrainer_app/widgets/app_bar_min.dart'; import 'package:aitrainer_app/widgets/bottom_nav.dart'; -import 'package:aitrainer_app/widgets/splash.dart'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:toggle_switch/toggle_switch.dart'; -class SettingsPage extends StatelessWidget { +// ignore: must_be_immutable +class SettingsPage extends StatelessWidget with Trans { @override Widget build(BuildContext context) { // ignore: close_sinks SettingsBloc settingsBloc = BlocProvider.of(context); settingsBloc.setLocale(AppLanguage().appLocal); settingsBloc.context = context; + setContext(context); MenuBloc menuBloc = BlocProvider.of(context); return Scaffold( - appBar: AppBar( - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(AppLocalizations.of(context).translate('Settings')), - Image.asset( - 'asset/image/WT_long_logo.png', - fit: BoxFit.cover, - height: 65.0, - ), - ], - ), - //title: Text(AppLocalizations.of(context).translate('Settings')), - backgroundColor: Colors.transparent, - ), + appBar: AppBarMin(), body: Container( decoration: BoxDecoration( image: DecorationImage( @@ -70,13 +60,10 @@ class SettingsPage extends StatelessWidget { return ListView(padding: EdgeInsets.only(top: 150), children: [ ListTile( leading: Icon(Icons.language), - subtitle: Text(AppLocalizations.of(context).translate("Change App Language")), + subtitle: Text(t("Change App Language")), title: DropdownButton( - value: settingsBloc.getLocale() == Locale('en') - ? AppLocalizations.of(context).translate("English") - : AppLocalizations.of(context).translate("Hungarian"), - items: [AppLocalizations.of(context).translate("English"), AppLocalizations.of(context).translate("Hungarian")] - .map>((String value) { + value: settingsBloc.getLocale() == Locale('en') ? t("English") : t("Hungarian"), + items: [t("English"), t("Hungarian")].map>((String value) { return DropdownMenuItem( value: value, child: Text(value), @@ -85,6 +72,37 @@ class SettingsPage extends StatelessWidget { onChanged: (String lang) => { settingsBloc.add(SettingsChangeLanguage(language: lang)), })), + getServer(), ]); } + + ListTile getServer() { + if (Cache().userLoggedIn.admin != 1) { + return ListTile( + title: Container(), + ); + } + return ListTile( + leading: Icon(Icons.data_usage_sharp), + subtitle: Text("For Test purpuses select Test-Server. After that please restart the the App"), + title: ToggleSwitch( + minWidth: 120.0, + minHeight: 30.0, + fontSize: 14.0, + initialLabelIndex: Cache().liveServer + ? Cache().testEnvironment == "1" + ? 1 + : 0 + : 1, + activeBgColor: Colors.indigo, + activeFgColor: Colors.white, + inactiveBgColor: Colors.white60, + inactiveFgColor: Colors.grey[900], + labels: [t('Live-Server'), t('Test-Server')], + onToggle: (index) { + Cache().setServer(index == 0); + }, + ), + ); + } } diff --git a/lib/widgets/app_bar.dart b/lib/widgets/app_bar.dart index 0388d77..23558a4 100644 --- a/lib/widgets/app_bar.dart +++ b/lib/widgets/app_bar.dart @@ -8,11 +8,11 @@ import 'package:aitrainer_app/util/common.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; import 'package:rainbow_color/rainbow_color.dart'; - -class AppBarNav extends StatefulWidget implements PreferredSizeWidget { +class AppBarNav extends StatefulWidget implements PreferredSizeWidget { final MenuBloc menuBloc; final bool isMenu; final int depth; @@ -25,18 +25,17 @@ class AppBarNav extends StatefulWidget implements PreferredSizeWidget { Size get preferredSize => const Size.fromHeight(50); } -class _AppBarNav extends State with SingleTickerProviderStateMixin, Common { +class _AppBarNav extends State with SingleTickerProviderStateMixin, Common { Animation colorAnim; AnimationController colorController; MenuBloc menuBloc; @override void initState() { + colorController = AnimationController(duration: Duration(seconds: 4), vsync: this); - colorController = - AnimationController(duration: Duration(seconds: 4), vsync:this); - - colorAnim = RainbowColorTween([Colors.white70, + colorAnim = RainbowColorTween([ + Colors.white70, Colors.blueGrey, Colors.blueAccent, Colors.lightBlue, @@ -45,18 +44,20 @@ class _AppBarNav extends State with SingleTickerProviderStateMixin, Colors.orange, Colors.orangeAccent, Colors.yellowAccent, - Color(0xffcce6ff)]) - .animate(colorController) - ..addListener(() { setState(() {}); }) + Color(0xffcce6ff) + ]).animate(colorController) + ..addListener(() { + setState(() {}); + }) ..addStatusListener((status) { if (status == AnimationStatus.completed) { Timer(Duration(seconds: 10), () { - if ( mounted ) { + if (mounted) { colorController.forward(); } }); } else if (status == AnimationStatus.dismissed) { - colorController.forward(); + colorController.forward(); } }); colorController.forward(); @@ -72,33 +73,35 @@ class _AppBarNav extends State with SingleTickerProviderStateMixin, title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - getAnimatedWidget(), - Image.asset( - 'asset/image/WT_long_logo.png', - //fit: BoxFit.cover, - height: 45.0, + Stack( + children: [ + Image.asset( + 'asset/image/WT_long_logo.png', + //fit: BoxFit.cover, + height: 45.0, + ), + getTestServer(), + ], ), ], ), leading: IconButton( icon: Icon(Icons.arrow_back, color: Colors.white), - onPressed: () => - { - if ( widget.isMenu != null ) { - if ( menuBloc.workoutItem != null ) { - menuBloc.add(MenuTreeUp(parent: menuBloc.workoutItem.parent)), + onPressed: () => { + if (widget.isMenu != null) + { + if (menuBloc.workoutItem != null) + { + menuBloc.add(MenuTreeUp(parent: menuBloc.workoutItem.parent)), + } } - } else if ( widget.depth != null ) { - if ( widget.depth == 0 ) { - Navigator.of(context).pushNamed('home') - } else { - Navigator.of(context).pop() + else if (widget.depth != null) + { + if (widget.depth == 0) {Navigator.of(context).pushNamed('home')} else {Navigator.of(context).pop()} } - } }, - ) - ); + )); } @override @@ -107,48 +110,70 @@ class _AppBarNav extends State with SingleTickerProviderStateMixin, super.dispose(); } + Widget getTestServer() { + if (Cache().liveServer) { + return Container(); + } else { + return Text("TEST", + style: GoogleFonts.archivoBlack( + color: Colors.red, + fontWeight: FontWeight.bold, + shadows: [ + Shadow( + offset: Offset(5.0, 5.0), + blurRadius: 12.0, + color: Colors.black54, + ), + Shadow( + offset: Offset(-3.0, 3.0), + blurRadius: 12.0, + color: Colors.black54, + ), + ], + )); + } + } + Widget getAnimatedWidget() { double cWidth = mediaSizeWidth(context); double percent = Cache().getPercentExercises(); - if ( percent == -1) { + if (percent == -1) { menuBloc.menuTreeRepository.createTree(); ExerciseRepository exerciseRepository = ExerciseRepository(); exerciseRepository.getBaseExerciseFinishedPercent(); percent = Cache().getPercentExercises(); } - int sizeExerciseList = Cache().getExercises() == null? 0 : Cache().getExercises().length; - if ( sizeExerciseList == 0 ) { + int sizeExerciseList = Cache().getExercises() == null ? 0 : Cache().getExercises().length; + if (sizeExerciseList == 0) { String text = AppLocalizations.of(context).translate("Make your first test"); double fontSize = text.length > 24 ? 13 : 16; - return Stack( - alignment: Alignment.topLeft, - overflow: Overflow.clip, - children: [ - Text(text, - style: TextStyle(fontSize: fontSize, color: colorAnim.value, shadows: [Shadow(color: Colors.purple , blurRadius: 15)]), - - ), - //TestProgress(animation: sizeAnim), - ] - ); + return Stack(alignment: Alignment.topLeft, overflow: Overflow.clip, children: [ + Text( + text, + style: TextStyle(fontSize: fontSize, color: colorAnim.value, shadows: [Shadow(color: Colors.purple, blurRadius: 15)]), + ), + //TestProgress(animation: sizeAnim), + ]); } else { - return Stack( alignment: Alignment.topLeft, children: [ - LinearPercentIndicator( - width: cWidth / 4, - lineHeight: 14.0, - percent: percent, - center: Text( - (percent * 100).toStringAsFixed(0) + "% " + AppLocalizations.of(context).translate("finished"), - style: new TextStyle(fontSize: 10.0), - ), - trailing: Icon(percent > 0.6 ? Icons.mood : Icons.mood_bad, color: colorAnim.value,), - linearStrokeCap: LinearStrokeCap.roundAll, - backgroundColor: colorAnim.value, - progressColor: Color(0xff73e600), - animation: true, + LinearPercentIndicator( + width: cWidth / 4, + lineHeight: 14.0, + percent: percent, + center: Text( + (percent * 100).toStringAsFixed(0) + "% " + AppLocalizations.of(context).translate("finished"), + style: new TextStyle(fontSize: 10.0), + ), + trailing: Icon( + percent > 0.6 ? Icons.mood : Icons.mood_bad, + color: colorAnim.value, + ), + linearStrokeCap: LinearStrokeCap.roundAll, + backgroundColor: colorAnim.value, + progressColor: Color(0xff73e600), + animation: true, ), ], ); diff --git a/lib/widgets/app_bar_min.dart b/lib/widgets/app_bar_min.dart index 35be973..3b04f97 100644 --- a/lib/widgets/app_bar_min.dart +++ b/lib/widgets/app_bar_min.dart @@ -1,6 +1,8 @@ +import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/util/common.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; // ignore: must_be_immutable class AppBarMin extends StatefulWidget implements PreferredSizeWidget { @@ -27,10 +29,15 @@ class _AppBarNav extends State with Common { title: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - Image.asset( - 'asset/image/WT_long_logo.png', - //fit: BoxFit.cover, - height: 45.0, + Stack( + children: [ + Image.asset( + 'asset/image/WT_long_logo.png', + //fit: BoxFit.cover, + height: 45.0, + ), + getTestServer(), + ], ), ], ), @@ -46,4 +53,28 @@ class _AppBarNav extends State with Common { void dispose() { super.dispose(); } + + Widget getTestServer() { + if (Cache().liveServer) { + return Container(); + } else { + return Text("TEST", + style: GoogleFonts.archivoBlack( + color: Colors.red, + fontWeight: FontWeight.bold, + shadows: [ + 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, + ), + ], + )); + } + } } diff --git a/lib/widgets/menu_info_widget.dart b/lib/widgets/menu_info_widget.dart index 4abe6c2..11cde5d 100644 --- a/lib/widgets/menu_info_widget.dart +++ b/lib/widgets/menu_info_widget.dart @@ -58,31 +58,26 @@ class MenuInfoWidget extends StatelessWidget with Common { title, maxLines: 4, textAlign: TextAlign.center, - style: TextStyle( - color: titleColor, - fontSize: titleSize, - fontWeight: titleWeight), + style: TextStyle(color: titleColor, fontSize: titleSize, fontWeight: titleWeight), ), Divider(), Text( text, maxLines: 6, - style: TextStyle( - color: textColor, fontSize: textSize, fontWeight: textWeight), + style: TextStyle(color: textColor, fontSize: textSize, fontWeight: textWeight), ), - Divider(), + /* Divider(), Text( text2, maxLines: 6, style: TextStyle( color: textColor, fontSize: textSize, fontWeight: textWeight), - ), + ), */ Divider(), Text( text3, maxLines: 6, - style: TextStyle( - color: textColor, fontSize: textSize, fontWeight: textWeight), + style: TextStyle(color: textColor, fontSize: textSize, fontWeight: textWeight), ), getLink(), ], @@ -97,15 +92,10 @@ class MenuInfoWidget extends StatelessWidget with Common { return InkWell( child: new Text( link, - style: TextStyle( - color: Colors.lightBlueAccent, - fontSize: textSize, - fontFamily: 'Arial', - fontWeight: textWeight), + style: TextStyle(color: Colors.lightBlueAccent, fontSize: textSize, fontFamily: 'Arial', fontWeight: textWeight), ), onTap: () => { - missingId = bloc.menuTreeRepository - .getMissingTreeIdByName(bloc.missingTreeName), + missingId = bloc.menuTreeRepository.getMissingTreeIdByName(bloc.missingTreeName), print("menu " + missingId.toString()), bloc.add(MenuTreeJump(parent: missingId)) }); diff --git a/lib/widgets/menu_page_widget.dart b/lib/widgets/menu_page_widget.dart index 6e7d74d..2de7bee 100644 --- a/lib/widgets/menu_page_widget.dart +++ b/lib/widgets/menu_page_widget.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'package:aitrainer_app/bloc/menu/menu_bloc.dart'; +import 'package:aitrainer_app/localization/app_language.dart'; import 'package:aitrainer_app/localization/app_localization.dart'; import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/workout_menu_tree.dart'; @@ -17,6 +18,8 @@ import 'menu_info_widget.dart'; // ignore: must_be_immutable class MenuPageWidget extends StatelessWidget with Trans { int parent; + final double baseWidth = 312; + final double baseHeight = 675.2; MenuPageWidget({this.parent}); @@ -27,13 +30,172 @@ class MenuPageWidget extends StatelessWidget with Trans { double cWidth = MediaQuery.of(context).size.width; double cHeight = MediaQuery.of(context).size.height; - return CustomScrollView( - scrollDirection: Axis.vertical, slivers: [buildMenuColumn(parent, context, menuBloc, cWidth, cHeight)]); + return CustomScrollView(scrollDirection: Axis.vertical, slivers: buildMenuColumn(parent, context, menuBloc, cWidth, cHeight)); } - SliverGrid buildMenuColumn(int parent, BuildContext context, MenuBloc menuBloc, double cWidth, double cHeight) { - final List _columnChildren = List(); + List buildMenuColumn(int parent, BuildContext context, MenuBloc menuBloc, double cWidth, double cHeight) { + final List slivers = List(); + bool isChild = menuBloc.menuTreeRepository.isChildAndGym(menuBloc.parent); + if (!isChild) { + slivers.add(getInfoWidget(context, menuBloc)); + } else { + slivers.add(getFilterWidget(parent, menuBloc)); + slivers.add(getFilterElements(menuBloc)); + } + + final List _columnChildren = List(); + final double distortionHeight = cHeight / baseHeight; + + if (menuBloc.getFilteredBranch(menuBloc.parent).isEmpty) { + _columnChildren.add(Container( + padding: EdgeInsets.only(top: 15.0), + child: Center( + child: Stack(alignment: Alignment.bottomLeft, children: [ + Text(t("All Exercises has been filtered out"), style: GoogleFonts.inter(color: Colors.white)), + ])))); + } else { + menuBloc.getFilteredBranch(menuBloc.parent).forEach((treeName, value) { + WorkoutMenuTree workoutTree = value; + /* double textLength = workoutTree.name.length * workoutTree.fontSize; + double top = textLength < cWidth - 30 + ? (cHeight / 3 - 2.5 * workoutTree.fontSize) / distortionHeight + : (cHeight / 3 - 3.6 * workoutTree.fontSize) / distortionHeight; + + print(" dH: " + + distortionHeight.toStringAsFixed(1) + + " W: " + + cWidth.toStringAsFixed(0) + + " H: " + + cHeight.toStringAsFixed(0) + + " TOP: " + + top.toStringAsFixed(0) + + " tL: " + + textLength.toStringAsFixed(0)); */ + _columnChildren.add(Container( + padding: EdgeInsets.only(top: 15.0, left: 15, right: 15), + height: 225, //cHeight / 3 * distortionHeight, + child: Badge( + padding: EdgeInsets.all(8), + position: BadgePosition.bottomEnd(end: 0), + animationDuration: Duration(milliseconds: 500), + animationType: BadgeAnimationType.slide, + badgeColor: Colors.orange[800], + showBadge: workoutTree.base, + badgeContent: Text(t("base"), + style: TextStyle( + color: Colors.white, + fontSize: 12, + )), + child: Stack(alignment: Alignment.bottomLeft, children: [ + FlatButton( + child: badgedIcon(workoutTree, cWidth, cHeight), + padding: EdgeInsets.only(left: 0.0, bottom: 0), + onPressed: () => menuClick(workoutTree, menuBloc, context), + ), + Container( + padding: EdgeInsets.only(left: 15, bottom: 10), + child: InkWell( + onTap: () => menuClick(workoutTree, menuBloc, context), + child: Text( + workoutTree.name, + maxLines: 3, + style: GoogleFonts.archivoBlack(color: workoutTree.color, fontSize: workoutTree.fontSize, height: 1.1), + ), + highlightColor: workoutTree.color, + ), + ), + ])))); + }); + } + + SliverList sliverList = SliverList( + delegate: SliverChildListDelegate(_columnChildren), + /* gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 1, + mainAxisSpacing: 6.0, + crossAxisSpacing: 10.0, + childAspectRatio: cWidth > 375 ? 1.8 : 1.8, + ) */ + ); + + slivers.add(sliverList); + return slivers; + } + + SliverGrid getFilterWidget(int parent, MenuBloc menuBloc) { + SliverGrid sliverList = SliverGrid( + delegate: SliverChildListDelegate([ + Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ + Text( + t("Equipment Filter"), + textAlign: TextAlign.center, + style: GoogleFonts.archivoBlack( + fontSize: 24, + color: Colors.white, + shadows: [ + 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, + ), + ], + ), + ), + ]) + ]), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 1, + mainAxisSpacing: 5.0, + crossAxisSpacing: 5.0, + childAspectRatio: 9, + )); + + return sliverList; + } + + SliverGrid getFilterElements(MenuBloc menuBloc) { + List list = List(); + + menuBloc.exerciseDeviceRepository.getGymDevices().forEach((element) { + String deviceName = AppLanguage().appLocal == Locale('en') ? element.name : element.nameTranslation; + ChoiceChip chip = ChoiceChip( + //padding: EdgeInsets.zero, + labelPadding: EdgeInsets.only(right: 5), + avatar: Icon( + Icons.remove_circle_outline, + color: Colors.orange, + size: 18, + ), + label: Text(deviceName), + labelStyle: TextStyle(fontSize: 9, color: Colors.black), + selectedColor: Colors.white, + selected: menuBloc.selectedDevice(element.exerciseDeviceId), + backgroundColor: Colors.blue[100], + shadowColor: Colors.black54, + onSelected: (value) => menuBloc.add(MenuFilterExerciseType(deviceId: element.exerciseDeviceId)), + ); + list.add(chip); + }); + + SliverGrid sliverList = SliverGrid( + delegate: SliverChildListDelegate(list), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + mainAxisSpacing: 1.0, + crossAxisSpacing: 1.0, + childAspectRatio: 3, + )); + return sliverList; + } + + SliverGrid getInfoWidget(BuildContext context, MenuBloc menuBloc) { + final List _columnChildren = List(); if (context != null) { menuBloc.setContext(context); menuBloc.setMenuInfo(); @@ -53,55 +215,14 @@ class MenuPageWidget extends StatelessWidget with Trans { ); _columnChildren.add(info); } - - menuBloc.menuTreeRepository.getBranch(menuBloc.parent).forEach((treeName, value) { - WorkoutMenuTree workoutTree = value as WorkoutMenuTree; - _columnChildren.add(Container( - padding: EdgeInsets.only(top: 15.0), - child: Center( - child: Stack(alignment: Alignment.bottomLeft, - //clipBehavior: Clip.antiAliasWithSaveLayer, - children: [ - FlatButton( - child: badgedIcon(workoutTree, cWidth, cHeight), - padding: EdgeInsets.only(left: 0.0, bottom: 0), - shape: getShape(workoutTree), - onPressed: () => menuClick(workoutTree, menuBloc, context), - ), - Positioned( - top: workoutTree.name.length > 15 ? - workoutTree.fontSize > 25 ? 130 : 140 : - workoutTree.fontSize > 25 ? 165 : 175, - left: 8, - child: Container( - height: cWidth * .95, - width: 280, - child: InkWell( - onTap: () => menuClick(workoutTree, menuBloc, context), - child: Text(workoutTree.name, - maxLines: 2, - style: GoogleFonts.archivoBlack( - color: workoutTree.color, - fontSize: workoutTree.fontSize, - ), - ), - highlightColor: workoutTree.color, - ), - color: Colors.transparent, - ), - ), - ])))); - }); - SliverGrid sliverList = SliverGrid( delegate: SliverChildListDelegate(_columnChildren), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 1, - mainAxisSpacing: 8.0, - crossAxisSpacing: 10.0, - childAspectRatio: cWidth > 375 ? 1.8 : 2.0, + mainAxisSpacing: 5.0, + crossAxisSpacing: 5.0, + childAspectRatio: 2, )); - return sliverList; } @@ -114,8 +235,7 @@ class MenuPageWidget extends StatelessWidget with Trans { if (Cache().userLoggedIn == null) { Scaffold.of(context).showSnackBar(SnackBar( backgroundColor: Colors.orange, - content: - Text(AppLocalizations.of(context).translate('Please log in'), style: TextStyle(color: Colors.white)))); + content: Text(AppLocalizations.of(context).translate('Please log in'), style: TextStyle(color: Colors.white)))); } else { if (workoutTree.exerciseType.name == "Custom" && Cache().userLoggedIn.admin == 1) { Navigator.of(context).pushNamed('exerciseCustomPage', arguments: workoutTree.exerciseType); @@ -130,11 +250,9 @@ class MenuPageWidget extends StatelessWidget with Trans { bool base = workoutTree.base; dynamic returnCode = (base == true) ? RoundedRectangleBorder( - side: BorderSide(width: 4, color: Colors.orangeAccent), - borderRadius: BorderRadius.all(Radius.circular(12.0))) + side: BorderSide(width: 6, color: Colors.orangeAccent), borderRadius: BorderRadius.all(Radius.circular(24.0))) : RoundedRectangleBorder( - side: BorderSide(width: 1, color: Colors.transparent), - borderRadius: BorderRadius.all(Radius.circular(8.0))); + side: BorderSide(width: 1, color: Colors.transparent), borderRadius: BorderRadius.all(Radius.circular(8.0))); return returnCode; } @@ -142,10 +260,10 @@ class MenuPageWidget extends StatelessWidget with Trans { dynamic image; try { image = ClipRRect( - borderRadius: BorderRadius.circular(12.0), + borderRadius: BorderRadius.circular(24), child: Image.asset( workoutTree.imageName, - height: cHeight * 0.85, + height: cHeight, errorBuilder: (context, error, stackTrace) { String url = Cache.mediaUrl + 'images/' + workoutTree.imageName.substring(11); Widget image = FadeInImage.assetNetwork( diff --git a/pubspec.yaml b/pubspec.yaml index 8bf9eca..5bdc46e 100644 --- a/pubspec.yaml +++ b/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. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.1.2+35 +version: 1.1.2+36 environment: sdk: ">=2.10.0 <3.0.0"