Merge branch 'feature/exercise-crowdsourcing' of https://github.com/wger-project/flutter into feature/exercise-crowdsourcing

This commit is contained in:
Yair Chen
2021-09-14 12:36:51 +03:00
24 changed files with 657 additions and 446 deletions

View File

@@ -1,9 +1,6 @@
name: Continous Integration
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
on: [pull_request, push]
jobs:
test:
runs-on: ubuntu-20.04

View File

@@ -20,11 +20,10 @@ import 'package:json_annotation/json_annotation.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/exercise.dart';
import 'package:wger/models/exercises/image.dart';
import 'package:wger/models/exercises/muscle.dart';
import 'exercise2.dart';
part 'base.g.dart';
@JsonSerializable(explicitToJson: true)
@@ -69,7 +68,7 @@ class ExerciseBase {
List<ExerciseImage> images = [];
@JsonKey(ignore: true)
List<Exercise2> exercises = [];
List<Exercise> exercises = [];
ExerciseBase(
{required this.id,

View File

@@ -17,22 +17,33 @@
*/
import 'package:json_annotation/json_annotation.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';
part 'exercise.g.dart';
@JsonSerializable(explicitToJson: true)
@JsonSerializable()
class Exercise {
@JsonKey(required: true)
final int id;
@JsonKey(required: true, name: 'exercise_base')
final int baseId;
@JsonKey(required: true)
final String uuid;
@JsonKey(required: true, name: 'language')
final int languageId;
@JsonKey(ignore: true)
late Language language;
@JsonKey(required: true, name: 'creation_date')
final DateTime creationDate;
@@ -42,62 +53,37 @@ class Exercise {
@JsonKey(required: true)
final String description;
@JsonKey(required: false, ignore: true)
late int categoryId;
@JsonKey(ignore: true)
late ExerciseBase base;
@JsonKey(required: true, name: 'category')
late final ExerciseCategory categoryObj;
@JsonKey(required: true)
List<Muscle> muscles = [];
@JsonKey(required: true, name: 'muscles_secondary')
List<Muscle> musclesSecondary = [];
@JsonKey(required: true)
List<Equipment> equipment = [];
@JsonKey(required: true)
List<ExerciseImage> images = [];
@JsonKey(required: true, name: 'comments')
@JsonKey(ignore: true)
List<Comment> tips = [];
Exercise(
{required this.id,
required this.baseId,
required this.uuid,
required this.creationDate,
required this.languageId,
required this.name,
required this.description,
List<Muscle>? muscles,
List<Muscle>? musclesSecondary,
List<Equipment>? equipment,
List<ExerciseImage>? images,
List<Comment>? tips,
ExerciseCategory? category}) {
this.tips = tips ?? [];
this.images = images ?? [];
this.equipment = equipment ?? [];
this.musclesSecondary = musclesSecondary ?? [];
this.muscles = muscles ?? [];
if (category != null) {
this.categoryObj = category;
this.categoryId = category.id;
base,
language}) {
if (base != null) {
this.base = base;
}
if (language != null) {
this.language = language;
}
}
ExerciseImage? get getMainImage {
try {
return images.firstWhere((image) => image.isMain);
} on StateError catch (e) {
return null;
}
}
set category(ExerciseCategory category) {
this.categoryId = category.id;
this.categoryObj = category;
}
ExerciseImage? get getMainImage => base.getMainImage;
ExerciseCategory get category => base.category;
List<ExerciseImage> get images => base.images;
List<Equipment> get equipment => base.equipment;
List<Muscle> get muscles => base.muscles;
List<Muscle> get musclesSecondary => base.musclesSecondary;
// Boilerplate
factory Exercise.fromJson(Map<String, dynamic> json) => _$ExerciseFromJson(json);

View File

@@ -9,51 +9,30 @@ part of 'exercise.dart';
Exercise _$ExerciseFromJson(Map<String, dynamic> json) {
$checkKeys(json, requiredKeys: const [
'id',
'exercise_base',
'uuid',
'language',
'creation_date',
'name',
'description',
'category',
'muscles',
'muscles_secondary',
'equipment',
'images',
'comments'
'description'
]);
return Exercise(
id: json['id'] as int,
baseId: json['exercise_base'] as int,
uuid: json['uuid'] as String,
creationDate: DateTime.parse(json['creation_date'] as String),
languageId: json['language'] as int,
name: json['name'] as String,
description: json['description'] as String,
muscles: (json['muscles'] as List<dynamic>?)
?.map((e) => Muscle.fromJson(e as Map<String, dynamic>))
.toList(),
musclesSecondary: (json['muscles_secondary'] as List<dynamic>?)
?.map((e) => Muscle.fromJson(e as Map<String, dynamic>))
.toList(),
equipment: (json['equipment'] as List<dynamic>?)
?.map((e) => Equipment.fromJson(e as Map<String, dynamic>))
.toList(),
images: (json['images'] as List<dynamic>?)
?.map((e) => ExerciseImage.fromJson(e as Map<String, dynamic>))
.toList(),
tips: (json['comments'] as List<dynamic>?)
?.map((e) => Comment.fromJson(e as Map<String, dynamic>))
.toList(),
)..categoryObj = ExerciseCategory.fromJson(json['category'] as Map<String, dynamic>);
);
}
Map<String, dynamic> _$ExerciseToJson(Exercise instance) => <String, dynamic>{
'id': instance.id,
'exercise_base': instance.baseId,
'uuid': instance.uuid,
'language': instance.languageId,
'creation_date': instance.creationDate.toIso8601String(),
'name': instance.name,
'description': instance.description,
'category': instance.categoryObj.toJson(),
'muscles': instance.muscles.map((e) => e.toJson()).toList(),
'muscles_secondary': instance.musclesSecondary.map((e) => e.toJson()).toList(),
'equipment': instance.equipment.map((e) => e.toJson()).toList(),
'images': instance.images.map((e) => e.toJson()).toList(),
'comments': instance.tips.map((e) => e.toJson()).toList(),
};

View File

@@ -1,104 +0,0 @@
/*
* This file is part of wger Workout Manager <https://github.com/wger-project>.
* Copyright (C) 2020, 2021 wger Team
*
* wger Workout Manager is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:json_annotation/json_annotation.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/muscle.dart';
part 'exercise2.g.dart';
@JsonSerializable(explicitToJson: true)
class Exercise2 {
@JsonKey(required: true)
final int id;
@JsonKey(required: true, name: 'exercise_base')
final int baseId;
@JsonKey(required: true)
final String uuid;
@JsonKey(required: true, name: 'creation_date')
final DateTime creationDate;
@JsonKey(required: true)
final String name;
@JsonKey(required: true)
final String description;
@JsonKey(ignore: true)
late final ExerciseCategory categoryObj;
@JsonKey(ignore: true)
List<Muscle> muscles = [];
@JsonKey(ignore: true)
List<Muscle> musclesSecondary = [];
@JsonKey(ignore: true)
List<Equipment> equipment = [];
@JsonKey(ignore: true)
List<ExerciseImage> images = [];
@JsonKey(ignore: true)
List<Comment> tips = [];
Exercise2(
{required this.id,
required this.baseId,
required this.uuid,
required this.creationDate,
required this.name,
required this.description,
List<Muscle>? muscles,
List<Muscle>? musclesSecondary,
List<Equipment>? equipment,
List<ExerciseImage>? images,
List<Comment>? tips,
ExerciseCategory? category}) {
this.tips = tips ?? [];
this.images = images ?? [];
this.equipment = equipment ?? [];
this.musclesSecondary = musclesSecondary ?? [];
this.muscles = muscles ?? [];
if (category != null) {
this.categoryObj = category;
}
}
ExerciseImage? get getMainImage {
try {
return images.firstWhere((image) => image.isMain);
} on StateError {
return null;
}
}
set category(ExerciseCategory category) {
this.categoryObj = category;
}
// Boilerplate
factory Exercise2.fromJson(Map<String, dynamic> json) => _$Exercise2FromJson(json);
Map<String, dynamic> toJson() => _$Exercise2ToJson(this);
}

View File

@@ -1,35 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'exercise2.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Exercise2 _$Exercise2FromJson(Map<String, dynamic> json) {
$checkKeys(json, requiredKeys: const [
'id',
'exercise_base',
'uuid',
'creation_date',
'name',
'description'
]);
return Exercise2(
id: json['id'] as int,
baseId: json['exercise_base'] as int,
uuid: json['uuid'] as String,
creationDate: DateTime.parse(json['creation_date'] as String),
name: json['name'] as String,
description: json['description'] as String,
);
}
Map<String, dynamic> _$Exercise2ToJson(Exercise2 instance) => <String, dynamic>{
'id': instance.id,
'exercise_base': instance.baseId,
'uuid': instance.uuid,
'creation_date': instance.creationDate.toIso8601String(),
'name': instance.name,
'description': instance.description,
};

View File

@@ -0,0 +1,47 @@
/*
* This file is part of wger Workout Manager <https://github.com/wger-project>.
* Copyright (C) 2020, 2021 wger Team
*
* wger Workout Manager is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
part 'language.g.dart';
@JsonSerializable()
class Language extends Equatable {
@JsonKey(required: true)
final int id;
@JsonKey(required: true, name: 'short_name')
final String shortName;
@JsonKey(required: true, name: 'full_name')
final String fullName;
const Language({
required this.id,
required this.shortName,
required this.fullName,
});
// Boilerplate
factory Language.fromJson(Map<String, dynamic> json) => _$LanguageFromJson(json);
Map<String, dynamic> toJson() => _$LanguageToJson(this);
@override
List<Object?> get props => [id, shortName, fullName];
}

View File

@@ -0,0 +1,22 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'language.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Language _$LanguageFromJson(Map<String, dynamic> json) {
$checkKeys(json, requiredKeys: const ['id', 'short_name', 'full_name']);
return Language(
id: json['id'] as int,
shortName: json['short_name'] as String,
fullName: json['full_name'] as String,
);
}
Map<String, dynamic> _$LanguageToJson(Language instance) => <String, dynamic>{
'id': instance.id,
'short_name': instance.shortName,
'full_name': instance.fullName,
};

View File

@@ -21,6 +21,7 @@ import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:wger/exceptions/no_such_entry_exception.dart';
@@ -29,18 +30,18 @@ import 'package:wger/models/exercises/base.dart';
import 'package:wger/models/exercises/category.dart';
import 'package:wger/models/exercises/equipment.dart';
import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/exercises/exercise2.dart';
import 'package:wger/models/exercises/language.dart';
import 'package:wger/models/exercises/muscle.dart';
import 'package:wger/providers/base_provider.dart';
class ExercisesProvider with ChangeNotifier {
final WgerBaseProvider baseProvider;
static const daysToCache = 7;
static const EXERCISE_CACHE_DAYS = 7;
static const _exerciseInfoUrlPath = 'exerciseinfo';
static const _exerciseBaseUrlPath = 'exercise-base';
static const _exerciseTranslationUrlPath = 'exercise-translation';
static const _exerciseUrlPath = 'exercise';
static const _exerciseSearchPath = 'exercise/search';
static const _exerciseCommentUrlPath = 'exercisecomment';
@@ -48,12 +49,14 @@ class ExercisesProvider with ChangeNotifier {
static const _categoriesUrlPath = 'exercisecategory';
static const _musclesUrlPath = 'muscle';
static const _equipmentUrlPath = 'equipment';
static const _languageUrlPath = 'language';
List<ExerciseBase> _exerciseBases = [];
List<Exercise> _exercises = [];
List<ExerciseCategory> _categories = [];
List<Muscle> _muscles = [];
List<Equipment> _equipment = [];
List<Language> _languages = [];
Filters? _filters;
Filters? get filters => _filters;
set filters(Filters? newFilters) {
@@ -111,8 +114,7 @@ class ExercisesProvider with ChangeNotifier {
// Filter by exercise category and equipment (REPLACE WITH HTTP REQUEST)
filteredExercises = filteredItems.where((exercise) {
final bool isInAnyCategory =
filters!.exerciseCategories.selected.contains(exercise.categoryObj);
final bool isInAnyCategory = filters!.exerciseCategories.selected.contains(exercise.category);
final bool doesContainAnyEquipment = filters!.equipment.selected.any(
(selectedEquipment) => exercise.equipment.contains(selectedEquipment),
@@ -123,9 +125,18 @@ class ExercisesProvider with ChangeNotifier {
}).toList();
}
/// Clears all lists
clear() {
_equipment = [];
_muscles = [];
_categories = [];
_languages = [];
_exerciseBases = [];
}
List<Exercise> findByCategory(ExerciseCategory? category) {
if (category == null) return this.items;
return this.items.where((exercise) => exercise.categoryObj == category).toList();
return this.items.where((exercise) => exercise.category == category).toList();
}
/// Find exercise by ID
@@ -144,7 +155,7 @@ class ExercisesProvider with ChangeNotifier {
);
}
/// Find category by ID
/// Find equipment by ID
Equipment findEquipmentById(int id) {
return _equipment.firstWhere(
(equipment) => equipment.id == id,
@@ -160,6 +171,14 @@ class ExercisesProvider with ChangeNotifier {
);
}
/// Find language by ID
Language findLanguageById(int id) {
return _languages.firstWhere(
(language) => language.id == id,
orElse: () => throw NoSuchEntryException(),
);
}
Future<void> fetchAndSetCategories() async {
final categories = await baseProvider.fetch(baseProvider.makeUrl(_categoriesUrlPath));
try {
@@ -193,6 +212,17 @@ class ExercisesProvider with ChangeNotifier {
}
}
Future<void> fetchAndSetLanguages() async {
final languageData = await baseProvider.fetch(baseProvider.makeUrl(_languageUrlPath));
try {
for (final language in languageData['results']) {
_languages.add(Language.fromJson(language));
}
} catch (error) {
throw (error);
}
}
/// Returns the exercise with the given ID
///
/// If the exercise is not known locally, it is fetched from the server.
@@ -201,94 +231,147 @@ class ExercisesProvider with ChangeNotifier {
Future<Exercise> fetchAndSetExercise(int exerciseId) async {
try {
return findExerciseById(exerciseId);
} on StateError {
} on NoSuchEntryException {
// Get exercise from the server and save to cache
final data =
await baseProvider.fetch(baseProvider.makeUrl(_exerciseInfoUrlPath, id: exerciseId));
final exercise = Exercise.fromJson(data);
_exercises.add(exercise);
// TODO: do this right (and save to cache)
final exerciseTranslationData = await baseProvider.fetch(
baseProvider.makeUrl(
_exerciseUrlPath,
id: exerciseId,
),
);
final exercise = Exercise.fromJson(exerciseTranslationData);
final exerciseBaseData = await baseProvider.fetch(
baseProvider.makeUrl(_exerciseBaseUrlPath, id: exercise.baseId),
);
final base = ExerciseBase.fromJson(exerciseBaseData);
setExerciseBaseData(base, [exercise]);
/*
final prefs = await SharedPreferences.getInstance();
final exerciseData = json.decode(prefs.getString(PREFS_EXERCISES)!);
exerciseData['exercises'].add(exercise.toJson());
prefs.setString(PREFS_EXERCISES, json.encode(exerciseData));
log("Saved exercise '${exercise.name}' to cache.");
final exerciseTranslationData = await baseProvider.fetch(
baseProvider.makeUrl(
_exerciseUrlPath,
id: exerciseId,
),
);
final exercise = Exercise.fromJson(exerciseTranslationData);
final exerciseBaseData = await baseProvider.fetch(
baseProvider.makeUrl(_exerciseBaseUrlPath, id: exercise.baseId),
);
final base = setExerciseBaseData(ExerciseBase.fromJson(exerciseBaseData), [exercise]);
//exerciseData['exercises'].add(exercise.toJson());
//prefs.setString(PREFS_EXERCISES, json.encode(exerciseData));
//log("Saved exercise '${exercise.name}' to cache.");
*/
return exercise;
}
}
Future<void> fetchAndSetExercisesTEST() async {
// Load categories, muscles and equipments
await fetchAndSetCategories();
await fetchAndSetMuscles();
await fetchAndSetEquipment();
/// Helper function that sets different objects such as category, etc.
ExerciseBase setExerciseBaseData(ExerciseBase base, List<Exercise> exercises) {
base.category = findCategoryById(base.categoryId);
base.muscles = base.musclesIds.map((e) => findMuscleById(e)).toList();
base.musclesSecondary = base.musclesSecondaryIds.map((e) => findMuscleById(e)).toList();
base.equipment = base.equipmentIds.map((e) => findEquipmentById(e)).toList();
final exercisesData = await baseProvider.fetch(
baseProvider.makeUrl(_exerciseBaseUrlPath, query: {'limit': '10'}),
);
exercisesData['results'].forEach((e) async {
var base = ExerciseBase.fromJson(e);
base.category = findCategoryById(base.categoryId);
base.muscles = base.musclesIds.map((e) => findMuscleById(e)).toList();
base.musclesSecondary = base.musclesSecondaryIds.map((e) => findMuscleById(e)).toList();
base.equipment = base.equipmentIds.map((e) => findEquipmentById(e)).toList();
final exerciseTranslationData = await baseProvider.fetch(
baseProvider.makeUrl(
_exerciseTranslationUrlPath,
query: {'limit': '10', 'exercise_base': base.id.toString()},
),
);
exerciseTranslationData['results'].forEach((e) async {
base.exercises.add(Exercise2.fromJson(e));
});
exercises.forEach((e) {
e.base = base;
e.language = findLanguageById(e.languageId);
});
base.exercises = [];
base.exercises = exercises;
return base;
}
Future<void> fetchAndSetExercises() async {
// Load exercises from cache, if available
this.clear();
print(Intl.getCurrentLocale());
print(Intl.shortLocale(Intl.getCurrentLocale()));
print('---------');
final prefs = await SharedPreferences.getInstance();
if (prefs.containsKey(PREFS_EXERCISES)) {
final exerciseData = json.decode(prefs.getString(PREFS_EXERCISES)!);
if (DateTime.parse(exerciseData['expiresIn']).isAfter(DateTime.now())) {
exerciseData['exercises'].forEach((e) => _exercises.add(Exercise.fromJson(e)));
exerciseData['equipment'].forEach((e) => _equipment.add(Equipment.fromJson(e)));
exerciseData['muscles'].forEach((e) => _muscles.add(Muscle.fromJson(e)));
exerciseData['categories'].forEach((e) => _categories.add(ExerciseCategory.fromJson(e)));
final cacheData = json.decode(prefs.getString(PREFS_EXERCISES)!);
if (DateTime.parse(cacheData['expiresIn']).isAfter(DateTime.now())) {
cacheData['equipment'].forEach((e) => _equipment.add(Equipment.fromJson(e)));
cacheData['muscles'].forEach((e) => _muscles.add(Muscle.fromJson(e)));
cacheData['categories'].forEach((e) => _categories.add(ExerciseCategory.fromJson(e)));
cacheData['languages'].forEach((e) => _languages.add(Language.fromJson(e)));
cacheData['exercise-translations'].forEach((e) => _exercises.add(Exercise.fromJson(e)));
cacheData['bases'].forEach((e) {
var base = setExerciseBaseData(
ExerciseBase.fromJson(e),
_exercises.where((element) => element.baseId == e['id']).toList(),
);
_exerciseBases.add(base);
});
_initFilters();
log("Read ${exerciseData['exercises'].length} exercises from cache. Valid till ${exerciseData['expiresIn']}");
log("Read ${_exerciseBases.length} exercises from cache. Valid till ${cacheData['expiresIn']}");
return;
}
}
// Load categories, muscles and equipments
await fetchAndSetCategories();
await fetchAndSetMuscles();
await fetchAndSetEquipment();
// Load categories, muscles, equipment and languages
await Future.wait([
fetchAndSetCategories(),
fetchAndSetMuscles(),
fetchAndSetEquipment(),
fetchAndSetLanguages(),
]);
final exercisesData = await baseProvider.fetch(
baseProvider.makeUrl(_exerciseInfoUrlPath, query: {'limit': '1000'}),
final exerciseBaseData = await baseProvider.fetch(
baseProvider.makeUrl(_exerciseBaseUrlPath, query: {'limit': '1000'}),
);
final exerciseTranslationData = await baseProvider.fetch(
baseProvider.makeUrl(
_exerciseUrlPath,
query: {'limit': '1000'},
),
);
List<Exercise> exerciseTranslation = exerciseTranslationData['results'].map<Exercise>((e) {
return Exercise.fromJson(e);
}).toList();
for (var e in exerciseBaseData['results']) {
var base = setExerciseBaseData(
ExerciseBase.fromJson(e),
exerciseTranslation.where((element) => element.baseId == e['id']).toList(),
);
_exerciseBases.add(base);
}
try {
// Load exercises
exercisesData['results'].forEach((e) => _exercises.add(Exercise.fromJson(e)));
List<Exercise> exerciseTranslations = [];
_exerciseBases.forEach((base) {
base.exercises.forEach((exercise) {
exerciseTranslations.add(exercise);
});
});
// Save the result to the cache
final exerciseData = {
final cacheData = {
'date': DateTime.now().toIso8601String(),
'expiresIn': DateTime.now().add(Duration(days: daysToCache)).toIso8601String(),
'exercises': _exercises.map((e) => e.toJson()).toList(),
'expiresIn': DateTime.now().add(Duration(days: EXERCISE_CACHE_DAYS)).toIso8601String(),
'equipment': _equipment.map((e) => e.toJson()).toList(),
'categories': _categories.map((e) => e.toJson()).toList(),
'muscles': _muscles.map((e) => e.toJson()).toList(),
'languages': _languages.map((e) => e.toJson()).toList(),
'exercise-translations': exerciseTranslations.map((e) => e.toJson()).toList(),
'bases': _exerciseBases.map((e) => e.toJson()).toList(),
};
log("Saved ${_exercises.length} exercises from cache. Valid till ${exerciseData['expiresIn']}");
log("Saved ${_exercises.length} exercises from cache. Valid till ${cacheData['expiresIn']}");
prefs.setString(PREFS_EXERCISES, json.encode(exerciseData));
prefs.setString(PREFS_EXERCISES, json.encode(cacheData));
_initFilters();
notifyListeners();
} on MissingRequiredKeysException catch (error) {

View File

@@ -42,7 +42,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
children: [
IconButton(
onPressed: () {
Provider.of<ExercisesProvider>(context, listen: false).fetchAndSetExercisesTEST();
Provider.of<ExercisesProvider>(context, listen: false).fetchAndSetExercises();
},
icon: Icon(Icons.update),
),

View File

@@ -32,7 +32,6 @@ import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/dashboard.dart';
import 'package:wger/screens/exercises_screen.dart';
import 'package:wger/screens/gallery_screen.dart';
import 'package:wger/screens/nutritional_plans_screen.dart';
import 'package:wger/screens/weight_screen.dart';
import 'package:wger/screens/workout_plans_screen.dart';
import 'package:wger/theme/theme.dart';

View File

@@ -39,7 +39,7 @@ class ExerciseDetail extends StatelessWidget {
AppLocalizations.of(context).category,
style: Theme.of(context).textTheme.headline6,
),
Text(_exercise.categoryObj.name),
Text(_exercise.category.name),
SizedBox(height: 8),
// Equipment

View File

@@ -38,7 +38,7 @@ class ExerciseListTile extends StatelessWidget {
borderRadius: BorderRadius.circular(5),
),
child: Text(
exercise.categoryObj.name,
exercise.category.name,
),
),
Text(

View File

@@ -405,7 +405,7 @@ class _SetFormWidgetState extends State<SetFormWidget> {
),
title: Text(exerciseSuggestion.name),
subtitle: Text(
'${exerciseSuggestion.categoryObj.name} / ${exerciseSuggestion.equipment.map((e) => e.name).join(', ')}',
'${exerciseSuggestion.category.name} / ${exerciseSuggestion.equipment.map((e) => e.name).join(', ')}',
),
);
},
@@ -633,7 +633,7 @@ class ExerciseSetting extends StatelessWidget {
_exercise.name,
style: Theme.of(context).textTheme.headline6,
),
subtitle: Text(_exercise.categoryObj.name),
subtitle: Text(_exercise.category.name),
contentPadding: EdgeInsets.zero,
leading: ExerciseImageWidget(image: _exercise.getMainImage),
trailing: IconButton(

View File

@@ -658,7 +658,7 @@ class ExerciseOverview extends StatelessWidget {
padding: EdgeInsets.symmetric(horizontal: 15),
children: [
Text(
_exercise.categoryObj.name,
_exercise.category.name,
style: Theme.of(context).textTheme.headline6,
textAlign: TextAlign.center,
),

View File

@@ -5,6 +5,7 @@ import 'package:mockito/mockito.dart';
import 'package:wger/exceptions/no_such_entry_exception.dart';
import 'package:wger/models/exercises/category.dart';
import 'package:wger/models/exercises/equipment.dart';
import 'package:wger/models/exercises/language.dart';
import 'package:wger/models/exercises/muscle.dart';
import 'package:wger/providers/exercises.dart';
@@ -18,6 +19,7 @@ main() {
String categoryUrl = 'exercisecategory';
String muscleUrl = 'muscle';
String equipmentUrl = 'equipment';
String languageUrl = 'language';
Uri tCategoryEntriesUri = Uri(
scheme: 'http',
@@ -37,13 +39,21 @@ main() {
path: 'api/v2/' + equipmentUrl + '/',
);
Uri tLanguageEntriesUri = Uri(
scheme: 'http',
host: 'localhost',
path: 'api/v2/' + languageUrl + '/',
);
final category1 = ExerciseCategory(id: 1, name: 'Arms');
final muscle1 = Muscle(id: 1, name: 'Biceps brachii', isFront: true);
final equipment1 = Equipment(id: 1, name: 'Barbell');
final language1 = Language(id: 1, shortName: 'de', fullName: 'Deutsch');
Map<String, dynamic> tCategoryMap = jsonDecode(fixture('exercise_category_entries.json'));
Map<String, dynamic> tMucleMap = jsonDecode(fixture('exercise_muscles_entries.json'));
Map<String, dynamic> tMuscleMap = jsonDecode(fixture('exercise_muscles_entries.json'));
Map<String, dynamic> tEquipmentMap = jsonDecode(fixture('exercise_equipment_entries.json'));
Map<String, dynamic> tLanguageMap = jsonDecode(fixture('exercise_language_entries.json'));
setUp(() {
mockBaseProvider = MockWgerBaseProvider();
@@ -55,12 +65,16 @@ main() {
// Mock muscles
when(mockBaseProvider.makeUrl(muscleUrl)).thenReturn(tMuscleEntriesUri);
when(mockBaseProvider.fetch(tMuscleEntriesUri)).thenAnswer((_) => Future.value(tMucleMap));
when(mockBaseProvider.fetch(tMuscleEntriesUri)).thenAnswer((_) => Future.value(tMuscleMap));
// Mock equipment
when(mockBaseProvider.makeUrl(equipmentUrl)).thenReturn(tEquipmentEntriesUri);
when(mockBaseProvider.fetch(tEquipmentEntriesUri))
.thenAnswer((_) => Future.value(tEquipmentMap));
// Mock languages
when(mockBaseProvider.makeUrl(languageUrl)).thenReturn(tLanguageEntriesUri);
when(mockBaseProvider.fetch(tLanguageEntriesUri)).thenAnswer((_) => Future.value(tLanguageMap));
});
group('findCategoryById()', () {
@@ -116,4 +130,22 @@ main() {
expect(() => provider.findEquipmentById(10), throwsA(isA<NoSuchEntryException>()));
});
});
group('findLanguageById()', () {
test('should return a language for an id', () async {
// arrange
await provider.fetchAndSetLanguages();
// act
final result = provider.findLanguageById(1);
// assert
expect(result, language1);
});
test('should throw a NoResultException if no equipment is found', () {
// act & assert
expect(() => provider.findLanguageById(10), throwsA(isA<NoSuchEntryException>()));
});
});
}

View File

@@ -31,7 +31,7 @@ main() {
supportedLocales: AppLocalizations.supportedLocales,
navigatorKey: GlobalKey<NavigatorState>(),
home: Scaffold(
body: ExerciseDetail(exercise1),
body: ExerciseDetail(getExercise()[0]),
),
);
}

View File

@@ -0,0 +1,32 @@
{
"count": 5,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"short_name": "de",
"full_name": "Deutsch"
},
{
"id": 2,
"short_name": "en",
"full_name": "English"
},
{
"id": 4,
"short_name": "es",
"full_name": "Español"
},
{
"id": 12,
"short_name": "fr",
"full_name": "Français"
},
{
"id": 13,
"short_name": "it",
"full_name": "Italian"
}
]
}

View File

@@ -19,34 +19,45 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart';
import 'package:wger/models/workouts/workout_plan.dart';
import 'package:wger/providers/exercises.dart';
import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/gym_mode.dart';
import 'package:wger/screens/workout_plan_screen.dart';
import 'package:wger/widgets/workouts/forms.dart';
import 'package:wger/widgets/workouts/gym_mode.dart';
import '../test_data/exercises.dart';
import '../test_data/workouts.dart';
import 'base_provider_test.mocks.dart';
import 'gym_mode_screen_test.mocks.dart';
import 'utils.dart';
@GenerateMocks([ExercisesProvider])
void main() {
Widget createHomeScreen({locale = 'en'}) {
final key = GlobalKey<NavigatorState>();
final client = MockClient();
final mockExerciseProvider = MockExercisesProvider();
WorkoutPlan workoutPlan = getWorkout();
when(mockExerciseProvider.findExerciseById(1)).thenReturn(getExercise()[0]);
when(mockExerciseProvider.findExerciseById(2)).thenReturn(getExercise()[1]);
when(mockExerciseProvider.findExerciseById(3)).thenReturn(getExercise()[2]);
return ChangeNotifierProvider<WorkoutPlansProvider>(
create: (context) => WorkoutPlansProvider(
testAuthProvider,
testExercisesProvider,
mockExerciseProvider,
[workoutPlan],
client,
),
child: ChangeNotifierProvider(
create: (context) => testExercisesProvider,
child: ChangeNotifierProvider<ExercisesProvider>(
create: (context) => mockExerciseProvider,
child: MaterialApp(
locale: Locale(locale),
localizationsDelegates: AppLocalizations.localizationsDelegates,

View File

@@ -0,0 +1,156 @@
// Mocks generated by Mockito 5.0.15 from annotations
// in wger/test/gym_mode_screen_test.dart.
// Do not manually edit this file.
import 'dart:async' as _i10;
import 'dart:ui' as _i11;
import 'package:mockito/mockito.dart' as _i1;
import 'package:wger/models/exercises/base.dart' as _i8;
import 'package:wger/models/exercises/category.dart' as _i4;
import 'package:wger/models/exercises/equipment.dart' as _i5;
import 'package:wger/models/exercises/exercise.dart' as _i3;
import 'package:wger/models/exercises/language.dart' as _i7;
import 'package:wger/models/exercises/muscle.dart' as _i6;
import 'package:wger/providers/base_provider.dart' as _i2;
import 'package:wger/providers/exercises.dart' as _i9;
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
class _FakeWgerBaseProvider_0 extends _i1.Fake implements _i2.WgerBaseProvider {
}
class _FakeExercise_1 extends _i1.Fake implements _i3.Exercise {}
class _FakeExerciseCategory_2 extends _i1.Fake implements _i4.ExerciseCategory {
}
class _FakeEquipment_3 extends _i1.Fake implements _i5.Equipment {}
class _FakeMuscle_4 extends _i1.Fake implements _i6.Muscle {}
class _FakeLanguage_5 extends _i1.Fake implements _i7.Language {}
class _FakeExerciseBase_6 extends _i1.Fake implements _i8.ExerciseBase {}
/// A class which mocks [ExercisesProvider].
///
/// See the documentation for Mockito's code generation for more information.
class MockExercisesProvider extends _i1.Mock implements _i9.ExercisesProvider {
MockExercisesProvider() {
_i1.throwOnMissingStub(this);
}
@override
_i2.WgerBaseProvider get baseProvider =>
(super.noSuchMethod(Invocation.getter(#baseProvider),
returnValue: _FakeWgerBaseProvider_0()) as _i2.WgerBaseProvider);
@override
List<_i3.Exercise> get items => (super.noSuchMethod(Invocation.getter(#items),
returnValue: <_i3.Exercise>[]) as List<_i3.Exercise>);
@override
List<_i4.ExerciseCategory> get categories =>
(super.noSuchMethod(Invocation.getter(#categories),
returnValue: <_i4.ExerciseCategory>[]) as List<_i4.ExerciseCategory>);
@override
bool get hasListeners =>
(super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false)
as bool);
@override
void initFilters() => super.noSuchMethod(Invocation.method(#initFilters, []),
returnValueForMissingStub: null);
@override
List<_i3.Exercise> findByFilters() =>
(super.noSuchMethod(Invocation.method(#findByFilters, []),
returnValue: <_i3.Exercise>[]) as List<_i3.Exercise>);
@override
List<_i3.Exercise> findByCategory(_i4.ExerciseCategory? category) =>
(super.noSuchMethod(Invocation.method(#findByCategory, [category]),
returnValue: <_i3.Exercise>[]) as List<_i3.Exercise>);
@override
_i3.Exercise findExerciseById(int? id) =>
(super.noSuchMethod(Invocation.method(#findExerciseById, [id]),
returnValue: _FakeExercise_1()) as _i3.Exercise);
@override
_i4.ExerciseCategory findCategoryById(int? id) =>
(super.noSuchMethod(Invocation.method(#findCategoryById, [id]),
returnValue: _FakeExerciseCategory_2()) as _i4.ExerciseCategory);
@override
_i5.Equipment findEquipmentById(int? id) =>
(super.noSuchMethod(Invocation.method(#findEquipmentById, [id]),
returnValue: _FakeEquipment_3()) as _i5.Equipment);
@override
_i6.Muscle findMuscleById(int? id) =>
(super.noSuchMethod(Invocation.method(#findMuscleById, [id]),
returnValue: _FakeMuscle_4()) as _i6.Muscle);
@override
_i7.Language findLanguageById(int? id) =>
(super.noSuchMethod(Invocation.method(#findLanguageById, [id]),
returnValue: _FakeLanguage_5()) as _i7.Language);
@override
_i10.Future<void> fetchAndSetCategories() => (super.noSuchMethod(
Invocation.method(#fetchAndSetCategories, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i10.Future<void>);
@override
_i10.Future<void> fetchAndSetMuscles() => (super.noSuchMethod(
Invocation.method(#fetchAndSetMuscles, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i10.Future<void>);
@override
_i10.Future<void> fetchAndSetEquipment() => (super.noSuchMethod(
Invocation.method(#fetchAndSetEquipment, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i10.Future<void>);
@override
_i10.Future<void> fetchAndSetLanguages() => (super.noSuchMethod(
Invocation.method(#fetchAndSetLanguages, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i10.Future<void>);
@override
_i10.Future<_i3.Exercise> fetchAndSetExercise(int? exerciseId) =>
(super.noSuchMethod(Invocation.method(#fetchAndSetExercise, [exerciseId]),
returnValue: Future<_i3.Exercise>.value(_FakeExercise_1()))
as _i10.Future<_i3.Exercise>);
@override
_i8.ExerciseBase setExerciseBaseData(
_i8.ExerciseBase? base, List<_i3.Exercise>? exercises) =>
(super.noSuchMethod(
Invocation.method(#setExerciseBaseData, [base, exercises]),
returnValue: _FakeExerciseBase_6()) as _i8.ExerciseBase);
@override
_i10.Future<void> fetchAndSetExercises() => (super.noSuchMethod(
Invocation.method(#fetchAndSetExercises, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i10.Future<void>);
@override
_i10.Future<List<dynamic>> searchExercise(String? name,
[String? languageCode = r'en']) =>
(super.noSuchMethod(
Invocation.method(#searchExercise, [name, languageCode]),
returnValue: Future<List<dynamic>>.value(<dynamic>[]))
as _i10.Future<List<dynamic>>);
@override
String toString() => super.toString();
@override
void addListener(_i11.VoidCallback? listener) =>
super.noSuchMethod(Invocation.method(#addListener, [listener]),
returnValueForMissingStub: null);
@override
void removeListener(_i11.VoidCallback? listener) =>
super.noSuchMethod(Invocation.method(#removeListener, [listener]),
returnValueForMissingStub: null);
@override
void dispose() => super.noSuchMethod(Invocation.method(#dispose, []),
returnValueForMissingStub: null);
@override
void notifyListeners() =>
super.noSuchMethod(Invocation.method(#notifyListeners, []),
returnValueForMissingStub: null);
}

View File

@@ -27,16 +27,16 @@ void main() {
final workout = getWorkout();
expect(workout.logs.length, 3);
final logExercise1 = workout.filterLogsByExercise(exercise1);
final logExercise1 = workout.filterLogsByExercise(getExercise()[0]);
expect(logExercise1.length, 2);
expect(logExercise1[0].id, 1);
expect(logExercise1[1].id, 2);
final logExercise2 = workout.filterLogsByExercise(exercise2);
final logExercise2 = workout.filterLogsByExercise(getExercise()[1]);
expect(logExercise2.length, 1);
expect(logExercise2[0].id, 3);
expect(workout.filterLogsByExercise(exercise3).length, 0);
expect(workout.filterLogsByExercise(getExercise()[2]).length, 0);
});
});
}

View File

@@ -2,17 +2,18 @@
// in wger/test/workout_set_form_test.dart.
// Do not manually edit this file.
import 'dart:async' as _i9;
import 'dart:ui' as _i10;
import 'dart:async' as _i10;
import 'dart:ui' as _i11;
import 'package:http/http.dart' as _i3;
import 'package:mockito/mockito.dart' as _i1;
import 'package:wger/models/exercises/category.dart' as _i5;
import 'package:wger/models/exercises/equipment.dart' as _i6;
import 'package:wger/models/exercises/exercise.dart' as _i4;
import 'package:wger/models/exercises/muscle.dart' as _i7;
import 'package:wger/providers/auth.dart' as _i2;
import 'package:wger/providers/exercises.dart' as _i8;
import 'package:wger/models/exercises/base.dart' as _i8;
import 'package:wger/models/exercises/category.dart' as _i4;
import 'package:wger/models/exercises/equipment.dart' as _i5;
import 'package:wger/models/exercises/exercise.dart' as _i3;
import 'package:wger/models/exercises/language.dart' as _i7;
import 'package:wger/models/exercises/muscle.dart' as _i6;
import 'package:wger/providers/base_provider.dart' as _i2;
import 'package:wger/providers/exercises.dart' as _i9;
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
@@ -22,151 +23,127 @@ import 'package:wger/providers/exercises.dart' as _i8;
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
class _FakeAuthProvider_0 extends _i1.Fake implements _i2.AuthProvider {}
class _FakeClient_1 extends _i1.Fake implements _i3.Client {}
class _FakeExercise_2 extends _i1.Fake implements _i4.Exercise {}
class _FakeExerciseCategory_3 extends _i1.Fake implements _i5.ExerciseCategory {
class _FakeWgerBaseProvider_0 extends _i1.Fake implements _i2.WgerBaseProvider {
}
class _FakeEquipment_4 extends _i1.Fake implements _i6.Equipment {}
class _FakeExercise_1 extends _i1.Fake implements _i3.Exercise {}
class _FakeMuscle_5 extends _i1.Fake implements _i7.Muscle {}
class _FakeExerciseCategory_2 extends _i1.Fake implements _i4.ExerciseCategory {
}
class _FakeUri_6 extends _i1.Fake implements Uri {}
class _FakeEquipment_3 extends _i1.Fake implements _i5.Equipment {}
class _FakeResponse_7 extends _i1.Fake implements _i3.Response {}
class _FakeMuscle_4 extends _i1.Fake implements _i6.Muscle {}
class _FakeLanguage_5 extends _i1.Fake implements _i7.Language {}
class _FakeExerciseBase_6 extends _i1.Fake implements _i8.ExerciseBase {}
/// A class which mocks [ExercisesProvider].
///
/// See the documentation for Mockito's code generation for more information.
class MockExercisesProvider extends _i1.Mock implements _i8.ExercisesProvider {
class MockExercisesProvider extends _i1.Mock implements _i9.ExercisesProvider {
MockExercisesProvider() {
_i1.throwOnMissingStub(this);
}
@override
List<_i4.Exercise> get items => (super.noSuchMethod(Invocation.getter(#items),
returnValue: <_i4.Exercise>[]) as List<_i4.Exercise>);
_i2.WgerBaseProvider get baseProvider =>
(super.noSuchMethod(Invocation.getter(#baseProvider),
returnValue: _FakeWgerBaseProvider_0()) as _i2.WgerBaseProvider);
@override
List<_i5.ExerciseCategory> get categories =>
List<_i3.Exercise> get items => (super.noSuchMethod(Invocation.getter(#items),
returnValue: <_i3.Exercise>[]) as List<_i3.Exercise>);
@override
List<_i4.ExerciseCategory> get categories =>
(super.noSuchMethod(Invocation.getter(#categories),
returnValue: <_i5.ExerciseCategory>[]) as List<_i5.ExerciseCategory>);
@override
_i2.AuthProvider get auth => (super.noSuchMethod(Invocation.getter(#auth),
returnValue: _FakeAuthProvider_0()) as _i2.AuthProvider);
@override
set auth(_i2.AuthProvider? _auth) =>
super.noSuchMethod(Invocation.setter(#auth, _auth),
returnValueForMissingStub: null);
@override
_i3.Client get client => (super.noSuchMethod(Invocation.getter(#client),
returnValue: _FakeClient_1()) as _i3.Client);
@override
set client(_i3.Client? _client) =>
super.noSuchMethod(Invocation.setter(#client, _client),
returnValueForMissingStub: null);
returnValue: <_i4.ExerciseCategory>[]) as List<_i4.ExerciseCategory>);
@override
bool get hasListeners =>
(super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false)
as bool);
@override
List<_i4.Exercise> findByCategory(_i5.ExerciseCategory? category) =>
void initFilters() => super.noSuchMethod(Invocation.method(#initFilters, []),
returnValueForMissingStub: null);
@override
List<_i3.Exercise> findByFilters() =>
(super.noSuchMethod(Invocation.method(#findByFilters, []),
returnValue: <_i3.Exercise>[]) as List<_i3.Exercise>);
@override
List<_i3.Exercise> findByCategory(_i4.ExerciseCategory? category) =>
(super.noSuchMethod(Invocation.method(#findByCategory, [category]),
returnValue: <_i4.Exercise>[]) as List<_i4.Exercise>);
returnValue: <_i3.Exercise>[]) as List<_i3.Exercise>);
@override
_i4.Exercise findExerciseById(int? id) =>
_i3.Exercise findExerciseById(int? id) =>
(super.noSuchMethod(Invocation.method(#findExerciseById, [id]),
returnValue: _FakeExercise_2()) as _i4.Exercise);
returnValue: _FakeExercise_1()) as _i3.Exercise);
@override
_i5.ExerciseCategory findCategoryById(int? id) =>
_i4.ExerciseCategory findCategoryById(int? id) =>
(super.noSuchMethod(Invocation.method(#findCategoryById, [id]),
returnValue: _FakeExerciseCategory_3()) as _i5.ExerciseCategory);
returnValue: _FakeExerciseCategory_2()) as _i4.ExerciseCategory);
@override
_i6.Equipment findEquipmentById(int? id) =>
_i5.Equipment findEquipmentById(int? id) =>
(super.noSuchMethod(Invocation.method(#findEquipmentById, [id]),
returnValue: _FakeEquipment_4()) as _i6.Equipment);
returnValue: _FakeEquipment_3()) as _i5.Equipment);
@override
_i7.Muscle findMuscleById(int? id) =>
_i6.Muscle findMuscleById(int? id) =>
(super.noSuchMethod(Invocation.method(#findMuscleById, [id]),
returnValue: _FakeMuscle_5()) as _i7.Muscle);
returnValue: _FakeMuscle_4()) as _i6.Muscle);
@override
_i9.Future<void> fetchAndSetCategories() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetCategories, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
_i7.Language findLanguageById(int? id) =>
(super.noSuchMethod(Invocation.method(#findLanguageById, [id]),
returnValue: _FakeLanguage_5()) as _i7.Language);
@override
_i9.Future<void> fetchAndSetMuscles() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetMuscles, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
_i10.Future<void> fetchAndSetCategories() => (super.noSuchMethod(
Invocation.method(#fetchAndSetCategories, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i10.Future<void>);
@override
_i9.Future<void> fetchAndSetEquipment() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetEquipment, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
_i10.Future<void> fetchAndSetMuscles() => (super.noSuchMethod(
Invocation.method(#fetchAndSetMuscles, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i10.Future<void>);
@override
_i9.Future<_i4.Exercise> fetchAndSetExercise(int? exerciseId) =>
_i10.Future<void> fetchAndSetEquipment() => (super.noSuchMethod(
Invocation.method(#fetchAndSetEquipment, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i10.Future<void>);
@override
_i10.Future<void> fetchAndSetLanguages() => (super.noSuchMethod(
Invocation.method(#fetchAndSetLanguages, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i10.Future<void>);
@override
_i10.Future<_i3.Exercise> fetchAndSetExercise(int? exerciseId) =>
(super.noSuchMethod(Invocation.method(#fetchAndSetExercise, [exerciseId]),
returnValue: Future<_i4.Exercise>.value(_FakeExercise_2()))
as _i9.Future<_i4.Exercise>);
returnValue: Future<_i3.Exercise>.value(_FakeExercise_1()))
as _i10.Future<_i3.Exercise>);
@override
_i9.Future<void> fetchAndSetExercisesTEST() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetExercisesTEST, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
_i8.ExerciseBase setExerciseBaseData(
_i8.ExerciseBase? base, List<_i3.Exercise>? exercises) =>
(super.noSuchMethod(
Invocation.method(#setExerciseBaseData, [base, exercises]),
returnValue: _FakeExerciseBase_6()) as _i8.ExerciseBase);
@override
_i9.Future<void> fetchAndSetExercises() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetExercises, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
_i10.Future<void> fetchAndSetExercises() => (super.noSuchMethod(
Invocation.method(#fetchAndSetExercises, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i10.Future<void>);
@override
_i9.Future<List<dynamic>> searchExercise(String? name,
_i10.Future<List<dynamic>> searchExercise(String? name,
[String? languageCode = r'en']) =>
(super.noSuchMethod(
Invocation.method(#searchExercise, [name, languageCode]),
returnValue: Future<List<dynamic>>.value(<dynamic>[]))
as _i9.Future<List<dynamic>>);
@override
Uri makeUrl(String? path,
{int? id, String? objectMethod, Map<String, dynamic>? query}) =>
(super.noSuchMethod(
Invocation.method(#makeUrl, [path],
{#id: id, #objectMethod: objectMethod, #query: query}),
returnValue: _FakeUri_6()) as Uri);
@override
_i9.Future<Map<String, dynamic>> fetch(Uri? uri) => (super.noSuchMethod(
Invocation.method(#fetch, [uri]),
returnValue: Future<Map<String, dynamic>>.value(<String, dynamic>{}))
as _i9.Future<Map<String, dynamic>>);
@override
_i9.Future<Map<String, dynamic>> post(Map<String, dynamic>? data, Uri? uri) =>
(super.noSuchMethod(Invocation.method(#post, [data, uri]),
returnValue:
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
as _i9.Future<Map<String, dynamic>>);
@override
_i9.Future<Map<String, dynamic>> patch(
Map<String, dynamic>? data, Uri? uri) =>
(super.noSuchMethod(Invocation.method(#patch, [data, uri]),
returnValue:
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
as _i9.Future<Map<String, dynamic>>);
@override
_i9.Future<_i3.Response> deleteRequest(String? url, int? id) =>
(super.noSuchMethod(Invocation.method(#deleteRequest, [url, id]),
returnValue: Future<_i3.Response>.value(_FakeResponse_7()))
as _i9.Future<_i3.Response>);
as _i10.Future<List<dynamic>>);
@override
String toString() => super.toString();
@override
void addListener(_i10.VoidCallback? listener) =>
void addListener(_i11.VoidCallback? listener) =>
super.noSuchMethod(Invocation.method(#addListener, [listener]),
returnValueForMissingStub: null);
@override
void removeListener(_i10.VoidCallback? listener) =>
void removeListener(_i11.VoidCallback? listener) =>
super.noSuchMethod(Invocation.method(#removeListener, [listener]),
returnValueForMissingStub: null);
@override

View File

@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:wger/models/exercises/base.dart';
import 'package:wger/models/exercises/category.dart';
import 'package:wger/models/exercises/equipment.dart';
import 'package:wger/models/exercises/exercise.dart';
@@ -32,38 +33,67 @@ const category3 = ExerciseCategory(id: 3, name: 'Abs');
const equipment1 = Equipment(id: 1, name: 'Bench');
const equipment2 = Equipment(id: 1, name: 'Dumbbell');
final exercise1 = Exercise(
id: 1,
uuid: 'uuid',
creationDate: DateTime(2021, 1, 15),
name: 'test exercise 1',
description: 'add clever text',
category: category1,
muscles: [muscle1, muscle2],
musclesSecondary: [muscle3],
equipment: [equipment1, equipment2],
);
List<Exercise> getExercise() {
final base1 = ExerciseBase(
id: 1,
uuid: 'uuid1',
creationDate: DateTime(2021, 09, 01),
updateDate: DateTime(2021, 09, 10),
category: category1,
equipment: [equipment1, equipment2],
muscles: [muscle1, muscle2],
musclesSecondary: [muscle3],
);
final exercise2 = Exercise(
id: 2,
uuid: '111-2222-44444',
creationDate: DateTime(2021, 1, 15),
name: 'test exercise 2',
description: 'Lorem ipsum etc',
category: category2,
muscles: [muscle1],
musclesSecondary: [muscle2],
equipment: [equipment2],
);
final exercise1 = Exercise(
id: 1,
baseId: 1,
uuid: 'uuid',
languageId: 1,
creationDate: DateTime(2021, 1, 15),
name: 'test exercise 1',
description: 'add clever text',
base: base1);
final exercise3 = Exercise(
id: 3,
uuid: 'a3b6c7bb-9d22-4119-a5fc-818584d5e9bc',
creationDate: DateTime(2021, 4, 1),
name: 'test exercise 3',
description: 'The man in black fled across the desert, and the gunslinger followed',
category: category3,
muscles: [muscle1],
musclesSecondary: [muscle2],
equipment: [equipment2],
);
final base2 = ExerciseBase(
id: 2,
uuid: 'uuid2',
creationDate: DateTime(2021, 08, 01),
updateDate: DateTime(2021, 08, 10),
category: category2,
equipment: [equipment2],
muscles: [muscle1],
musclesSecondary: [muscle2],
);
final exercise2 = Exercise(
id: 2,
baseId: 2,
uuid: '111-2222-44444',
languageId: 2,
creationDate: DateTime(2021, 1, 15),
name: 'test exercise 2',
description: 'Lorem ipsum etc',
base: base2);
final base3 = ExerciseBase(
id: 3,
uuid: 'uuid3',
creationDate: DateTime(2021, 08, 01),
updateDate: DateTime(2021, 08, 01),
category: category3,
equipment: [equipment2],
muscles: [muscle1],
musclesSecondary: [muscle2],
);
final exercise3 = Exercise(
id: 3,
baseId: 2,
uuid: 'a3b6c7bb-9d22-4119-a5fc-818584d5e9bc',
languageId: 2,
creationDate: DateTime(2021, 4, 1),
name: 'test exercise 3',
description: 'The man in black fled across the desert, and the gunslinger followed',
base: base3);
return [exercise1, exercise2, exercise3];
}

View File

@@ -45,7 +45,7 @@ WorkoutPlan getWorkout() {
);
setting1.repetitionUnit = repetitionUnit1;
setting1.weightUnit = weightUnit1;
setting1.exercise = exercise1;
setting1.exercise = getExercise()[0];
setting1.weight = 10;
var log1 = Log.empty()
@@ -55,7 +55,7 @@ WorkoutPlan getWorkout() {
..date = DateTime(2021, 5, 1)
..reps = 10
..workoutPlan = 1;
log1.exercise = exercise1;
log1.exercise = getExercise()[0];
log1.weightUnit = weightUnit1;
log1.repetitionUnit = repetitionUnit1;
@@ -66,7 +66,7 @@ WorkoutPlan getWorkout() {
..date = DateTime(2021, 5, 1)
..reps = 12
..workoutPlan = 1;
log2.exercise = exercise1;
log2.exercise = getExercise()[0];
log2.weightUnit = weightUnit1;
log2.repetitionUnit = repetitionUnit1;
@@ -77,7 +77,7 @@ WorkoutPlan getWorkout() {
..date = DateTime(2021, 5, 2)
..reps = 8
..workoutPlan = 1;
log3.exercise = exercise2;
log3.exercise = getExercise()[1];
log3.weightUnit = weightUnit1;
log3.repetitionUnit = repetitionUnit1;
@@ -88,7 +88,7 @@ WorkoutPlan getWorkout() {
order: 1,
comment: 'Important to do exercises correctly',
);
set1.addExercise(exercise1);
set1.addExercise(getExercise()[0]);
set1.settings.add(setting1);
set1.settingsComputed = [setting1, setting1];