Fix video thumbnails on native (#8774)
This commit is contained in:
+1
-1
@@ -142,7 +142,7 @@
|
|||||||
"expo-file-system": "~18.1.10",
|
"expo-file-system": "~18.1.10",
|
||||||
"expo-font": "~13.3.1",
|
"expo-font": "~13.3.1",
|
||||||
"expo-haptics": "~14.1.4",
|
"expo-haptics": "~14.1.4",
|
||||||
"expo-image": "~2.2.1",
|
"expo-image": "^2.4.0",
|
||||||
"expo-image-crop-tool": "^0.1.8",
|
"expo-image-crop-tool": "^0.1.8",
|
||||||
"expo-image-manipulator": "~13.1.7",
|
"expo-image-manipulator": "~13.1.7",
|
||||||
"expo-image-picker": "~16.1.4",
|
"expo-image-picker": "~16.1.4",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {useRef} from 'react'
|
import {useImperativeHandle, useRef, useState} from 'react'
|
||||||
import {Pressable, type StyleProp, View, type ViewStyle} from 'react-native'
|
import {Pressable, type StyleProp, View, type ViewStyle} from 'react-native'
|
||||||
import {type AppBskyEmbedVideo} from '@atproto/api'
|
import {type AppBskyEmbedVideo} from '@atproto/api'
|
||||||
import {BlueskyVideoView} from '@haileyok/bluesky-video'
|
import {BlueskyVideoView} from '@haileyok/bluesky-video'
|
||||||
@@ -17,91 +17,88 @@ import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
|||||||
import {useVideoMuteState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
|
import {useVideoMuteState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
|
||||||
import {TimeIndicator} from './TimeIndicator'
|
import {TimeIndicator} from './TimeIndicator'
|
||||||
|
|
||||||
export const VideoEmbedInnerNative = React.forwardRef(
|
export function VideoEmbedInnerNative({
|
||||||
function VideoEmbedInnerNative(
|
ref,
|
||||||
{
|
embed,
|
||||||
embed,
|
setStatus,
|
||||||
setStatus,
|
setIsLoading,
|
||||||
setIsLoading,
|
setIsActive,
|
||||||
setIsActive,
|
}: {
|
||||||
}: {
|
ref: React.Ref<{togglePlayback: () => void}>
|
||||||
embed: AppBskyEmbedVideo.View
|
embed: AppBskyEmbedVideo.View
|
||||||
setStatus: (status: 'playing' | 'paused') => void
|
setStatus: (status: 'playing' | 'paused') => void
|
||||||
setIsLoading: (isLoading: boolean) => void
|
setIsLoading: (isLoading: boolean) => void
|
||||||
setIsActive: (isActive: boolean) => void
|
setIsActive: (isActive: boolean) => void
|
||||||
|
}) {
|
||||||
|
const {_} = useLingui()
|
||||||
|
const videoRef = useRef<BlueskyVideoView>(null)
|
||||||
|
const autoplayDisabled = useAutoplayDisabled()
|
||||||
|
const isWithinMessage = useIsWithinMessage()
|
||||||
|
const [muted, setMuted] = useVideoMuteState()
|
||||||
|
|
||||||
|
const [isPlaying, setIsPlaying] = useState(false)
|
||||||
|
const [timeRemaining, setTimeRemaining] = useState(0)
|
||||||
|
const [error, setError] = useState<string>()
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
togglePlayback: () => {
|
||||||
|
videoRef.current?.togglePlayback()
|
||||||
},
|
},
|
||||||
ref: React.Ref<{togglePlayback: () => void}>,
|
}))
|
||||||
) {
|
|
||||||
const {_} = useLingui()
|
|
||||||
const videoRef = useRef<BlueskyVideoView>(null)
|
|
||||||
const autoplayDisabled = useAutoplayDisabled()
|
|
||||||
const isWithinMessage = useIsWithinMessage()
|
|
||||||
const [muted, setMuted] = useVideoMuteState()
|
|
||||||
|
|
||||||
const [isPlaying, setIsPlaying] = React.useState(false)
|
if (error) {
|
||||||
const [timeRemaining, setTimeRemaining] = React.useState(0)
|
throw new Error(error)
|
||||||
const [error, setError] = React.useState<string>()
|
}
|
||||||
|
|
||||||
React.useImperativeHandle(ref, () => ({
|
return (
|
||||||
togglePlayback: () => {
|
<View style={[a.flex_1, a.relative]}>
|
||||||
videoRef.current?.togglePlayback()
|
<BlueskyVideoView
|
||||||
},
|
url={embed.playlist}
|
||||||
}))
|
autoplay={!autoplayDisabled && !isWithinMessage}
|
||||||
|
beginMuted={autoplayDisabled ? false : muted}
|
||||||
if (error) {
|
style={[a.rounded_sm]}
|
||||||
throw new Error(error)
|
onActiveChange={e => {
|
||||||
}
|
setIsActive(e.nativeEvent.isActive)
|
||||||
|
}}
|
||||||
return (
|
onLoadingChange={e => {
|
||||||
<View style={[a.flex_1, a.relative]}>
|
setIsLoading(e.nativeEvent.isLoading)
|
||||||
<BlueskyVideoView
|
}}
|
||||||
url={embed.playlist}
|
onMutedChange={e => {
|
||||||
autoplay={!autoplayDisabled && !isWithinMessage}
|
setMuted(e.nativeEvent.isMuted)
|
||||||
beginMuted={autoplayDisabled ? false : muted}
|
}}
|
||||||
style={[a.rounded_sm]}
|
onStatusChange={e => {
|
||||||
onActiveChange={e => {
|
setStatus(e.nativeEvent.status)
|
||||||
setIsActive(e.nativeEvent.isActive)
|
setIsPlaying(e.nativeEvent.status === 'playing')
|
||||||
}}
|
}}
|
||||||
onLoadingChange={e => {
|
onTimeRemainingChange={e => {
|
||||||
setIsLoading(e.nativeEvent.isLoading)
|
setTimeRemaining(e.nativeEvent.timeRemaining)
|
||||||
}}
|
}}
|
||||||
onMutedChange={e => {
|
onError={e => {
|
||||||
setMuted(e.nativeEvent.isMuted)
|
setError(e.nativeEvent.error)
|
||||||
}}
|
}}
|
||||||
onStatusChange={e => {
|
ref={videoRef}
|
||||||
setStatus(e.nativeEvent.status)
|
accessibilityLabel={
|
||||||
setIsPlaying(e.nativeEvent.status === 'playing')
|
embed.alt ? _(msg`Video: ${embed.alt}`) : _(msg`Video`)
|
||||||
}}
|
}
|
||||||
onTimeRemainingChange={e => {
|
accessibilityHint=""
|
||||||
setTimeRemaining(e.nativeEvent.timeRemaining)
|
/>
|
||||||
}}
|
<VideoControls
|
||||||
onError={e => {
|
enterFullscreen={() => {
|
||||||
setError(e.nativeEvent.error)
|
videoRef.current?.enterFullscreen(true)
|
||||||
}}
|
}}
|
||||||
ref={videoRef}
|
toggleMuted={() => {
|
||||||
accessibilityLabel={
|
videoRef.current?.toggleMuted()
|
||||||
embed.alt ? _(msg`Video: ${embed.alt}`) : _(msg`Video`)
|
}}
|
||||||
}
|
togglePlayback={() => {
|
||||||
accessibilityHint=""
|
videoRef.current?.togglePlayback()
|
||||||
/>
|
}}
|
||||||
<VideoControls
|
isPlaying={isPlaying}
|
||||||
enterFullscreen={() => {
|
timeRemaining={timeRemaining}
|
||||||
videoRef.current?.enterFullscreen(true)
|
/>
|
||||||
}}
|
<MediaInsetBorder />
|
||||||
toggleMuted={() => {
|
</View>
|
||||||
videoRef.current?.toggleMuted()
|
)
|
||||||
}}
|
}
|
||||||
togglePlayback={() => {
|
|
||||||
videoRef.current?.togglePlayback()
|
|
||||||
}}
|
|
||||||
isPlaying={isPlaying}
|
|
||||||
timeRemaining={timeRemaining}
|
|
||||||
/>
|
|
||||||
<MediaInsetBorder />
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
function VideoControls({
|
function VideoControls({
|
||||||
enterFullscreen,
|
enterFullscreen,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {useCallback, useState} from 'react'
|
import {useCallback, useRef, useState} from 'react'
|
||||||
import {ActivityIndicator, View} from 'react-native'
|
import {ActivityIndicator, View} from 'react-native'
|
||||||
import {ImageBackground} from 'expo-image'
|
import {ImageBackground} from 'expo-image'
|
||||||
import {type AppBskyEmbedVideo} from '@atproto/api'
|
import {type AppBskyEmbedVideo} from '@atproto/api'
|
||||||
@@ -81,13 +81,13 @@ export function VideoEmbed({embed, crop}: Props) {
|
|||||||
|
|
||||||
function InnerWrapper({embed}: Props) {
|
function InnerWrapper({embed}: Props) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const ref = React.useRef<{togglePlayback: () => void}>(null)
|
const ref = useRef<{togglePlayback: () => void}>(null)
|
||||||
|
|
||||||
const [status, setStatus] = React.useState<'playing' | 'paused' | 'pending'>(
|
const [status, setStatus] = useState<'playing' | 'paused' | 'pending'>(
|
||||||
'pending',
|
'pending',
|
||||||
)
|
)
|
||||||
const [isLoading, setIsLoading] = React.useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [isActive, setIsActive] = React.useState(false)
|
const [isActive, setIsActive] = useState(false)
|
||||||
const showSpinner = useThrottledValue(isActive && isLoading, 100)
|
const showSpinner = useThrottledValue(isActive && isLoading, 100)
|
||||||
|
|
||||||
const showOverlay =
|
const showOverlay =
|
||||||
@@ -96,11 +96,9 @@ function InnerWrapper({embed}: Props) {
|
|||||||
(status === 'paused' && !isActive) ||
|
(status === 'paused' && !isActive) ||
|
||||||
status === 'pending'
|
status === 'pending'
|
||||||
|
|
||||||
React.useEffect(() => {
|
if (!isActive && status !== 'pending') {
|
||||||
if (!isActive && status !== 'pending') {
|
setStatus('pending')
|
||||||
setStatus('pending')
|
}
|
||||||
}
|
|
||||||
}, [isActive, status])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -131,8 +129,7 @@ function InnerWrapper({embed}: Props) {
|
|||||||
onPress={() => {
|
onPress={() => {
|
||||||
ref.current?.togglePlayback()
|
ref.current?.togglePlayback()
|
||||||
}}
|
}}
|
||||||
label={_(msg`Play video`)}
|
label={_(msg`Play video`)}>
|
||||||
color="secondary">
|
|
||||||
{showSpinner ? (
|
{showSpinner ? (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
|
|||||||
@@ -11301,10 +11301,10 @@ expo-image-picker@~16.1.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
expo-image-loader "~5.1.0"
|
expo-image-loader "~5.1.0"
|
||||||
|
|
||||||
expo-image@~2.2.1:
|
expo-image@^2.4.0:
|
||||||
version "2.2.1"
|
version "2.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/expo-image/-/expo-image-2.2.1.tgz#b4aa706a25f7e8902ac854a8da249caf4a90cd67"
|
resolved "https://registry.yarnpkg.com/expo-image/-/expo-image-2.4.0.tgz#02f7fd743387206914cd431a6367f5be53509e3e"
|
||||||
integrity sha512-5ZSggMi0X2G9AN0aM+sdkCyyZ6YcWvGs9KYLYrRBVUN3ph6RBiu6mKGpaNN1TAscySRnH1eHbUE1H+Qeq7qm1g==
|
integrity sha512-TQ/LvrtJ9JBr+Tf198CAqflxcvdhuj7P24n0LQ1jHaWIVA7Z+zYKbYHnSMPSDMul/y0U46Z5bFLbiZiSidgcNw==
|
||||||
|
|
||||||
expo-json-utils@~0.15.0:
|
expo-json-utils@~0.15.0:
|
||||||
version "0.15.0"
|
version "0.15.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user