tooot/src/components/Timeline/Shared/Attachment/Video.tsx

161 lines
5.2 KiB
TypeScript
Raw Normal View History

2020-12-26 23:05:17 +01:00
import Button from '@components/Button'
2023-02-08 01:10:59 +01:00
import GracefullyImage from '@components/GracefullyImage'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { connectMedia } from '@utils/api/helpers/connect'
import { useAccountStorage, useGlobalStorage } from '@utils/storage/actions'
2021-01-18 00:23:40 +01:00
import { StyleConstants } from '@utils/styles/constants'
2022-05-08 23:40:42 +02:00
import { ResizeMode, Video, VideoFullscreenUpdate } from 'expo-av'
import { Platform } from 'expo-modules-core'
import * as ScreenOrientation from 'expo-screen-orientation'
2022-12-04 18:42:01 +01:00
import React, { useRef, useState } from 'react'
import { Pressable, View } from 'react-native'
2022-06-03 23:18:24 +02:00
import AttachmentAltText from './AltText'
import { aspectRatio } from './dimensions'
2020-12-25 18:20:09 +01:00
export interface Props {
2021-01-18 00:23:40 +01:00
total: number
index: number
2020-12-25 18:20:09 +01:00
sensitiveShown: boolean
video: Mastodon.AttachmentVideo | Mastodon.AttachmentGifv
gifv?: boolean
2020-12-25 18:20:09 +01:00
}
2021-01-18 00:23:40 +01:00
const AttachmentVideo: React.FC<Props> = ({
total,
index,
sensitiveShown,
video,
gifv = false
2021-01-18 00:23:40 +01:00
}) => {
const { reduceMotionEnabled } = useAccessibility()
const [autoplayGifv] = useGlobalStorage.boolean('app.auto_play_gifv')
const [preferences] = useAccountStorage.object('preferences')
const shouldAutoplayGifv =
preferences?.['reading:autoplay:gifs'] !== undefined
? preferences['reading:autoplay:gifs']
: autoplayGifv
2020-12-25 18:20:09 +01:00
const videoPlayer = useRef<Video>(null)
const [videoLoading, setVideoLoading] = useState(false)
2020-12-25 18:20:09 +01:00
const [videoLoaded, setVideoLoaded] = useState(false)
2022-10-10 23:43:26 +02:00
const [videoResizeMode, setVideoResizeMode] = useState<ResizeMode>(ResizeMode.COVER)
2022-12-04 18:42:01 +01:00
const playOnPress = async () => {
setVideoLoading(true)
2020-12-25 18:20:09 +01:00
if (!videoLoaded) {
await videoPlayer.current?.loadAsync(connectMedia({ uri: video.url }) as { uri: string })
2020-12-25 18:20:09 +01:00
}
setVideoLoading(false)
2020-12-25 18:20:09 +01:00
2022-12-04 18:42:01 +01:00
Platform.OS === 'android' && setVideoResizeMode(ResizeMode.CONTAIN)
await videoPlayer.current?.presentFullscreenPlayer()
2021-09-15 22:52:21 +02:00
2022-12-04 18:42:01 +01:00
videoPlayer.current?.playAsync()
2021-09-15 22:52:21 +02:00
}
2020-12-25 18:20:09 +01:00
return (
2021-01-18 00:23:40 +01:00
<View
2022-06-03 23:18:24 +02:00
style={{
flex: 1,
flexBasis: '50%',
padding: StyleConstants.Spacing.XS / 2,
aspectRatio: aspectRatio({ total, index, ...video.meta?.original })
2022-06-03 23:18:24 +02:00
}}
2021-01-18 00:23:40 +01:00
>
2020-12-25 18:20:09 +01:00
<Video
2021-04-09 21:43:12 +02:00
accessibilityLabel={video.description}
2020-12-25 18:20:09 +01:00
ref={videoPlayer}
2022-12-04 18:42:01 +01:00
style={{ width: '100%', height: '100%', opacity: sensitiveShown ? 0 : 1 }}
2020-12-25 18:20:09 +01:00
usePoster
2022-10-10 23:43:26 +02:00
resizeMode={videoResizeMode}
2021-03-27 00:47:14 +01:00
{...(gifv
? {
shouldPlay: reduceMotionEnabled || !shouldAutoplayGifv ? false : true,
isMuted: true,
isLooping: true,
source: connectMedia({ uri: video.url }) as { uri: string }
}
2021-03-27 00:47:14 +01:00
: {
posterSource: connectMedia({ uri: video.preview_url }),
2022-05-08 23:40:42 +02:00
posterStyle: { resizeMode: ResizeMode.COVER }
2021-03-27 00:47:14 +01:00
})}
2020-12-25 18:20:09 +01:00
useNativeControls={false}
onFullscreenUpdate={async ({ fullscreenUpdate }) => {
switch (fullscreenUpdate) {
case VideoFullscreenUpdate.PLAYER_DID_PRESENT:
Platform.OS === 'android' && (await ScreenOrientation.unlockAsync())
break
case VideoFullscreenUpdate.PLAYER_WILL_DISMISS:
Platform.OS === 'android' &&
(await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT))
Platform.OS === 'android' && setVideoResizeMode(ResizeMode.COVER)
if (gifv && !reduceMotionEnabled && shouldAutoplayGifv) {
videoPlayer.current?.playAsync()
} else {
videoPlayer.current?.pauseAsync()
}
break
2022-12-04 18:42:01 +01:00
}
}}
onPlaybackStatusUpdate={event => {
if (event.isLoaded) {
!videoLoaded && setVideoLoaded(true)
if (event.didJustFinish) {
videoPlayer.current?.setPositionAsync(0)
2021-08-11 00:17:37 +02:00
}
2021-01-16 00:00:31 +01:00
}
}}
2020-12-25 18:20:09 +01:00
/>
2022-06-03 23:18:24 +02:00
<Pressable
style={{
position: 'absolute',
width: '100%',
height: '100%',
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}}
2022-12-04 18:42:01 +01:00
disabled={gifv ? (sensitiveShown ? true : false) : true}
2022-06-03 23:18:24 +02:00
onPress={gifv ? playOnPress : null}
>
2020-12-25 18:20:09 +01:00
{sensitiveShown ? (
2020-12-30 11:55:51 +01:00
video.blurhash ? (
2023-02-08 01:10:59 +01:00
<GracefullyImage
sources={{ blurhash: video.blurhash }}
style={{ width: '100%', height: '100%' }}
/>
2020-12-30 11:55:51 +01:00
) : null
) : !gifv || (gifv && (reduceMotionEnabled || !shouldAutoplayGifv)) ? (
2020-12-26 23:05:17 +01:00
<Button
2020-12-28 16:54:19 +01:00
round
2020-12-26 23:05:17 +01:00
overlay
size='L'
type='icon'
content='play-circle'
2020-12-26 23:05:17 +01:00
onPress={playOnPress}
loading={videoLoading}
2020-12-26 23:05:17 +01:00
/>
2021-03-27 00:47:14 +01:00
) : null}
2022-10-10 23:43:26 +02:00
<AttachmentAltText sensitiveShown={sensitiveShown} text={video.description} />
2020-12-25 18:20:09 +01:00
</Pressable>
{gifv && !shouldAutoplayGifv ? (
2022-12-23 18:19:14 +01:00
<Button
style={{
position: 'absolute',
left: StyleConstants.Spacing.S,
bottom: StyleConstants.Spacing.S
}}
overlay
size='S'
type='text'
content='GIF'
fontBold
onPress={() => {}}
/>
) : null}
2020-12-28 16:54:19 +01:00
</View>
2020-12-25 18:20:09 +01:00
)
}
export default AttachmentVideo