render player earlier, allowing preload

This commit is contained in:
Samuel Newman
2024-08-02 21:58:32 +02:00
parent 17f5d0980a
commit dd0e44e665
5 changed files with 15 additions and 49 deletions
@@ -1,11 +1,7 @@
import React, {useCallback, useEffect, useRef, useState} from 'react' import React, {useEffect, useRef, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonIcon} from '#/components/Button'
import {Play_Filled_Corner2_Rounded as PlayIcon} from '#/components/icons/Play'
import {useActiveVideoView} from './ActiveVideoContext' import {useActiveVideoView} from './ActiveVideoContext'
import {VideoEmbedInner} from './VideoEmbedInner' import {VideoEmbedInner} from './VideoEmbedInner'
@@ -17,10 +13,6 @@ export function VideoEmbed({source}: {source: string}) {
source, source,
}) })
const [onScreen, setOnScreen] = useState(false) const [onScreen, setOnScreen] = useState(false)
const [hasBeenOnScreen, setHasBeenOnScreen] = useState(false)
const {_} = useLingui()
const onPress = useCallback(() => setActive(), [setActive])
useEffect(() => { useEffect(() => {
if (!ref.current) return if (!ref.current) return
@@ -29,9 +21,6 @@ export function VideoEmbed({source}: {source: string}) {
const entry = entries[0] const entry = entries[0]
if (!entry) return if (!entry) return
setOnScreen(entry.isIntersecting) setOnScreen(entry.isIntersecting)
if (entry.isIntersecting) {
setHasBeenOnScreen(true)
}
sendPosition( sendPosition(
entry.boundingClientRect.y + entry.boundingClientRect.height / 2, entry.boundingClientRect.y + entry.boundingClientRect.height / 2,
) )
@@ -42,11 +31,6 @@ export function VideoEmbed({source}: {source: string}) {
return () => observer.disconnect() return () => observer.disconnect()
}, [sendPosition]) }, [sendPosition])
const onGoFarOffScreen = useCallback(() => {
setOnScreen(false)
setHasBeenOnScreen(false)
}, [])
return ( return (
<View <View
style={[ style={[
@@ -60,27 +44,14 @@ export function VideoEmbed({source}: {source: string}) {
ref={ref} ref={ref}
style={{display: 'flex', flex: 1}} style={{display: 'flex', flex: 1}}
onClick={evt => evt.stopPropagation()}> onClick={evt => evt.stopPropagation()}>
{hasBeenOnScreen || active ? ( <VideoEmbedInner
<VideoEmbedInner source={source}
source={source} active={active}
active={active} setActive={setActive}
setActive={setActive} sendPosition={sendPosition}
sendPosition={sendPosition} onScreen={onScreen}
onScreen={onScreen} isAnyViewActive={currentActiveView !== null}
isAnyViewActive={currentActiveView !== null} />
onGoFarOffScreen={onGoFarOffScreen}
/>
) : (
<Button
style={[a.flex_1, t.atoms.bg_contrast_25, a.rounded_sm]}
onPress={onPress}
label={_(msg`Play video`)}
variant="ghost"
color="secondary"
size="large">
<ButtonIcon icon={PlayIcon} />
</Button>
)}
</div> </div>
</View> </View>
) )
@@ -20,7 +20,6 @@ export function VideoEmbedInner({}: {
sendPosition: (position: number) => void sendPosition: (position: number) => void
onScreen: boolean onScreen: boolean
isAnyViewActive?: boolean isAnyViewActive?: boolean
onGoFarOffScreen: () => void
}) { }) {
const player = useVideoPlayer() const player = useVideoPlayer()
const aref = useAnimatedRef<Animated.View>() const aref = useAnimatedRef<Animated.View>()
@@ -9,7 +9,6 @@ export function VideoEmbedInner({
active, active,
sendPosition, sendPosition,
isAnyViewActive, isAnyViewActive,
onGoFarOffScreen,
...props ...props
}: { }: {
source: string source: string
@@ -17,10 +16,10 @@ export function VideoEmbedInner({
setActive: () => void setActive: () => void
sendPosition: (position: number) => void sendPosition: (position: number) => void
onScreen: boolean onScreen: boolean
onGoFarOffScreen: () => void
isAnyViewActive?: boolean isAnyViewActive?: boolean
}) { }) {
const ref = useRef<HTMLDivElement>(null) const ref = useRef<HTMLDivElement>(null)
const [nearScreen, setNearScreen] = useState(false)
// Send position when scrolling. This is done with an IntersectionObserver // Send position when scrolling. This is done with an IntersectionObserver
// observing a div of 100vh height // observing a div of 100vh height
@@ -33,16 +32,13 @@ export function VideoEmbedInner({
const position = const position =
entry.boundingClientRect.y + entry.boundingClientRect.height / 2 entry.boundingClientRect.y + entry.boundingClientRect.height / 2
sendPosition(position) sendPosition(position)
if (!entry.isIntersecting) { setNearScreen(entry.isIntersecting)
// unmounts the video player
onGoFarOffScreen()
}
}, },
{threshold: Array.from({length: 101}, (_, i) => i / 100)}, {threshold: Array.from({length: 101}, (_, i) => i / 100)},
) )
observer.observe(ref.current) observer.observe(ref.current)
return () => observer.disconnect() return () => observer.disconnect()
}, [sendPosition, onGoFarOffScreen]) }, [sendPosition])
// In case scrolling hasn't started yet, send up the position // In case scrolling hasn't started yet, send up the position
useEffect(() => { useEffect(() => {
@@ -55,7 +51,7 @@ export function VideoEmbedInner({
return ( return (
<View style={[a.flex_1, a.flex_row]}> <View style={[a.flex_1, a.flex_row]}>
<VideoPlayer active={active} {...props} /> {nearScreen && <VideoPlayer active={active} {...props} />}
<div <div
ref={ref} ref={ref}
style={{ style={{
@@ -3,7 +3,7 @@ import type Hls from 'hls.js'
export function Controls({}: { export function Controls({}: {
videoRef: React.RefObject<HTMLVideoElement> videoRef: React.RefObject<HTMLVideoElement>
hlsRef: React.RefObject<Hls> hlsRef: React.RefObject<Hls | undefined>
active: boolean active: boolean
setActive: () => void setActive: () => void
focused: boolean focused: boolean
@@ -40,7 +40,7 @@ export function Controls({
hasSubtitleTrack, hasSubtitleTrack,
}: { }: {
videoRef: React.RefObject<HTMLVideoElement> videoRef: React.RefObject<HTMLVideoElement>
hlsRef: React.RefObject<Hls> hlsRef: React.RefObject<Hls | undefined>
active: boolean active: boolean
setActive: () => void setActive: () => void
focused: boolean focused: boolean