work on the sticker expo app up to the emoji picker

This commit is contained in:
evansteelepdx 2024-08-10 18:22:40 -07:00
parent d9922d5ec5
commit ba572f9d69
No known key found for this signature in database
GPG Key ID: 56E2903FDA9F3F06
9 changed files with 276 additions and 5 deletions

84
App.js
View File

@ -1,10 +1,69 @@
import { StatusBar } from 'expo-status-bar'; import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native'; import { StyleSheet, Text, View, Image } from 'react-native';
import { useState } from 'react';
import * as ImagePicker from 'expo-image-picker';
import ImageViewer from './components/ImageViewer';
import Button from './components/Button';
import CircleButton from './components/CircleButton';
import IconButton from './components/IconButton';
import Picker from './components/Picker';
const backgroundImage = require('./assets/images/background-image.png')
export default function App() { export default function App() {
const [selectedImage, setSelectedImage] = useState(null);
const [showAppOptions, setShowAppOptions] = useState(false);
const [isModalVisible, setIsModalVisible] = useState(false);
const pickImageAsync = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
quality: 1,
});
if (!result.canceled) {
setSelectedImage(result.assets[0].uri);
setShowAppOptions(true);
} else {
alert('You did not select any image.');
}
};
const onReset = () => {
setShowAppOptions(false);
};
const onAddSticker = () => {
setIsModalVisible(true);
};
const onModalClose = () => {
setIsModalVisible(false);
};
const onSaveImageAsync = async () => {
// we will implement this later
};
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text> <View style={styles.imageContainer}>
<ImageViewer placeholderImageSource={backgroundImage} selectedImage={selectedImage} />
</View>
{showAppOptions ? (
<View style={styles.optionsContainer}>
<View style={styles.optionsRow}>
<IconButton icon="refresh" label="Reset" onPress={onReset} />
<CircleButton onPress={onAddSticker} />
<IconButton icon="save-alt" label="Save" onPress={onSaveImageAsync} />
</View>
</View>
) : (
<View style={styles.buttonContainer}>
<Button label="Choose a photo" override={true} onPress={pickImageAsync} />
<Button label="Use this photo" override={false} onPress={() => setShowAppOptions(true)} />
</View>
)}
<Picker isVisible={isModalVisible} onClose={onModalClose}>
{/* A list of emoji component will go here */}
</Picker>
<StatusBar style="auto" /> <StatusBar style="auto" />
</View> </View>
); );
@ -13,8 +72,25 @@ export default function App() {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
backgroundColor: '#fff', backgroundColor: '#e9ffdb',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center'
}, },
imageContainer: {
flex: 1,
paddingTop: 59
},
buttonContainer: {
flex: 1 / 3,
alignItems: 'center',
rowGap: 10
},
optionsContainer: {
position: 'absolute',
bottom: 80,
},
optionsRow: {
alignItems: 'center',
flexDirection: 'row',
}
}); });

48
components/Button.js Normal file
View File

@ -0,0 +1,48 @@
import { StyleSheet, View, Pressable, Text } from 'react-native';
import FontAwesome from "@expo/vector-icons/FontAwesome";
export default function Button({ label, override, onPress }) {
if (override) {
return (
<View style={styles.buttonContainer}>
<Pressable style={styles.button} onPress={onPress}>
<FontAwesome
name="picture-o"
size={18}
color="#25292e"
style={styles.buttonIcon}
/>
<Text style={styles.primaryButtonLabel}>{label}</Text>
</Pressable>
</View>
);
} else {
return (
<View style={styles.buttonContainer}>
<Pressable style={styles.button} onPress={onPress}>
<Text style={styles.buttonLabel}>{label}</Text>
</Pressable>
</View>
);
}
}
const styles = StyleSheet.create({
buttonContainer: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
width: 320,
height: 68,
marginHorizontal: 20,
alignItems: 'center',
justifyContent: 'center',
padding: 3,
backgroundColor: '#E3F988',
borderRadius: 80
},
buttonIcon: {
position: 'absolute',
marginLeft: -30
}
});

View File

@ -0,0 +1,31 @@
import { View, Pressable, StyleSheet } from 'react-native';
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
export default function CircleButton({ onPress }) {
return (
<View style={styles.circleButtonContainer}>
<Pressable style={styles.circleButton} onPress={onPress}>
<MaterialIcons name="add" size={38} color="#25292e" />
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
circleButtonContainer: {
width: 84,
height: 84,
marginHorizontal: 60,
borderWidth: 4,
borderColor: '#ffd33d',
borderRadius: 42,
padding: 3,
},
circleButton: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 42,
backgroundColor: '#fff',
},
});

22
components/IconButton.js Normal file
View File

@ -0,0 +1,22 @@
import { Pressable, StyleSheet, Text } from 'react-native';
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
export default function IconButton({ icon, label, onPress }) {
return (
<Pressable style={styles.iconButton} onPress={onPress}>
<MaterialIcons name={icon} size={24} color="#000" />
<Text style={styles.iconButtonLabel}>{label}</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
iconButton: {
justifyContent: 'center',
alignItems: 'center',
},
iconButtonLabel: {
color: '#000',
marginTop: 12,
},
});

17
components/ImageViewer.js Normal file
View File

@ -0,0 +1,17 @@
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, Image } from 'react-native';
export default function ImageViewer({placeholderImageSource,selectedImage}){
const imageSource = selectedImage ? { uri: selectedImage } : placeholderImageSource;
return (
<Image source={imageSource} style={styles.image} />
);
}
const styles = StyleSheet.create({
image:{
width:350,
height:450,
borderRadius:80
}
})

44
components/Picker.js Normal file
View File

@ -0,0 +1,44 @@
import { Modal, View, Text, Pressable, StyleSheet } from 'react-native';
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
export default function Picker({ isVisible, children, onClose }) {
return (
<Modal animationType="slide" transparent={true} visible={isVisible}>
<View style={styles.modalContent}>
<View style={styles.titleContainer}>
<Text style={styles.title}>Choose a sticker</Text>
<Pressable onPress={onClose}>
<MaterialIcons name="close" color="#000" size={22} />
</Pressable>
</View>
{children}
</View>
</Modal>
);
}
const styles = StyleSheet.create({
modalContent: {
height: '25%',
width: '100%',
backgroundColor: '#25292e',
borderTopRightRadius: 18,
borderTopLeftRadius: 18,
position: 'absolute',
bottom: 0,
},
titleContainer: {
height: '16%',
backgroundColor: '#464C55',
borderTopRightRadius: 10,
borderTopLeftRadius: 10,
paddingHorizontal: 20,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
title: {
color: '#000',
fontSize: 16,
},
});

10
jsconfig.json Normal file
View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"allowSyntheticDefaultImports": true
},
"exclude": [
"node_modules"
]
}

21
package-lock.json generated
View File

@ -9,7 +9,9 @@
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@expo/metro-runtime": "~3.2.1", "@expo/metro-runtime": "~3.2.1",
"@expo/vector-icons": "^14.0.2",
"expo": "~51.0.22", "expo": "~51.0.22",
"expo-image-picker": "~15.0.7",
"expo-status-bar": "~1.12.1", "expo-status-bar": "~1.12.1",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
@ -7796,6 +7798,25 @@
"expo": "*" "expo": "*"
} }
}, },
"node_modules/expo-image-loader": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-4.7.0.tgz",
"integrity": "sha512-cx+MxxsAMGl9AiWnQUzrkJMJH4eNOGlu7XkLGnAXSJrRoIiciGaKqzeaD326IyCTV+Z1fXvIliSgNW+DscvD8g==",
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-image-picker": {
"version": "15.0.7",
"resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-15.0.7.tgz",
"integrity": "sha512-u8qiPZNfDb+ap6PJ8pq2iTO7JKX+ikAUQ0K0c7gXGliKLxoXgDdDmXxz9/6QdICTshJBJlBvI0MwY5NWu7A/uw==",
"dependencies": {
"expo-image-loader": "~4.7.0"
},
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-keep-awake": { "node_modules/expo-keep-awake": {
"version": "13.0.2", "version": "13.0.2",
"resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-13.0.2.tgz", "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-13.0.2.tgz",

View File

@ -15,7 +15,9 @@
"react-native": "0.74.3", "react-native": "0.74.3",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-native-web": "~0.19.10", "react-native-web": "~0.19.10",
"@expo/metro-runtime": "~3.2.1" "@expo/metro-runtime": "~3.2.1",
"@expo/vector-icons": "^14.0.2",
"expo-image-picker": "~15.0.7"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.0" "@babel/core": "^7.20.0"