Bluesky app fork with some witchin' additions 馃挮
at main 122 lines 3.4 kB view raw
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 {useHighQualityImages} from '#/state/preferences/high-quality-images' 13import { 14 applyImageTransforms, 15 useImageCdnHost, 16} from '#/state/preferences/image-cdn-host' 17import {type Dimensions} from '#/view/com/lightbox/ImageViewing/@types' 18import {atoms as a} from '#/alf' 19import {AutoSizedImage} from '#/components/images/AutoSizedImage' 20import {ImageLayoutGrid} from '#/components/images/ImageLayoutGrid' 21import {PostEmbedViewContext} from '#/components/Post/Embed/types' 22import {type EmbedType} from '#/types/bsky/post' 23import {type CommonProps} from './types' 24 25export function ImageEmbed({ 26 embed, 27 ...rest 28}: CommonProps & { 29 embed: EmbedType<'images'> 30}) { 31 const {openLightbox} = useLightboxControls() 32 const highQualityImages = useHighQualityImages() 33 const imageCdnHost = useImageCdnHost() 34 const {images} = embed.view 35 36 if (images.length > 0) { 37 const items = images.map(img => ({ 38 uri: applyImageTransforms(img.fullsize, { 39 imageCdnHost, 40 highQualityImages, 41 }), 42 thumbUri: applyImageTransforms(img.thumb, { 43 imageCdnHost, 44 highQualityImages, 45 }), 46 alt: img.alt, 47 dimensions: img.aspectRatio ?? null, 48 })) 49 const _openLightbox = ( 50 index: number, 51 thumbRects: (MeasuredDimensions | null)[], 52 fetchedDims: (Dimensions | null)[], 53 ) => { 54 openLightbox({ 55 images: items.map((item, i) => ({ 56 ...item, 57 thumbRect: thumbRects[i] ?? null, 58 thumbDimensions: fetchedDims[i] ?? null, 59 type: 'image', 60 })), 61 index, 62 }) 63 } 64 const onPress = ( 65 index: number, 66 refs: AnimatedRef<any>[], 67 fetchedDims: (Dimensions | null)[], 68 ) => { 69 runOnUI(() => { 70 'worklet' 71 const rects: (MeasuredDimensions | null)[] = [] 72 for (const r of refs) { 73 rects.push(measure(r)) 74 } 75 runOnJS(_openLightbox)(index, rects, fetchedDims) 76 })() 77 } 78 const onPressIn = (_: number) => { 79 InteractionManager.runAfterInteractions(() => { 80 Image.prefetch( 81 items.map(i => i.uri), 82 'memory', 83 ) 84 }) 85 } 86 87 if (images.length === 1) { 88 const image = images[0] 89 return ( 90 <View style={[a.mt_sm, rest.style]}> 91 <AutoSizedImage 92 crop={ 93 rest.viewContext === PostEmbedViewContext.ThreadHighlighted 94 ? 'none' 95 : rest.viewContext === 96 PostEmbedViewContext.FeedEmbedRecordWithMedia 97 ? 'square' 98 : 'constrained' 99 } 100 image={image} 101 onPress={(containerRef, dims) => onPress(0, [containerRef], [dims])} 102 onPressIn={() => onPressIn(0)} 103 hideBadge={ 104 rest.viewContext === PostEmbedViewContext.FeedEmbedRecordWithMedia 105 } 106 /> 107 </View> 108 ) 109 } 110 111 return ( 112 <View style={[a.mt_sm, rest.style]}> 113 <ImageLayoutGrid 114 images={images} 115 onPress={onPress} 116 onPressIn={onPressIn} 117 viewContext={rest.viewContext} 118 /> 119 </View> 120 ) 121 } 122}