Styling camera on React native - react-native

On a screen, I want to scan tickets this way :
class Tickets extends Component {
constructor(props) {
super(props);
this.state = {
Press: false,
hasCameraPermission: null,
reference: '',
lastScannedUrl:null,
displayArray: []
};
}
initListData = async () => {
let list = await getProductByRef(1);
if (list) {
this.setState({
displayArray: list,
reference: list.reference
});
}
console.log('reference dans initListData =', list.reference)
};
async UNSAFE_componentWillMount() {
this.initListData();
console.log('reference dans le state =', this.state.reference)
};
componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === "granted" });
};
_onPress_Scan = () => {
this.setState({
Press: true
});
}
handleBarCodeScanned = ({ type, data }) => {
this.setState({ Press: false, scanned: true, reference: data });
this.props.navigation.navigate('ProductDetails', {reference : parseInt(this.state.state.reference)})
};
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
if (hasCameraPermission === null) {
return <Text>{i18n.t("scan.request")}</Text>;
}
if (hasCameraPermission === false) {
return <Text>{i18n.t("scan.noaccess")}</Text>;
}
return (
<View
style={{
flex: 1,
...StyleSheet.absoluteFillObject
}}
>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
style={{ flex:1, ...StyleSheet.absoluteFillObject}}
/>
{scanned && (
<Button
title={"Tap to Scan Again"}
onPress={() => this.setState({ scanned: false })}
/>
)}
</View>
);
}
render() {
const { hasCameraPermission, scanned, Press } = this.state;
let marker = null;
console.log('displayArray', this.state.displayArray, 'reference', this.state.displayArray.reference)
return (
<View style={{flex:1}}>
<KeyboardAvoidingView behavior="padding" enabled style={{flex:1}}>
<ScrollView contentContainerStyle={{flexGrow: 1 }} >
{Press ? (
<View style={{flex:1}}>
{this.renderBarcodeReader()}
</View>
) : (
<View style={{flex:1, justifyContent:'center', alignItems:'center'}}>
<Button
color="#F78400"
title={i18n.t("scan.scan")}
onPress={this._onPress_Scan}>
</Button>
</View>
)}
</ScrollView>
</KeyboardAvoidingView>
</View>
);
}
}
export default Tickets;
This code gives me
As you can see I have a top and bottom margin. I would like there to be no space, for the camera to take the entire screen (and for any buttons to be displayed over the camera image)
How can I do it, the style of which element should I change?
Thanks for any help and explanations

can you leave your code for that part? now everything is okay but i believe the image width and height is static and you are not using resizeMode for that image, for camera it will be different .
you can check resizeMode for the camera library you are using

Related

improving elements styles to make a full screen scan

I will need a helping hand to edit this page. i have all the elements but i need help styling.
I would like to have the camera (the image you see is the typical emulator camera, that's why it makes an image) in full screen and from above at the top, the message in red and the 'autocomplete.
If you want, to explain better, I would like to respect the image below: autocomplete at the top left above the camera in full screen.
would it be possible for you to help me, I'm getting a little confused. I tried to do a snack but failed. I will add it later if i can.
const autocompletes = [...Array(10).keys()];
const apiUrl = "https://5b927fd14c818e001456e967.mockapi.io/branches";
class Tickets extends Component {
constructor(props) {
super(props);
this.state = {
Press: false,
hasCameraPermission: null,
reference: '',
lastScannedUrl:null,
displayArray: []
};
}
initListData = async () => {
let list = await getProductByRef(1);
if (list) {
this.setState({
displayArray: list,
reference: list.reference
});
}
// console.log('reference dans initListData =', list.reference)
};
async UNSAFE_componentWillMount() {
this.initListData();
// console.log('reference dans le state =', this.state.reference)
};
componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === "granted" });
};
_onPress_Scan = () => {
this.setState({
Press: true
});
}
handleBarCodeScanned = ({ type, data }) => {
this.setState({ Press: false, scanned: true, reference: data });
this.props.navigation.navigate('ProductDetails', {reference : parseInt(this.state.state.reference)})
};
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
if (hasCameraPermission === null) {
return <Text>{i18n.t("scan.request")}</Text>;
}
if (hasCameraPermission === false) {
return <Text>{i18n.t("scan.noaccess")}</Text>;
}
return (
<View
style={{
flex: 1,
...StyleSheet.absoluteFillObject
}}
>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
style={{ flex:1, height:'100%', ...StyleSheet.absoluteFillObject}}
/>
{scanned && (
<Button
title={"Tap to Scan Again"}
onPress={() => this.setState({ scanned: false })}
/>
)}
</View>
);
}
handleSelectItem(item, index) {
const {onDropdownClose} = this.props;
onDropdownClose();
console.log(item);
}
render() {
const { hasCameraPermission, scanned, Press } = this.state;
let marker = null;
const {scrollToInput, onDropdownClose, onDropdownShow} = this.props;
// console.log('displayArray', this.state.displayArray, 'reference', this.state.displayArray.reference)
return (
<View style={styles.container}>
{Press ? (
<View style={{flex:1}}>
<View style={styles.dropdownContainerStyle}>
<Autocomplete
key={shortid.generate()}
containerStyle={styles.autocompleteContainer}
inputStyle={{ borderWidth: 1, borderColor: '#F78400'}}
placeholder={i18n.t("tickets.warning")}
pickerStyle={styles.autocompletePicker}
scrollStyle={styles.autocompleteScroll}
scrollToInput={ev => scrollToInput(ev)}
handleSelectItem={(item, id) => this.handleSelectItem(item, id)}
onDropdownClose={() => onDropdownClose()}
onDropdownShow={() => onDropdownShow()}
fetchDataUrl={apiUrl}
minimumCharactersCount={2}
highlightText
valueExtractor={item => item.name}
rightContent
rightTextExtractor={item => item.properties}
/>
</View>
{this.renderBarcodeReader()}
</View>
) : (
<View style={{flex:1, justifyContent:'center', alignItems:'center'}}>
<Button
color="#F78400"
title={i18n.t("scan.scan")}
onPress={this._onPress_Scan}>
</Button>
</View>
)}
</View>
);
}
}
export default Tickets;
This gives me (after pressing the button) :
SNACK CODE TEST
I notice You are using a component from Expo called BarCodeScanner
There's a github issue open about the fact that this component is not possible to be styled for full screen: https://github.com/expo/expo/issues/5212
However one user proposes a good solution: replace BarCodeScanner with Camera and use barcodescannersettings
Here's a link for the answer on the gitHub issue: https://github.com/expo/expo/issues/5212#issuecomment-653478266
Your code should look something like:
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
[ ... ] // the rest of your code here
return (
<View
style={{
flex: 1,
...StyleSheet.absoluteFillObject
}}
>
<Camera
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
style={{ flex:1}}
barCodeScannerSettings={{
barCodeTypes: [BarCodeScanner.Constants.BarCodeType.qr],
}}
/>
</View>
);
}

Understand error : Cannot update a component from inside the function body of a different component

I have this error and I don't understand where it came from.
I'm trying to set up a screen where I scan products and when it's done, I redirect to another page.
Could you help me identify the problem and why it behaves like this?
the error is :
Warning: Cannot update a component from inside the function body of a
different component.
My Code :
class Scan extends Component {
constructor(props) {
super(props);
this.state = {
Press: false,
hasCameraPermission: null,
reference: '',
displayArray: []
};
}
initListData = async () => {
let list = await getProducts(1);
if (list) {
this.setState({
displayArray: list,
});
}
};
async UNSAFE_componentWillMount() {
this.initListData();
if (parseInt(this.state.reference) > 0) {
let product_data = await getProductByRef(this.state.reference);
console.log(this.state.reference);
if (product_data && product_data.reference_id && parseInt(product_data.reference_id) > 0) {
this.props.navigation.navigate('ProductDetails', {reference : parseInt(this.state.displayArray.reference)})
} else {
this.props.navigation.goBack();
}
} else {
this.props.navigation.goBack();
}
};
componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === "granted" });
};
_onPress_Scan = () => {
this.setState({
Press: true
});
}
handleBarCodeScanned = ({ type, data }) => {
this.setState({ Press: false, scanned: true, lastScannedUrl: data });
};
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
if (hasCameraPermission === null) {
return <Text>{i18n.t("scan.request")}</Text>;
}
if (hasCameraPermission === false) {
return <Text>{i18n.t("scan.noaccess")}</Text>;
}
return (
<View
style={{
flex: 1,
flexDirection: "column",
justifyContent: "flex-end",
}}
>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
style={{ flex:1, ...StyleSheet.absoluteFillObject}}
/>
{scanned && (
<Button
title={"Tap to Scan Again"}
onPress={() => this.setState({ scanned: false })}
/>
)}
<Button
color="#F78400"
title= {i18n.t("scan.details")}
onPress={() => this.props.navigation.navigate('ProductDetails', {reference : parseInt(this.state.displayArray.reference)})}>{i18n.t("scan.details")}
</Button>
</View>
);
}
render() {
const { hasCameraPermission, scanned, Press } = this.state;
let marker = null;
console.log('displayArray', this.state.displayArray, 'reference', this.state.displayArray.reference)
return (
<View style={{flex:1}}>
<KeyboardAvoidingView behavior="padding" enabled style={{flex:1}}>
<ScrollView contentContainerStyle={{flexGrow: 1}} >
{Press ? (
<View style={{flex:1}}>
{this.renderBarcodeReader()}
</View>
) : (
<View style={{flex:1, justifyContent:'center', alignItems:'center'}}>
<TouchableOpacity
onPress={this._onPress_Scan}
activeOpacity={3}
>
<Text style={styles.viewDetails}>Scan BarCode</Text>
</TouchableOpacity>
</View>
)}
</ScrollView>
</KeyboardAvoidingView>
</View>
);
}
}
export default Scan;

Add a condition to allow a scan

I want to add a condition in my code and for that, I would like your help.
To explain the purpose of this screen: I have a camera used to scan tickets at an event.
I want to force the user to first choose the event for which he wants to scan the ticket thanks to the implementation of an autocomplete input that I made thanks to the package
'react-native-dropdown-autocomplete'
So, I don't really know how to do this, adding a condition to prevent the user from scanning his QrCode / Barcode before having selected his event.
Where do you think I can put my condition? And how do you put it in place ?
Thanks for all the time you spent helping me. :)
class Tickets extends Component {
constructor(props) {
super(props);
this.state = {
Press: false,
hasCameraPermission: null,
name: '',
lastScannedUrl:null,
displayArray: []
};
}
initListData = async () => {
let list = await getProducts(1);
if (list) {
this.setState({
displayArray: list,
name: list.name
});
}
//console.log('reference dans initListData =', list.reference)
};
async UNSAFE_componentWillMount() {
this.initListData();
//console.log('reference dans le state =', this.state.reference)
};
componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === "granted" });
};
handleBarCodeScanned = ({ type, data }) => {
this.setState({ Press: false, scanned: true, reference: data });
this.props.navigation.navigate('ProductDetails', {reference : parseInt(this.state.state.reference)})
};
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
if (hasCameraPermission === null) {
return <Text>{i18n.t("scan.request")}</Text>;
}
if (hasCameraPermission === false) {
return <Text>{i18n.t("scan.noaccess")}</Text>;
}
return (
<View
style={{
flex: 1,
...StyleSheet.absoluteFillObject
}}
>
<Camera
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
barCodeScannerSettings={[Camera.Constants.Type.qr]}
style={{flex:1}}
/>
{scanned && (
<Button
title={"Tap to Scan Again"}
onPress={() => this.setState({ scanned: false })}
/>
)}
</View>
);
}
handleSelectItem(item, index) {
const {onDropdownClose} = this.props;
onDropdownClose();
console.log(item);
}
render() {
const { hasCameraPermission, scanned, Press } = this.state;
let marker = null;
const {scrollToInput, onDropdownClose, onDropdownShow} = this.props;
console.log('displayArray', this.state.displayArray, 'reference', this.state.displayArray.name)
return (
<View style={{flex:1}}>
<Text style={{zIndex:100, color: 'red', fontStyle: 'italic', fontSize: 14}}>{i18n.t("tickets.warning")}</Text>
<View style={{width: "100%", zIndex: 100}}>
<Autocomplete
key={shortid.generate()}
containerStyle={{margin: 0, padding: 0, borderBottomColor: 'transparent',}}
inputStyle={{ width: '80%', borderWidth: 1, backgroundColor: '#FFF', opacity: 0.9, borderColor: '#F78400'}}
placeholder={i18n.t("tickets.event")}
placeholderColor="#F78400"
pickerStyle={styles.autocompletePicker}
scrollStyle={styles.autocompleteScroll}
scrollToInput={ev => {}}
handleSelectItem={(item, id) => this.handleSelectItem(item, id)}
onDropdownClose={() => onDropdownClose()}
onDropdownShow={() => onDropdownShow()}
fetchDataUrl={Api}
minimumCharactersCount={2}
highlightText
valueExtractor={item => item.name}
rightContent
rightTextExtractor={item => item.properties}
/>
</View>
{this.renderBarcodeReader()}
</View>
);
}
}
export default Tickets;
First you need to maintain the selectedItem in the state
this.state = {
Press: false,
hasCameraPermission: null,
name: '',
lastScannedUrl:null,
displayArray: [],
selectedItem:null // this should be added
};
Then set that from handleSelectItem
handleSelectItem=(item, index)=> {
const {onDropdownClose} = this.props;
onDropdownClose();
console.log(item);
this.setState({
selectedItem:item
});
}
And you can disable the button based on that
<Button
title={"Tap to Scan Again"}
onPress={() => this.setState({ scanned: false })}
disabled={this.state.selectedItem===null}
/>
The button would be disabled until you select an item, or you can conditionally call renderBarcodeReader based on this.state.selectedItem
What you can do is add conditional checking if you have event selected before rendering the component. When there isnt event selected display black block with border (something like this maybe => https://ibb.co/8mMtNBB) and only render if event is selected. Alternatively, you can add the same boolean that indicates wether an even has been selected to the on onBarCodeScanned method and call your function only if there's an event selected.

How to cache data and fetch in reactnative?

I am new to Reactnative and Javascript and I am trying to cache the data from APi and get it. But it is not working. I could not render the data. I am getting the error. How can I cache and retrieve data from cache when there is no internent? I have implemented the code for caching as follows:
export default class ViewpagerP extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: [] }
}
async componentDidMount() {
const photoStorage = await AsyncStorage.getItem('GalleryPhotos')
console.log(photoStorage);
if(!photoStorage) {
try {
console.log("Null inside")
const photoResp = await axios.get('https://rallycoding.herokuapp.com/api/music_albums')
console.log(photoResp)
const photoData = await JSON.stringify(photoResp.data);
this.setState({data:photoResp,isLoading:false})
await AsyncStorage.setItem('GalleryPhotos', photoData);
} catch(e) {
console.warn("fetch Error: ", error)
}
then(response => this.setState({ data: response.data,isLoading:false }))
}else{
this.getPhotos;
}
}
getPhotos = async()=> {
try {
data = JSON.parse(await AsyncStorage.getItem('GalleryPhotos'));
this.setState({data:data,isLoading:false})
console.log(data);
}
catch (error) {
console.error(error);
}
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
)
}
console.log(this.state.data);
return (
<View style={styles.container}>
<ImageSlider style={styles.viewPagerStyle}
loopBothSides
autoPlayWithInterval={6000}
images={this.state.data}
customSlide={({ index, item, style, width }) => (
<View key={index} style={[style, styles.customSlideStyle]}>
<View style={styles.contentContainer}>
<Image source={{ uri: item.image }} style={styles.customImage} />
<View style={styles.textContainerStyle}>
<Text style={styles.textStyle}>{item.title}</Text>
</View>
</View>
</View>
)
}
/>
</View>
);
}
}
You need some correction in code
this.getPhotos;
to
this.getPhotos();
And also you can check internate is on off by using
import { NetInfo} from 'react-native';
Check the below artical it will help you
enter link description here
here is come correction
export default class ViewpagerP extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: [] }
}
async componentDidMount() {
const photoStorage = await AsyncStorage.getItem('GalleryPhotos')
console.log(photoStorage);
if(!photoStorage) {
try {
console.log("Null inside")
const photoResp = await axios.get('https://rallycoding.herokuapp.com/api/music_albums')
console.log(photoResp)
const photoData = await JSON.stringify(photoResp.data);
this.setState({data:photoResp,isLoading:false})
await AsyncStorage.setItem('GalleryPhotos', photoData);
} catch(e) {
console.warn("fetch Error: ", error)
}
}else{
this.getPhotos();
}
}
getPhotos = async()=> {
try {
data = JSON.parse(await AsyncStorage.getItem('GalleryPhotos'));
this.setState({data:data,isLoading:false})
console.log(data);
}
catch (error) {
console.error(error);
}
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
)
}
console.log(this.state.data);
return (
<View style={styles.container}>
<ImageSlider style={styles.viewPagerStyle}
loopBothSides
autoPlayWithInterval={6000}
images={this.state.data}
customSlide={({ index, item, style, width }) => (
<View key={index} style={[style, styles.customSlideStyle]}>
<View style={styles.contentContainer}>
<Image source={{ uri: item.image }} style={styles.customImage} />
<View style={styles.textContainerStyle}>
<Text style={styles.textStyle}>{item.title}</Text>
</View>
</View>
</View>
)
}
/>
</View>
);
}
}

How to get ref in flat list item onpress?

I am trying to capture screen with react-native-view-shot. On press this.refs.viewShot.capture showing undefined.
Here is my code
Flat list code:
<FlatList
ref={(list) => this.myFlatList = list}
data={this.state.newsListArray}
keyExtractor={this._keyExtractor}
renderItem={this.renderRowItem}
/>
render on press link:
<TouchableOpacity onPress={ () => {
Platform.OS === 'ios' ?
this._captureScreenIos('5c63f7307518134a2aa288ce') :
this._captureScreenAndroid('5c63f7307518134a2aa288ce')
}}>
<View style={{flexDirection:'row'}}>
<Icon name="share-alt" size={16} color="#ffb6cf" />
<Text style={{paddingLeft:6,fontSize:12,fontWeight:'500'}}>Share News</Text>
</View>
</TouchableOpacity>
And that's the function:
_captureScreenIos = (refId) => {
console.log("Clicked for IOS");
this.changeLoaderStatus();
var thisFun = this;
var viewShotRef = 'viewShot-5c63f7307518134a2aa288ce';
this.myFlatList.viewShot.capture({width: 2048 / PixelRatio.get(), height: 2048 / PixelRatio.get()}).then(res => {
RNFetchBlob.fs.readFile(res, 'base64').then((base64data) => {
console.log("base64data",base64data)
let base64Image = `data:image/jpeg;base64,${base64data}`;
const shareOptions = {
title: "My Beauty Squad",
//message: "Download my beauty squad with below link."+ "\n" + "https://itunes.apple.com/uk/app/my-beauty-squad/id1454212046?mt=8" ,
url: base64Image,
subject: "Share news feed"
};
Share.open(shareOptions);
thisFun.changeLoaderStatus();
})
}).catch(error => {
console.log(error, 'this is error');
this.changeLoaderStatus();
})
}
Please let me know if anyone having a solution for the same.
**This is my app screen **
It's blur when we have long list items.
Try this:
import { captureRef } from react-native-view-shot
constructor(props) {
super(props);
this.refs = {};
}
renderItem = ({item, index}) => (
<TouchableOpacity
onPress={ () => {
captureRef(this.refs[`${index}`], options).then(.....)
}
>
<View
style={{flexDirection:'row'}}
ref={shot => this.refs[`${index}`] = shot}
>
...........
</View>
</TouchableOpacity>
)
React Native View Shot
I hope it help you.
That is a good amount of code. Try https://reactnativecode.com/take-screenshot-of-app-programmatically/
setting the state and try passing in the object you are referencing.
export default class App extends Component {
constructor(){
super();
this.state={
imageURI : 'https://reactnativecode.com/wp-content/uploads/2018/02/motorcycle.jpg'
}
}
captureScreenFunction=()=>{
captureScreen({
format: "jpg",
quality: 0.8
})
.then(
uri => this.setState({ imageURI : uri }),
error => console.error("Oops, Something Went Wrong", error)
);
}
Here is answer:
constructor(props) {
this.screenshot = {};
}
This is my function:
_captureScreenIos(itemId) {
this.changeLoaderStatus();
var thisFun = this;
var viewShotRef = itemId;
captureRef(this.screenshot[itemId],{format: 'jpg',quality: 0.8}).then(res => {
RNFetchBlob.fs.readFile(res, 'base64').then((base64data) => {
console.log("base64data",base64data)
let base64Image = `data:image/jpeg;base64,${base64data}`;
const shareOptions = {
title: "My Beauty Squad",
//message: "Download my beauty squad with below link."+ "\n" + "https://itunes.apple.com/uk/app/my-beauty-squad/id1454212046?mt=8" ,
url: base64Image,
subject: "Share news feed"
};
Share.open(shareOptions);
thisFun.changeLoaderStatus();
})
}).catch(error => {
console.log(error, 'this is error');
this.changeLoaderStatus();
})
}
This is the view:
<View collapsable={false} ref={(shot) => { this.screenshot[itemId] = shot; }} >
//some content here
<TouchableOpacity onPress={ () => {
Platform.OS === 'ios' ?
this._captureScreenIos(itemData.item._id) :
this._captureScreenAndroid(itemData.item._id)
}}>
<View style={{flexDirection:'row'}}>
<Icon name="share-alt" size={16} color="#ffb6cf" />
<Text style={{paddingLeft:6,fontSize:12,fontWeight:'500'}}>Share News</Text>
</View>
</TouchableOpacity>
</View>