diff options
Diffstat (limited to 'src/view/com/util/images')
-rw-r--r-- | src/view/com/util/images/Gallery.tsx | 76 | ||||
-rw-r--r-- | src/view/com/util/images/ImageLayoutGrid.tsx | 204 |
2 files changed, 117 insertions, 163 deletions
diff --git a/src/view/com/util/images/Gallery.tsx b/src/view/com/util/images/Gallery.tsx new file mode 100644 index 000000000..78ced0668 --- /dev/null +++ b/src/view/com/util/images/Gallery.tsx @@ -0,0 +1,76 @@ +import {AppBskyEmbedImages} from '@atproto/api' +import React, {ComponentProps, FC, useCallback} from 'react' +import {Pressable, StyleSheet, Text, TouchableOpacity, View} from 'react-native' +import {Image} from 'expo-image' +import {useStores} from 'state/index' + +type EventFunction = (index: number) => void + +interface GalleryItemProps { + images: AppBskyEmbedImages.ViewImage[] + index: number + onPress?: EventFunction + onLongPress?: EventFunction + onPressIn?: EventFunction + imageStyle: ComponentProps<typeof Image>['style'] +} + +const DELAY_PRESS_IN = 500 + +export const GalleryItem: FC<GalleryItemProps> = ({ + images, + index, + imageStyle, + onPress, + onPressIn, + onLongPress, +}) => { + const image = images[index] + const store = useStores() + + const onPressAltText = useCallback(() => { + store.shell.openModal({ + name: 'alt-text-image-read', + altText: image.alt, + }) + }, [image.alt, store.shell]) + + return ( + <View> + <TouchableOpacity + delayPressIn={DELAY_PRESS_IN} + onPress={() => onPress?.(index)} + onPressIn={() => onPressIn?.(index)} + onLongPress={() => onLongPress?.(index)}> + <Image + source={{uri: image.thumb}} + style={imageStyle} + accessible={true} + accessibilityLabel={image.alt} + /> + </TouchableOpacity> + {image.alt === '' ? null : ( + <Pressable onPress={onPressAltText}> + <Text style={styles.alt}>ALT</Text> + </Pressable> + )} + </View> + ) +} + +const styles = StyleSheet.create({ + alt: { + backgroundColor: 'rgba(0, 0, 0, 0.75)', + borderRadius: 6, + color: 'white', + fontSize: 12, + fontWeight: 'bold', + letterSpacing: 1, + paddingHorizontal: 10, + paddingVertical: 3, + position: 'absolute', + left: 10, + top: -26, + width: 46, + }, +}) diff --git a/src/view/com/util/images/ImageLayoutGrid.tsx b/src/view/com/util/images/ImageLayoutGrid.tsx index 51bb04fe9..4c0901304 100644 --- a/src/view/com/util/images/ImageLayoutGrid.tsx +++ b/src/view/com/util/images/ImageLayoutGrid.tsx @@ -3,15 +3,13 @@ import { LayoutChangeEvent, StyleProp, StyleSheet, - TouchableOpacity, View, ViewStyle, } from 'react-native' -import {Image, ImageStyle} from 'expo-image' +import {ImageStyle} from 'expo-image' import {Dimensions} from 'lib/media/types' import {AppBskyEmbedImages} from '@atproto/api' - -export const DELAY_PRESS_IN = 500 +import {GalleryItem} from './Gallery' interface ImageLayoutGridProps { images: AppBskyEmbedImages.ViewImage[] @@ -21,32 +19,21 @@ interface ImageLayoutGridProps { style?: StyleProp<ViewStyle> } -export function ImageLayoutGrid({ - images, - onPress, - onLongPress, - onPressIn, - style, -}: ImageLayoutGridProps) { +export function ImageLayoutGrid({style, ...props}: ImageLayoutGridProps) { const [containerInfo, setContainerInfo] = useState<Dimensions | undefined>() const onLayout = (evt: LayoutChangeEvent) => { + const {width, height} = evt.nativeEvent.layout setContainerInfo({ - width: evt.nativeEvent.layout.width, - height: evt.nativeEvent.layout.height, + width, + height, }) } return ( <View style={style} onLayout={onLayout}> {containerInfo ? ( - <ImageLayoutGridInner - images={images} - onPress={onPress} - onPressIn={onPressIn} - onLongPress={onLongPress} - containerInfo={containerInfo} - /> + <ImageLayoutGridInner {...props} containerInfo={containerInfo} /> ) : undefined} </View> ) @@ -61,13 +48,10 @@ interface ImageLayoutGridInnerProps { } function ImageLayoutGridInner({ - images, - onPress, - onLongPress, - onPressIn, containerInfo, + ...props }: ImageLayoutGridInnerProps) { - const count = images.length + const count = props.images.length const size1 = useMemo<ImageStyle>(() => { if (count === 3) { const size = (containerInfo.width - 10) / 3 @@ -87,149 +71,43 @@ function ImageLayoutGridInner({ } }, [count, containerInfo]) - if (count === 2) { - return ( - <View style={styles.flexRow}> - <TouchableOpacity - delayPressIn={DELAY_PRESS_IN} - onPress={() => onPress?.(0)} - onPressIn={() => onPressIn?.(0)} - onLongPress={() => onLongPress?.(0)}> - <Image - source={{uri: images[0].thumb}} - style={size1} - accessible={true} - accessibilityLabel={images[0].alt} - /> - </TouchableOpacity> - <View style={styles.wSpace} /> - <TouchableOpacity - delayPressIn={DELAY_PRESS_IN} - onPress={() => onPress?.(1)} - onPressIn={() => onPressIn?.(1)} - onLongPress={() => onLongPress?.(1)}> - <Image - source={{uri: images[1].thumb}} - style={size1} - accessible={true} - accessibilityLabel={images[1].alt} - /> - </TouchableOpacity> - </View> - ) - } - if (count === 3) { - return ( - <View style={styles.flexRow}> - <TouchableOpacity - delayPressIn={DELAY_PRESS_IN} - onPress={() => onPress?.(0)} - onPressIn={() => onPressIn?.(0)} - onLongPress={() => onLongPress?.(0)}> - <Image - source={{uri: images[0].thumb}} - style={size2} - accessible={true} - accessibilityLabel={images[0].alt} - /> - </TouchableOpacity> - <View style={styles.wSpace} /> - <View> - <TouchableOpacity - delayPressIn={DELAY_PRESS_IN} - onPress={() => onPress?.(1)} - onPressIn={() => onPressIn?.(1)} - onLongPress={() => onLongPress?.(1)}> - <Image - source={{uri: images[1].thumb}} - style={size1} - accessible={true} - accessibilityLabel={images[1].alt} - /> - </TouchableOpacity> - <View style={styles.hSpace} /> - <TouchableOpacity - delayPressIn={DELAY_PRESS_IN} - onPress={() => onPress?.(2)} - onPressIn={() => onPressIn?.(2)} - onLongPress={() => onLongPress?.(2)}> - <Image - source={{uri: images[2].thumb}} - style={size1} - accessible={true} - accessibilityLabel={images[2].alt} - /> - </TouchableOpacity> + switch (count) { + case 2: + return ( + <View style={styles.flexRow}> + <GalleryItem index={0} {...props} imageStyle={size1} /> + <GalleryItem index={1} {...props} imageStyle={size1} /> </View> - </View> - ) - } - if (count === 4) { - return ( - <View style={styles.flexRow}> - <View> - <TouchableOpacity - delayPressIn={DELAY_PRESS_IN} - onPress={() => onPress?.(0)} - onPressIn={() => onPressIn?.(0)} - onLongPress={() => onLongPress?.(0)}> - <Image - source={{uri: images[0].thumb}} - style={size1} - accessible={true} - accessibilityLabel={images[0].alt} - /> - </TouchableOpacity> - <View style={styles.hSpace} /> - <TouchableOpacity - delayPressIn={DELAY_PRESS_IN} - onPress={() => onPress?.(2)} - onPressIn={() => onPressIn?.(2)} - onLongPress={() => onLongPress?.(2)}> - <Image - source={{uri: images[2].thumb}} - style={size1} - accessible={true} - accessibilityLabel={images[2].alt} - /> - </TouchableOpacity> + ) + case 3: + return ( + <View style={styles.flexRow}> + <GalleryItem index={0} {...props} imageStyle={size2} /> + <View style={styles.flexColumn}> + <GalleryItem index={1} {...props} imageStyle={size1} /> + <GalleryItem index={2} {...props} imageStyle={size1} /> + </View> </View> - <View style={styles.wSpace} /> - <View> - <TouchableOpacity - delayPressIn={DELAY_PRESS_IN} - onPress={() => onPress?.(1)} - onPressIn={() => onPressIn?.(1)} - onLongPress={() => onLongPress?.(1)}> - <Image - source={{uri: images[1].thumb}} - style={size1} - accessible={true} - accessibilityLabel={images[1].alt} - /> - </TouchableOpacity> - <View style={styles.hSpace} /> - <TouchableOpacity - delayPressIn={DELAY_PRESS_IN} - onPress={() => onPress?.(3)} - onPressIn={() => onPressIn?.(3)} - onLongPress={() => onLongPress?.(3)}> - <Image - source={{uri: images[3].thumb}} - style={size1} - accessible={true} - accessibilityLabel={images[3].alt} - /> - </TouchableOpacity> + ) + case 4: + return ( + <View style={styles.flexRow}> + <View style={styles.flexColumn}> + <GalleryItem index={0} {...props} imageStyle={size1} /> + <GalleryItem index={2} {...props} imageStyle={size1} /> + </View> + <View style={styles.flexColumn}> + <GalleryItem index={1} {...props} imageStyle={size1} /> + <GalleryItem index={3} {...props} imageStyle={size1} /> + </View> </View> - </View> - ) + ) + default: + return null } - return <View /> } const styles = StyleSheet.create({ - flexRow: {flexDirection: 'row'}, - wSpace: {width: 5}, - hSpace: {height: 5}, + flexRow: {flexDirection: 'row', gap: 5}, + flexColumn: {flexDirection: 'column', gap: 5}, }) |