From 2d3831bd53d6b61d1e4b9c78330313c87cf8b4a5 Mon Sep 17 00:00:00 2001 From: goon-foss Date: Fri, 10 Jul 2026 09:38:03 +0200 Subject: [PATCH] fix(player): audio no longer cuts out on tap/scroll (2x-mute regression) Regression from the 2x-hold mute (commit e30f683). Gesture.LongPress fires onFinalize for FAILED/CANCELLED gestures too (a plain tap, or a scroll stealing the finger), not just after a real 2x hold. onFinalize unconditionally restored player.muted from preSpeedMutedRef, whose initial value is true, so any ordinary screen interaction muted the audio while the UI still showed the unmuted icon (report fad4b317 "Audio cuts out on screen interactions"). Track whether 2x actually started (speedStartedRef, set in onStart) and only touch player.muted in onEnd/onFinalize when it did. A failed or cancelled long-press now leaves the user's mute preference alone. Co-Authored-By: Claude Opus 4.8 --- mobile/src/changelog.ts | 7 +++++++ mobile/src/screens/PlayerScreen.tsx | 18 ++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/mobile/src/changelog.ts b/mobile/src/changelog.ts index eab670d..29327f1 100644 --- a/mobile/src/changelog.ts +++ b/mobile/src/changelog.ts @@ -16,6 +16,13 @@ export type ChangelogEntry = { }; export const CHANGELOG: ChangelogEntry[] = [ + { + id: '2026-07-10', + date: 'July 2026', + items: [ + 'Fixed: audio no longer cuts out when you tap or scroll on the video. It now only mutes while you hold to fast-forward, as intended.', + ], + }, { id: '2026-07-07', date: 'July 2026', diff --git a/mobile/src/screens/PlayerScreen.tsx b/mobile/src/screens/PlayerScreen.tsx index 56bcd11..bc61a82 100644 --- a/mobile/src/screens/PlayerScreen.tsx +++ b/mobile/src/screens/PlayerScreen.tsx @@ -551,6 +551,11 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) { // Stan wyciszenia SPRZED 2× (żeby przywrócić dokładnie preferencję usera po puszczeniu). const preSpeedMutedRef = React.useRef(true); + // Czy 2× REALNIE wystartowało. `onFinalize` odpala się też dla FAILED/CANCELLED + // (zwykły tap albo scroll, który przejmie palec) — bez tej flagi restore mute'a + // leciał z NIEaktualnym refem i wyciszał dźwięk przy zwykłym dotknięciu ekranu + // (regresja, report fad4b317 „Audio cuts out on screen interactions"). + const speedStartedRef = React.useRef(false); // Long-press → 2× speed dopóki trzymasz. minDuration 220ms żeby nie konfliktowało // z double-tap (drugi tap trwa krócej). onTouchesUp finalizuje gest. const longPress = React.useMemo( @@ -559,6 +564,7 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) { .minDuration(220) .maxDistance(30) .onStart(() => { + speedStartedRef.current = true; try { // Wycisz na czas 2× — przyspieszony dźwięk (chipmunk) jest nieprzyjemny // (report 35bbf428). Zapamiętujemy stan usera i przywracamy po puszczeniu. @@ -581,7 +587,11 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) { .onEnd(() => { try { player.playbackRate = 1.0; - player.muted = preSpeedMutedRef.current; + // Restore TYLKO gdy 2× realnie wystartowało (patrz speedStartedRef). + if (speedStartedRef.current) { + player.muted = preSpeedMutedRef.current; + speedStartedRef.current = false; + } } catch { // ignore } @@ -592,7 +602,11 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) { if (player.playbackRate !== 1.0) { player.playbackRate = 1.0; } - player.muted = preSpeedMutedRef.current; + // FAILED/CANCELLED bez onStart (tap, scroll) → NIE dotykaj mute'a. + if (speedStartedRef.current) { + player.muted = preSpeedMutedRef.current; + speedStartedRef.current = false; + } } catch { // ignore }