diff --git a/lib/providers/add_exercise_provider.dart b/lib/providers/add_exercise_provider.dart index 562b2db9..91783b34 100644 --- a/lib/providers/add_exercise_provider.dart +++ b/lib/providers/add_exercise_provider.dart @@ -2,6 +2,7 @@ import 'dart:developer'; import 'dart:io'; import 'package:flutter/foundation.dart'; +import 'package:http/http.dart' as http; import 'package:wger/models/exercises/base.dart'; import 'package:wger/models/exercises/category.dart'; import 'package:wger/models/exercises/equipment.dart'; @@ -23,7 +24,7 @@ class AddExerciseProvider with ChangeNotifier { Language? _language; List _alternativeNamesEn = []; List _alternativeNamesTranslation = []; - ExerciseCategory? _targetArea; + ExerciseCategory? _category; List _variations = []; List _equipment = []; List _primaryMuscles = []; @@ -32,13 +33,14 @@ class AddExerciseProvider with ChangeNotifier { AddExerciseProvider(this.baseProvider); static const _exerciseBaseUrlPath = 'exercise-base'; + static const _imagesUrlPath = 'exerciseimage'; static const _exerciseTranslationUrlPath = 'exercise-translation'; void clear() { _exerciseImages = []; _alternativeNamesEn = []; _alternativeNamesTranslation = []; - _targetArea = null; + _category = null; _equipment = []; _primaryMuscles = []; _secondaryMuscles = []; @@ -52,12 +54,15 @@ class AddExerciseProvider with ChangeNotifier { set alternateNamesTrans(List names) => _alternativeNamesTranslation = names; set equipment(List equipment) => _equipment = equipment; - set targetArea(ExerciseCategory target) => _targetArea = target; + List get equipment => [..._equipment]; + set category(ExerciseCategory category) => _category = category; + ExerciseCategory get category => _category!; set language(Language language) => _language = language; + Language get language => _language!; ExerciseBase get base { return ExerciseBase( - category: _targetArea, + category: _category, equipment: _equipment, muscles: _primaryMuscles, musclesSecondary: _secondaryMuscles, @@ -107,7 +112,7 @@ class AddExerciseProvider with ChangeNotifier { log('------------------------'); log('Base data...'); - log('Target area : $_targetArea'); + log('Target area : $_category'); log('Primary muscles: $_primaryMuscles'); log('Secondary muscles: $_secondaryMuscles'); log('Equipment: $_equipment'); @@ -133,14 +138,14 @@ class AddExerciseProvider with ChangeNotifier { // Create the translations final exerciseTranslationEn = exerciseEn; exerciseTranslationEn.base = base; - addExerciseTranslation(exerciseTranslationEn); + await addExerciseTranslation(exerciseTranslationEn); final exerciseTranslationTranslation = exerciseTranslation; exerciseTranslationTranslation.base = base; - addExerciseTranslation(exerciseTranslationTranslation); + await addExerciseTranslation(exerciseTranslationTranslation); // Create the images - // ... + await addImages(base); } Future addExerciseBase() async { @@ -153,6 +158,22 @@ class AddExerciseProvider with ChangeNotifier { return newExerciseBase; } + Future addImages(ExerciseBase base) async { + for (final image in _exerciseImages) { + final request = http.MultipartRequest('POST', baseProvider.makeUrl(_imagesUrlPath)); + request.headers.addAll(baseProvider.getDefaultHeaders(includeAuth: true)); + + request.files.add(await http.MultipartFile.fromPath('image', image.path)); + request.fields['exercise_base'] = base.id!.toString(); + request.fields['style'] = '4'; + + final res = await request.send(); + //final respStr = await res.stream.bytesToString(); + } + + notifyListeners(); + } + Future addExerciseTranslation(Exercise exercise) async { final Uri postUri = baseProvider.makeUrl(_exerciseTranslationUrlPath); diff --git a/lib/providers/base_provider.dart b/lib/providers/base_provider.dart index ea863fd8..15ef98da 100644 --- a/lib/providers/base_provider.dart +++ b/lib/providers/base_provider.dart @@ -37,6 +37,19 @@ class WgerBaseProvider { this.client = client ?? http.Client(); } + Map getDefaultHeaders({includeAuth = false}) { + final out = { + HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8', + HttpHeaders.userAgentHeader: auth.getAppNameHeader(), + }; + + if (includeAuth) { + out[HttpHeaders.authorizationHeader] = 'Token ${auth.token}'; + } + + return out; + } + /// Helper function to make a URL. Uri makeUrl(String path, {int? id, String? objectMethod, Map? query}) { return makeUri(auth.serverUrl!, path, id, objectMethod, query); @@ -47,10 +60,7 @@ class WgerBaseProvider { // Send the request final response = await client.get( uri, - headers: { - HttpHeaders.authorizationHeader: 'Token ${auth.token}', - HttpHeaders.userAgentHeader: auth.getAppNameHeader(), - }, + headers: getDefaultHeaders(includeAuth: true), ); // Something wrong with our request @@ -66,11 +76,7 @@ class WgerBaseProvider { Future> post(Map data, Uri uri) async { final response = await client.post( uri, - headers: { - HttpHeaders.authorizationHeader: 'Token ${auth.token}', - HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8', - HttpHeaders.userAgentHeader: auth.getAppNameHeader(), - }, + headers: getDefaultHeaders(includeAuth: true), body: json.encode(data), ); @@ -86,11 +92,7 @@ class WgerBaseProvider { Future> patch(Map data, Uri uri) async { final response = await client.patch( uri, - headers: { - HttpHeaders.authorizationHeader: 'Token ${auth.token}', - HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8', - HttpHeaders.userAgentHeader: auth.getAppNameHeader(), - }, + headers: getDefaultHeaders(includeAuth: true), body: json.encode(data), ); @@ -108,10 +110,7 @@ class WgerBaseProvider { final response = await client.delete( deleteUrl, - headers: { - HttpHeaders.authorizationHeader: 'Token ${auth.token}', - HttpHeaders.userAgentHeader: auth.getAppNameHeader(), - }, + headers: getDefaultHeaders(includeAuth: true), ); // Something wrong with our request diff --git a/lib/screens/add_exercise_screen.dart b/lib/screens/add_exercise_screen.dart index 3b5d96f6..b0be651a 100644 --- a/lib/screens/add_exercise_screen.dart +++ b/lib/screens/add_exercise_screen.dart @@ -44,15 +44,16 @@ class _AddExerciseScreenState extends State { Widget _controlsBuilder(BuildContext context, ControlsDetails details) { return Row( children: [ - _currentStep == lastStepIndex - ? ElevatedButton( - onPressed: details.onStepContinue, - child: Text(AppLocalizations.of(context).save), - ) - : TextButton( - onPressed: details.onStepContinue, - child: Text(AppLocalizations.of(context).next), - ), + if (_currentStep == lastStepIndex) + ElevatedButton( + onPressed: details.onStepContinue, + child: Text(AppLocalizations.of(context).save), + ) + else + TextButton( + onPressed: details.onStepContinue, + child: Text(AppLocalizations.of(context).next), + ), TextButton( onPressed: details.onStepCancel, child: Text(AppLocalizations.of(context).previous), @@ -140,13 +141,14 @@ class _BasicStepContent extends StatelessWidget { categories: categories, title: AppLocalizations.of(context).category, callback: (ExerciseCategory newValue) { - addExerciseProvider.targetArea = newValue; + addExerciseProvider.category = newValue; }, displayName: (ExerciseCategory c) => c.name, ), AddExerciseMultiselectButton( title: AppLocalizations.of(context).equipment, items: equipment, + initialItems: addExerciseProvider.equipment, onChange: (dynamic value) => print(value), onSaved: (dynamic entries) { if (entries != null && entries.isNotEmpty) { @@ -157,6 +159,7 @@ class _BasicStepContent extends StatelessWidget { AddExerciseMultiselectButton( title: AppLocalizations.of(context).muscles, items: muscles, + initialItems: addExerciseProvider.primaryMuscles, onChange: (dynamic value) => print(value), onSaved: (dynamic muscles) { if (muscles != null && muscles.isNotEmpty) { @@ -166,6 +169,7 @@ class _BasicStepContent extends StatelessWidget { AddExerciseMultiselectButton( title: AppLocalizations.of(context).musclesSecondary, items: muscles, + initialItems: addExerciseProvider.secondaryMuscles, onChange: (dynamic value) => print(value), onSaved: (dynamic muscles) { if (muscles != null && muscles.isNotEmpty) { @@ -233,13 +237,9 @@ class _ImagesStepContentState extends State<_ImagesStepContent> with ExerciseIma MaterialStateProperty.resolveWith((states) => Colors.black)), ), ), - RichText( - text: TextSpan( - style: Theme.of(context).textTheme.caption, - children: const [ - TextSpan(text: 'Only JPEG, PNG and WEBP files below 20 MB are supported'), - ], - ), + Text( + 'Only JPEG, PNG and WEBP files below 20 MB are supported', + style: Theme.of(context).textTheme.caption, ) ], ), diff --git a/lib/widgets/add_exercise/add_exercise_multiselect_button.dart b/lib/widgets/add_exercise/add_exercise_multiselect_button.dart index 389b27ee..e519eaf7 100644 --- a/lib/widgets/add_exercise/add_exercise_multiselect_button.dart +++ b/lib/widgets/add_exercise/add_exercise_multiselect_button.dart @@ -3,15 +3,17 @@ import 'package:multi_select_flutter/multi_select_flutter.dart'; class AddExerciseMultiselectButton extends StatefulWidget { final List items; + List initialItems = []; final String title; final ValueChanged> onChange; final FormFieldSetter?>? onSaved; - const AddExerciseMultiselectButton({ + AddExerciseMultiselectButton({ Key? key, required this.items, required this.title, required this.onChange, + this.initialItems = const [], this.onSaved, }) : super(key: key); @@ -26,6 +28,7 @@ class _AddExerciseMultiselectButtonState extends State MultiSelectItem(item, item.name)).toList(), onConfirm: (value) {