From 6886035632bfd93f9384fcd6c9b8acdbc056941c Mon Sep 17 00:00:00 2001 From: jack <212554440+jackjackbits@users.noreply.github.com> Date: Wed, 8 Jul 2026 09:20:54 +0200 Subject: [PATCH] Fix press-and-hold mic dying instantly in private chats (#1405) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The private-chat sheet wraps its entire content — composer included — in a high-priority swipe-right-to-leave DragGesture. A high-priority ancestor drag preempts child gestures, so the composer mic's press-and-hold was cancelled 3-10 ms after touch-down (observed on both iOS and macOS in field logs), making voice notes unrecordable inside DMs while working fine in the public timeline. Same starvation mechanism as the DM image-reveal bug (#1402), hitting a drag instead of a tap. The swipe-to-leave gesture now attaches to the message list only — where users actually swipe — leaving the composer's gestures (mic hold, text field, buttons) out of its reach. Co-authored-by: jack Co-authored-by: Claude Fable 5 --- bitchat/Views/ContentSheetViews.swift | 28 ++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/bitchat/Views/ContentSheetViews.swift b/bitchat/Views/ContentSheetViews.swift index 4d9d5c5b..f8fb9411 100644 --- a/bitchat/Views/ContentSheetViews.swift +++ b/bitchat/Views/ContentSheetViews.swift @@ -393,6 +393,11 @@ private struct ContentPrivateChatSheetView: View { ) .themedSurface() .frame(maxWidth: .infinity, maxHeight: .infinity) + // Swipe-right-to-leave lives on the message list only. On the + // whole sheet it preempted the composer's press-and-hold mic + // gesture (a high-priority ancestor drag cancels child gestures + // within milliseconds — same starvation as the image-reveal bug). + .highPriorityGesture(swipeToLeaveGesture) if !theme.usesGlassChrome { Divider() @@ -423,18 +428,19 @@ private struct ContentPrivateChatSheetView: View { } .themedSheetBackground() .foregroundColor(palette.primary) - .highPriorityGesture( - DragGesture(minimumDistance: 25, coordinateSpace: .local) - .onEnded { value in - let horizontal = value.translation.width - let vertical = abs(value.translation.height) - guard horizontal > 80, vertical < 60 else { return } - withAnimation(.easeInOut(duration: TransportConfig.uiAnimationMediumSeconds)) { - showSidebar = true - privateConversationModel.endConversation() - } + } + + private var swipeToLeaveGesture: some Gesture { + DragGesture(minimumDistance: 25, coordinateSpace: .local) + .onEnded { value in + let horizontal = value.translation.width + let vertical = abs(value.translation.height) + guard horizontal > 80, vertical < 60 else { return } + withAnimation(.easeInOut(duration: TransportConfig.uiAnimationMediumSeconds)) { + showSidebar = true + privateConversationModel.endConversation() } - ) + } } /// Persistent one-line reminder that this composer feeds a private