From 8bce08b30599c552410b3e0bf199d96e48c9c4c9 Mon Sep 17 00:00:00 2001 From: Vetle Finstad Date: Tue, 4 Aug 2026 10:11:32 +0200 Subject: [PATCH] Fix compact CameraPreview toolbar clipping --- CHANGELOG.md | 3 ++ .../API/Camera/Preview/CameraPreview.cs | 37 ++++++++++++---- .../API/Camera/Preview/CameraPreviewTests.cs | 42 +++++++++++++++++++ 3 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 src/tests/unittests/API/Camera/Preview/CameraPreviewTests.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b2b266f8..5b6c642c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [62.1.5] +- [CameraPreview] Fixed custom bottom toolbar content being clipped on compact phone screens (Arena.Mobile #2053). + ## [62.1.4] - [Gallery] Fixed issue where only one of multiple image rotations was retained. diff --git a/src/library/DIPS.Mobile.UI/API/Camera/Preview/CameraPreview.cs b/src/library/DIPS.Mobile.UI/API/Camera/Preview/CameraPreview.cs index 5ffd515f0..bf0c48219 100644 --- a/src/library/DIPS.Mobile.UI/API/Camera/Preview/CameraPreview.cs +++ b/src/library/DIPS.Mobile.UI/API/Camera/Preview/CameraPreview.cs @@ -54,6 +54,7 @@ public Grid ConstructView() VerticalOptions = LayoutOptions.End, BackgroundColor = Colors.Transparent, }; + m_bottomToolbarContainer.SizeChanged += OnBottomToolbarContainerSizeChanged; m_topToolbarContainer = new Grid { @@ -101,7 +102,7 @@ internal static float ComputeTopToolbarHeight(float width, float frameHeight) } /// - /// Here we set the height of the top and bottom toolbar relative to the + /// Reserves the camera letterbox area for the toolbars while allowing toolbar content to grow when needed. /// /// internal void SetToolbarHeights(float frameHeight) @@ -116,12 +117,9 @@ internal void SetToolbarHeights(float frameHeight) var topToolbarHeight = ComputeTopToolbarHeight((float)Width, frameHeight); m_topToolbarContainer.HeightRequest = topToolbarHeight; - m_bottomToolbarContainer.HeightRequest = Math.Max(totalLetterBoxHeight - topToolbarHeight, 0); + m_bottomToolbarContainer.MinimumHeightRequest = Math.Max(totalLetterBoxHeight - topToolbarHeight, 0); - if (CameraZoomView is not null) - { - CameraZoomView.Margin = new Thickness(0, 0, 0, Sizes.GetSize(SizeName.content_margin_small) + m_bottomToolbarContainer.HeightRequest); - } + UpdateCameraZoomMargin(); PreviewView.TranslationY -= topToolbarHeight; m_hasSetToolbarHeights = true; @@ -137,13 +135,38 @@ internal double BottomOverlayOffset get { var zoomHeight = CameraZoomView?.Height ?? 0; - return m_bottomToolbarContainer.HeightRequest + return GetBottomToolbarHeight() + Sizes.GetSize(SizeName.content_margin_small) + zoomHeight + Sizes.GetSize(SizeName.content_margin_small); } } + private void OnBottomToolbarContainerSizeChanged(object? sender, EventArgs e) + { + if (!m_hasSetToolbarHeights) + return; + + UpdateCameraZoomMargin(); + } + + private void UpdateCameraZoomMargin() + { + if (CameraZoomView is null) + return; + + CameraZoomView.Margin = new Thickness( + 0, + 0, + 0, + Sizes.GetSize(SizeName.content_margin_small) + GetBottomToolbarHeight()); + } + + private double GetBottomToolbarHeight() + { + return Math.Max(0, Math.Max(m_bottomToolbarContainer.MinimumHeightRequest, m_bottomToolbarContainer.Height)); + } + internal void AddFocusIndicator(float percentX, float percentY) { m_grid?.Remove(m_indicatorWrapper); diff --git a/src/tests/unittests/API/Camera/Preview/CameraPreviewTests.cs b/src/tests/unittests/API/Camera/Preview/CameraPreviewTests.cs new file mode 100644 index 000000000..d4cefdfc4 --- /dev/null +++ b/src/tests/unittests/API/Camera/Preview/CameraPreviewTests.cs @@ -0,0 +1,42 @@ +using System.Linq; +using DIPS.Mobile.UI.API.Camera.Preview; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Graphics; + +namespace DIPS.Mobile.UI.UnitTests.API.Camera.Preview; + +public class CameraPreviewTests +{ + [Fact] + public void BottomToolbar_CompactScreen_DoesNotClipContent() + { + // Matches the specimen-scanner frame and bottom content measured on an iPhone SE. + const double previewWidth = 375; + const double previewHeight = 593; + const double bottomContentHeight = 102; + + var cameraPreview = new CameraPreview(); + var root = cameraPreview.ConstructView(); + cameraPreview.Content = root; + cameraPreview.Measure(previewWidth, previewHeight); + cameraPreview.Arrange(new Rect(0, 0, previewWidth, previewHeight)); + cameraPreview.SetToolbarHeights((float)previewHeight); + + var bottomContent = new Grid + { + HeightRequest = bottomContentHeight + }; + cameraPreview.AddBottomToolbarView(bottomContent); + + var bottomToolbar = root.Children + .OfType() + .Single(grid => grid.Children.Contains(bottomContent)); + var expectedLetterboxHeight = previewHeight + - previewWidth / CameraPreview.ThreeFourRatio + - CameraPreview.ComputeTopToolbarHeight((float)previewWidth, (float)previewHeight); + + bottomToolbar.HeightRequest.Should().Be(-1); + bottomToolbar.MinimumHeightRequest.Should().BeApproximately(expectedLetterboxHeight, 0.01); + bottomContent.HeightRequest.Should().BeGreaterThan(bottomToolbar.MinimumHeightRequest); + } +}