mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {InteractionManager, View} from 'react-native'
2import {
3 type AnimatedRef,
4 measure,
5 type MeasuredDimensions,
6 runOnJS,
7 runOnUI,
8} from 'react-native-reanimated'
9import {Image} from 'expo-image'
10
11import {useLightboxControls} from '#/state/lightbox'
12import {type Dimensions} from '#/view/com/lightbox/ImageViewing/@types'
13import {AutoSizedImage} from '#/view/com/util/images/AutoSizedImage'
14import {ImageLayoutGrid} from '#/view/com/util/images/ImageLayoutGrid'
15import {atoms as a} from '#/alf'
16import {PostEmbedViewContext} from '#/components/Post/Embed/types'
17import {type EmbedType} from '#/types/bsky/post'
18import {type CommonProps} from './types'
19
20export function ImageEmbed({
21 embed,
22 ...rest
23}: CommonProps & {
24 embed: EmbedType<'images'>
25}) {
26 const {openLightbox} = useLightboxControls()
27 const {images} = embed.view
28
29 if (images.length > 0) {
30 const items = images.map(img => ({
31 uri: img.fullsize,
32 thumbUri: img.thumb,
33 alt: img.alt,
34 dimensions: img.aspectRatio ?? null,
35 }))
36 const _openLightbox = (
37 index: number,
38 thumbRects: (MeasuredDimensions | null)[],
39 fetchedDims: (Dimensions | null)[],
40 ) => {
41 openLightbox({
42 images: items.map((item, i) => ({
43 ...item,
44 thumbRect: thumbRects[i] ?? null,
45 thumbDimensions: fetchedDims[i] ?? null,
46 type: 'image',
47 })),
48 index,
49 })
50 }
51 const onPress = (
52 index: number,
53 refs: AnimatedRef<any>[],
54 fetchedDims: (Dimensions | null)[],
55 ) => {
56 runOnUI(() => {
57 'worklet'
58 const rects: (MeasuredDimensions | null)[] = []
59 for (const r of refs) {
60 rects.push(measure(r))
61 }
62 runOnJS(_openLightbox)(index, rects, fetchedDims)
63 })()
64 }
65 const onPressIn = (_: number) => {
66 InteractionManager.runAfterInteractions(() => {
67 Image.prefetch(items.map(i => i.uri))
68 })
69 }
70
71 if (images.length === 1) {
72 const image = images[0]
73 return (
74 <View style={[a.mt_sm, rest.style]}>
75 <AutoSizedImage
76 crop={
77 rest.viewContext === PostEmbedViewContext.ThreadHighlighted
78 ? 'none'
79 : rest.viewContext ===
80 PostEmbedViewContext.FeedEmbedRecordWithMedia
81 ? 'square'
82 : 'constrained'
83 }
84 image={image}
85 onPress={(containerRef, dims) => onPress(0, [containerRef], [dims])}
86 onPressIn={() => onPressIn(0)}
87 hideBadge={
88 rest.viewContext === PostEmbedViewContext.FeedEmbedRecordWithMedia
89 }
90 />
91 </View>
92 )
93 }
94
95 return (
96 <View style={[a.mt_sm, rest.style]}>
97 <ImageLayoutGrid
98 images={images}
99 onPress={onPress}
100 onPressIn={onPressIn}
101 viewContext={rest.viewContext}
102 />
103 </View>
104 )
105 }
106}