1import {
2  Image,
3  ImageContentFit,
4  ImageContentPosition,
5  ImageContentPositionString,
6} from 'expo-image';
7import { ScrollView, StyleSheet, Text, View } from 'react-native';
8
9import HeadingText from '../../components/HeadingText';
10import { Colors } from '../../constants';
11
12const CONTENT_FITS: ImageContentFit[] = ['cover', 'contain', 'fill', 'none', 'scale-down'];
13
14const CONTENT_POSITIONS: ImageContentPositionString[] = [
15  'center',
16  'top',
17  'right',
18  'bottom',
19  'left',
20  'top center',
21  'top right',
22  'top left',
23  'right center',
24  'right top',
25  'right bottom',
26  'bottom center',
27  'bottom right',
28  'bottom left',
29  'left center',
30  'left top',
31  'left bottom',
32];
33
34type ContentFitExample = {
35  size: [number, number];
36  position?: ImageContentPosition;
37};
38
39const EXAMPLES: ContentFitExample[] = [
40  {
41    size: [1500, 1000],
42  },
43  {
44    size: [300, 200],
45  },
46  {
47    size: [200, 300],
48  },
49  {
50    size: [240, 160],
51    position: { top: 10, left: 20 },
52  },
53  {
54    size: [240, 160],
55    position: { top: 0, right: 0 },
56  },
57  {
58    size: [240, 160],
59    position: { bottom: 5, left: 10 },
60  },
61  {
62    size: [240, 160],
63    position: { bottom: '10%', right: '10%' },
64  },
65  {
66    size: [240, 160],
67    position: { left: '15%' },
68  },
69  {
70    size: [240, 160],
71    position: { top: '-50%', right: '10%' },
72  },
73];
74
75function sourceWithSize(size: [number, number]): string {
76  return `https://picsum.photos/seed/138/${size[0]}/${size[1]}`;
77}
78
79function renderExample(contentFit: ImageContentFit, example: ContentFitExample, index: number) {
80  const sizeText = example.size.join(' x ');
81  const positionText = example.position
82    ? JSON.stringify(example.position).replaceAll(/[{}"]/g, '').replaceAll(/[:,]/g, ' ')
83    : null;
84
85  return (
86    <View key={index} style={styles.imageContainer}>
87      <Image
88        style={styles.image}
89        source={{ uri: sourceWithSize(example.size) }}
90        contentFit={contentFit}
91        contentPosition={example.position}
92      />
93      <Text style={styles.description}>{[sizeText, positionText].filter(Boolean).join('\n')}</Text>
94    </View>
95  );
96}
97
98function renderContentFitExamples(contentFit: ImageContentFit, index: number) {
99  return (
100    <View key={index} style={styles.contentFitExamples}>
101      <HeadingText style={styles.headingText}>{`Content fit: "${contentFit}"`}</HeadingText>
102      <ScrollView style={styles.examplesScrollView} horizontal indicatorStyle="black">
103        {EXAMPLES.map((example, index) => renderExample(contentFit, example, index))}
104      </ScrollView>
105    </View>
106  );
107}
108
109function renderContentPositionExample(contentPosition: ImageContentPositionString, index: number) {
110  const example: ContentFitExample = {
111    size: [100, 100],
112    position: contentPosition,
113  };
114  return renderExample('none', example, index);
115}
116
117export default function ImageContentFitScreen() {
118  return (
119    <ScrollView style={styles.container}>
120      <HeadingText style={styles.headingText}>Full-size image</HeadingText>
121      <Image style={styles.fullImageExample} source={{ uri: sourceWithSize([1500, 1000]) }} />
122      <Text style={styles.description}>1500 x 1000</Text>
123
124      {CONTENT_FITS.map(renderContentFitExamples)}
125
126      <View style={styles.contentFitExamples}>
127        <HeadingText style={styles.headingText}>Content positions (strings)</HeadingText>
128        <ScrollView style={styles.examplesScrollView} horizontal indicatorStyle="black">
129          {CONTENT_POSITIONS.map(renderContentPositionExample)}
130        </ScrollView>
131      </View>
132    </ScrollView>
133  );
134}
135
136const styles = StyleSheet.create({
137  container: {
138    flex: 1,
139  },
140  contentFitExamples: {
141    backgroundColor: Colors.greyBackground,
142    borderTopColor: Colors.border,
143    borderTopWidth: StyleSheet.hairlineWidth,
144  },
145  fullImageExample: {
146    width: 300,
147    height: 200,
148    margin: 10,
149    alignSelf: 'center',
150  },
151  headingText: {
152    marginTop: -6,
153    marginBottom: 6,
154    marginHorizontal: 10,
155  },
156  examplesScrollView: {
157    padding: 10,
158  },
159  imageContainer: {
160    marginRight: 15,
161    alignItems: 'center',
162  },
163  image: {
164    width: 100,
165    height: 100,
166    borderColor: Colors.tintColor,
167    borderStyle: 'solid',
168    borderWidth: 1,
169  },
170  description: {
171    padding: 5,
172    fontSize: 11,
173    textAlign: 'center',
174  },
175});
176