render player earlier, allowing preload
This commit is contained in:
@@ -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 {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
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 {VideoEmbedInner} from './VideoEmbedInner'
|
||||
|
||||
@@ -17,10 +13,6 @@ export function VideoEmbed({source}: {source: string}) {
|
||||
source,
|
||||
})
|
||||
const [onScreen, setOnScreen] = useState(false)
|
||||
const [hasBeenOnScreen, setHasBeenOnScreen] = useState(false)
|
||||
const {_} = useLingui()
|
||||
|
||||
const onPress = useCallback(() => setActive(), [setActive])
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current) return
|
||||
@@ -29,9 +21,6 @@ export function VideoEmbed({source}: {source: string}) {
|
||||
const entry = entries[0]
|
||||
if (!entry) return
|
||||
setOnScreen(entry.isIntersecting)
|
||||
if (entry.isIntersecting) {
|
||||
setHasBeenOnScreen(true)
|
||||
}
|
||||
sendPosition(
|
||||
entry.boundingClientRect.y + entry.boundingClientRect.height / 2,
|
||||
)
|
||||
@@ -42,11 +31,6 @@ export function VideoEmbed({source}: {source: string}) {
|
||||
return () => observer.disconnect()
|
||||
}, [sendPosition])
|
||||
|
||||
const onGoFarOffScreen = useCallback(() => {
|
||||
setOnScreen(false)
|
||||
setHasBeenOnScreen(false)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
@@ -60,27 +44,14 @@ export function VideoEmbed({source}: {source: string}) {
|
||||
ref={ref}
|
||||
style={{display: 'flex', flex: 1}}
|
||||
onClick={evt => evt.stopPropagation()}>
|
||||
{hasBeenOnScreen || active ? (
|
||||
<VideoEmbedInner
|
||||
source={source}
|
||||
active={active}
|
||||
setActive={setActive}
|
||||
sendPosition={sendPosition}
|
||||
onScreen={onScreen}
|
||||
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>
|
||||
)}
|
||||
<VideoEmbedInner
|
||||
source={source}
|
||||
active={active}
|
||||
setActive={setActive}
|
||||
sendPosition={sendPosition}
|
||||
onScreen={onScreen}
|
||||
isAnyViewActive={currentActiveView !== null}
|
||||
/>
|
||||
</div>
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -20,7 +20,6 @@ export function VideoEmbedInner({}: {
|
||||
sendPosition: (position: number) => void
|
||||
onScreen: boolean
|
||||
isAnyViewActive?: boolean
|
||||
onGoFarOffScreen: () => void
|
||||
}) {
|
||||
const player = useVideoPlayer()
|
||||
const aref = useAnimatedRef<Animated.View>()
|
||||
|
||||
@@ -9,7 +9,6 @@ export function VideoEmbedInner({
|
||||
active,
|
||||
sendPosition,
|
||||
isAnyViewActive,
|
||||
onGoFarOffScreen,
|
||||
...props
|
||||
}: {
|
||||
source: string
|
||||
@@ -17,10 +16,10 @@ export function VideoEmbedInner({
|
||||
setActive: () => void
|
||||
sendPosition: (position: number) => void
|
||||
onScreen: boolean
|
||||
onGoFarOffScreen: () => void
|
||||
isAnyViewActive?: boolean
|
||||
}) {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const [nearScreen, setNearScreen] = useState(false)
|
||||
|
||||
// Send position when scrolling. This is done with an IntersectionObserver
|
||||
// observing a div of 100vh height
|
||||
@@ -33,16 +32,13 @@ export function VideoEmbedInner({
|
||||
const position =
|
||||
entry.boundingClientRect.y + entry.boundingClientRect.height / 2
|
||||
sendPosition(position)
|
||||
if (!entry.isIntersecting) {
|
||||
// unmounts the video player
|
||||
onGoFarOffScreen()
|
||||
}
|
||||
setNearScreen(entry.isIntersecting)
|
||||
},
|
||||
{threshold: Array.from({length: 101}, (_, i) => i / 100)},
|
||||
)
|
||||
observer.observe(ref.current)
|
||||
return () => observer.disconnect()
|
||||
}, [sendPosition, onGoFarOffScreen])
|
||||
}, [sendPosition])
|
||||
|
||||
// In case scrolling hasn't started yet, send up the position
|
||||
useEffect(() => {
|
||||
@@ -55,7 +51,7 @@ export function VideoEmbedInner({
|
||||
|
||||
return (
|
||||
<View style={[a.flex_1, a.flex_row]}>
|
||||
<VideoPlayer active={active} {...props} />
|
||||
{nearScreen && <VideoPlayer active={active} {...props} />}
|
||||
<div
|
||||
ref={ref}
|
||||
style={{
|
||||
|
||||
@@ -3,7 +3,7 @@ import type Hls from 'hls.js'
|
||||
|
||||
export function Controls({}: {
|
||||
videoRef: React.RefObject<HTMLVideoElement>
|
||||
hlsRef: React.RefObject<Hls>
|
||||
hlsRef: React.RefObject<Hls | undefined>
|
||||
active: boolean
|
||||
setActive: () => void
|
||||
focused: boolean
|
||||
|
||||
@@ -40,7 +40,7 @@ export function Controls({
|
||||
hasSubtitleTrack,
|
||||
}: {
|
||||
videoRef: React.RefObject<HTMLVideoElement>
|
||||
hlsRef: React.RefObject<Hls>
|
||||
hlsRef: React.RefObject<Hls | undefined>
|
||||
active: boolean
|
||||
setActive: () => void
|
||||
focused: boolean
|
||||
|
||||
Reference in New Issue
Block a user