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