Expo React Native TakeSnapShot Async Returning Black Screen - react-native

I'm new to React Native and am trying to create an app that will use Expo's Camera and Takesnapshot Async to take a picture and save it to Cameraroll.
I'm probably doing something really dumb, but right now (even though the view is showing the camera before I press the snapshot button), my code is saving a black image when I click the button instead of the image captured by the camera to the camera roll.
Here is my code for the CameraScreen (I'm using code from https://docs.expo.io/versions/latest/sdk/camera to open the camera and code from https://snack.expo.io/SJRvlSxvb to save a snapshot):
class CameraScreen extends React.Component {
state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
cameraRollUri: null,
};
async componentWillMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === 'granted' });
}
render() {
const { hasCameraPermission } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else {
return (
<View style={{ flex: 1 }} >
<Camera style={{ flex: 1 }}
type={this.state.type}
collapsable={false}
ref={view => {
this._container = view;
}} >
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
}} >
{this.state.cameraRollUri &&
<Image
source={{ uri: this.state.cameraRollUri }}
style={{ width: 200, height: 200 }
}
/>}
<TouchableOpacity style={styles.gridItem} onPress={this._saveToCameraRollAsync}>
</TouchableOpacity>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
this.setState({
type: this.state.type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
});
}}>
<Text
style={{ fontSize: 18, marginBottom: 10, color: 'white' }}>
{' '}Flip{' '}
</Text>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
}
_saveToCameraRollAsync = async () => {
let result = await takeSnapshotAsync(this._container, {
format: 'png',
result: 'file',
});
let saveResult = await CameraRoll.saveToCameraRoll(result, 'photo');
this.setState({ cameraRollUri: saveResult });
};
}
I first thought that the view saved to this._components wasn't the right view, but I tried attaching the code
ref={view => {
this._container = view;
}
to different views in the class but nothing seems to be changing.
Thanks in advance for any help - I've been struggling for this for a pretty long time now :(
PS: This is my first stack overflow post; I apologize in advance if there anything wrong with my post.

Expo Camera doesn’t support snapshot instead you can use the method takePictureAsync from Camera which return an image object.
const image = await this._container.takePictureAsync();

Camera component from Expo doesn't support takeSnapshotAsync.
Otherwise if you are using any Expo-pixi component, this code can be helpful:
const { uri } = await this.sketch.takeSnapshotAsync();
//save sketch/signature/doodles in DCIM folder.
let saveResult = await CameraRoll.saveToCameraRoll(uri, 'photo');

Related

SafeAreaView does not take the whole screen after placing on the background

I am using RN 0.59. Every time I placed the app on the background then reopen it immediately, the SafeAreaView does not take the whole screen.
But, if I placed the app on the background and reopen it after a while (for about 3 seconds) it is working fine.
Here's my snippet on SafeAreaView
...
const SafeAreaViewUI = ({children}) => {
return (
<SafeAreaView style={styles.container}>
<View style={styles.content}>
{ children }
</View>
</SafeAreaView>
);
};
...
export default SafeAreaViewUI;
for my styling
container: {
flex: 1,
backgroundColor: Platform.OS === 'android' ? blurple : null,
paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,
},
content: {
flexGrow: 1,
color: text,
backgroundColor: white,
}
Any insight for this one?
This worked on my end.
const SafeAreaViewUI = ({children}) => {
const [ height, setHeight ] = useState(0)
return (
<SafeAreaView
onLayout={() => {
if (Platform.OS === 'android') {
setHeight(StatusBar.currentHeight || 0);
}
}}
style={[styles.container, { paddingTop: height }]}>
<View style={styles.content}>
{ children }
</View>
</SafeAreaView>
);
If there's other possible answer. Kindly post it here.
Thanks!

how make my hook valid ? Object are not valid as a react child

i'm doing my hook with firestore. I did praticly exactly the same on an ohter page and he works. But this one i have the error : Objects are not valid as a React child (found: object with keys {_U, _V, _W, _X}). If you meant to render a collection of children, use an array instead.
On my console i can see an empty array like that
cc []
also my hook
async function GetFriendsRequest() {
const [TeamsArray, updateTeamArray] = React.useState([]);
firestore()
.collection("Teams")
// Filter results
.where("uid", "==", await AsyncStorage.getItem("userID"))
.get()
.then((querySnapshot) => {
if (querySnapshot.empty) {
console.log("no documents found");
} else {
querySnapshot.forEach(async (doc) => {
let Teams = doc._data;
TeamsArray.length = 0;
updateTeamArray((arr) => [...arr, Teams]);
console.log("cc", JSON.stringify(TeamsArray));
});
}
});
return (
<View>
{TeamsArray.map((element, key) => {
<View style={{ flex: 1, flexDirection: "row" }}>
<View>
<Text style={{ color: "#5DC1D3" }}>
{element.MembersList.nickName}
</Text>
<Text style={{ color: "#5DC1D3" }}>{element.Activity} </Text>
</View>
</View>;
})}
</View>
);
}
Something is wrong ?
Your .map() callback isn't returning anything. You need to replace the braces with parentheses in the body of the callback in order to return your JSX:
{TeamsArray.map((element, key) => (
<View style={{ flex: 1, flexDirection: "row" }}>
<View>
<Text style={{ color: "#5DC1D3" }}>
{element.MembersList.nickName}
</Text>
<Text style={{ color: "#5DC1D3" }}>{element.Activity} </Text>
</View>
</View>;
))}
There's a few mistakes in your component, you'll have to fix those first before debugging.
// This is a component, not a hook, so use it like <GetFriendsRequest />
async function GetFriendsRequest() {
const [TeamsArray, updateTeamArray] = React.useState([]);
// This code was in the render loop
// put it inside a function so it doesn't run on every single render
const init = async () => {
const uid = await AsyncStorage.getItem("userID");
firestore()
.collection("Teams")
// Filter results
.where("uid", "==", uid)
.get()
.then((querySnapshot) => {
if (querySnapshot.empty) {
console.log("no documents found");
} else {
const results = [];
querySnapshot.forEach(async (doc) => {
let Teams = doc.data();
// Don't mutate react state, it should be treated as immutable
// TeamsArray.length = 0;
// This is an async function, but it's being
// called as if it were syncronous
// updateTeamArray((arr) => [...arr, Teams]);
results.push(Teams);
});
// Schedule a single state update
updateTeamArray([...results, ...TeamsArray]);
}
});
}
// Use an expression like this to debug
useEffect(() => {
// Log state every time it updates
console.log(TeamsArray);
}, [TeamsArray]);
useEffect(() => {
init();
}, []);
return (
<View>
{TeamsArray.map((element, key) => {
// Something has to be returned from this map
return <View style={{ flex: 1, flexDirection: "row" }}>
<View>
<Text style={{ color: "#5DC1D3" }}>
{element.MembersList.nickName}
</Text>
<Text style={{ color: "#5DC1D3" }}>{element.Activity} </Text>
</View>
</View>;
})}
</View>
);
};

Why is my message not getting displayed in React Native FlatList?

Im making a dating app in react native and im using FlatList to display messages. I implemented inverted and onEndReached props and messages are getting fetched when scrolling up no problem. but when sending a message, (im using socket.io-client with my nodejs server), the new message does not get displayed. Here is my code:
sendMessage func
const sendMessage = async () => {
if (!currentConversation) return;
if (isUserBlocked(getRecipient(currentConversation))) return;
if (isRecipientBlocked(getRecipient(currentConversation)._id)) return;
if (!newMessage.trim()) return;
if (user && currentConversation) {
const v4 = uuid.v4();
const message = {
text: newMessage,
user,
uuid: v4,
};
socket.emit("message", {
message: { ...message, conversation: currentConversation },
});
socket.emit("conversation", {
userId: getRecipient(currentConversation)._id,
message: { ...message, conversation: currentConversation },
});
setNewMessage("");
await (await HttpClient()).post(config.SERVER_URL + "/api/message/send", {
...message,
conversationId: currentConversation._id,
});
}
};
useEffect to get new Message
the setMessages() func doesnt work
useEffect(() => {
const handler = (message) => {
const conversationIndex = conversations.findIndex(
(c) => c._id === message.conversation._id
);
if (conversationIndex >= 0) {
const _conversations = [...conversations];
message.conversation.latestMessage = message.text;
_conversations.splice(conversationIndex, 1);
_conversations.unshift(message.conversation);
setConversations(_conversations);
setDefaultConversations(_conversations);
}
if (message.conversation._id !== currentConversation._id) return;
console.log(message.text); //works
setMessages([...messages, { ...message }]); //doesnt work
};
socket.on("message", handler);
return () => {
socket.off("message", handler);
};
}, [messages]);
flatlist
<FlatList
onEndReached={() =>
getMessages(currentConversation, messages.length)
}
onEndReachedThreshold={0.8}
inverted
data={messages}
renderItem={(message) => (
<View
style={{
flexDirection: "row",
padding: 5,
justifyContent: isOwnMessage(message.item)
? "flex-end"
: "flex-start",
}}
>
<View
style={{
padding: 10,
backgroundColor: "#2196F3",
marginBottom: 5,
borderRadius: 5,
maxWidth: "50%",
}}
>
<Text style={{ fontWeight: "bold" }}>
{message.item.user.displayName}
</Text>
<Text>{message.item.text}</Text>
<Text style={{ fontSize: 10 }}>
{moment(message.item.createdAt).fromNow()}
</Text>
</View>
</View>
)}
keyExtractor={(item) => item.uuid}
/>
I solved this issue. The new message WAS being added, but to the top, due to the inverted property. So I just changed the setMessages to first include the message, and then the rest of the messages.

Possible Unhandled Promise Rejection (id: 0): TypeError: undefined is not an object (evaluating '_this.props.navigation.navigate')

I'm trying to display an image I have captured using expo-camera, from the camera component I'm trying to navigate to a new file which will display the image but after I took the image it won't navigate to the new page.
I tried importing the file and then navigate it but it still won't work and give me the warning instead.
This is the code where I tried to navigate to the new file.
export default class CameraExample extends React.Component {
state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
};
async componentDidMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === 'granted' });
}
snap = async() => {
if(this.camera) {
console.log('Taking photo');
const options = {quality: 1, base64: true, fixOrientation: true, exif: true};
const photo = await this.camera.takePictureAsync(options);
this.props.navigation.navigate("Show", {photouri: photo.uri})
}
}
render() {
const { hasCameraPermission } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else {
return (
<View style={{ flex: 1 }}>
<Camera style={{ flex: 1 }} type={this.state.type}
ref = {ref => {
this.camera = ref;
}}
>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
}}>
<TouchableOpacity onPress={this.snap.bind(this)}>
<Ionicons
name = "md-camera"
color = "white"
size = {30}
/>
</TouchableOpacity>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
this.setState({
type:
this.state.type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
});
}}>
<Ionicons
name = "md-reverse-camera"
color = "white"
size = {30}
/>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
}
}
And this is the code where I try to display the image.
export default class ShowImages extends React.Component{
render(){
console.log('OK')
const { navigation } = this.props;
const paramm = navigation.getParam('photouri');
return(
<Content>
<View>
<Text>
paramm: {JSON.stringify(paramm)}
</Text>
<Image style={{height: 700, width: 850, alignSelf: "center"}}
source={{uri: this.props.navigation.state.paramm.photouri}}
resizeMode="contain"/>
</View>
</Content>
)
}
}
I expect it to navigate to the new page and display the captured
image but it gave me the warning. I can't seem to find what is wrong with my code. Can anyone suggest what I should do? Thank you.
change this
<TouchableOpacity onPress={this.snap.bind(this)}> => <TouchableOpacity onPress={this.snap}>
Put it in the status value and pass it on.
export default class ShowImages extends React.Component{
constructor(props) {
super(props);
this.state = {
paramm: this.props.navigation.state.params.photouri
};
}
...
<Image style={{height: 700, width: 850, alignSelf: "center"}}
source={{uri: this.state.paramm }}
resizeMode="contain"/>

How do I upload an image taken React-Native-camera to Firebase storage?

I want upload image taken with react-native-camera to https://github.com/invertase/react-native-firebase storage on RN
I can't upload image.
I tried image-picker-library and did work.
import React, { Component } from 'react';
import {Image, View, Text, StyleSheet, Dimensions,TouchableOpacity} from 'react-native'
import { RNCamera } from 'react-native-camera';
import {strings} from '../Lang/Strings';
import { Actions } from 'react-native-router-flux';
const { width, height } = Dimensions.get('window');
export default class ScanPage extends Component {
constructor(props) {
super(props);
this.state = {
takePicture = async () => {
if (this.camera) {
const options = { quality: 0.5, base64: true }
const data = await this.camera.takePictureAsync(options)
Actions.ProfilePage({imagePath:data.uri,
selectedIndex:this.state.selectedIndex,
shapes:this.state.shapes });
this.uploadPhoto(data);
};
};
render() {
const {selectedIndex, images, shapes} = this.state;
return(
<View style={styles.container}>
<RNCamera
ref={ref => {
this.camera = ref;
}}
style={styles.preview}
type={RNCamera.Constants.Type.front}
permissionDialogTitle={'Permission to use camera'}
permissionDialogMessage={'We need your permission to use your camera phone'} />
<View style={{flex:1,justifyContent:'center' ,alignItems:'center'}}>
<View style={{marginTop:120}}>
<Image source={images[selectedIndex]} >
</Image>
</View>
</View>
<View style={styles.buttonSection}>
<TouchableOpacity onPress={this._TogglePrev}>
<View style={styles.buttons}>
<Text style={{textAlign:'center',color: 'white'}}>
{strings.back}
</Text>
</View>
</TouchableOpacity>
<View style={{alignItems:'center', justifyContent:'center',
height:height*0.04}}>
<Text style ={{color:'white',textAlign:'center'}}>{shapes[selectedIndex]} </Text>
</View>
<TouchableOpacity onPress={this._ToggleNext}>
<View style={styles.buttons}>
<Text style={{textAlign:'center', color: 'white'}}>
{strings.next}
</Text>
</View>
</TouchableOpacity>
</View>
<View style={{alignItems:'center', justifyContent:'center',
backgroundColor:'#D9E6FF',height:height*0.001,width:width*1}}>
<Text style ={{color:'white',textAlign:'center'}}> </Text>
</View>
<View style={{ flex: 0, flexDirection: 'row', justifyContent: 'center'}}>
<TouchableOpacity onPress={this.takePicture.bind(this)} style={styles.capture}
>
<View style={{
backgroundColor: 'white',
borderRadius: (height*0.16)/2,
padding: 15,
alignSelf: 'center',
margin: 25,
height:height*0.085,
width:width*0.16,
justifyContent:'center',
alignItems:'center',
borderWidth:0.9,
borderColor:'#D9E6FF',}}></View>
</TouchableOpacity>
</View>
</View>
);
}
takePicture = async function() {
if (this.camera) {
const options = { quality: 0.5, base64: true };
const data = await this.camera.takePictureAsync(options);
Actions.ProfilePage({imagePath:data.uri,
selectedIndex:this.state.selectedIndex,
shapes:this.state.shapes
});
}
};
}
I didn't upload firebase,
versions
react: 16.4.1,
react-native: 0.56.0,
react-native-camera:1.12.0,
react-native-firebase:5.2.3
react-native-router-flux:4.0.1
Can't believe I've figured it out >.<
if you've set up your project correctly to include firebase
takePicture = async() => {
if (this.camera) {
// this code takes the picture
const options = { quality: 0.5, base64: true };
const data = await this.camera.takePictureAsync(options);
// open debug to see the uri of image
console.log(data.uri);
// send your data.uri off to firebase! :D
const processed = await firebase.vision().imageLabelerProcessImage(data.uri, {
confidenceThreshold: 0.8,
});
//Look at your debugger again
console.log('Label: ', processed);
}
};
I hope this helps!
_publish = async () => {
const imageuri= this.state.imagePath;
//this is where + how you want your image to be stored into
const refFile= firebase.storage().ref().child('profile_pic');
refFile.putFile(imageuri)
.catch(error => {
console.log(error);
// Alert.alert('Hey', error);
});
}
hope it helps!