[Video] Lexicon implementation (#4881)

* implement AppBskyEmbedVideo lexicon in player

* add alt to native player

* add prerelease package

* update prerelease

* add video embed view manually from record

* fix type error on example video

* black bg + use aspect ratio on web

* add video to feeds

* fix video overflowing aspect ratio

* remove prerelease package

---------

Co-authored-by: Samuel Newman <10959775+mozzius@users.noreply.github.com>
This commit is contained in:
Samuel Newman
2024-08-29 15:58:22 +01:00
committed by GitHub
parent b136c44287
commit d92731b1eb
9 changed files with 211 additions and 91 deletions
+47 -21
View File
@@ -1,21 +1,25 @@
import React, {useCallback, useState} from 'react'
import {View} from 'react-native'
import {Image} from 'expo-image'
import {AppBskyEmbedVideo} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {VideoEmbedInnerNative} from 'view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative'
import {clamp} from '#/lib/numbers'
import {useGate} from '#/lib/statsig/statsig'
import {VideoEmbedInnerNative} from '#/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative'
import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonIcon} from '#/components/Button'
import {Button} from '#/components/Button'
import {Play_Filled_Corner2_Rounded as PlayIcon} from '#/components/icons/Play'
import {VisibilityView} from '../../../../../modules/expo-bluesky-swiss-army'
import {ErrorBoundary} from '../ErrorBoundary'
import {useActiveVideoNative} from './ActiveVideoNativeContext'
import * as VideoFallback from './VideoEmbedInner/VideoFallback'
export function VideoEmbed({source}: {source: string}) {
export function VideoEmbed({embed}: {embed: AppBskyEmbedVideo.View}) {
const t = useTheme()
const {activeSource, setActiveSource} = useActiveVideoNative()
const isActive = source === activeSource
const isActive = embed.playlist === activeSource
const {_} = useLingui()
const [key, setKey] = useState(0)
@@ -25,39 +29,61 @@ export function VideoEmbed({source}: {source: string}) {
),
[key],
)
const gate = useGate()
if (!gate('videos')) {
return null
}
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.w_full,
a.rounded_sm,
{aspectRatio: 16 / 9},
a.overflow_hidden,
t.atoms.bg_contrast_25,
{aspectRatio},
{backgroundColor: t.palette.black},
a.my_xs,
]}>
<ErrorBoundary renderError={renderError} key={key}>
<VisibilityView
enabled={true}
onChangeStatus={isActive => {
if (isActive) {
setActiveSource(source)
onChangeStatus={isVisible => {
if (isVisible) {
setActiveSource(embed.playlist)
}
}}>
{isActive ? (
<VideoEmbedInnerNative />
<VideoEmbedInnerNative embed={embed} />
) : (
<Button
style={[a.flex_1, t.atoms.bg_contrast_25]}
onPress={() => {
setActiveSource(source)
}}
label={_(msg`Play video`)}
variant="ghost"
color="secondary"
size="large">
<ButtonIcon icon={PlayIcon} />
</Button>
<>
<Image
source={{uri: embed.thumbnail}}
alt={embed.alt}
style={a.flex_1}
contentFit="contain"
accessibilityIgnoresInvertColors
/>
<Button
style={[a.absolute, a.inset_0]}
onPress={() => {
setActiveSource(embed.playlist)
}}
label={_(msg`Play video`)}
variant="ghost"
color="secondary"
size="large">
<PlayIcon width={48} fill={t.palette.white} />
</Button>
</>
)}
</VisibilityView>
</ErrorBoundary>