From c69c639facce8b6a1677a61460a34deb978b40f6 Mon Sep 17 00:00:00 2001 From: Abhishek Saini <78199221+Abhisheksainii@users.noreply.github.com> Date: Sat, 23 Dec 2023 14:28:38 +0530 Subject: [PATCH] fix(drift): built a model for exercise and fixes in fromSql type converter --- flatpak/scripts/flatpak_packager.dart | 46 ++- flatpak/scripts/flatpak_shared.dart | 55 ++- flatpak/scripts/manifest_generator.dart | 18 +- integration_test/1_dashboard.dart | 9 +- integration_test/2_workout.dart | 3 +- integration_test/3_gym_mode.dart | 6 +- integration_test/4_measurements.dart | 3 +- integration_test/make_screenshots_test.dart | 27 +- .../exercise_DB/exercise_database.dart | 12 +- .../exercise_DB/exercise_database.g.dart | 170 +++++--- lib/database/exercise_DB/type_converters.dart | 82 +++- lib/exceptions/http_exception.dart | 5 +- lib/helpers/charts.dart | 4 +- lib/helpers/exercises/forms.dart | 6 +- lib/helpers/json.dart | 3 +- lib/helpers/misc.dart | 4 +- lib/helpers/platform.dart | 3 +- lib/helpers/ui.dart | 9 +- lib/main.dart | 32 +- lib/models/body_weight/weight_entry.dart | 3 +- lib/models/body_weight/weight_entry.g.dart | 3 +- lib/models/exercises/alias.dart | 4 +- lib/models/exercises/alias.g.dart | 4 +- lib/models/exercises/base.dart | 23 +- lib/models/exercises/base.g.dart | 36 +- lib/models/exercises/category.dart | 3 +- lib/models/exercises/category.g.dart | 3 +- lib/models/exercises/comment.dart | 5 +- lib/models/exercises/comment.g.dart | 2 +- lib/models/exercises/equipment.dart | 3 +- lib/models/exercises/exercise_base_data.dart | 30 ++ .../exercises/exercise_base_data.freezed.dart | 380 ++++++++++++++++++ .../exercises/exercise_base_data.g.dart | 48 +++ lib/models/exercises/exercise_model.dart | 23 ++ .../exercises/exercise_model.freezed.dart | 325 +++++++++++++++ lib/models/exercises/exercise_model.g.dart | 40 ++ lib/models/exercises/image.dart | 3 +- lib/models/exercises/image.g.dart | 3 +- lib/models/exercises/language.dart | 3 +- lib/models/exercises/muscle.dart | 3 +- lib/models/exercises/translation.dart | 13 +- lib/models/exercises/translation.g.dart | 21 +- lib/models/exercises/variation.dart | 3 +- .../measurements/measurement_category.g.dart | 4 +- .../measurements/measurement_entry.dart | 10 +- .../measurements/measurement_entry.g.dart | 3 +- lib/models/nutrition/image.dart | 3 +- lib/models/nutrition/image.g.dart | 3 +- lib/models/nutrition/ingredient.dart | 15 +- lib/models/nutrition/ingredient.g.dart | 3 +- .../nutrition/ingredient_weight_unit.g.dart | 6 +- lib/models/nutrition/log.dart | 8 +- lib/models/nutrition/log.g.dart | 9 +- lib/models/nutrition/meal.dart | 6 +- lib/models/nutrition/meal_item.dart | 3 +- lib/models/nutrition/nutritional_plan.dart | 27 +- lib/models/nutrition/nutritional_plan.g.dart | 3 +- lib/models/nutrition/nutritional_values.dart | 4 +- lib/models/nutrition/weight_unit.dart | 3 +- lib/models/nutrition/weight_unit.g.dart | 3 +- lib/models/user/profile.dart | 3 +- lib/models/user/profile.g.dart | 7 +- lib/models/workouts/day.dart | 3 +- lib/models/workouts/log.dart | 7 +- lib/models/workouts/repetition_unit.dart | 3 +- lib/models/workouts/repetition_unit.g.dart | 3 +- lib/models/workouts/session.dart | 15 +- lib/models/workouts/session.g.dart | 12 +- lib/models/workouts/set.dart | 4 +- lib/models/workouts/setting.dart | 16 +- lib/models/workouts/weight_unit.dart | 3 +- lib/models/workouts/weight_unit.g.dart | 3 +- lib/models/workouts/workout_plan.dart | 10 +- lib/models/workouts/workout_plan.g.dart | 3 +- lib/providers/add_exercise.dart | 29 +- lib/providers/auth.dart | 17 +- lib/providers/base_provider.dart | 3 +- lib/providers/body_weight.dart | 6 +- lib/providers/exercises.dart | 136 ++++--- lib/providers/gallery.dart | 12 +- lib/providers/measurement.dart | 28 +- lib/providers/nutrition.dart | 42 +- lib/providers/user.dart | 3 +- lib/providers/workout_plans.dart | 80 ++-- lib/screens/add_exercise_screen.dart | 22 +- lib/screens/auth_screen.dart | 54 ++- lib/screens/exercise_screen.dart | 7 +- lib/screens/exercises_screen.dart | 3 +- lib/screens/form_screen.dart | 3 +- lib/screens/home_tabs_screen.dart | 3 +- lib/screens/measurement_entries_screen.dart | 21 +- lib/screens/nutritional_diary_screen.dart | 6 +- lib/screens/nutritional_plan_screen.dart | 14 +- lib/screens/nutritional_plans_screen.dart | 3 +- lib/screens/workout_plan_screen.dart | 14 +- lib/screens/workout_plans_screen.dart | 3 +- lib/theme/theme.dart | 8 +- .../add_exercise_dropdown_button.dart | 6 +- .../add_exercise_multiselect_button.dart | 11 +- .../add_exercise/add_exercise_text_area.dart | 6 +- .../mixins/image_picker_mixin.dart | 9 +- lib/widgets/add_exercise/preview_images.dart | 11 +- .../add_exercise/steps/step1basics.dart | 20 +- .../add_exercise/steps/step2variations.dart | 20 +- .../add_exercise/steps/step3description.dart | 3 +- .../add_exercise/steps/step4translations.dart | 10 +- .../add_exercise/steps/step5images.dart | 6 +- lib/widgets/core/about.dart | 22 +- lib/widgets/core/app_bar.dart | 12 +- lib/widgets/core/core.dart | 3 +- lib/widgets/dashboard/calendar.dart | 23 +- lib/widgets/dashboard/widgets.dart | 68 +++- lib/widgets/exercises/exercises.dart | 29 +- lib/widgets/exercises/filter_modal.dart | 9 +- lib/widgets/exercises/filter_row.dart | 13 +- lib/widgets/exercises/forms.dart | 6 +- lib/widgets/exercises/list_tile.dart | 10 +- lib/widgets/exercises/videos.dart | 3 +- lib/widgets/gallery/forms.dart | 9 +- lib/widgets/gallery/overview.dart | 15 +- lib/widgets/measurements/categories.dart | 3 +- lib/widgets/measurements/categories_card.dart | 4 +- lib/widgets/measurements/charts.dart | 19 +- lib/widgets/measurements/entries.dart | 10 +- lib/widgets/measurements/forms.dart | 47 ++- lib/widgets/nutrition/charts.dart | 21 +- lib/widgets/nutrition/forms.dart | 64 ++- lib/widgets/nutrition/helpers.dart | 3 +- lib/widgets/nutrition/meal.dart | 40 +- .../nutrition/nutritional_diary_detail.dart | 70 ++-- .../nutrition/nutritional_plan_detail.dart | 67 ++- .../nutrition/nutritional_plans_list.dart | 21 +- lib/widgets/nutrition/widgets.dart | 50 ++- lib/widgets/user/forms.dart | 10 +- lib/widgets/weight/entries_list.dart | 11 +- lib/widgets/weight/forms.dart | 15 +- lib/widgets/workouts/app_bar.dart | 3 +- lib/widgets/workouts/charts.dart | 16 +- lib/widgets/workouts/day.dart | 43 +- lib/widgets/workouts/forms.dart | 127 ++++-- lib/widgets/workouts/gym_mode.dart | 104 +++-- lib/widgets/workouts/log.dart | 16 +- lib/widgets/workouts/workout_plan_detail.dart | 3 +- lib/widgets/workouts/workout_plans_list.dart | 26 +- pubspec.lock | 16 + pubspec.yaml | 4 +- test/auth/auth_provider_test.dart | 24 +- test/auth/auth_screen_test.dart | 6 +- test/exercises/contribute_exercise_test.dart | 15 +- .../contribute_exercise_test.mocks.dart | 13 +- .../exercise_provider_load_test.dart | 17 +- test/exercises/exercise_provider_test.dart | 82 ++-- .../exercises_detail_widget_test.dart | 18 +- test/gallery/gallery_form_test.dart | 12 +- test/gallery/gallery_form_test.mocks.dart | 16 +- test/gallery/gallery_provider_test.dart | 3 +- test/gallery/gallery_screen_test.dart | 18 +- test/gallery/gallery_screen_test.mocks.dart | 16 +- .../measurement_categories_screen_test.dart | 31 +- ...surement_categories_screen_test.mocks.dart | 16 +- .../measurement_category_test.dart | 9 +- .../measurement_entries_screen_test.dart | 23 +- test/measurements/measurement_entry_test.dart | 6 +- .../measurement_provider_test.dart | 83 ++-- .../measurement_provider_test.mocks.dart | 16 +- test/nutrition/nutrition_provider_test.dart | 9 +- test/nutrition/nutritional_diary_test.dart | 15 +- .../nutrition/nutritional_meal_form_test.dart | 3 +- .../nutritional_meal_form_test.mocks.dart | 43 +- .../nutritional_meal_item_form_test.dart | 44 +- .../nutrition/nutritional_plan_form_test.dart | 21 +- .../nutritional_plan_form_test.mocks.dart | 43 +- .../nutritional_plan_model_test.dart | 9 +- .../nutritional_plan_screen_test.dart | 9 +- .../nutritional_plan_screen_test.mocks.dart | 84 ++-- .../nutritional_plans_screen_test.dart | 15 +- .../nutritional_plans_screen_test.mocks.dart | 88 ++-- .../nutritional_values_class_test.dart | 15 +- test/other/base_provider_test.dart | 33 +- test/other/base_provider_test.mocks.dart | 31 +- test/user/provider_test.mocks.dart | 16 +- test/utils.dart | 3 +- test/weight/weight_model_test.dart | 21 +- test/weight/weight_provider_test.dart | 23 +- test/weight/weight_provider_test.mocks.dart | 16 +- test/weight/weight_screen_test.dart | 15 +- test/weight/weight_screen_test.mocks.dart | 19 +- test/workout/gym_mode_screen_test.dart | 9 +- test/workout/gym_mode_screen_test.mocks.dart | 48 ++- test/workout/plate_calculator_test.dart | 6 +- .../repetition_unit_form_widget_test.dart | 6 +- ...epetition_unit_form_widget_test.mocks.dart | 61 ++- .../workout/weight_unit_form_widget_test.dart | 3 +- .../weight_unit_form_widget_test.mocks.dart | 19 +- test/workout/workout_day_form_test.dart | 15 +- test/workout/workout_day_form_test.mocks.dart | 61 ++- test/workout/workout_form_test.dart | 47 ++- test/workout/workout_form_test.mocks.dart | 61 ++- test/workout/workout_plan_model_test.dart | 9 +- test/workout/workout_plan_screen_test.dart | 12 +- .../workout_plan_screen_test.mocks.dart | 16 +- test/workout/workout_plans_screen_test.dart | 27 +- .../workout_plans_screen_test.mocks.dart | 16 +- test/workout/workout_provider_test.dart | 33 +- test/workout/workout_provider_test.mocks.dart | 16 +- test/workout/workout_set_form_test.dart | 15 +- test/workout/workout_set_form_test.mocks.dart | 106 +++-- test_data/body_weight.dart | 6 +- test_data/exercises.dart | 29 +- test_data/measurements.dart | 21 +- test_data/workouts.dart | 3 +- test_driver/screenshot_driver.dart | 3 +- 212 files changed, 3674 insertions(+), 1313 deletions(-) create mode 100644 lib/models/exercises/exercise_base_data.dart create mode 100644 lib/models/exercises/exercise_base_data.freezed.dart create mode 100644 lib/models/exercises/exercise_base_data.g.dart create mode 100644 lib/models/exercises/exercise_model.dart create mode 100644 lib/models/exercises/exercise_model.freezed.dart create mode 100644 lib/models/exercises/exercise_model.g.dart diff --git a/flatpak/scripts/flatpak_packager.dart b/flatpak/scripts/flatpak_packager.dart index 5346a605..36b5e4a0 100644 --- a/flatpak/scripts/flatpak_packager.dart +++ b/flatpak/scripts/flatpak_packager.dart @@ -18,7 +18,8 @@ void main(List arguments) async { 'You must run this script with a metadata file argument, using the --meta flag.'); } if (arguments.length == metaIndex + 1) { - throw Exception('The --meta flag must be followed by the path to the metadata file.'); + throw Exception( + 'The --meta flag must be followed by the path to the metadata file.'); } final metaFile = File(arguments[metaIndex + 1]); @@ -30,14 +31,18 @@ void main(List arguments) async { final fetchFromGithub = arguments.contains('--github'); - final outputDir = Directory('${Directory.current.path}/flatpak_generator_exports'); + final outputDir = + Directory('${Directory.current.path}/flatpak_generator_exports'); outputDir.createSync(); - final packageGenerator = PackageGenerator(inputDir: metaFile.parent, meta: meta); + final packageGenerator = + PackageGenerator(inputDir: metaFile.parent, meta: meta); packageGenerator.generatePackage( outputDir, - PackageGenerator.runningOnARM() ? CPUArchitecture.aarch64 : CPUArchitecture.x86_64, + PackageGenerator.runningOnARM() + ? CPUArchitecture.aarch64 + : CPUArchitecture.x86_64, fetchFromGithub, ); } @@ -49,8 +54,8 @@ class PackageGenerator { PackageGenerator({required this.inputDir, required this.meta}); - Future generatePackage( - Directory outputDir, CPUArchitecture arch, bool fetchReleasesFromGithub) async { + Future generatePackage(Directory outputDir, CPUArchitecture arch, + bool fetchReleasesFromGithub) async { final tempDir = outputDir.createTempSync('flutter_generator_temp'); final appId = meta.appId; @@ -85,7 +90,8 @@ class PackageGenerator { } final editedAppDataContent = AppDataModifier.replaceVersions( - origAppDataFile.readAsStringSync(), await meta.getReleases(fetchReleasesFromGithub)); + origAppDataFile.readAsStringSync(), + await meta.getReleases(fetchReleasesFromGithub)); final editedAppDataFile = File('${tempDir.path}/$appId.appdata.xml'); editedAppDataFile.writeAsStringSync(editedAppDataContent); @@ -101,17 +107,21 @@ class PackageGenerator { final destDir = Directory('${tempDir.path}/bin'); destDir.createSync(); - final baseFileName = '${meta.lowercaseAppName}-linux-${arch.flatpakArchCode}'; + final baseFileName = + '${meta.lowercaseAppName}-linux-${arch.flatpakArchCode}'; final packagePath = '${outputDir.absolute.path}/$baseFileName.tar.gz'; - Process.runSync('cp', ['-r', '${buildDir.absolute.path}/.', destDir.absolute.path]); - Process.runSync('tar', ['-czvf', packagePath, '.'], workingDirectory: tempDir.absolute.path); + Process.runSync( + 'cp', ['-r', '${buildDir.absolute.path}/.', destDir.absolute.path]); + Process.runSync('tar', ['-czvf', packagePath, '.'], + workingDirectory: tempDir.absolute.path); print('Generated $packagePath'); final preShasum = Process.runSync('shasum', ['-a', '256', packagePath]); final sha256 = preShasum.stdout.toString().split(' ').first; - final shaFile = await File('${outputDir.path}/$baseFileName.sha256').writeAsString(sha256); + final shaFile = await File('${outputDir.path}/$baseFileName.sha256') + .writeAsString(sha256); print('Generated ${shaFile.path}'); shaByArch.putIfAbsent(arch, () => sha256); @@ -128,17 +138,21 @@ class PackageGenerator { // updates releases in ${appName}.appdata.xml class AppDataModifier { - static String replaceVersions(String origAppDataContent, List versions) { - final joinedReleases = - versions.map((v) => '\t\t').join('\n'); - final releasesSection = '\n$joinedReleases\n\t'; //todo check this + static String replaceVersions( + String origAppDataContent, List versions) { + final joinedReleases = versions + .map((v) => '\t\t') + .join('\n'); + final releasesSection = + '\n$joinedReleases\n\t'; //todo check this if (origAppDataContent.contains('') .replaceFirst(RegExp(''), releasesSection) .replaceAll('<~>', '\n'); } else { - return origAppDataContent.replaceFirst('', '\n\t$releasesSection\n'); + return origAppDataContent.replaceFirst( + '', '\n\t$releasesSection\n'); } } } diff --git a/flatpak/scripts/flatpak_shared.dart b/flatpak/scripts/flatpak_shared.dart index 4e16b65f..223387d2 100644 --- a/flatpak/scripts/flatpak_shared.dart +++ b/flatpak/scripts/flatpak_shared.dart @@ -43,8 +43,9 @@ class Icon { _fileExtension = path.split('.').last; } - String getFilename(String appId) => - (type == _symbolicType) ? '$appId-symbolic.$_fileExtension' : '$appId.$_fileExtension'; + String getFilename(String appId) => (type == _symbolicType) + ? '$appId-symbolic.$_fileExtension' + : '$appId.$_fileExtension'; } class GithubReleases { @@ -73,7 +74,8 @@ class GithubReleases { final releaseJsonContent = (await http.get(Uri( scheme: 'https', host: 'api.github.com', - path: '/repos/$githubReleaseOrganization/$githubReleaseProject/releases'))) + path: + '/repos/$githubReleaseOrganization/$githubReleaseProject/releases'))) .body; final decodedJson = jsonDecode(releaseJsonContent) as List; @@ -84,8 +86,10 @@ class GithubReleases { await Future.forEach(decodedJson, (dynamic releaseDynamic) async { final releaseMap = releaseDynamic as Map; - final releaseDateAndTime = DateTime.parse(releaseMap['published_at'] as String); - final releaseDateString = releaseDateAndTime.toIso8601String().split('T').first; + final releaseDateAndTime = + DateTime.parse(releaseMap['published_at'] as String); + final releaseDateString = + releaseDateAndTime.toIso8601String().split('T').first; if (latestReleaseAssetDate == null || (latestReleaseAssetDate?.compareTo(releaseDateAndTime) == -1)) { @@ -96,7 +100,8 @@ class GithubReleases { } } - releases.add(Release(version: releaseMap['name'] as String, date: releaseDateString)); + releases.add(Release( + version: releaseMap['name'] as String, date: releaseDateString)); }); if (releases.isNotEmpty) { @@ -115,7 +120,8 @@ class GithubReleases { final downloadUrl = amMap['browser_download_url'] as String; final filename = amMap['name'] as String; final fileExtension = filename.substring(filename.indexOf('.') + 1); - final filenameWithoutExtension = filename.substring(0, filename.indexOf('.')); + final filenameWithoutExtension = + filename.substring(0, filename.indexOf('.')); final arch = filenameWithoutExtension.endsWith('aarch64') ? CPUArchitecture.aarch64 @@ -212,7 +218,8 @@ class FlatpakMeta { : _localReleases = localReleases, _localReleaseAssets = localReleaseAssets { if (githubReleaseOrganization != null && githubReleaseProject != null) { - _githubReleases = GithubReleases(githubReleaseOrganization!, githubReleaseProject!); + _githubReleases = + GithubReleases(githubReleaseOrganization!, githubReleaseProject!); } } @@ -225,13 +232,15 @@ class FlatpakMeta { return await _githubReleases!.getReleases(); } else { if (_localReleases == null) { - throw Exception('Metadata must include releases if not fetching releases from Github.'); + throw Exception( + 'Metadata must include releases if not fetching releases from Github.'); } return _localReleases!; } } - Future?> getReleaseAssets(bool fetchReleasesFromGithub) async { + Future?> getReleaseAssets( + bool fetchReleasesFromGithub) async { if (fetchReleasesFromGithub) { if (_githubReleases == null) { throw Exception( @@ -240,7 +249,8 @@ class FlatpakMeta { return _githubReleases!.getLatestReleaseAssets(); } else { if (_localReleases == null) { - throw Exception('Metadata must include releases if not fetching releases from Github.'); + throw Exception( + 'Metadata must include releases if not fetching releases from Github.'); } return _localReleaseAssets; } @@ -252,13 +262,17 @@ class FlatpakMeta { return FlatpakMeta( appId: json['appId'] as String, lowercaseAppName: json['lowercaseAppName'] as String, - githubReleaseOrganization: json['githubReleaseOrganization'] as String?, + githubReleaseOrganization: + json['githubReleaseOrganization'] as String?, githubReleaseProject: json['githubReleaseProject'] as String?, localReleases: (json['localReleases'] as List?)?.map((dynamic r) { final rMap = r as Map; - return Release(version: rMap['version'] as String, date: rMap['date'] as String); + return Release( + version: rMap['version'] as String, + date: rMap['date'] as String); }).toList(), - localReleaseAssets: (json['localReleaseAssets'] as List?)?.map((dynamic ra) { + localReleaseAssets: + (json['localReleaseAssets'] as List?)?.map((dynamic ra) { final raMap = ra as Map; final archString = raMap['arch'] as String; final arch = (archString == CPUArchitecture.x86_64.flatpakArchCode) @@ -270,8 +284,10 @@ class FlatpakMeta { throw Exception( 'Architecture must be either "${CPUArchitecture.x86_64.flatpakArchCode}" or "${CPUArchitecture.aarch64.flatpakArchCode}"'); } - final tarballPath = '${jsonFile.parent.path}/${raMap['tarballPath'] as String}'; - final preShasum = Process.runSync('shasum', ['-a', '256', tarballPath]); + final tarballPath = + '${jsonFile.parent.path}/${raMap['tarballPath'] as String}'; + final preShasum = + Process.runSync('shasum', ['-a', '256', tarballPath]); final shasum = preShasum.stdout.toString().split(' ').first; if (preShasum.exitCode != 0) { throw Exception(preShasum.stderr); @@ -286,14 +302,17 @@ class FlatpakMeta { appDataPath: json['appDataPath'] as String, desktopPath: json['desktopPath'] as String, icons: (json['icons'] as Map).entries.map((mapEntry) { - return Icon(type: mapEntry.key as String, path: mapEntry.value as String); + return Icon( + type: mapEntry.key as String, path: mapEntry.value as String); }).toList(), freedesktopRuntime: json['freedesktopRuntime'] as String, buildCommandsAfterUnpack: (json['buildCommandsAfterUnpack'] as List?) ?.map((dynamic bc) => bc as String) .toList(), extraModules: json['extraModules'] as List?, - finishArgs: (json['finishArgs'] as List).map((dynamic fa) => fa as String).toList()); + finishArgs: (json['finishArgs'] as List) + .map((dynamic fa) => fa as String) + .toList()); } catch (e) { throw Exception('Could not parse JSON file, due to this error:\n$e'); } diff --git a/flatpak/scripts/manifest_generator.dart b/flatpak/scripts/manifest_generator.dart index da27f860..6d152ba0 100644 --- a/flatpak/scripts/manifest_generator.dart +++ b/flatpak/scripts/manifest_generator.dart @@ -14,7 +14,8 @@ void main(List arguments) async { 'You must run this script with a metadata file argument, using the --meta flag.'); } if (arguments.length == metaIndex + 1) { - throw Exception('The --meta flag must be followed by the path to the metadata file.'); + throw Exception( + 'The --meta flag must be followed by the path to the metadata file.'); } final metaFile = File(arguments[metaIndex + 1]); @@ -26,17 +27,20 @@ void main(List arguments) async { final fetchFromGithub = arguments.contains('--github'); - final outputDir = Directory('${Directory.current.path}/flatpak_generator_exports'); + final outputDir = + Directory('${Directory.current.path}/flatpak_generator_exports'); outputDir.createSync(); final manifestGenerator = FlatpakManifestGenerator(meta); - final manifestContent = await manifestGenerator.generateFlatpakManifest(fetchFromGithub); + final manifestContent = + await manifestGenerator.generateFlatpakManifest(fetchFromGithub); final manifestPath = '${outputDir.path}/${meta.appId}.json'; final manifestFile = File(manifestPath); manifestFile.writeAsStringSync(manifestContent); print('Generated $manifestPath'); - final flathubJsonContent = await manifestGenerator.generateFlathubJson(fetchFromGithub); + final flathubJsonContent = + await manifestGenerator.generateFlathubJson(fetchFromGithub); if (flathubJsonContent != null) { final flathubJsonPath = '${outputDir.path}/flathub.json'; final flathubJsonFile = File(flathubJsonPath); @@ -115,7 +119,8 @@ class FlatpakManifestGenerator { const encoder = JsonEncoder.withIndent(' '); - final onlyArchListInput = fetchFromGithub ? _githubArchSupport! : _localArchSupport!; + final onlyArchListInput = + fetchFromGithub ? _githubArchSupport! : _localArchSupport!; final onlyArchList = List.empty(growable: true); for (final e in onlyArchListInput.entries) { @@ -131,7 +136,8 @@ class FlatpakManifestGenerator { } } - void _lazyGenerateArchSupportMap(bool fetchFromGithub, List assets) { + void _lazyGenerateArchSupportMap( + bool fetchFromGithub, List assets) { if (fetchFromGithub) { if (_githubArchSupport == null) { _githubArchSupport = { diff --git a/integration_test/1_dashboard.dart b/integration_test/1_dashboard.dart index 31578858..8c7de80b 100644 --- a/integration_test/1_dashboard.dart +++ b/integration_test/1_dashboard.dart @@ -34,17 +34,20 @@ Widget createDashboardScreen({locale = 'en'}) { } ] }; - when(mockWorkoutProvider.fetchSessionData()).thenAnswer((a) => Future.value(logs)); + when(mockWorkoutProvider.fetchSessionData()) + .thenAnswer((a) => Future.value(logs)); final mockNutritionProvider = MockNutritionPlansProvider(); - when(mockNutritionProvider.currentPlan).thenAnswer((realInvocation) => getNutritionalPlan()); + when(mockNutritionProvider.currentPlan) + .thenAnswer((realInvocation) => getNutritionalPlan()); when(mockNutritionProvider.items).thenReturn([getNutritionalPlan()]); final mockWeightProvider = MockBodyWeightProvider(); when(mockWeightProvider.items).thenReturn(getWeightEntries()); final mockMeasurementProvider = MockMeasurementProvider(); - when(mockMeasurementProvider.categories).thenReturn(getMeasurementCategories()); + when(mockMeasurementProvider.categories) + .thenReturn(getMeasurementCategories()); return MultiProvider( providers: [ diff --git a/integration_test/2_workout.dart b/integration_test/2_workout.dart index 3b6f4fa9..5354ba7d 100644 --- a/integration_test/2_workout.dart +++ b/integration_test/2_workout.dart @@ -15,7 +15,8 @@ Widget createWorkoutDetailScreen({locale = 'en'}) { final mockWorkoutProvider = MockWorkoutPlansProvider(); final workout = getWorkout(); when(mockWorkoutProvider.activePlan).thenReturn(workout); - when(mockWorkoutProvider.fetchAndSetWorkoutPlanFull(1)).thenAnswer((_) => Future.value(workout)); + when(mockWorkoutProvider.fetchAndSetWorkoutPlanFull(1)) + .thenAnswer((_) => Future.value(workout)); return MultiProvider( providers: [ diff --git a/integration_test/3_gym_mode.dart b/integration_test/3_gym_mode.dart index 8ffcbdc2..addc9b32 100644 --- a/integration_test/3_gym_mode.dart +++ b/integration_test/3_gym_mode.dart @@ -20,8 +20,10 @@ Widget createGymModeScreen({locale = 'en'}) { final mockExerciseProvider = MockExercisesProvider(); - when(mockExerciseProvider.findExerciseBaseById(1)).thenReturn(bases[0]); // bench press - when(mockExerciseProvider.findExerciseBaseById(6)).thenReturn(bases[5]); // side raises + when(mockExerciseProvider.findExerciseBaseById(1)) + .thenReturn(bases[0]); // bench press + when(mockExerciseProvider.findExerciseBaseById(6)) + .thenReturn(bases[5]); // side raises //when(mockExerciseProvider.findExerciseBaseById(2)).thenReturn(bases[1]); // crunches //when(mockExerciseProvider.findExerciseBaseById(3)).thenReturn(bases[2]); // dead lift diff --git a/integration_test/4_measurements.dart b/integration_test/4_measurements.dart index 668618ef..4ba6832b 100644 --- a/integration_test/4_measurements.dart +++ b/integration_test/4_measurements.dart @@ -11,7 +11,8 @@ import '../test_data/measurements.dart'; Widget createMeasurementScreen({locale = 'en'}) { final mockMeasurementProvider = MockMeasurementProvider(); - when(mockMeasurementProvider.categories).thenReturn(getMeasurementCategories()); + when(mockMeasurementProvider.categories) + .thenReturn(getMeasurementCategories()); return MultiProvider( providers: [ diff --git a/integration_test/make_screenshots_test.dart b/integration_test/make_screenshots_test.dart index 14891f96..5b1877ae 100644 --- a/integration_test/make_screenshots_test.dart +++ b/integration_test/make_screenshots_test.dart @@ -11,12 +11,14 @@ import '4_measurements.dart'; import '5_nutritional_plan.dart'; import '6_weight.dart'; -Future takeScreenshot(tester, binding, String language, String name) async { +Future takeScreenshot( + tester, binding, String language, String name) async { if (Platform.isAndroid) { await binding.convertFlutterSurfaceToImage(); await tester.pumpAndSettle(); } - final filename = 'fastlane/metadata/android/$language/images/phoneScreenshots/$name.png'; + final filename = + 'fastlane/metadata/android/$language/images/phoneScreenshots/$name.png'; await binding.takeScreenshot(filename); } @@ -60,8 +62,10 @@ void main() { await takeScreenshot(tester, binding, language, '01 - dashboard'); }); - testWidgets('workout detail screen - $language', (WidgetTester tester) async { - await tester.pumpWidget(createWorkoutDetailScreen(locale: languageCode)); + testWidgets('workout detail screen - $language', + (WidgetTester tester) async { + await tester + .pumpWidget(createWorkoutDetailScreen(locale: languageCode)); await tester.tap(find.byType(TextButton)); await tester.pumpAndSettle(); await takeScreenshot(tester, binding, language, '02 - workout detail'); @@ -74,19 +78,24 @@ void main() { await takeScreenshot(tester, binding, language, '03 - gym mode'); }); - testWidgets('measurement screen - $language', (WidgetTester tester) async { + testWidgets('measurement screen - $language', + (WidgetTester tester) async { await tester.pumpWidget(createMeasurementScreen(locale: languageCode)); await takeScreenshot(tester, binding, language, '04 - measurements'); }); - testWidgets('nutritional plan detail - $language', (WidgetTester tester) async { - await tester.pumpWidget(createNutritionalPlanScreen(locale: languageCode)); + testWidgets('nutritional plan detail - $language', + (WidgetTester tester) async { + await tester + .pumpWidget(createNutritionalPlanScreen(locale: languageCode)); await tester.tap(find.byType(TextButton)); await tester.pumpAndSettle(); - await takeScreenshot(tester, binding, language, '05 - nutritional plan'); + await takeScreenshot( + tester, binding, language, '05 - nutritional plan'); }); - testWidgets('body weight screen - $language', (WidgetTester tester) async { + testWidgets('body weight screen - $language', + (WidgetTester tester) async { await tester.pumpWidget(createWeightScreen(locale: languageCode)); await tester.pumpAndSettle(); await takeScreenshot(tester, binding, language, '06 - weight'); diff --git a/lib/database/exercise_DB/exercise_database.dart b/lib/database/exercise_DB/exercise_database.dart index c8e0a8e8..0a913b80 100644 --- a/lib/database/exercise_DB/exercise_database.dart +++ b/lib/database/exercise_DB/exercise_database.dart @@ -17,12 +17,16 @@ part 'exercise_database.g.dart'; @DataClassName('ExerciseTable') class ExerciseTableItems extends Table { IntColumn get id => integer().autoIncrement()(); - TextColumn get exercisebase => text().map(const ExerciseBaseConverter()).nullable()(); + TextColumn get exercisebase => + text().map(const ExerciseBaseConverter()).nullable()(); TextColumn get muscle => text().map(const MuscleConverter()).nullable()(); - TextColumn get category => text().map(const ExerciseCategoryConverter()).nullable()(); - TextColumn get variation => text().map(const VariationConverter()).nullable()(); + TextColumn get category => + text().map(const ExerciseCategoryConverter()).nullable()(); + TextColumn get variation => + text().map(const VariationConverter()).nullable()(); TextColumn get language => text().map(const LanguageConverter()).nullable()(); - TextColumn get equipment => text().map(const EquipmentConverter()).nullable()(); + TextColumn get equipment => + text().map(const EquipmentConverter()).nullable()(); DateTimeColumn get expiresIn => dateTime().nullable()(); } diff --git a/lib/database/exercise_DB/exercise_database.g.dart b/lib/database/exercise_DB/exercise_database.g.dart index 6880d80d..636c8d93 100644 --- a/lib/database/exercise_DB/exercise_database.g.dart +++ b/lib/database/exercise_DB/exercise_database.g.dart @@ -11,55 +11,76 @@ class $ExerciseTableItemsTable extends ExerciseTableItems $ExerciseTableItemsTable(this.attachedDatabase, [this._alias]); static const VerificationMeta _idMeta = const VerificationMeta('id'); @override - late final GeneratedColumn id = GeneratedColumn('id', aliasedName, false, + late final GeneratedColumn id = GeneratedColumn( + 'id', aliasedName, false, hasAutoIncrement: true, type: DriftSqlType.int, requiredDuringInsert: false, - defaultConstraints: GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT')); - static const VerificationMeta _exercisebaseMeta = const VerificationMeta('exercisebase'); + defaultConstraints: + GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT')); + static const VerificationMeta _exercisebaseMeta = + const VerificationMeta('exercisebase'); @override - late final GeneratedColumnWithTypeConverter exercisebase = - GeneratedColumn('exercisebase', aliasedName, true, + late final GeneratedColumnWithTypeConverter + exercisebase = GeneratedColumn('exercisebase', aliasedName, true, type: DriftSqlType.string, requiredDuringInsert: false) - .withConverter($ExerciseTableItemsTable.$converterexercisebasen); + .withConverter( + $ExerciseTableItemsTable.$converterexercisebasen); static const VerificationMeta _muscleMeta = const VerificationMeta('muscle'); @override - late final GeneratedColumnWithTypeConverter muscle = GeneratedColumn( - 'muscle', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false) - .withConverter($ExerciseTableItemsTable.$convertermusclen); - static const VerificationMeta _categoryMeta = const VerificationMeta('category'); - @override - late final GeneratedColumnWithTypeConverter category = - GeneratedColumn('category', aliasedName, true, + late final GeneratedColumnWithTypeConverter muscle = + GeneratedColumn('muscle', aliasedName, true, type: DriftSqlType.string, requiredDuringInsert: false) - .withConverter($ExerciseTableItemsTable.$convertercategoryn); - static const VerificationMeta _variationMeta = const VerificationMeta('variation'); + .withConverter($ExerciseTableItemsTable.$convertermusclen); + static const VerificationMeta _categoryMeta = + const VerificationMeta('category'); + @override + late final GeneratedColumnWithTypeConverter + category = GeneratedColumn('category', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false) + .withConverter( + $ExerciseTableItemsTable.$convertercategoryn); + static const VerificationMeta _variationMeta = + const VerificationMeta('variation'); @override late final GeneratedColumnWithTypeConverter variation = GeneratedColumn('variation', aliasedName, true, type: DriftSqlType.string, requiredDuringInsert: false) - .withConverter($ExerciseTableItemsTable.$convertervariationn); - static const VerificationMeta _languageMeta = const VerificationMeta('language'); + .withConverter( + $ExerciseTableItemsTable.$convertervariationn); + static const VerificationMeta _languageMeta = + const VerificationMeta('language'); @override - late final GeneratedColumnWithTypeConverter language = GeneratedColumn( - 'language', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false) - .withConverter($ExerciseTableItemsTable.$converterlanguagen); - static const VerificationMeta _equipmentMeta = const VerificationMeta('equipment'); + late final GeneratedColumnWithTypeConverter language = + GeneratedColumn('language', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false) + .withConverter( + $ExerciseTableItemsTable.$converterlanguagen); + static const VerificationMeta _equipmentMeta = + const VerificationMeta('equipment'); @override late final GeneratedColumnWithTypeConverter equipment = GeneratedColumn('equipment', aliasedName, true, type: DriftSqlType.string, requiredDuringInsert: false) - .withConverter($ExerciseTableItemsTable.$converterequipmentn); - static const VerificationMeta _expiresInMeta = const VerificationMeta('expiresIn'); + .withConverter( + $ExerciseTableItemsTable.$converterequipmentn); + static const VerificationMeta _expiresInMeta = + const VerificationMeta('expiresIn'); @override late final GeneratedColumn expiresIn = GeneratedColumn( 'expires_in', aliasedName, true, type: DriftSqlType.dateTime, requiredDuringInsert: false); @override - List get $columns => - [id, exercisebase, muscle, category, variation, language, equipment, expiresIn]; + List get $columns => [ + id, + exercisebase, + muscle, + category, + variation, + language, + equipment, + expiresIn + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -80,8 +101,8 @@ class $ExerciseTableItemsTable extends ExerciseTableItems context.handle(_languageMeta, const VerificationResult.success()); context.handle(_equipmentMeta, const VerificationResult.success()); if (data.containsKey('expires_in')) { - context.handle( - _expiresInMeta, expiresIn.isAcceptableOrUnknown(data['expires_in']!, _expiresInMeta)); + context.handle(_expiresInMeta, + expiresIn.isAcceptableOrUnknown(data['expires_in']!, _expiresInMeta)); } return context; } @@ -92,20 +113,26 @@ class $ExerciseTableItemsTable extends ExerciseTableItems ExerciseTable map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return ExerciseTable( - id: attachedDatabase.typeMapping.read(DriftSqlType.int, data['${effectivePrefix}id'])!, - exercisebase: $ExerciseTableItemsTable.$converterexercisebasen.fromSql(attachedDatabase - .typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}exercisebase'])), + id: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}id'])!, + exercisebase: $ExerciseTableItemsTable.$converterexercisebasen.fromSql( + attachedDatabase.typeMapping.read( + DriftSqlType.string, data['${effectivePrefix}exercisebase'])), muscle: $ExerciseTableItemsTable.$convertermusclen.fromSql( - attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}muscle'])), - category: $ExerciseTableItemsTable.$convertercategoryn.fromSql(attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}category'])), - variation: $ExerciseTableItemsTable.$convertervariationn.fromSql(attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}variation'])), - language: $ExerciseTableItemsTable.$converterlanguagen.fromSql(attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}language'])), - equipment: $ExerciseTableItemsTable.$converterequipmentn.fromSql(attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}equipment'])), + attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}muscle'])), + category: $ExerciseTableItemsTable.$convertercategoryn.fromSql( + attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}category'])), + variation: $ExerciseTableItemsTable.$convertervariationn.fromSql( + attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}variation'])), + language: $ExerciseTableItemsTable.$converterlanguagen.fromSql( + attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}language'])), + equipment: $ExerciseTableItemsTable.$converterequipmentn.fromSql( + attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}equipment'])), expiresIn: attachedDatabase.typeMapping .read(DriftSqlType.dateTime, data['${effectivePrefix}expires_in']), ); @@ -116,23 +143,28 @@ class $ExerciseTableItemsTable extends ExerciseTableItems return $ExerciseTableItemsTable(attachedDatabase, alias); } - static TypeConverter $converterexercisebase = const ExerciseBaseConverter(); + static TypeConverter $converterexercisebase = + const ExerciseBaseConverter(); static TypeConverter $converterexercisebasen = NullAwareTypeConverter.wrap($converterexercisebase); - static TypeConverter $convertermuscle = const MuscleConverter(); + static TypeConverter $convertermuscle = + const MuscleConverter(); static TypeConverter $convertermusclen = NullAwareTypeConverter.wrap($convertermuscle); static TypeConverter $convertercategory = const ExerciseCategoryConverter(); static TypeConverter $convertercategoryn = NullAwareTypeConverter.wrap($convertercategory); - static TypeConverter $convertervariation = const VariationConverter(); + static TypeConverter $convertervariation = + const VariationConverter(); static TypeConverter $convertervariationn = NullAwareTypeConverter.wrap($convertervariation); - static TypeConverter $converterlanguage = const LanguageConverter(); + static TypeConverter $converterlanguage = + const LanguageConverter(); static TypeConverter $converterlanguagen = NullAwareTypeConverter.wrap($converterlanguage); - static TypeConverter $converterequipment = const EquipmentConverter(); + static TypeConverter $converterequipment = + const EquipmentConverter(); static TypeConverter $converterequipmentn = NullAwareTypeConverter.wrap($converterequipment); } @@ -192,18 +224,31 @@ class ExerciseTable extends DataClass implements Insertable { ExerciseTableItemsCompanion toCompanion(bool nullToAbsent) { return ExerciseTableItemsCompanion( id: Value(id), - exercisebase: - exercisebase == null && nullToAbsent ? const Value.absent() : Value(exercisebase), - muscle: muscle == null && nullToAbsent ? const Value.absent() : Value(muscle), - category: category == null && nullToAbsent ? const Value.absent() : Value(category), - variation: variation == null && nullToAbsent ? const Value.absent() : Value(variation), - language: language == null && nullToAbsent ? const Value.absent() : Value(language), - equipment: equipment == null && nullToAbsent ? const Value.absent() : Value(equipment), - expiresIn: expiresIn == null && nullToAbsent ? const Value.absent() : Value(expiresIn), + exercisebase: exercisebase == null && nullToAbsent + ? const Value.absent() + : Value(exercisebase), + muscle: + muscle == null && nullToAbsent ? const Value.absent() : Value(muscle), + category: category == null && nullToAbsent + ? const Value.absent() + : Value(category), + variation: variation == null && nullToAbsent + ? const Value.absent() + : Value(variation), + language: language == null && nullToAbsent + ? const Value.absent() + : Value(language), + equipment: equipment == null && nullToAbsent + ? const Value.absent() + : Value(equipment), + expiresIn: expiresIn == null && nullToAbsent + ? const Value.absent() + : Value(expiresIn), ); } - factory ExerciseTable.fromJson(Map json, {ValueSerializer? serializer}) { + factory ExerciseTable.fromJson(Map json, + {ValueSerializer? serializer}) { serializer ??= driftRuntimeOptions.defaultSerializer; return ExerciseTable( id: serializer.fromJson(json['id']), @@ -242,7 +287,8 @@ class ExerciseTable extends DataClass implements Insertable { Value expiresIn = const Value.absent()}) => ExerciseTable( id: id ?? this.id, - exercisebase: exercisebase.present ? exercisebase.value : this.exercisebase, + exercisebase: + exercisebase.present ? exercisebase.value : this.exercisebase, muscle: muscle.present ? muscle.value : this.muscle, category: category.present ? category.value : this.category, variation: variation.present ? variation.value : this.variation, @@ -266,8 +312,8 @@ class ExerciseTable extends DataClass implements Insertable { } @override - int get hashCode => - Object.hash(id, exercisebase, muscle, category, variation, language, equipment, expiresIn); + int get hashCode => Object.hash(id, exercisebase, muscle, category, variation, + language, equipment, expiresIn); @override bool operator ==(Object other) => identical(this, other) || @@ -363,7 +409,8 @@ class ExerciseTableItemsCompanion extends UpdateCompanion { if (exercisebase.present) { final converter = $ExerciseTableItemsTable.$converterexercisebasen; - map['exercisebase'] = Variable(converter.toSql(exercisebase.value)); + map['exercisebase'] = + Variable(converter.toSql(exercisebase.value)); } if (muscle.present) { final converter = $ExerciseTableItemsTable.$convertermusclen; @@ -414,7 +461,8 @@ class ExerciseTableItemsCompanion extends UpdateCompanion { abstract class _$ExerciseDatabase extends GeneratedDatabase { _$ExerciseDatabase(QueryExecutor e) : super(e); - late final $ExerciseTableItemsTable exerciseTableItems = $ExerciseTableItemsTable(this); + late final $ExerciseTableItemsTable exerciseTableItems = + $ExerciseTableItemsTable(this); @override Iterable> get allTables => allSchemaEntities.whereType>(); diff --git a/lib/database/exercise_DB/type_converters.dart b/lib/database/exercise_DB/type_converters.dart index 74a039de..fa4f3378 100644 --- a/lib/database/exercise_DB/type_converters.dart +++ b/lib/database/exercise_DB/type_converters.dart @@ -1,19 +1,93 @@ import 'dart:convert'; import 'package:drift/drift.dart'; +import 'package:flutter/src/widgets/framework.dart'; +// import 'package:path/path.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/exceptions/no_such_entry_exception.dart'; +import 'package:wger/models/exercises/alias.dart'; import 'package:wger/models/exercises/base.dart'; import 'package:wger/models/exercises/category.dart'; +import 'package:wger/models/exercises/comment.dart'; import 'package:wger/models/exercises/equipment.dart'; +import 'package:wger/models/exercises/image.dart'; import 'package:wger/models/exercises/language.dart'; import 'package:wger/models/exercises/muscle.dart'; +import 'package:wger/models/exercises/translation.dart'; import 'package:wger/models/exercises/variation.dart'; +import 'package:wger/models/exercises/video.dart'; +import 'package:wger/providers/auth.dart'; +import 'package:wger/providers/base_provider.dart'; + +// List _languages = []; +// Future fetchAndSetLanguages(BuildContext context) async { +// final baseProvider= WgerBaseProvider(Provider.of(context, listen: false)) +// final languageData = await baseProvider.fetchPaginated(baseProvider.makeUrl('language')); + +// for (final language in languageData) { +// _languages.add(Language.fromJson(language)); +// } +// } + +// Language findLanguageById(int id) { +// return _languages.firstWhere( +// (language) => language.id == id, +// orElse: () => throw NoSuchEntryException(), +// ); +// } class ExerciseBaseConverter extends TypeConverter { const ExerciseBaseConverter(); @override ExerciseBase fromSql(String fromDb) { - return ExerciseBase.fromJson(json.decode(fromDb) as Map); + final Map baseData = json.decode(fromDb); + + final category = ExerciseCategory.fromJson(baseData['categories']); + final musclesPrimary = + baseData['muscless'].map((e) => Muscle.fromJson(e)).toList(); + final musclesSecondary = + baseData['musclesSecondary'].map((e) => Muscle.fromJson(e)).toList(); + final equipment = + baseData['equipments'].map((e) => Equipment.fromJson(e)).toList(); + final images = + baseData['images'].map((e) => ExerciseImage.fromJson(e)).toList(); + final videos = baseData['videos'].map((e) => Video.fromJson(e)).toList(); + + final List exercises = []; + for (final exerciseData in baseData['translations']) { + final exercise = Translation( + id: exerciseData['id'], + name: exerciseData['name'], + description: exerciseData['description'], + baseId: baseData['id'], + ); + exercise.aliases = exerciseData['aliases'] + .map((e) => Alias.fromJson(e)) + .toList() + .cast(); + exercise.notes = exerciseData['notes'] + .map((e) => Comment.fromJson(e)) + .toList() + .cast(); + exercise.language = Language.fromJson(exerciseData['languageObj']); + exercises.add(exercise); + } + + final exerciseBase = ExerciseBase( + id: baseData['id'], + uuid: baseData['uuid'], + created: null, + //creationDate: toDate(baseData['creation_date']), + musclesSecondary: musclesSecondary.cast(), + muscles: musclesPrimary.cast(), + equipment: equipment.cast(), + category: category, + images: images.cast(), + exercises: exercises, + videos: videos.cast