diff --git a/mobile/src/screens/PlayerScreen.tsx b/mobile/src/screens/PlayerScreen.tsx index e8cdb2e..0cd53cc 100644 --- a/mobile/src/screens/PlayerScreen.tsx +++ b/mobile/src/screens/PlayerScreen.tsx @@ -161,8 +161,19 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) { const player = useVideoPlayer(source, (p) => { p.loop = false; + // Start wyciszony — dźwięk dopiero po tapnięciu przycisku (UX request 2026-06-07). + // Dodatkowo: muted autoplay nie wymaga audio-focus, więc nie ucisza muzyki usera + // przy podglądzie i nie zaskakuje głośnym startem. + p.muted = true; p.play(); }); + const [muted, setMuted] = React.useState(true); + const toggleMute = React.useCallback(() => { + const next = !player.muted; + player.muted = next; + setMuted(next); + setControlsVisible(true); + }, [player]); const statusEvent = useEvent(player, 'statusChange', { status: player.status }); const status = statusEvent?.status ?? player.status; @@ -637,6 +648,14 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) { )} + {/* Unmute pill — zawsze widoczny gdy wyciszone (poza fade controls), bo start jest + muted i user musi wiedzieć jak włączyć dźwięk. Tap → unmute. */} + {muted && ( + + 🔇 Tap for sound + + )} + {/* Controls overlay — pointerEvents box-none żeby gesture overlay pod spodem dalej dostawał taps poza interactive elements (back, play, scrubber). */} )} + + {muted ? '🔇' : '🔊'} + {isLandscape ? '⤬' : '⛶'} @@ -1053,7 +1075,12 @@ const INJECTED_JS = ` // i ma valid src, próbujemy odpalić. if (el.tagName === 'VIDEO' && el.paused && (el.src || el.currentSrc)) { try { - el.muted = false; + // Start muted (UX request 2026-06-07: dźwięk dopiero po geście usera). + // Bonus: muted autoplay jest dozwolony przez politykę przeglądarki, więc + // video faktycznie rusza bez gestu → szybsza ekstrakcja CDN URL (potem + // nav.replace na NativeVideoPlayer). W odsłoniętym WebView dźwięk włącza + // user przez własne kontrolki playera hostera. + el.muted = true; const p = el.play(); if (p && p.catch) p.catch(function(){}); } catch (e) {} @@ -1614,4 +1641,18 @@ const styles = StyleSheet.create({ borderRadius: 14, overflow: 'hidden', }, + unmutePill: { + position: 'absolute', + bottom: 96, + alignSelf: 'center', + backgroundColor: 'rgba(0,0,0,0.78)', + paddingVertical: 8, + paddingHorizontal: 16, + borderRadius: 18, + }, + unmutePillText: { + color: theme.fg, + fontSize: 14, + fontWeight: '700', + }, });