[Videos] handle app backgrounding (#4912)

* play when returning from background

* play when unfullscreening

* play when entering fullscreen, just to be sure

* state -> ref

---------

Co-authored-by: Samuel Newman <10959775+mozzius@users.noreply.github.com>
zio/stable
Samuel Newman 2024-08-09 23:35:21 +01:00 committed by GitHub
parent 0a9782ac19
commit ab0da7c892
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 36 additions and 7 deletions

View File

@ -7,6 +7,7 @@ import {useLingui} from '@lingui/react'
import {useIsFocused} from '@react-navigation/native' import {useIsFocused} from '@react-navigation/native'
import {HITSLOP_30} from '#/lib/constants' import {HITSLOP_30} from '#/lib/constants'
import {useAppState} from '#/lib/hooks/useAppState'
import {useVideoPlayer} from '#/view/com/util/post-embeds/VideoPlayerContext' import {useVideoPlayer} from '#/view/com/util/post-embeds/VideoPlayerContext'
import {android, atoms as a, useTheme} from '#/alf' import {android, atoms as a, useTheme} from '#/alf'
import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
@ -21,6 +22,18 @@ export function VideoEmbedInnerNative() {
const player = useVideoPlayer() const player = useVideoPlayer()
const ref = useRef<VideoView>(null) const ref = useRef<VideoView>(null)
const isScreenFocused = useIsFocused() const isScreenFocused = useIsFocused()
const isAppFocused = useAppState()
const prevFocusedRef = useRef(isAppFocused)
// resume video when coming back from background
useEffect(() => {
if (isAppFocused !== prevFocusedRef.current) {
prevFocusedRef.current = isAppFocused
if (isAppFocused === 'active') {
player.play()
}
}
}, [isAppFocused, player])
// pause the video when the screen is not focused // pause the video when the screen is not focused
useEffect(() => { useEffect(() => {
@ -34,6 +47,10 @@ export function VideoEmbedInnerNative() {
} }
}, [isScreenFocused, player]) }, [isScreenFocused, player])
const enterFullscreen = useCallback(() => {
ref.current?.enterFullscreen()
}, [])
return ( return (
<View style={[a.flex_1, a.relative]}> <View style={[a.flex_1, a.relative]}>
<VideoView <VideoView
@ -50,14 +67,10 @@ export function VideoEmbedInnerNative() {
PlatformInfo.setAudioCategory(AudioCategory.Ambient) PlatformInfo.setAudioCategory(AudioCategory.Ambient)
PlatformInfo.setAudioMixWithOthers(true) PlatformInfo.setAudioMixWithOthers(true)
player.muted = true player.muted = true
if (!player.playing) player.play()
}} }}
/> />
<Controls <Controls player={player} enterFullscreen={enterFullscreen} />
player={player}
enterFullscreen={() => {
ref.current?.enterFullscreen()
}}
/>
</View> </View>
) )
} }
@ -102,6 +115,22 @@ function Controls({
} }
}, [player]) }, [player])
const onPressFullscreen = useCallback(() => {
switch (player.status) {
case 'idle':
case 'loading':
case 'readyToPlay': {
if (!player.playing) player.play()
enterFullscreen()
break
}
case 'error': {
player.replay()
break
}
}
}, [player, enterFullscreen])
const toggleMuted = useCallback(() => { const toggleMuted = useCallback(() => {
const muted = !player.muted const muted = !player.muted
// We want to set this to the _inverse_ of the new value, because we actually want for the audio to be mixed when // We want to set this to the _inverse_ of the new value, because we actually want for the audio to be mixed when
@ -150,7 +179,7 @@ function Controls({
</Animated.View> </Animated.View>
)} )}
<Pressable <Pressable
onPress={enterFullscreen} onPress={onPressFullscreen}
style={a.flex_1} style={a.flex_1}
accessibilityLabel={_(msg`Video`)} accessibilityLabel={_(msg`Video`)}
accessibilityHint={_(msg`Tap to enter full screen`)} accessibilityHint={_(msg`Tap to enter full screen`)}