Skip to content

Fix CropView auto-commit during held-still pinch#307

Merged
muukii merged 1 commit into
v5from
claude/epic-goldstine-be65b2
Jun 17, 2026
Merged

Fix CropView auto-commit during held-still pinch#307
muukii merged 1 commit into
v5from
claude/epic-goldstine-be65b2

Conversation

@muukii

@muukii muukii commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Problem

In Crop mode, holding a pinch still (fingers down, no movement) would snap the scroll view back to the recorded crop after ~0.8s, making it look like the crop was committed mid-gesture.

Cause

cropSurface.onDidZoom schedules updateCropLayout() on a trailing debounce (interval 0.8s). updateCropLayout()updateScrollContainerView()customZoom(to: crop.zoomExtent()) resets the scroll view to state.proposedCrop, which is not updated mid-pinch (record() only runs on settle).

While the user moves their fingers, continuous scrollViewDidZoom events keep resetting the 0.8s debounce. The moment the user holds still with fingers down, events stop firing and the debounce fires mid-gesture, snapping the view.

The sibling onDidScroll debounce already guards against this for drags with an isTracking == false check, but onDidZoom had no equivalent guard — and both closures share the same debounce instance, so whether the snap happens depends on which event was scheduled last.

Fix

Guard the onDidZoom settle layout with cropSurface.isInteractiveZoomGestureActive == false (pinch recognizer not in .began/.changed), deferring the reflow until the pinch actually ends.

The crop recording path (record() via the scrollViewSettleDebouncedidSettleScrollViewAdjustment) already checks isContentOffsetResting (isZooming == false, etc.), so commit semantics are unchanged — this only stops the premature layout snap.

Verification

  • BrightroomUI builds (iPhone 17 Pro, iOS 26.5).
  • Confirmed in SwiftUIDemo PhotosCrop: pinching and holding still no longer auto-snaps the crop.

🤖 Generated with Claude Code

In Crop mode, holding a pinch still (fingers down, no movement) would
snap the scroll view back to the recorded crop after ~0.8s, looking like
the crop was committed mid-gesture.

The `onDidZoom` trailing debounce ran `updateCropLayout()` — whose
`customZoom(to:)` resets the scroll view to the not-yet-recorded
`proposedCrop`. While moving, continuous `scrollViewDidZoom` events kept
resetting the 0.8s debounce; once the user held still, events stopped and
the debounce fired mid-pinch. The sibling `onDidScroll` debounce already
guarded against this with an `isTracking == false` check, but `onDidZoom`
had no equivalent guard (and both share the same debounce).

Guard the `onDidZoom` settle layout with
`cropSurface.isInteractiveZoomGestureActive == false` so the reflow is
deferred until the pinch actually ends. The crop recording path
(`record()` via the settle debounce) already checks
`isContentOffsetResting`, so commit semantics are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@muukii muukii merged commit 6a8bf77 into v5 Jun 17, 2026
2 checks passed
@muukii muukii deleted the claude/epic-goldstine-be65b2 branch June 17, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant