diff options
Diffstat (limited to 'src/view/com/util/post-embeds/VideoEmbedInner')
-rw-r--r-- | src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx | 29 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx | 75 |
2 files changed, 66 insertions, 38 deletions
diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx index ea56f2997..f08fe0bf5 100644 --- a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx +++ b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx @@ -2,12 +2,14 @@ import React, {useCallback, useEffect, useRef, useState} from 'react' import {Pressable, View} from 'react-native' import Animated, {FadeInDown} from 'react-native-reanimated' import {VideoPlayer, VideoView} from 'expo-video' +import {AppBskyEmbedVideo} from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useIsFocused} from '@react-navigation/native' import {HITSLOP_30} from '#/lib/constants' import {useAppState} from '#/lib/hooks/useAppState' +import {clamp} from '#/lib/numbers' import {logger} from '#/logger' import {useActiveVideoNative} from 'view/com/util/post-embeds/ActiveVideoNativeContext' import {atoms as a, useTheme} from '#/alf' @@ -19,7 +21,12 @@ import { } from '../../../../../../modules/expo-bluesky-swiss-army' import {TimeIndicator} from './TimeIndicator' -export function VideoEmbedInnerNative() { +export function VideoEmbedInnerNative({ + embed, +}: { + embed: AppBskyEmbedVideo.View +}) { + const {_} = useLingui() const {player} = useActiveVideoNative() const ref = useRef<VideoView>(null) const isScreenFocused = useIsFocused() @@ -47,13 +54,23 @@ export function VideoEmbedInnerNative() { ref.current?.enterFullscreen() }, []) + let aspectRatio = 16 / 9 + + if (embed.aspectRatio) { + const {width, height} = embed.aspectRatio + aspectRatio = width / height + aspectRatio = clamp(aspectRatio, 1 / 1, 3 / 1) + } + return ( - <View style={[a.flex_1, a.relative]}> + <View style={[a.flex_1, a.relative, {aspectRatio}]}> <VideoView ref={ref} player={player} style={[a.flex_1, a.rounded_sm]} + contentFit="contain" nativeControls={true} + accessibilityIgnoresInvertColors onEnterFullscreen={() => { PlatformInfo.setAudioCategory(AudioCategory.Playback) PlatformInfo.setAudioActive(true) @@ -65,13 +82,17 @@ export function VideoEmbedInnerNative() { player.muted = true if (!player.playing) player.play() }} + accessibilityLabel={ + embed.alt ? _(msg`Video: ${embed.alt}`) : _(msg`Video`) + } + accessibilityHint="" /> - <Controls player={player} enterFullscreen={enterFullscreen} /> + <VideoControls player={player} enterFullscreen={enterFullscreen} /> </View> ) } -function Controls({ +function VideoControls({ player, enterFullscreen, }: { diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx index c0021d9bb..77295c00c 100644 --- a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx +++ b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx @@ -1,31 +1,27 @@ -import React, {useEffect, useRef, useState} from 'react' +import React, {useEffect, useId, useRef, useState} from 'react' import {View} from 'react-native' +import {AppBskyEmbedVideo} from '@atproto/api' import Hls from 'hls.js' import {atoms as a} from '#/alf' import {Controls} from './VideoWebControls' export function VideoEmbedInnerWeb({ - source, + embed, active, setActive, onScreen, }: { - source: string - active?: boolean - setActive?: () => void - onScreen?: boolean + embed: AppBskyEmbedVideo.View + active: boolean + setActive: () => void + onScreen: boolean }) { - if (active == null || setActive == null || onScreen == null) { - throw new Error( - 'active, setActive, and onScreen are required VideoEmbedInner props on web.', - ) - } - const containerRef = useRef<HTMLDivElement>(null) const ref = useRef<HTMLVideoElement>(null) const [focused, setFocused] = useState(false) const [hasSubtitleTrack, setHasSubtitleTrack] = useState(false) + const figId = useId() const hlsRef = useRef<Hls | undefined>(undefined) @@ -37,7 +33,7 @@ export function VideoEmbedInnerWeb({ hlsRef.current = hls hls.attachMedia(ref.current) - hls.loadSource(source) + hls.loadSource(embed.playlist) // initial value, later on it's managed by Controls hls.autoLevelCapping = 0 @@ -53,29 +49,40 @@ export function VideoEmbedInnerWeb({ hls.detachMedia() hls.destroy() } - }, [source]) + }, [embed.playlist]) return ( - <View - style={[ - a.w_full, - a.rounded_sm, - // TODO: get from embed metadata - // max should be 1 / 1 - {aspectRatio: 16 / 9}, - a.overflow_hidden, - ]}> - <div - ref={containerRef} - style={{width: '100%', height: '100%', display: 'flex'}}> - <video - ref={ref} - style={{width: '100%', height: '100%', objectFit: 'contain'}} - playsInline - preload="none" - loop - muted={!focused} - /> + <View style={[a.flex_1, a.rounded_sm, a.overflow_hidden]}> + <div ref={containerRef} style={{height: '100%', width: '100%'}}> + <figure style={{margin: 0, position: 'absolute', inset: 0}}> + <video + ref={ref} + poster={embed.thumbnail} + style={{width: '100%', height: '100%', objectFit: 'contain'}} + playsInline + preload="none" + loop + muted={!focused} + aria-labelledby={embed.alt ? figId : undefined} + /> + {embed.alt && ( + <figcaption + id={figId} + style={{ + position: 'absolute', + width: 1, + height: 1, + padding: 0, + margin: -1, + overflow: 'hidden', + clip: 'rect(0, 0, 0, 0)', + whiteSpace: 'nowrap', + borderWidth: 0, + }}> + {embed.alt} + </figcaption> + )} + </figure> <Controls videoRef={ref} hlsRef={hlsRef} |