1import { useState, useRef } from 'react';
2import { StatusBar } from 'expo-status-bar';
3import { StyleSheet, View } from 'react-native';
4import * as ImagePicker from 'expo-image-picker';
5import { GestureHandlerRootView } from 'react-native-gesture-handler';
6import * as MediaLibrary from 'expo-media-library';
7import { captureRef } from 'react-native-view-shot';
8
9import Button from './components/Button';
10import ImageViewer from './components/ImageViewer';
11import CircleButton from './components/CircleButton';
12import IconButton from './components/IconButton';
13import EmojiPicker from './components/EmojiPicker';
14import EmojiList from './components/EmojiList';
15import EmojiSticker from './components/EmojiSticker';
16
17const PlaceholderImage = require('./assets/images/background-image.png');
18
19export default function App() {
20  const [isModalVisible, setIsModalVisible] = useState(false);
21  const [showAppOptions, setShowAppOptions] = useState(false);
22  const [pickedEmoji, setPickedEmoji] = useState(null);
23  const [selectedImage, setSelectedImage] = useState(null);
24
25  const [status, requestPermission] = MediaLibrary.usePermissions();
26  const imageRef = useRef();
27
28  if (status === null) {
29    requestPermission();
30  }
31
32  const pickImageAsync = async () => {
33    let result = await ImagePicker.launchImageLibraryAsync({
34      allowsEditing: true,
35      quality: 1,
36    });
37
38    if (!result.canceled) {
39      setSelectedImage(result.assets[0].uri);
40      setShowAppOptions(true);
41    } else {
42      alert('You did not select any image.');
43    }
44  };
45
46  const onReset = () => {
47    setShowAppOptions(false);
48  };
49
50  const onAddSticker = () => {
51    setIsModalVisible(true);
52  };
53
54  const onModalClose = () => {
55    setIsModalVisible(false);
56  };
57
58
59  const onSaveImageAsync = async () => {
60    try {
61      const localUri = await captureRef(imageRef, {
62        height: 440,
63        quality: 1,
64      });
65
66      await MediaLibrary.saveToLibraryAsync(localUri);
67      if (localUri) {
68        alert("Saved!");
69      }
70    } catch (e) {
71      console.log(e);
72    }
73  };
74
75  return (
76    <GestureHandlerRootView style={styles.container}>
77      <View style={styles.imageContainer}>
78        <View ref={imageRef} collapsable={false}>
79          <ImageViewer
80            ref={imageRef}
81            placeholderImageSource={PlaceholderImage}
82            selectedImage={selectedImage}
83          />
84          {pickedEmoji !== null ? (
85            <EmojiSticker imageSize={40} stickerSource={pickedEmoji} />
86          ) : null}
87        </View>
88      </View>
89      {showAppOptions ? (
90        <View style={styles.optionsContainer}>
91          <View style={styles.optionsRow}>
92            <IconButton icon="refresh" label="Reset" onPress={onReset} />
93            <CircleButton onPress={onAddSticker} />
94            <IconButton icon="save-alt" label="Save" onPress={onSaveImageAsync} />
95          </View>
96        </View>
97      ) : (
98        <View style={styles.footerContainer}>
99          <Button theme="primary" label="Choose a photo" onPress={pickImageAsync} />
100          <Button
101            label="Use this photo" onPress={() => setShowAppOptions(true)}
102          />
103        </View>
104      )}
105      <EmojiPicker isVisible={isModalVisible} onClose={onModalClose}>
106        <EmojiList onSelect={setPickedEmoji} onCloseModal={onModalClose} />
107      </EmojiPicker>
108      <StatusBar style="auto" />
109    </GestureHandlerRootView>
110  );
111}
112
113const styles = StyleSheet.create({
114  container: {
115    flex: 1,
116    backgroundColor: '#25292e',
117    alignItems: 'center',
118  },
119  imageContainer: {
120    flex:1,
121    paddingTop: 58
122  },
123  footerContainer: {
124    flex: 1 / 3,
125    alignItems: 'center',
126  },
127  optionsContainer: {
128    position: 'absolute',
129    bottom: 80,
130  },
131  optionsRow: {
132    alignItems: 'center',
133    flexDirection: 'row',
134    justifyContent: 'center',
135  },
136});
137