Last active
November 1, 2022 18:02
-
-
Save wheelie33/676a194ce6ee05703187a7821a24e715 to your computer and use it in GitHub Desktop.
Cropping Crash
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Fatal: TypeError null is not an object (evaluating 'v.default.handleSetJSResponder') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"dependencies": { | |
"@expo/react-native-action-sheet": "^4.0.0", | |
"@expo/vector-icons": "^13.0.0", | |
"@react-native-async-storage/async-storage": "~1.17.3", | |
"@react-native-community/netinfo": "9.3.0", | |
"@react-navigation/bottom-tabs": "^6.4.0", | |
"@react-navigation/native": "^6.0.13", | |
"@react-navigation/stack": "^6.3.1", | |
"expo": "~46.0.13", | |
"expo-application": "~4.2.2", | |
"expo-av": "~12.0.4", | |
"expo-camera": "~12.3.0", | |
"expo-constants": "~13.2.4", | |
"expo-device": "~4.3.0", | |
"expo-image-cropper": "^1.0.9", | |
"expo-image-picker": "~13.3.1", | |
"expo-intent-launcher": "~10.3.0", | |
"expo-linking": "~3.2.2", | |
"expo-local-authentication": "~12.3.0", | |
"expo-localization": "~13.1.0", | |
"expo-notifications": "~0.16.1", | |
"expo-secure-store": "~11.3.0", | |
"expo-splash-screen": "~0.16.2", | |
"expo-status-bar": "~1.4.0", | |
"expo-system-ui": "~1.3.0", | |
"expo-updates": "~0.14.6", | |
"firebase": "9.4.1", | |
"jwt-decode": "^3.1.2", | |
"react": "18.0.0", | |
"react-native": "0.69.6", | |
"react-native-exception-handler": "^2.10.10", | |
"react-native-gifted-chat": "^1.0.4", | |
"react-native-safe-area-context": "4.3.1", | |
"react-native-screens": "~3.15.0", | |
"react-native-uuid": "^2.0.1" | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useRef, useState } from "react" | |
import { View, Text, StyleSheet, TouchableOpacity, Image, Button, SafeAreaView } from "react-native" | |
import { Ionicons, MaterialCommunityIcons, Feather } from "@expo/vector-icons" | |
import * as ImagePicker from "expo-image-picker" | |
import ImageEditor from "expo-image-cropper" | |
import { Camera } from "expo-camera" | |
import useAuth from "../AuthContext/AuthContext" | |
import { useActionSheet } from "@expo/react-native-action-sheet" | |
function ProfileImagesScreen() { | |
let cameraRef = useRef() | |
const [uploadStatus, setUploadStatus] = useState(false) | |
const [isUploading, setIsUploading] = useState(false) | |
const [hasPermission, setHasPermission] = useState(null) | |
const [type, setType] = useState(Camera.Constants.Type.front) | |
const [useFlash, setUseFlash] = useState(Camera.Constants.FlashMode.on) | |
const [photo, setPhoto] = useState(null) | |
const [selectedPhoto, setSelectedPhoto] = useState(null) | |
const [showEditor, setShowEditor] = useState(false) | |
const [profilePhoto, setProfilePhoto] = useState("https://placekitten.com/100/100") | |
const [showCamera, setShowCamera] = useState(false) | |
const { authState } = useAuth() | |
const { showActionSheetWithOptions } = useActionSheet() | |
const userId = authState.profile.userId | |
const buttonClickedHandler = () => { | |
const options = ["Take Photo", "Choose from Library", "Cancel"] | |
const cancelButtonIndex = 2 | |
showActionSheetWithOptions( | |
{ | |
options, | |
cancelButtonIndex, | |
}, | |
(selectedIndex) => { | |
switch (selectedIndex) { | |
case 0: { | |
// Take Photo | |
;(async () => { | |
const { status } = await Camera.requestCameraPermissionsAsync() | |
setHasPermission(status === "granted") | |
setShowCamera(true) | |
})() | |
break | |
} | |
case 1: { | |
// Choose from Library | |
alert("Choose from Library") | |
break | |
} | |
case cancelButtonIndex: | |
// Canceled | |
} | |
} | |
) | |
} | |
const takePhoto = async () => { | |
if (!cameraRef) return | |
const options = { | |
quality: 0.5, | |
base64: false, | |
exif: false, | |
skipProcessing: true, | |
} | |
console.log("Taking photo") | |
const newPhoto = await cameraRef.current.takePictureAsync(options) | |
setShowCamera(false) | |
setPhoto(newPhoto) | |
} | |
if (showCamera) { | |
if (hasPermission === null || hasPermission === false) { | |
alert("No access to camera") | |
setShowCamera(false) | |
setPhoto(null) | |
} | |
const iconSize = 36 | |
return ( | |
<Camera ref={cameraRef} style={styles.photoPreviewContainer} type={type} flashMode={useFlash}> | |
<View style={styles.buttonContainer}> | |
<TouchableOpacity onPress={() => setType(type === Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back)}> | |
<MaterialCommunityIcons name='rotate-360' size={iconSize} color={type === Camera.Constants.Type.back ? "white" : "yellow"} /> | |
</TouchableOpacity> | |
<TouchableOpacity onPress={takePhoto}> | |
<Ionicons name='camera-sharp' size={iconSize} color='white' /> | |
</TouchableOpacity> | |
<TouchableOpacity | |
onPress={() => setUseFlash(useFlash === Camera.Constants.FlashMode.off ? Camera.Constants.FlashMode.on : Camera.Constants.FlashMode.off)} | |
> | |
<Ionicons name='flash' size={iconSize} color={useFlash === Camera.Constants.FlashMode.off ? "white" : "yellow"} /> | |
</TouchableOpacity> | |
<TouchableOpacity onPress={() => setShowCamera(false)}> | |
<Feather name='x' size={iconSize} color='white' /> | |
</TouchableOpacity> | |
</View> | |
</Camera> | |
) | |
} | |
if (photo != null) { | |
return ( | |
<SafeAreaView style={styles.photoPreviewContainer}> | |
<Image source={{ uri: photo.uri }} style={styles.previewImage} /> | |
<View style={styles.buttonContainer}> | |
<Button | |
title='Use Photo' | |
onPress={async () => { | |
const fileName = Math.round(Date.now() / 1000) | |
//await uploadMedia(fileName, photo.uri) | |
setShowCamera(false) | |
setSelectedPhoto(photo.uri) | |
setPhoto(null) | |
setShowEditor(true) | |
}} | |
/> | |
<Button | |
title='Take another' | |
onPress={() => { | |
setPhoto(null) | |
setShowCamera(true) | |
}} | |
/> | |
<Button | |
title='Cancel' | |
onPress={() => { | |
setShowCamera(false) | |
setPhoto(null) | |
}} | |
/> | |
</View> | |
</SafeAreaView> | |
) | |
} | |
if (showEditor) { | |
return ( | |
<ImageEditor | |
imageUri={selectedPhoto} | |
fixedAspectRatio={1 / 1} | |
lockAspectRatio={true} | |
minimumCropDimensions={{ | |
width: 150, | |
height: 150, | |
}} | |
onEditingCancel={() => { | |
setShowCamera(false) | |
setPhoto(null) | |
setSelectedPhoto(null) | |
setShowEditor(false) | |
}} | |
onEditingComplete={(image) => { | |
const fileName = Math.round(Date.now() / 1000) | |
//await uploadMedia(fileName, photo.uri) | |
setShowCamera(false) | |
setSelectedPhoto(null) | |
setPhoto(null) | |
setShowEditor(false) | |
setProfilePhoto(image.uri) | |
}} | |
/> | |
) | |
} | |
return ( | |
<View style={styles.screen}> | |
<View style={styles.profileImageContainer}> | |
<Image source={{ uri: profilePhoto }} style={styles.image} /> | |
<View style={styles.cameraButtonContainer}> | |
<TouchableOpacity style={styles.button} onPress={buttonClickedHandler}> | |
<Ionicons name='camera-sharp' size={24} style={{ color: "#C0C0C0" }} /> | |
</TouchableOpacity> | |
</View> | |
</View> | |
</View> | |
) | |
} | |
// Styles | |
const styles = StyleSheet.create({ | |
screen: { | |
flex: 1, | |
justifyContent: "center", | |
alignItems: "center", | |
}, | |
profileImageContainer: { | |
width: 150, | |
height: 150, | |
}, | |
image: { | |
width: 150, | |
height: 150, | |
position: "absolute", | |
top: 0, | |
left: 0, | |
}, | |
cameraButtonContainer: { | |
padding: 5, | |
backgroundColor: "rgba(0,0,0,0.35)", | |
position: "absolute", | |
bottom: 0, | |
right: 4, | |
}, | |
photoPreviewContainer: { | |
flex: 1, | |
alignItems: "center", | |
justifyContent: "center", | |
}, | |
buttonContainer: { | |
flex: 1, | |
flexDirection: "row", | |
justifyContent: "space-between", | |
backgroundColor: "black", | |
position: "absolute", | |
bottom: 0, | |
left: 0, | |
right: 0, | |
padding: 12, | |
}, | |
previewImage: { | |
alignSelf: "stretch", | |
flex: 1, | |
}, | |
}) | |
export default ProfileImagesScreen |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment