about summary refs log tree commit diff
path: root/src/view/com/util/images
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/util/images')
-rw-r--r--src/view/com/util/images/Gallery.tsx76
-rw-r--r--src/view/com/util/images/ImageLayoutGrid.tsx204
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},
 })