Force uniform 1:1 square crop on all gallery cells

Replace ZStack-based cell with Color.clear.aspectRatio(1,.fit) + .overlay.
The overlay constrains all children (image, video badge, sync dot) to the
exact square frame, so scaledToFill cannot inflate the cell height in
LazyVGrid. Previously, the ZStack let the filled image push beyond the
aspectRatio constraint, causing inconsistent row heights.

Co-Authored-By: Kutesir <kutesir@provoc.ug>
Co-Authored-By: Sentry <sentry@provoc.ug>
This commit is contained in:
Robin Kutesa
2026-05-19 09:53:42 +03:00
parent 47867f2ef3
commit 0bcb8f849c

View File

@@ -260,21 +260,11 @@ struct GalleryCell: View {
@State private var taskID = UUID()
var body: some View {
ZStack {
cellBackground
if item.mediaType == .video, image != nil {
videoOverlay.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomLeading)
}
syncDot.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomTrailing)
}
// Color.clear anchors the 1:1 square; .overlay constrains all children to that
// exact frame so scaledToFill never inflates the cell height in LazyVGrid.
Color.clear
.aspectRatio(1, contentMode: .fit)
.clipped()
.id(taskID)
.task(id: taskID) { await loadThumbnail() }
}
@ViewBuilder
private var cellBackground: some View {
.overlay {
if let img = image {
Image(uiImage: img)
.resizable()
@@ -286,6 +276,14 @@ struct GalleryCell: View {
.shimmer()
}
}
.overlay(alignment: .bottomLeading) {
if item.mediaType == .video, image != nil { videoOverlay }
}
.overlay(alignment: .bottomTrailing) { syncDot }
.clipped()
.id(taskID)
.task(id: taskID) { await loadThumbnail() }
}
private var videoOverlay: some View {
HStack(spacing: 3) {