Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at cope-settings-sync 138 lines 4.1 kB view raw
1import {Pressable, type StyleProp, View, type ViewStyle} from 'react-native' 2import {type AnimatedRef} from 'react-native-reanimated' 3import {Image, type ImageStyle} from 'expo-image' 4import {type AppBskyEmbedImages} from '@atproto/api' 5import {utils} from '@bsky.app/alf' 6import {msg} from '@lingui/core/macro' 7import {useLingui} from '@lingui/react' 8import {Trans} from '@lingui/react/macro' 9 10import {type Dimensions} from '#/lib/media/types' 11import {useHighQualityImages} from '#/state/preferences/high-quality-images' 12import { 13 applyImageTransforms, 14 useImageCdnHost, 15} from '#/state/preferences/image-cdn-host' 16import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge' 17import {atoms as a, useTheme} from '#/alf' 18import {MediaInsetBorder} from '#/components/MediaInsetBorder' 19import {PostEmbedViewContext} from '#/components/Post/Embed/types' 20import {Text} from '#/components/Typography' 21 22type EventFunction = (index: number) => void 23 24interface Props { 25 images: AppBskyEmbedImages.ViewImage[] 26 index: number 27 onPress?: ( 28 index: number, 29 containerRefs: AnimatedRef<any>[], 30 fetchedDims: (Dimensions | null)[], 31 ) => void 32 onLongPress?: EventFunction 33 onPressIn?: EventFunction 34 imageStyle?: StyleProp<ImageStyle> 35 viewContext?: PostEmbedViewContext 36 insetBorderStyle?: StyleProp<ViewStyle> 37 containerRefs: AnimatedRef<any>[] 38 thumbDimsRef: React.RefObject<(Dimensions | null)[]> 39} 40 41export function GalleryItem({ 42 images, 43 index, 44 imageStyle, 45 onPress, 46 onPressIn, 47 onLongPress, 48 viewContext, 49 insetBorderStyle, 50 containerRefs, 51 thumbDimsRef, 52}: Props) { 53 const t = useTheme() 54 const {_} = useLingui() 55 const largeAltBadge = useLargeAltBadgeEnabled() 56 const highQualityImages = useHighQualityImages() 57 const imageCdnHost = useImageCdnHost() 58 const image = images[index] 59 const hasAlt = !!image.alt 60 const hideBadges = 61 viewContext === PostEmbedViewContext.FeedEmbedRecordWithMedia 62 return ( 63 <View style={a.flex_1} ref={containerRefs[index]} collapsable={false}> 64 <Pressable 65 onPress={ 66 onPress 67 ? () => onPress(index, containerRefs, thumbDimsRef.current.slice()) 68 : undefined 69 } 70 onPressIn={onPressIn ? () => onPressIn(index) : undefined} 71 onLongPress={onLongPress ? () => onLongPress(index) : undefined} 72 android_ripple={{ 73 color: utils.alpha(t.atoms.bg.backgroundColor, 0.2), 74 foreground: true, 75 }} 76 style={[ 77 a.flex_1, 78 a.overflow_hidden, 79 t.atoms.bg_contrast_25, 80 imageStyle, 81 ]} 82 accessibilityRole="button" 83 accessibilityLabel={image.alt || _(msg`Image`)} 84 accessibilityHint=""> 85 <Image 86 source={{ 87 uri: applyImageTransforms(image.thumb, { 88 imageCdnHost, 89 highQualityImages, 90 }), 91 }} 92 style={[a.flex_1]} 93 accessible={true} 94 accessibilityLabel={image.alt} 95 accessibilityHint="" 96 accessibilityIgnoresInvertColors 97 onLoad={e => { 98 thumbDimsRef.current[index] = { 99 width: e.source.width, 100 height: e.source.height, 101 } 102 }} 103 loading="lazy" 104 /> 105 <MediaInsetBorder style={insetBorderStyle} /> 106 </Pressable> 107 {hasAlt && !hideBadges ? ( 108 <View 109 accessible={false} 110 style={[ 111 a.absolute, 112 a.flex_row, 113 a.align_center, 114 a.rounded_xs, 115 t.atoms.bg_contrast_25, 116 { 117 gap: 3, 118 padding: 3, 119 bottom: a.p_xs.padding, 120 right: a.p_xs.padding, 121 opacity: 0.8, 122 }, 123 largeAltBadge && [ 124 { 125 gap: 4, 126 padding: 5, 127 }, 128 ], 129 ]}> 130 <Text 131 style={[a.font_bold, largeAltBadge ? a.text_xs : {fontSize: 8}]}> 132 <Trans>ALT</Trans> 133 </Text> 134 </View> 135 ) : null} 136 </View> 137 ) 138}