App stop working when Image Picker is opened in React Native - react-native

I am developing a React Native application using React Native. I am using react native image picker library, https://www.npmjs.com/package/react-native-imagepicker to pick up the images from the Gallery. But when I opened the image picker, my app stopped working and exited.
This is my code
import React from "react";
import { CameraRoll, View, Text, Button, Alert, Image } from "react-native";
import ImagePicker from "react-native-image-picker";
// More info on all the options is below in the API Reference... just some common use cases shown here
const options = {
title: "Select Avatar",
customButtons: [{ name: "fb", title: "Choose Photo from Facebook" }],
storageOptions: {
skipBackup: true,
path: "images"
}
};
class Gallery extends React.Component {
constructor(props) {
super(props);
this.state = {
url:"https://www.designevo.com/res/templates/thumb_small/terrible-black-bat-icon.png",
avatarSource: null
};
}
saveToCameraRoll = () => {
let { url } = this.state;
};
_handlePickImageButton = () => {
ImagePicker.showImagePicker(options, response => {
console.log("Response = ", response);
if (response.didCancel) {
Alert.alert("User cancelled image picker")
} else if (response.error) {
//console.log("ImagePicker Error: ", response.error);
Alert.alert("ImagePicker Error:");
} else if (response.customButton) {
//console.log("User tapped custom button: ", response.customButton);
Alert.alert("Custom button");
} else {
const source = { uri: response.uri };
// You can also display the image using data:
// const source = { uri: 'data:image/jpeg;base64,' + response.data };
this.setState({
avatarSource: source
});
}
});
};
render() {
return (
<View>
<Button
onPress={() => {
this._handlePickImageButton();
}}
title="Pick a image"
>
Pick image
</Button>
<Image source={this.state.avatarSource} />
</View>
);
}
}
export default Gallery;
What is wrong with my code? Also, I did not get any error info in the console as in the screenshot attached below.
I tried, opening in this way too
ImagePicker.launchImageLibrary(options, (response) => {
//nothing implemented yet
});
It just stopped working.
I added the following permission in the plist as well:
I tried this too
const options = {
noData: true
};
ImagePicker.launchImageLibrary(options, (response) => {
});

I found the issue. The problem was in the plist. When I was adding the permissions, I just copy-pasted from a post. Might be something was wrong with it. When I typed in the permissions in the XCode, I saw the suggestion box, so I just clicked on the suggestion box and added the description for each permission as below.
As you can see in the above screenshot, the String value in the Type column is grayed out and cannot be changed. In the screenshot attached in the question, those values can be changed. That is the difference.

Related

How to pass api data from react native to html and vice-versa in react-native-html-to-pdf

i am using react-native-html-to-pdf package to create a pdf file i want to pass the api response from react-native to html and receive the data from html. the options available for this npm package is very minimum
There is no options in the package so that i can use it, can someone help me with this ?
Below is my code.
import React, { Component } from 'react';
import { Text, TouchableOpacity, View, StyleSheet, Image, PermissionsAndroid, Platform,} from 'react-native';
import RNHTMLtoPDF from 'react-native-html-to-pdf';
import htmlContent from './htmlContent'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
apiData: [],
filePath: ''
}
}
askPermission() {
var that = this;
async function requestExternalWritePermission() {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
{
title: 'External Storage Write Permission',
message:
'App needs access to Storage data in your SD Card ',
}
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
that.createPDF();
} else {
alert('WRITE_EXTERNAL_STORAGE permission denied');
}
} catch (err) {
alert('Write permission err', err);
console.warn(err);
}
}
if (Platform.OS === 'android') {
requestExternalWritePermission();
} else {
this.createPDF();
}
}
componentDidMount(){
fetch(`http://API`)
.then((response) => response.json())
.then((responseJson) => {
**console.log("DATA", responseJson) // NEED TO SEND THIS DATA TO "HTML"**
this.setState(() => ({
apiData: responseJson
}))
})
}
async createPDF() {
let options = {
html:htmlContent, // API DATA SHOULD BE SENT TO HTML
fileName: 'RTT Report',
directory: 'docs',
width: 800,
};
let file = await RNHTMLtoPDF.convert(options);
console.log(file.filePath);
this.setState({filePath:file.filePath});
}
render() {
return (
<View style={styles.MainContainer}>
<TouchableOpacity onPress={this.askPermission.bind(this)}>
<View>
<Image
//We are showing the Image from online
source={{
uri:
'https://raw.githubusercontent.com/AboutReact/sampleresource/master/pdf.png',
}}
//You can also show the image from you project directory like below
//source={require('./Images/facebook.png')}
style={styles.ImageStyle}
/>
<Text style={styles.text}>Create PDF</Text>
</View>
</TouchableOpacity>
<Text style={styles.text}>{this.state.filePath}</Text>
</View>
);
}
}
In createPDF method :
// html:htmlContent, // API DATA SHOULD BE SENT TO HTML
html: this.state.apiData // <-- you have stored your html in the state
EDIT:
Probably I was too fast answering, now I think I got your point , here you have an example :
// html: '<h1>PDF TEST</h1>', <-- example from react-native-html-to-pdf
const exampleData = [
{
title: "Element title",
content: "Element content"
},
{
title: "Other title",
content: "Other element content"
}
]
function generateHTML () {
const data = exampleData
// const data = this.state.apiData // <-- in your case
let htmlContent = '<html><body>'
htmlContent += data.map(entry => {
return `<h5>${entry.title}</h5> <br /> <p>${entry.content}</p>`
}).join(' ')
htmlContent += '</body></html>'
return htmlContent
}

Firebase react native-Could not get a document field from firestore to display in react native app

I am new to react native and firestore
Context:
Firestore has a document "Users" and "Location" is a field.
Requirement : I want the location of one user/logged in user to display in the react native app.
I have written the following code, however post login the Location field is empty.
Please suggest where am I wrong.
import React from "react";
import { Image, Button, TextInput, ScrollView, Stylesheet, Text, View } from "react-native";
import Constants from 'expo-constants';
import * as firebase from 'firebase';
import 'firebase/firestore';
constructor(props) {
super(props);
this.state = {
profileuser: [],
profileuserlocation:''
};
}
componentDidMount() {
firebase.firestore().collection('users').doc(firebase.auth().currentUser.uid).get().then(snapshot => {
let profileuserlocation = snapshot.data().Location;
this.setState({ profileuserlocation: snapshot.data().Location });
});
}
render() {
const profileuserlocation=this.state.profileuserlocation;
return (
<View>
<Text style={{ fontSize: 20, fontWeight: "bold" }}> {this.state.profileuserlocation}</Text>
</View>
)
I know it's a bit late but just in case you never found the answer...
The standard way to get the current user's uid is:
firebase.auth().onAuthStateChanged(user => {
if (user) {
firebaseUser = {
uid: user.uid,
name: user.displayName,//this and the email can also be got from firebaseUser
email: user.email
};
this.setState({ uid: firebaseUser.uid });
}
});
Then, if you just want to display the field from your doc you don't need to use snapshot - that's really for if you want to keep watching for changes in the field and is used in a different way. If you just want to retrieve the field one time then use:
const docRef = firebase.firestore().collection('users').doc(this.state.uid)
this.docRef
.doc(this.state.uid)
.get().then(function (doc) {
if (doc.exists) {
//useful ES6 'destructuring' technique for if there are many fields you are
//saving
const {
Location
} = doc.data();
this.setState({
Location
})
//or for one field you can use "this.setState({Location:doc.data().Location})"
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function (error) {
console.log("Error getting document:", error);
});
You can get some good examples in the documents: firestore docs
Hope this helps someone...

Calling a lib function and another function on single onpress in react native

I am working on a react native app where i'm using react-native share. Here I am taking a screenshot of a component and I want to share the screenshot on any of the social platform. But I want to take the screenshot and share that on one button onpress which i'm not being able to do. Here's the code I have now:
import {RNViewShot,captureScreen} from "react-native-view-shot"
import Share, {ShareSheet} from 'react-native-share'
class First extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
uri:''
}
}
screenshot = () => {
captureScreen({
format: "jpg",
quality: 0.8
})
.then(
uri => this.setState({ uri: uri }),
error => console.error("Oops, snapshot failed", error)
);
}
onCancel() {
console.log("CANCEL")
this.setState({visible:false});
}
onOpen() {
console.log("OPEN")
this.setState({visible:true});
}
render() {
let shareOptions = {
title: "React Native",
message: "Hola shareOptions",
url: "uri",
subject: "Share Link" // for email
};
let shareImageBase64 = {
title: "React Native",
message: "This is from VIP live 4D",
url: this.state.uri,
subject: "Share Link" // for email
};
return (
<View>
<Button
onPress={() => Share.open(shareImageBase64) } >
<Text>Share </Text>
</Button>
</View>
);
}
}
export default withNavigation(First)
Is there any way to call the screenshot function on the button onpress with the lib function it already has?
Can you try this (modified from your code):
screenshot=()=> {
captureScreen({
format: "jpg",
quality: 0.8
}).then(uri => {
this.setState(()=>{
return { uri: uri };
), ()=>{
const shareImageBase64 = {
title : "React Native",
message: "This is from VIP live 4D",
url : this.state.uri,
subject: "Share Link" // for email
};
Share.open(shareImageBase64);
};
);
};
From what I can tell, the issue was that the Share.open was given the "this.state.uri" value before it was set. By taking the value from "this.state" in the setState callback, we can be sure that the value have been set at this point.

undefined is not an object (evaluating '_expo.Permission.askAsync')

i don't know what's the problem exactly but when i click on the button to choose image that erreur fire in the console
here's my code
_checkPermissions = async () => {
try {
const { status } = await Permission.askAsync(Permission.CAMERA);
this.setState({ camera: status });
const { statusRoll } = await Permission.askAsync(Permission.CAMERA_ROLL);
this.setState({ cameraRoll: statusRoll });
} catch (err) {
console.log(err);
}
};
findNewImage = async () => {
try {
this._checkPermissions();
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: "Images",
allowsEditing: true,
quality: 1
});
if (!result.cancelled) {
this.setState({
image: result.uri
});
} else {
console.log("cancel");
}
} catch (err) {
// console.log(err);
}
};
to me what solved it was importing the permissions and imagePicker like this:
import * as Permissions from 'expo-permissions';
import * as ImagePicker from 'expo-image-picker';
instead of this:
import Permissions from 'expo-permissions';
import ImagePicker from 'expo-image-picker';
And that's basically because there is no default export
It is getAsync(), not askAsync()
https://docs.expo.io/versions/latest/sdk/permissions/
I know I'm a little late to the party, but I feel it's important to show a way that is currently working (as of 2022) and also askAsync is deprecated ...
Getting image from (native) CAMERA
TL;DR: Even though we want "camera", we will actually use expo-image-picker FOR THE CAMERA (yes, you read right!)
I REPEAT: DO NOT USE expo-camera FOR CAMERA!
REMEMBER: USE ImagePickerExpo.requestCameraPermissionsAsync()AND ImagePickerExpo.launchCameraAsync() NOT Camera....!
So install it first: expo install expo-image-picker
Then import everything, from it under 1 alias, I like to use ImagePickerExpo because ImagePicker itself is confusing since it can mean more libraries, + import all needed for this code - you can replace Button with any other button/pressable that supports onPress (to use react-native-elements, you need to install it with yarn add react-native-elements)
Create displaying component
Create a state & setter to save current image source
Create a function that requests the permissions and opens the camera
Return the coponent with button binding onPress on function from 5. and Image that is displayed from the state from 4. but only when available.
working & tested(so far on android in expo go) code:
import React, { useState } from 'react';
import { View, Image, Alert, StyleSheet } from 'react-native';
import { Button } from 'react-native-elements';
import * as ImagePickerExpo from 'expo-image-picker';
const MyCameraComponent = () => {
const [selectedImage, setSelectedImage] = useState(null);
const openCameraWithPermission = async () => {
let permissionResult = await ImagePickerExpo.requestCameraPermissionsAsync();
if (permissionResult.granted === false) {
Alert.alert("For this to work app needs camera roll permissions...");
return;
}
let cameraResult = await ImagePickerExpo.launchCameraAsync({
// ...
});
console.log(cameraResult);
if (cameraResult.cancelled === true) {
return;
}
setSelectedImage({ localUri: cameraResult.uri });
};
return (
<View>
<Button title='Take a photo' onPress={openCameraWithPermission}></Button>
{(selectedImage !== null) && <Image
source={{ uri: selectedImage.localUri }}
style={styles.thumbnail}
/>}
</View>
);
}
const styles = StyleSheet.create({
thumbnail: {
width: 300,
height: 300,
resizeMode: "contain"
}
});
export default MyCameraComponent;
Note that I had to style the Image for it to display, it didn't display to me without proper styling which I find misleading, but I guess that's the react native way...
BTW: This also works in Android emulator (besides expo go in real Android device)
It also works on snack on desktop but only when you choose android (or Web) - https://snack.expo.dev/#jave.web/expo-camera-from-expo-image-picker
Getting image from (native) gallery (not camera)
In case you're wondering how to do the same for gallery, the code is basically the same, you just need a different callback function for the button that uses requestMediaLibraryPermissionsAsync / launchImageLibraryAsync instead of the camera ones.
let openImagePickerAsync = async () => {
let permissionResult = await ImagePickerExpo.requestMediaLibraryPermissionsAsync();
if (permissionResult.granted === false) {
Alert.alert("For this to work app needs media library/gallery permissions...");
return;
}
let pickerResult = await ImagePickerExpo.launchImageLibraryAsync({
presentationStyle: 0, // without this iOS was crashing
});
console.log(pickerResult);
if (pickerResult.cancelled === true) {
return;
}
setSelectedImage({ localUri: pickerResult.uri });
}

How to preload an image from local in react native with Expo

I'm doing a project but i'm stuck when loading a background image.
<Image
source={Images.welcomeBg}
style={styles.container}
>
...
</Image>
But Image spends 1-2 second to load it
I'm doing follow this link
It still doesn't work right now.
Plz help me fix this bug
you can do this
make new called cachedAssetAsync.js (sure you can choose whatever name you like)
import { Asset, Font } from 'expo';
export default function cacheAssetsAsync({
images = [],
fonts = [],
videos = [],
}) {
return Promise.all([
...cacheImages(images),
...cacheFonts(fonts),
...cacheVideos(videos),
]);
}
function cacheImages(images) {
return images.map(image => Asset.fromModule(image).downloadAsync());
}
function cacheVideos(videos) {
return videos.map(video => Asset.fromModule(video).downloadAsync());
}
function cacheFonts(fonts) {
return fonts.map(font => Font.loadAsync(font));
}
then in App.js or whatever your root component you use, can do like this
async _loadAssetsAsync() {
try {
await cacheAssetsAsync({
images: [require('./assets/images/exponent-icon.png')],
fonts: [
{ 'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf') },
MaterialIcons.font,
],
videos: [require('./assets/videos/ace.mp4')],
});
} catch (e) {
console.log({ e });
} finally {
this.setState({ appIsReady: true });
}
}
you can do the logic when appIsReady is false shows loading screen then when appIsReady is true show the actual screen. And sure you can do this in only one file.
expo doc: https://docs.expo.io/versions/latest/guides/preloading-and-caching-assets.html