diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index fd0e7ac0..ded39427 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -388,5 +388,11 @@ "selectIngredient": "Please select an ingredient", "@selectIngredient": { "description": "Error message when the user hasn't selected an ingredient from the autocompleter" - } + }, + "selectImage": "Please select an image", + "@selectImage": { + "description": "Label and error message when the user hasn't selected an image to save" + }, + "takePicture": "Take a picture", + "chooseFromLibrary": "Choose from photo library" } diff --git a/lib/providers/workout_plans.dart b/lib/providers/workout_plans.dart index 6fe419a8..082e111f 100644 --- a/lib/providers/workout_plans.dart +++ b/lib/providers/workout_plans.dart @@ -464,6 +464,32 @@ class WorkoutPlans extends WgerBaseProvider with ChangeNotifier { notifyListeners(); } + Future editImage(gallery.Image image, PickedFile? imageFile) async { + var request = http.MultipartRequest('PATCH', makeUrl(_galleryUrlPath, id: image.id)); + request.headers.addAll({ + HttpHeaders.authorizationHeader: 'Token ${auth.token}', + HttpHeaders.userAgentHeader: 'wger Workout Manager App', + }); + + // Only send the image if a new one was selected + if (imageFile != null) { + request.files.add(await http.MultipartFile.fromPath('image', imageFile.path)); + } + + // Update image info + final data = image.toJson(); + request.fields['id'] = data['id']; + request.fields['date'] = data['date']; + request.fields['description'] = data['description']; + + final res = await request.send(); + final respStr = await res.stream.bytesToString(); + final responseData = json.decode(respStr); + image.url = responseData['image']; + + notifyListeners(); + } + Future deleteImage(gallery.Image image) async { await deleteRequest(_galleryUrlPath, image.id!); images.removeWhere((element) => element.id == image.id); diff --git a/lib/widgets/gallery/forms.dart b/lib/widgets/gallery/forms.dart index 1cbb73a0..42e1887a 100644 --- a/lib/widgets/gallery/forms.dart +++ b/lib/widgets/gallery/forms.dart @@ -48,6 +48,8 @@ class _ImageFormState extends State { @override void initState() { + super.initState(); + dateController.text = toDate(widget._image.date)!; descriptionController.text = widget._image.description; } @@ -61,6 +63,33 @@ class _ImageFormState extends State { }); } + /// Returns widget with current picture, depending on whether the user is + /// editing an existing entry or adding a new one. A text message is shown if + /// neither is available + Widget getPicture() { + // An image file was selected, use it + if (_file != null) { + return Image( + image: FileImage(File(_file!.path)), + ); + } + + // We are editing an existing entry + if (widget._image.url != null) { + return Image.network(widget._image.url!); + } + + // No picture available, show a message to the user + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(AppLocalizations.of(context)!.selectImage), + SizedBox(height: 8), + Icon(Icons.photo_camera), + ], + ); + } + @override Widget build(BuildContext context) { return Form( @@ -84,7 +113,7 @@ class _ImageFormState extends State { _showPicker(ImageSource.camera); }, leading: Icon(Icons.photo_camera), - title: Text("Take a picture"), + title: Text(AppLocalizations.of(context)!.takePicture), ), ListTile( onTap: () { @@ -92,27 +121,14 @@ class _ImageFormState extends State { _showPicker(ImageSource.gallery); }, leading: Icon(Icons.photo_library), - title: Text("Choose from photo library")) + title: Text(AppLocalizations.of(context)!.chooseFromLibrary)) ], ), ); }, ); }, - child: _file != null - ? Image( - image: FileImage(File(_file!.path)), - //fit: BoxFit.none, - ) - : Column( - //mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('please select an image'), - SizedBox(height: 8), - Icon(Icons.photo_camera), - ], - ), + child: getPicture(), ), ), TextFormField( @@ -136,8 +152,8 @@ class _ImageFormState extends State { widget._image.date = DateTime.parse(newValue!); }, validator: (value) { - if (_file == null) { - return 'Please select an image'; + if (widget._image.id == null && _file == null) { + return AppLocalizations.of(context)!.selectImage; } return null; @@ -164,9 +180,12 @@ class _ImageFormState extends State { } _form.currentState!.save(); - if (_file != null) { + if (widget._image.id == null) { Provider.of(context, listen: false).addImage(widget._image, _file!); Navigator.of(context).pop(); + } else { + Provider.of(context, listen: false).editImage(widget._image, _file); + Navigator.of(context).pop(); } }, ), diff --git a/lib/widgets/gallery/overview.dart b/lib/widgets/gallery/overview.dart index b6730ef7..8cd49b1a 100644 --- a/lib/widgets/gallery/overview.dart +++ b/lib/widgets/gallery/overview.dart @@ -18,9 +18,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:wger/providers/workout_plans.dart'; +import 'package:wger/screens/form_screen.dart'; + +import 'forms.dart'; class Gallery extends StatelessWidget { const Gallery(); @@ -69,7 +73,19 @@ class Gallery extends StatelessWidget { .deleteImage(currentImage); Navigator.of(context).pop(); }), - IconButton(icon: Icon(Icons.edit), onPressed: () {}), + IconButton( + icon: Icon(Icons.edit), + onPressed: () { + Navigator.pushNamed( + context, + FormScreen.routeName, + arguments: FormScreenArguments( + AppLocalizations.of(context)!.edit, + ImageForm(currentImage), + true, + ), + ); + }), ], ) ],