about summary refs log tree commit diff
path: root/src/view/com/util/images/ImageLayoutGrid.tsx
blob: 4c09013043bc3837f50c9975fe9fbe55c9688ed5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import React, {useMemo, useState} from 'react'
import {
  LayoutChangeEvent,
  StyleProp,
  StyleSheet,
  View,
  ViewStyle,
} from 'react-native'
import {ImageStyle} from 'expo-image'
import {Dimensions} from 'lib/media/types'
import {AppBskyEmbedImages} from '@atproto/api'
import {GalleryItem} from './Gallery'

interface ImageLayoutGridProps {
  images: AppBskyEmbedImages.ViewImage[]
  onPress?: (index: number) => void
  onLongPress?: (index: number) => void
  onPressIn?: (index: number) => void
  style?: StyleProp<ViewStyle>
}

export function ImageLayoutGrid({style, ...props}: ImageLayoutGridProps) {
  const [containerInfo, setContainerInfo] = useState<Dimensions | undefined>()

  const onLayout = (evt: LayoutChangeEvent) => {
    const {width, height} = evt.nativeEvent.layout
    setContainerInfo({
      width,
      height,
    })
  }

  return (
    <View style={style} onLayout={onLayout}>
      {containerInfo ? (
        <ImageLayoutGridInner {...props} containerInfo={containerInfo} />
      ) : undefined}
    </View>
  )
}

interface ImageLayoutGridInnerProps {
  images: AppBskyEmbedImages.ViewImage[]
  onPress?: (index: number) => void
  onLongPress?: (index: number) => void
  onPressIn?: (index: number) => void
  containerInfo: Dimensions
}

function ImageLayoutGridInner({
  containerInfo,
  ...props
}: ImageLayoutGridInnerProps) {
  const count = props.images.length
  const size1 = useMemo<ImageStyle>(() => {
    if (count === 3) {
      const size = (containerInfo.width - 10) / 3
      return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
    } else {
      const size = (containerInfo.width - 5) / 2
      return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
    }
  }, [count, containerInfo])
  const size2 = React.useMemo<ImageStyle>(() => {
    if (count === 3) {
      const size = ((containerInfo.width - 10) / 3) * 2 + 5
      return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
    } else {
      const size = (containerInfo.width - 5) / 2
      return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
    }
  }, [count, containerInfo])

  switch (count) {
    case 2:
      return (
        <View style={styles.flexRow}>
          <GalleryItem index={0} {...props} imageStyle={size1} />
          <GalleryItem index={1} {...props} imageStyle={size1} />
        </View>
      )
    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>
      )
    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>
      )
    default:
      return null
  }
}

const styles = StyleSheet.create({
  flexRow: {flexDirection: 'row', gap: 5},
  flexColumn: {flexDirection: 'column', gap: 5},
})