mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React, {useCallback} from 'react'
2import {StyleProp, View, ViewStyle} from 'react-native'
3import {Image} from 'expo-image'
4import {AppBskyEmbedExternal} from '@atproto/api'
5
6import {usePalette} from 'lib/hooks/usePalette'
7import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
8import {shareUrl} from 'lib/sharing'
9import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player'
10import {toNiceDomain} from 'lib/strings/url-helpers'
11import {isNative} from 'platform/detection'
12import {useExternalEmbedsPrefs} from 'state/preferences'
13import {Link} from 'view/com/util/Link'
14import {ExternalGifEmbed} from 'view/com/util/post-embeds/ExternalGifEmbed'
15import {ExternalPlayer} from 'view/com/util/post-embeds/ExternalPlayerEmbed'
16import {GifEmbed} from 'view/com/util/post-embeds/GifEmbed'
17import {atoms as a, useTheme} from '#/alf'
18import {Text} from '../text/Text'
19
20export const ExternalLinkEmbed = ({
21 link,
22 onOpen,
23 style,
24 hideAlt,
25}: {
26 link: AppBskyEmbedExternal.ViewExternal
27 onOpen?: () => void
28 style?: StyleProp<ViewStyle>
29 hideAlt?: boolean
30}) => {
31 const pal = usePalette('default')
32 const {isMobile} = useWebMediaQueries()
33 const externalEmbedPrefs = useExternalEmbedsPrefs()
34
35 const embedPlayerParams = React.useMemo(() => {
36 const params = parseEmbedPlayerFromUrl(link.uri)
37
38 if (params && externalEmbedPrefs?.[params.source] !== 'hide') {
39 return params
40 }
41 }, [link.uri, externalEmbedPrefs])
42
43 if (embedPlayerParams?.source === 'tenor') {
44 return <GifEmbed params={embedPlayerParams} link={link} hideAlt={hideAlt} />
45 }
46
47 return (
48 <View style={[a.flex_col, a.rounded_sm, a.overflow_hidden, a.mt_sm]}>
49 <LinkWrapper link={link} onOpen={onOpen} style={style}>
50 {link.thumb && !embedPlayerParams ? (
51 <Image
52 style={{
53 aspectRatio: 1.91,
54 borderTopRightRadius: 6,
55 borderTopLeftRadius: 6,
56 }}
57 source={{uri: link.thumb}}
58 accessibilityIgnoresInvertColors
59 />
60 ) : undefined}
61 {embedPlayerParams?.isGif ? (
62 <ExternalGifEmbed link={link} params={embedPlayerParams} />
63 ) : embedPlayerParams ? (
64 <ExternalPlayer link={link} params={embedPlayerParams} />
65 ) : undefined}
66 <View
67 style={[
68 a.flex_1,
69 a.py_sm,
70 {
71 paddingHorizontal: isMobile ? 10 : 14,
72 },
73 ]}>
74 <Text
75 type="sm"
76 numberOfLines={1}
77 style={[pal.textLight, {marginVertical: 2}]}>
78 {toNiceDomain(link.uri)}
79 </Text>
80
81 {!embedPlayerParams?.isGif && !embedPlayerParams?.dimensions && (
82 <Text type="lg-bold" numberOfLines={3} style={[pal.text]}>
83 {link.title || link.uri}
84 </Text>
85 )}
86 {link.description ? (
87 <Text
88 type="md"
89 numberOfLines={link.thumb ? 2 : 4}
90 style={[pal.text, a.mt_xs]}>
91 {link.description}
92 </Text>
93 ) : undefined}
94 </View>
95 </LinkWrapper>
96 </View>
97 )
98}
99
100function LinkWrapper({
101 link,
102 onOpen,
103 style,
104 children,
105}: {
106 link: AppBskyEmbedExternal.ViewExternal
107 onOpen?: () => void
108 style?: StyleProp<ViewStyle>
109 children: React.ReactNode
110}) {
111 const t = useTheme()
112
113 const onShareExternal = useCallback(() => {
114 if (link.uri && isNative) {
115 shareUrl(link.uri)
116 }
117 }, [link.uri])
118
119 return (
120 <Link
121 asAnchor
122 anchorNoUnderline
123 href={link.uri}
124 style={[
125 a.flex_1,
126 a.border,
127 a.rounded_sm,
128 t.atoms.border_contrast_medium,
129 style,
130 ]}
131 hoverStyle={t.atoms.border_contrast_high}
132 onBeforePress={onOpen}
133 onLongPress={onShareExternal}>
134 {children}
135 </Link>
136 )
137}