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