Bluesky app fork with some witchin' additions 馃挮
witchsky.app
bluesky
fork
client
1import {useRef, useState} from 'react'
2import {type StyleProp, View, type ViewStyle} from 'react-native'
3import {msg} from '@lingui/core/macro'
4import {useLingui} from '@lingui/react'
5
6import {clamp} from '#/lib/numbers'
7import {type EmbedPlayerParams} from '#/lib/strings/embed-player'
8import {useAutoplayDisabled} from '#/state/preferences'
9import {atoms as a, useTheme} from '#/alf'
10import {Fill} from '#/components/Fill'
11import {MediaInsetBorder} from '#/components/MediaInsetBorder'
12import {GifView} from '../../../../../modules/expo-bluesky-gif-view'
13import {type GifViewStateChangeEvent} from '../../../../../modules/expo-bluesky-gif-view/src/GifView.types'
14import {GifPresentationControls} from '../VideoEmbed/GifPresentationControls'
15
16export function GifEmbed({
17 params,
18 thumb,
19 altText,
20 isPreferredAltText,
21 hideAlt,
22 style = {width: '100%'},
23}: {
24 params: EmbedPlayerParams
25 thumb: string | undefined
26 altText: string
27 isPreferredAltText: boolean
28 hideAlt?: boolean
29 style?: StyleProp<ViewStyle>
30}) {
31 const t = useTheme()
32 const {_} = useLingui()
33 const autoplayDisabled = useAutoplayDisabled()
34
35 const playerRef = useRef<GifView>(null)
36
37 const [playerState, setPlayerState] = useState<{
38 isPlaying: boolean
39 isLoaded: boolean
40 }>({
41 isPlaying: !autoplayDisabled,
42 isLoaded: false,
43 })
44
45 const onPlayerStateChange = (e: GifViewStateChangeEvent) => {
46 setPlayerState(e.nativeEvent)
47 }
48
49 const onPress = () => {
50 void playerRef.current?.toggleAsync()
51 }
52
53 let aspectRatio = 1
54 if (params.dimensions) {
55 const ratio = params.dimensions.width / params.dimensions.height
56 aspectRatio = clamp(ratio, 0.75, 4)
57 }
58
59 return (
60 <View
61 style={[
62 a.rounded_md,
63 a.overflow_hidden,
64 {backgroundColor: t.palette.black},
65 {aspectRatio},
66 style,
67 ]}>
68 <View
69 style={[
70 a.absolute,
71 /*
72 * Aspect ratio was being clipped weirdly on web -esb
73 */
74 {
75 top: -2,
76 bottom: -2,
77 left: -2,
78 right: -2,
79 },
80 ]}>
81 <MediaInsetBorder />
82 <GifPresentationControls
83 onPress={onPress}
84 isPlaying={playerState.isPlaying}
85 isLoading={!playerState.isLoaded}
86 altText={!hideAlt && isPreferredAltText ? altText : undefined}
87 />
88 <GifView
89 source={params.playerUri}
90 placeholderSource={thumb}
91 style={[a.flex_1]}
92 autoplay={!autoplayDisabled}
93 onPlayerStateChange={onPlayerStateChange}
94 ref={playerRef}
95 accessibilityHint={_(msg`Animated GIF`)}
96 accessibilityLabel={altText}
97 />
98 {!playerState.isPlaying && (
99 <Fill
100 style={[
101 t.name === 'light' ? t.atoms.bg_contrast_975 : t.atoms.bg,
102 {
103 opacity: 0.3,
104 },
105 ]}
106 />
107 )}
108 </View>
109 </View>
110 )
111}