From 1c625a26d811dc8df837c41e5199c8a044db3604 Mon Sep 17 00:00:00 2001 From: Vetle Finstad Date: Mon, 3 Aug 2026 10:38:39 +0200 Subject: [PATCH] Fix retaining multiple gallery image rotations --- CHANGELOG.md | 3 +++ .../Gallery/BottomSheet/GalleryBottomSheet.cs | 6 ++--- .../API/Camera/Gallery/GalleryThumbnails.cs | 5 ++-- .../Camera/Gallery/GalleryThumbnailsTests.cs | 26 +++++++++++++++++++ wiki/Media/ImageCapture.md | 11 ++++++++ 5 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 src/tests/unittests/API/Camera/Gallery/GalleryThumbnailsTests.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 10f41b309..4b2b266f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [62.1.4] +- [Gallery] Fixed issue where only one of multiple image rotations was retained. + ## [62.1.3] - [Dictation][Android] The dictation microphone now shows above the keyboard when the focused field is in a modal or a bottom sheet, instead of being hidden behind it. diff --git a/src/library/DIPS.Mobile.UI/API/Camera/Gallery/BottomSheet/GalleryBottomSheet.cs b/src/library/DIPS.Mobile.UI/API/Camera/Gallery/BottomSheet/GalleryBottomSheet.cs index 3b6c56c67..094edc257 100644 --- a/src/library/DIPS.Mobile.UI/API/Camera/Gallery/BottomSheet/GalleryBottomSheet.cs +++ b/src/library/DIPS.Mobile.UI/API/Camera/Gallery/BottomSheet/GalleryBottomSheet.cs @@ -30,7 +30,7 @@ namespace DIPS.Mobile.UI.API.Camera.Gallery.BottomSheet; internal partial class GalleryBottomSheet : ContentPage, IGalleryDefaultStateObserver, IImageEditStateObserver { private readonly Action m_onRemoveImage; - private readonly Action m_updateImages; + private readonly Action> m_updateImages; private readonly Button m_navigatePreviousImageButton; private readonly Button m_navigateNextImageButton; private readonly ContentView m_carouselViewWrapperView = new(); @@ -54,7 +54,7 @@ internal partial class GalleryBottomSheet : ContentPage, IGalleryDefaultStateObs private int? m_positionBeforeRemoval; private int? m_positionBeforeEdit; - public GalleryBottomSheet(List images, int startingIndex, Action onRemoveImage, Action updateImages) + public GalleryBottomSheet(List images, int startingIndex, Action onRemoveImage, Action> updateImages) { Background = Microsoft.Maui.Graphics.Colors.Black; @@ -432,7 +432,7 @@ void IImageEditStateObserver.OnSaveButtonTapped() Images[m_carouselView!.Position] = m_currentlyRotatedCaptureImageDisplayed; m_currentlyCapturedImageDisplayed = m_currentlyRotatedCaptureImageDisplayed; GoToDefaultState(); - m_updateImages.Invoke(); + m_updateImages.Invoke(Images); } void IImageEditStateObserver.OnCancelButtonTapped() diff --git a/src/library/DIPS.Mobile.UI/API/Camera/Gallery/GalleryThumbnails.cs b/src/library/DIPS.Mobile.UI/API/Camera/Gallery/GalleryThumbnails.cs index e87c300a7..78d3a2eec 100644 --- a/src/library/DIPS.Mobile.UI/API/Camera/Gallery/GalleryThumbnails.cs +++ b/src/library/DIPS.Mobile.UI/API/Camera/Gallery/GalleryThumbnails.cs @@ -61,10 +61,9 @@ private void OnTappedImage(int imageIndex) Shell.Current.Navigation.PushModalAsync(new NavigationPage(new GalleryBottomSheet(Images, imageIndex, OnRemoveImage, UpdateImages))); } - private void UpdateImages() + internal void UpdateImages(IReadOnlyList images) { - var copyOfImages = Images.ToList(); - Images = copyOfImages; + Images = images.ToList(); } private void OnRemoveImage(int imageIndex) diff --git a/src/tests/unittests/API/Camera/Gallery/GalleryThumbnailsTests.cs b/src/tests/unittests/API/Camera/Gallery/GalleryThumbnailsTests.cs new file mode 100644 index 000000000..436a14b30 --- /dev/null +++ b/src/tests/unittests/API/Camera/Gallery/GalleryThumbnailsTests.cs @@ -0,0 +1,26 @@ +using System.Linq; +using DIPS.Mobile.UI.API.Camera.Gallery; +using DIPS.Mobile.UI.API.Camera.ImageCapturing; + +namespace DIPS.Mobile.UI.UnitTests.API.Camera.Gallery; + +public class GalleryThumbnailsTests +{ + [Fact] + public void UpdateImages_MultipleEditsFromOpenGallery_RetainsEveryEdit() + { + var firstImage = new CapturedImage(); + var secondImage = new CapturedImage(); + var firstEditedImage = new CapturedImage(); + var secondEditedImage = new CapturedImage(); + var imagesBeingEdited = new List { firstImage, secondImage }; + var gallery = new GalleryThumbnails { Images = imagesBeingEdited.ToList() }; + + imagesBeingEdited[0] = firstEditedImage; + gallery.UpdateImages(imagesBeingEdited); + imagesBeingEdited[1] = secondEditedImage; + gallery.UpdateImages(imagesBeingEdited); + + gallery.Images.Should().Equal(firstEditedImage, secondEditedImage); + } +} diff --git a/wiki/Media/ImageCapture.md b/wiki/Media/ImageCapture.md index 78b685ac9..03f95f681 100644 --- a/wiki/Media/ImageCapture.md +++ b/wiki/Media/ImageCapture.md @@ -106,6 +106,17 @@ private void OnImageCaptured(CapturedImage capturedImage) In multi-capture this method is called once per image, in capture order. Pair it with `OnImageRemoved` so your list reflects every add and every removal the user makes. +## Reviewing captured images after capture + +Use `GalleryThumbnails` to display a list of captured images after the camera closes: + +```xaml + +``` + +Tapping a thumbnail opens a full-screen preview where the user can browse, rotate, inspect, or remove images. Saving a rotation updates `Images` immediately. Multiple images can be rotated during the same preview session, and every saved rotation is retained in the bound list. + ## Handling camera failures ```csharp