Skip to content

fix: avoid swipe conflict when seeking voice notes - #1681

Open
qtjg wants to merge 2 commits into
permissionlesstech:mainfrom
qtjg:contrib/bitchat-voice-note-seek
Open

fix: avoid swipe conflict when seeking voice notes#1681
qtjg wants to merge 2 commits into
permissionlesstech:mainfrom
qtjg:contrib/bitchat-voice-note-seek

Conversation

@qtjg

@qtjg qtjg commented Aug 18, 2026

Copy link
Copy Markdown

Fixes #1658.

Problem

The private conversation attaches a high-priority right-swipe-to-leave DragGesture to the message list, while WaveformView uses DragGesture(minimumDistance: 0) for seeking. A horizontal drag over a playing voice note could therefore be claimed by the ancestor gesture, causing the seek to fail or accidentally closing the conversation.

Fix

This change keeps the waveform's original drag-seeking behavior, including press-and-slide-to-target before release. While any voice note is actively playing, the private-chat swipe-to-leave gesture is excluded from subviews so the waveform receives the drag. The swipe gesture resumes as soon as playback stops.

This deliberately prioritizes playback seeking over swipe-to-leave while audio is audible. Leaving remains available through the sidebar, and a playing voice note can no longer cause a scrub to close the conversation.

The bounded seekFraction helper remains extracted and handles normal mapping, out-of-range coordinates, and zero-width geometry safely.

Test plan

  • Added regression coverage for swipe thresholds, playback suppression and resumption, coordinator activity state, paused playback release, stale deactivation, and playback takeover.
  • Retained coverage for seek-fraction mapping, bounds clamping, and zero-width geometry.
  • git diff --check and committed-diff validation pass.
  • Swift/Xcode test execution is pending in CI because the local sandbox does not include the Swift toolchain.

Fixes permissionlesstech#1658.

The private conversation attaches a high-priority right-swipe-to-leave DragGesture to the message list, while WaveformView used DragGesture(minimumDistance: 0) for seeking. A horizontal drag over a playing voice note could therefore close the conversation instead of seeking.

Use SpatialTapGesture for deterministic tap-to-seek behavior, preserve bounded progress mapping, and cover normal mapping, bounds clamping, and zero-width geometry with regression tests.

@Chessing234 Chessing234 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two things.

swapping DragGesture for SpatialTapGesture doesn't just make seeking deterministic, it removes press-and-slide-to-target. the old DragGesture(minimumDistance: 0).onEnded already only seeked on release, so you could press down and slide to the spot you wanted before lifting; with a tap you have to land on it directly. on a waveform that's a few points tall that's a real loss worth calling out in the description rather than leaving as a side effect.

second, this and #1668 both fix #1658 from opposite ends — that one stands down the swipe-to-leave gesture while a voice note is playing and keeps drag-seeking. they're mutually exclusive, so someone has to pick. disclosure: #1668 is mine, and i'd rather jack chose on merit than have two branches sit there fighting.

no objection to the seekFraction extraction, that part is a clear improvement and testable.

@qtjg

qtjg commented Aug 24, 2026

Copy link
Copy Markdown
Author

Thanks for the detailed review. I agree that replacing the drag with SpatialTapGesture would unnecessarily remove press-and-slide seeking, so I restored the original DragGesture(minimumDistance: 0) behavior.

I chose the alternative approach from #1668: while a voice note is actively playing, the private-chat swipe-to-leave gesture is excluded from subviews so the waveform receives the drag. The swipe resumes when playback stops, and leaving remains available from the sidebar. This preserves the existing seeking interaction while addressing the reported accidental-navigation bug.

The bounded seekFraction extraction and its edge-case coverage are retained, along with regression tests for swipe thresholds, playback suppression/resumption, coordinator activity, pause release, stale deactivation, and playback takeover. The local sandbox lacks Swift/Xcode, so the Swift test suite remains pending in CI; static diff validation passes and the branch has no merge conflicts.

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.

Dragging on a playing voice note in a DM can leave the conversation

2 participants