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 {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
|
||||||
|
|||||||
Reference in New Issue
Block a user