about summary refs log tree commit diff
path: root/src/view/com/util/post-embeds/VideoEmbedInner
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/util/post-embeds/VideoEmbedInner')
-rw-r--r--src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx29
-rw-r--r--src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb.tsx75
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}