POST images when creating new exercises

This commit is contained in:
Roland Geider
2022-02-20 15:54:32 +01:00
parent 19a504dcfb
commit b011ddcd25
4 changed files with 67 additions and 44 deletions

View File

@@ -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<String> _alternativeNamesEn = [];
List<String> _alternativeNamesTranslation = [];
ExerciseCategory? _targetArea;
ExerciseCategory? _category;
List<ExerciseBase> _variations = [];
List<Equipment> _equipment = [];
List<Muscle> _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<String> names) => _alternativeNamesTranslation = names;
set equipment(List<Equipment> equipment) => _equipment = equipment;
set targetArea(ExerciseCategory target) => _targetArea = target;
List<Equipment> 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<ExerciseBase> addExerciseBase() async {
@@ -153,6 +158,22 @@ class AddExerciseProvider with ChangeNotifier {
return newExerciseBase;
}
Future<void> 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<Exercise> addExerciseTranslation(Exercise exercise) async {
final Uri postUri = baseProvider.makeUrl(_exerciseTranslationUrlPath);

View File

@@ -37,6 +37,19 @@ class WgerBaseProvider {
this.client = client ?? http.Client();
}
Map<String, String> 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<String, dynamic>? 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<Map<String, dynamic>> post(Map<String, dynamic> 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<Map<String, dynamic>> patch(Map<String, dynamic> 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

View File

@@ -44,15 +44,16 @@ class _AddExerciseScreenState extends State<AddExerciseScreen> {
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<Equipment>(
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<Muscle>(
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<Muscle>(
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>[
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,
)
],
),

View File

@@ -3,15 +3,17 @@ import 'package:multi_select_flutter/multi_select_flutter.dart';
class AddExerciseMultiselectButton<T> extends StatefulWidget {
final List<T> items;
List<T> initialItems = [];
final String title;
final ValueChanged<List<T?>> onChange;
final FormFieldSetter<List<T?>?>? 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<T> extends State<AddExerciseMultiselect
return Padding(
padding: const EdgeInsets.all(8.0),
child: MultiSelectDialogField(
initialValue: widget.initialItems,
onSaved: widget.onSaved,
items: widget.items.map((item) => MultiSelectItem<T?>(item, item.name)).toList(),
onConfirm: (value) {