mirror of
https://github.com/tooot-app/app
synced 2025-04-16 03:07:32 +02:00
140 lines
3.6 KiB
TypeScript
140 lines
3.6 KiB
TypeScript
import Button from '@components/Button'
|
|
import { StyleConstants } from '@utils/styles/constants'
|
|
import { Video } from 'expo-av'
|
|
import React, { useCallback, useRef, useState } from 'react'
|
|
import { Pressable, StyleSheet, View } from 'react-native'
|
|
import { Blurhash } from 'react-native-blurhash'
|
|
import attachmentAspectRatio from './aspectRatio'
|
|
import analytics from '@components/analytics'
|
|
|
|
export interface Props {
|
|
total: number
|
|
index: number
|
|
sensitiveShown: boolean
|
|
video: Mastodon.AttachmentVideo | Mastodon.AttachmentGifv
|
|
gifv?: boolean
|
|
}
|
|
|
|
const AttachmentVideo: React.FC<Props> = ({
|
|
total,
|
|
index,
|
|
sensitiveShown,
|
|
video,
|
|
gifv = false
|
|
}) => {
|
|
const videoPlayer = useRef<Video>(null)
|
|
const [videoLoading, setVideoLoading] = useState(false)
|
|
const [videoLoaded, setVideoLoaded] = useState(false)
|
|
const [videoPosition, setVideoPosition] = useState<number>(0)
|
|
const playOnPress = useCallback(async () => {
|
|
analytics('timeline_shared_attachment_video_length', {
|
|
length: video.meta?.length
|
|
})
|
|
analytics('timeline_shared_attachment_vide_play_press', {
|
|
id: video.id,
|
|
timestamp: Date.now()
|
|
})
|
|
setVideoLoading(true)
|
|
if (!videoLoaded) {
|
|
await videoPlayer.current?.loadAsync({ uri: video.url })
|
|
}
|
|
await videoPlayer.current?.setPositionAsync(videoPosition)
|
|
await videoPlayer.current?.presentFullscreenPlayer()
|
|
videoPlayer.current?.playAsync()
|
|
setVideoLoading(false)
|
|
videoPlayer.current?.setOnPlaybackStatusUpdate(props => {
|
|
if (props.isLoaded) {
|
|
setVideoLoaded(true)
|
|
}
|
|
// @ts-ignore
|
|
if (props.positionMillis) {
|
|
// @ts-ignore
|
|
setVideoPosition(props.positionMillis)
|
|
}
|
|
})
|
|
}, [videoLoaded, videoPosition])
|
|
|
|
return (
|
|
<View
|
|
style={[
|
|
styles.base,
|
|
{ aspectRatio: attachmentAspectRatio({ total, index }) }
|
|
]}
|
|
>
|
|
<Video
|
|
accessibilityLabel={video.description}
|
|
ref={videoPlayer}
|
|
style={{
|
|
width: '100%',
|
|
height: '100%',
|
|
opacity: sensitiveShown ? 0 : 1
|
|
}}
|
|
usePoster
|
|
{...(gifv
|
|
? {
|
|
shouldPlay: true,
|
|
isMuted: true,
|
|
isLooping: true,
|
|
source: { uri: video.url }
|
|
}
|
|
: {
|
|
resizeMode: 'cover',
|
|
posterSource: { uri: video.preview_url },
|
|
posterStyle: { resizeMode: 'cover' }
|
|
})}
|
|
useNativeControls={false}
|
|
onFullscreenUpdate={event => {
|
|
if (event.fullscreenUpdate === 3) {
|
|
analytics('timeline_shared_attachment_video_pause_press', {
|
|
id: video.id,
|
|
timestamp: Date.now()
|
|
})
|
|
videoPlayer.current?.pauseAsync()
|
|
}
|
|
}}
|
|
/>
|
|
<Pressable style={styles.overlay}>
|
|
{sensitiveShown ? (
|
|
video.blurhash ? (
|
|
<Blurhash
|
|
blurhash={video.blurhash}
|
|
style={{
|
|
width: '100%',
|
|
height: '100%'
|
|
}}
|
|
/>
|
|
) : null
|
|
) : !gifv ? (
|
|
<Button
|
|
round
|
|
overlay
|
|
size='L'
|
|
type='icon'
|
|
content='PlayCircle'
|
|
onPress={playOnPress}
|
|
loading={videoLoading}
|
|
/>
|
|
) : null}
|
|
</Pressable>
|
|
</View>
|
|
)
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
base: {
|
|
flex: 1,
|
|
flexBasis: '50%',
|
|
padding: StyleConstants.Spacing.XS / 2
|
|
},
|
|
overlay: {
|
|
position: 'absolute',
|
|
width: '100%',
|
|
height: '100%',
|
|
flex: 1,
|
|
justifyContent: 'center',
|
|
alignItems: 'center'
|
|
}
|
|
})
|
|
|
|
export default AttachmentVideo
|