Several Interesting Problem on React Native - javascript

I want to share on of my react native project. Here I am getting some issues. I have tried to solve that many time, but failed. Can anyone fix that?
I have checked all the questions asked on stack overflow. I can assure that this a really new problem.
Errors: 1. In Location.Address it is showing that address module is not loaded.
2.Location.requestPermissionsAsync() not working. Showing a cross over the code.
In let {status} it is showing an error.
Please Note I have written this code in a .tsx file.
import React, {useState, useReducer,useEffect} from "react"
import {View, Text, StyleSheet, Image, Dimensions, TouchableOpacity} from "react-native"
import * as Location from "expo-location"
const screenWidth = Dimensions.get("screen").width
export const LandingScreen = () => {
const[errorMsg, setErrorMsg] = useState("")
const [address, setAddress] = useState<Location.Address>()
const [displayAddress, setDisplayAddress] = useState("Waiting for current location")
useEffect(() =>{
(async () =>{
let { status } = await Location.requestPermissionsAsync()
if(status !== "granted"){
setErrorMsg(
"permissions not granted ,Allow the app to use location service"
)
}
let location: any = await Location.getCurrentPositionAsync()
const {coords} = location
if(coords){
const{latitude, longitude} = coords;
let addressResponse: any = await Location.reverseGeocodeAsync({
latitude,
longitude
});
for(let item of addressResponse){
setAddress(item)
let currentAddress = `${item.name}, ${item.street}, ${item.postalCode}, ${item.city}`
setDisplayAddress(currentAddress)
/*if(address.length > 0){
setTimeout(()=>{
navigate("HomeScreen")
},1000)
}*/
}
}
})
},[])
return(
<View style={styles.container}>
<View style={styles.navigation}/>
<View style={styles.body}>
<Image source={require("../images/delivery.png")} style={styles.deliveryIcon}/>
<View style={styles.addressContainer}>
<Text style={styles.addressTitle}>Your deliver address</Text>
</View>
<Text style={styles.addressText}>{displayAddress}</Text>
</View>
<View style={styles.footer}/>
</View>
)
}
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor:'rgba(242,242,242,1)'
},
navigation:{
flex:2,
},
body:{
flex:9,
justifyContent:"center",
alignItems:"center",
},
footer:{
flex:1,
},
deliveryIcon:{
width:120,
height:120
},
addressContainer:{
width:screenWidth - 100,
borderBottomColor:"red",
borderBottomWidth:0.5,
padding:5,
marginBottom:10,
alignItems:"center"
},
addressTitle:{
fontSize:24,
fontWeight:"700",
color:"#7D7D7D"
},
addressText:{
fontSize:20,
fontWeight:"200",
color:"#4F4F4F"
}
})

Insted of
let { status } = await Location.requestPermissionsAsync()
use
let { status } = await Location.requestForegroundPermissionsAsync();
remove this <Location.Address> it should be const [address, setAddress] = useState()

as #komal-harmale mentioned use the [address, setAddress] = useState()
In Location.Address it is showing that address module is not loaded.
Location.requestPermissionsAsync() has been deprecated. https://docs.expo.dev/versions/latest/sdk/location/#locationrequestpermissionsasync
In that case you have to use In that case you have to use requestForegroundPermissionsAsync or requestBackgroundPermissionsAsync instead of that.
Same scenario happened to me and I overcame that by using requestForegroundPermissionsAsync, requestBackgroundPermissionsAsync and with a help of Modal. will explain briefly what I did.
1 . initialize these states variables where you wants to request permissions.
const [foreground, requestForeground] = ExpoLocation.useForegroundPermissions();
const [background, requestBackground] = ExpoLocation.useBackgroundPermissions();
2 . Create a Modal with the use of earlier mentioned state objects. Here is a sample Modal to request permissions from user.
import { Button, Linking, Modal, StyleSheet, Text, View } from "react-native";
export const LocationRequestModal = ({ foreground, requestForeground, background, requestBackground }) => {
return (
<Modal visible={foreground && !foreground.granted && background && !background.granted}>
<View style={Styles.backDrop}>
<View style={Styles.middleView}>
<View style={{ marginVertical: 16 }}>
<Text style={{ fontSize: 20, fontWeight: "bold" }}>Pleae grant permission.</Text>
</View>
<View style={{ marginVertical: 16 }}>
<Text style={{ fontSize: 18 }}>Foreground permission:</Text>
<Text>status: {foreground?.status || "pending"}</Text>
{foreground && !foreground.granted && foreground.canAskAgain && <Button title="Grant permission" onPress={requestForeground} />}
{foreground && !foreground.granted && !foreground.canAskAgain && (
<Button
title="Grant permission through settings"
onPress={() => requestForeground().then((p) => !p.granted && Linking.openSettings())}
/>
)}
</View>
<View style={{ marginVertical: 16 }}>
<Text style={{ fontSize: 18 }}>Background permission:</Text>
<Text>status: {background?.status || "pending"}</Text>
{!foreground?.granted && <Text>Grant foreground location permission first</Text>}
{foreground?.granted && background && !background.granted && background.canAskAgain && (
<Button title="Grant permission" onPress={requestBackground} />
)}
{foreground?.granted && background && !background.granted && !background.canAskAgain && (
<Button
title="Grant permission through settings"
onPress={() => requestBackground().then((p) => !p.granted && Linking.openSettings())}
/>
)}
</View>
</View>
</View>
</Modal>
);
};
const Styles = StyleSheet.create({
backDrop: {
backgroundColor: "rgba(52, 52, 52, 0.8)",
height: "100%",
width: "100%",
paddingBottom: "3%",
paddingTop: "3%",
paddingRight: "6%",
paddingLeft: "6%",
justifyContent: "center",
alignItems: "center",
},
middleView: { height: "60%", width: "60%", backgroundColor: "white", justifyContent: "center", alignItems: "center" },
});

Related

Displaying a Image from the Camera

I am relatively new to React-Native and mobile app development. I am trying to create a clone of Instagram. And in the post screen what I do is I have a button Camera and once I click on it, that should take me to CameraView screen. And in the CameraView screen I will take a picture using expo-camera and save the picture in a variable. So here, I want to export the picture and then import it in my Post screen, so that the user can have a preview of what the picture looks like before uploading. And another thing to note is that, the Post screen will by default have a Placeholder image and once the image is taken the placeholder image has to be replaced with the image.
I tried this code but it didnt work.
My Post screen :-
import { View, Text, Image, TextInput } from 'react-native';
import React, { useState, useEffect } from 'react'
import * as Yup from 'yup';
import { Formik } from 'formik'
import { Button, Divider } from 'react-native-elements';
import { useNavigation } from '#react-navigation/native';
import CameraView, { takePicture } from '../../screens/CameraView';
const PLACEHOLDER_IMG = require('../../assets/defImg.png')
const uploadPostSchema = Yup.object().shape({
caption: Yup.string().max(2200, 'Caption cannot exceed character limit.')
})
const FormikPostUploader = ({route}) => {
const [thumbnailUrl, setThumbnailUrl] = useState(PLACEHOLDER_IMG)
const navigation = useNavigation()
const handleCameraPress = () => {
UserImage = takePicture()
setThumbnailUrl(UserImage)
navigation.navigate('CameraView')
}
return (
<Formik
initialValues={{ imageUrl: '', caption:'' }}
onSubmit={(values) => console.log(values)}
validationSchema={uploadPostSchema}
validateOnMount={true}>
{({
handleBlur,
handleChange,
handleSubmit,
values,
errors,
isvalid
}) => (
<>
<View style={{ margin: 20, justifyContent: 'space-between', flexDirection: 'row' }}>
<Image source={thumbnailUrl} />
<View style={{ flex: 1, margin: 15 }}>
<TextInput
placeholder='Write a caption...'
placeholderTextColor='gray'
multiline={true}
style={{ color: 'white', fontSize: 17 }}
onChangeText={handleChange('caption')}
onBlur={handleBlur('caption')}
value={values.caption}
/>
</View>
</View>
<Divider width={0.5} orientation='vertical'/>
<View style={{ alignItems: 'center', marginTop: 15 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', color: 'white' }}>Choose Image</Text>
</View>
<View style={{ justifyContent: 'space-between', flexDirection: 'column', margin: 20 }}>
<View style={{ justifyContent: 'space-between', flexDirection: 'row', margin: 30 }}>
<Button title='Camera' onPress={handleCameraPress}/>
<Button title='Gallery' onPress={() => navigation.navigate('GalleryView')} />
</View>
<Button onPress={handleSubmit} title='Post' disabled={isvalid} />
</View>
</>
)}
</Formik>
)
}
export default FormikPostUploader
And my CameraView screen :-
import { View, Text, Image, StyleSheet, Button } from 'react-native'
import React, {useState, useEffect} from 'react'
import { Camera } from 'expo-camera'
import { TouchableOpacity } from 'react-native'
import { useNavigation } from '#react-navigation/native'
import { PLACEHOLDER_IMG } from '../components/newPost/FormikPostUploader'
export const takePicture = async(camera) => {
const data = await camera.takePictureAsync(null)
return data.uri
}
const Header = () =>{
const navigation = useNavigation()
return (
<View style = {styles.headerContainer}>
<TouchableOpacity style = {{marginBottom:15}} onPress={() => navigation.goBack()}>
<Image source = {require('../assets/back.png')} style = {{width:35, height:35, margin:20}}/>
</TouchableOpacity>
<Text style={{color:'white', fontWeight: '700', fontSize:20, marginRight: 25, marginTop:35, marginBottom:15}}>New Post</Text>
<Text> </Text>
</View>
)
}
const CameraView = () => {
const UserImage = takePicture()
const navigation = useNavigation()
const [hasCameraPermission, setHasCameraPermission] = useState(null)
const [thumbnailUrl, setThumbnailUrl] = useState(PLACEHOLDER_IMG)
const [camera, setCamera] = useState(null)
const [type, setType] = useState(Camera.Constants.Type.back)
const captureImage = async () => {
if (camera) {
const UserImage = await takePicture(camera)
setThumbnailUrl(UserImage)
}
}
useEffect(() => {
(async() => {
const cameraStatus = await Camera.requestCameraPermissionsAsync()
setHasCameraPermission(cameraStatus.status === 'granted')})()},
[])
if (hasCameraPermission === null) {
return <View/>
}
if (hasCameraPermission === false){
return <Text>Enable access for Camera to proceed</Text>
}
return (
<View style={{ flex: 1, backgroundColor: 'black'}}>
<Header/>
<Camera
ref = {ref => setCamera(ref)}
style={styles.fixedRatio}
type={type}
ratio={'1:1'}/>
<View style = {styles.cameraContainer}>
<TouchableOpacity onPress={() => {setType(type === Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back)}}>
<Image source={require('../assets/turn-camera.png')} style = {{width:70, height:70, margin: 15}}/>
</TouchableOpacity>
<TouchableOpacity onPress={() => {captureImage(), navigation.goBack(), console.log(UserImage)}}>
<Image source={require('../assets/camera-shutter.png')} style = {{width:70, height:70, marginRight:60}}/>
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
cameraContainer: {
flex:0.15,
backgroundColor: 'black',
flexDirection:'row',
justifyContent: 'space-between',
alignItems: 'center',
},
fixedRatio: {
flex:0.99,
aspectRatio:0.9
},
headerContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor:'black'
},
icon: {
width:25,
height: 25,
marginHorizontal:15,
marginTop:30,
},
iconContainer: {
flexDirection:'row',
justifyContent: 'space-between',
height:50,
},
}
)
export default CameraView
Am I doing anything wrong. Can you help me fix this. Thanks in advance!

Cannot update a component (`Categoriess`) while rendering a different component (`CellRenderer`)

I am getting this warning.
Warning: Cannot update a component (Categoriess) while rendering a different component (CellRenderer). To locate the bad setState() call inside, follow the stack trace as described in https://reactjs.org/link/setstate-in-render%60
I tried too much to fix this issue but I can't. Can anyone please solve this issue?
my code:
`
import { DrawerActions, useNavigation } from '#react-navigation/native';
import { Divider, NativeBaseProvider } from 'native-base';
import fetch from 'node-fetch';
import React, { useEffect, useState } from 'react';
import {
ActivityIndicator,
FlatList,
StyleSheet, Text, TouchableOpacity, View
} from 'react-native';
import AntDesign from 'react-native-vector-icons/AntDesign';
import { API_KEY, URL } from '../../globalVariable';
const Categoriess = () => {
const [data, setData] = useState([]);
const [homeID, setHomeId] = useState([]);
const [loading, setLoading] = useState(true)
const navigation = useNavigation();
const option = () => {
let url = `${URL}/store-api/category`;
let options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'sw-access-key': `${API_KEY}`,
},
};
fetch(url, options)
.then(res => res.json())
.then(json => {
setData(!!json?.elements ? json.elements : [])
setLoading(false)
})
.catch(err => { });
};
useEffect(() => {
option();
}, []);
return (
<View >
<TouchableOpacity
onPress={() => navigation.dispatch(DrawerActions.closeDrawer())}>
<View style={styles.closeDrawer}>
<Text style={styles.text}>Close Menu</Text>
<AntDesign name='close' size={30} />
</View>
</TouchableOpacity>
<Text style={{ fontSize: 25, fontWeight: 'bold', textAlign: 'center' }}>
Categories
</Text>
{
loading ? <ActivityIndicator /> : <FlatList
data={data}
initialNumToRender={7}
renderItem={({ item }) => {
{
if (item.level === 1 && item.afterCategoryId === null) {
setHomeId(item.id);
}
}
const newLocal =
item.level === 2 && item.parentId === homeID ? item.parentId : '';
return (
<View >
<View>
<View>
{item.visible === true && item.parentId === newLocal ? (
<View>
<TouchableOpacity
onPress={() => navigation.navigate('Products', item)}>
<Text style={styles.category}>{item.name}</Text>
<NativeBaseProvider>
<Divider thickness={3} bg="red.200" />
</NativeBaseProvider>
</TouchableOpacity>
{data.map((curElem, index) => {
return item.id === curElem.parentId ? (
<TouchableOpacity
key={index}
onPress={() =>
navigation.navigate('Products', curElem)
}>
<Text style={styles.subCategory}>
- {curElem.name}
</Text>
<NativeBaseProvider>
<Divider thickness={1} />
</NativeBaseProvider>
</TouchableOpacity>
) : null;
})
}
</View>
) : null}
</View>
</View>
</View>
);
}}
/>
}
</View>
);
};
export default Categoriess;
const styles = StyleSheet.create({
category: {
marginHorizontal: 15,
marginVertical: 5,
paddingVertical: 10,
fontSize: 18,
color: '#6779b4',
fontFamily: "Montserrat-Bold"
},
subCategory: {
marginLeft: 30,
marginBottom: 10,
fontSize: 15,
paddingVertical: 10,
fontFamily: "Montserrat-Bold"
},
closeDrawer: {
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 10,
paddingVertical: 5,
},
text: {
fontSize: 18,
fontFamily: "Montserrat-Bold"
},
});
`
Check this part in renderItem prop. This issue often happens when you trying setState something inside render function
if (item.level === 1 && item.afterCategoryId === null) {
setHomeId(item.id);
}
Looks like you shouldn't store this value in state. Just check it in every renderItem will be enough. FlatList optimisations do all other work well.
const homeID = item.level === 1 && item.afterCategoryId === null ? setHomeId(item.id) : null;
As example

How can I store the value of TextInput to local storage and get them when the app starts in react native?

I'm making a to-do list app. I need to store the input value locally or somewhere so that I can show them in the app even if the app is opened after closing once. Now when I'm closing the app and restarting all the previous values is being vanished. But I want to keep the previous data and If new data is given that will also be stored if I don't delete that manually. How can I solve this problem? I'm using expo.
Here is my code:
import React, { useState } from 'react';
import { View, Text, StyleSheet, Button, FlatList, TouchableOpacity, TextInput, ScrollView } from 'react-native';
import { MaterialIcons } from '#expo/vector-icons'
import Line from './Line';
function App() {
//storing data in array
const [initialElements, changeEl] = useState([
]);
const [value, setValue] = useState('')
const [idx, incr] = useState(1);
const [exampleState, setExampleState] = useState(initialElements);
//add button
const addElement = () => {
if (value != '') {
var newArray = [...initialElements, { id: idx, title: value }];
incr(idx + 1);
setExampleState(newArray);
changeEl(newArray);
}
}
//delete button
const delElement = (id) => {
let newArray = initialElements.filter(function (item) {
return item.id !== id
})
setExampleState(newArray);
changeEl(newArray);
}
//showing item
const Item = ({ title, id }) => (
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
<View style={{ borderWidth: 2, margin: 5, flex: 1, padding: 10, borderRadius: 10 }}>
<TouchableOpacity onPress={() => { alert(title) }}>
<Text >{title}</Text>
</TouchableOpacity>
</View>
<TouchableOpacity onPress={() => delElement(id)}>
<MaterialIcons name='delete' size={24} />
</TouchableOpacity>
</View>
);
//calling item for render
const renderItem = ({ item }) => {
<Item title={item.title} id={item.id} />
}
return (
<View style={styles.container}>
<View style={{ alignItems: 'center', marginBottom: 10 }}>
<Text style={{ fontSize: 20, fontWeight: '500' }}> To <Text style={{ color: 'skyblue', fontWeight: '900' }}>Do</Text> List</Text>
<Line />
</View>
<View>
<TextInput onChangeText={text => setValue(text)} placeholder="Enter to Todo" style={{ borderWidth: 2, borderRadius: 10, backgroundColor: 'skyblue', height: 40, paddingLeft: 10, borderColor: 'black' }}></TextInput>
</View>
<View style={{ alignItems: 'center' }}>
<TouchableOpacity onPress={() => addElement()} style={{ marginTop: 10 }}>
<View style={{ backgroundColor: 'black', width: 70, height: 40, justifyContent: 'center', borderRadius: 10 }}>
<Text style={{ color: 'white', textAlign: 'center' }}>Add</Text>
</View>
</TouchableOpacity>
</View>
<FlatList
style={{ borderWidth: 2, padding: 10, flex: 1, backgroundColor: '#EEDDD0', marginTop: 10 }}
data={exampleState}
renderItem={renderItem}
keyExtractor={item => item.id.toString()
}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
margin: 5,
}
})
export default App;
React Native provides a local storage option called AsyncStorage. You might use asyncstorage to save the data locally on the device and get that data inside useEffect() hook on startup.
You can find more about AsyncStorage here.
Although this is deprecated and now community package " #react-native-async-storage/async-storage " is used. The implementation remains the same.

How to save route.params with asyncstorage?

Srry if the title makes no sense. Don't know a better title.
How can I save route.params items that I pass to my second screen using AsyncStorage?
In my first screen i have a bunch of data in a FlatList that can be opened with a Modal. Inside that Modal I have a TouchableOpacity that can send the data thats inside the Modal to my second screen. The data that has been passed to the second screen is passed to a FlatList. The data in the FlatList should be saved to AsyncStorage. Tried alot of things getting this to work, but only getting warning message
undefined. Code below is the most recent progress.
Using React Navigation V5.
FIRST SCREEN
const [masterDataSource, setMasterDataSource] = useState(DataBase);
const [details, setDetails] = useState('');
<TouchableOpacity
onPress={() => {
const updated = [...masterDataSource];
updated.find(
(item) => item.id === details.id,
).selected = true;
setMasterDataSource(updated);
navigation.navigate('cart', {
screen: 'cart',
params: {
items: updated.filter((item) => item.selected),
},
});
setModalVisible(false);
}}>
<Text>Add to cart</Text>
</TouchableOpacity>
SECOND SCREEN
import React, { useEffect, useState } from 'react';
import { View, Text, FlatList, TouchableOpacity } from 'react-native';
import { useTheme } from '../Data/ThemeContext';
import AsyncStorage from '#react-native-async-storage/async-storage';
import Ionicons from 'react-native-vector-icons/Ionicons';
export default function ShoppingList({ route, navigation }) {
const [shoppingList, setShoppingList] = useState([]);
const { colors } = useTheme();
const todo = () => {
alert('Todo');
};
useEffect(() => {
restoreShoppingListAsync();
}, []);
const shoppingListAsync = () => {
const shoppingList = route.params && route.params.items;
setShoppingList(list);
storeShoppingList(list);
};
const asyncStorageKey = '#ShoppingList';
const storeShoppingListAsync = (list) => {
const stringifiedList = JSON.stringify(list);
AsyncStorage.setItem(asyncStorageKey, stringifiedList).catch((err) => {
console.warn(err);
});
};
const restoreShoppingListAsync = () => {
AsyncStorage.getItem(asyncStorageKey)
.then((stringifiedList) => {
console.log(stringifiedList);
const parsedShoppingList = JSON.parse(stringifiedList);
if (!parsedShoppingList || typeof parsedShoppingList !== 'object')
return;
setShoppingList(parsedShoppingList);
})
.then((err) => {
console.warn(err);
});
};
const RenderItem = ({ item }) => {
return (
<View>
<TouchableOpacity
style={{
marginLeft: 20,
marginRight: 20,
elevation: 3,
backgroundColor: colors.card,
borderRadius: 10,
}}>
<View style={{ margin: 10 }}>
<Text style={{ color: colors.text, fontWeight: '700' }}>
{item.name}
</Text>
<Text style={{ color: colors.text }}>{item.gluten}</Text>
<Text style={{ color: colors.text }}>{item.id}</Text>
</View>
</TouchableOpacity>
</View>
);
};
const emptyComponent = () => {
return (
<View style={{ alignItems: 'center' }}>
<Text style={{ color: colors.text }}>Listan är tom</Text>
</View>
);
};
const itemSeparatorComponent = () => {
return (
<View
style={{
margin: 3,
}}></View>
);
};
return (
<View
style={{
flex: 1,
}}>
<View
style={{
padding: 30,
backgroundColor: colors.Textinput,
elevation: 12,
}}>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<Ionicons name="arrow-back-outline" size={25} color="#fff" />
</TouchableOpacity>
<Text style={{ color: '#fff', fontSize: 20 }}>Inköpslista</Text>
<TouchableOpacity>
<Ionicons
name="trash-outline"
size={25}
color="#fff"
onPress={() => todo()}
/>
</TouchableOpacity>
</View>
</View>
<View style={{ flex: 1, marginTop: 30 }}>
<FlatList
data={shoppingList}
renderItem={RenderItem}
ListEmptyComponent={emptyComponent}
ItemSeparatorComponent={itemSeparatorComponent}
initialNumToRender={4}
maxToRenderPerBatch={5}
windowSize={10}
removeClippedSubviews={true}
updateCellsBatchingPeriod={100}
showsVerticalScrollIndicator={true}
contentContainerStyle={{ paddingBottom: 20 }}
/>
</View>
</View>
);
}
As you are using async storage to maintain the cart.
I would suggest an approach as below
Update the asyn storage when new items are added to or removed from the cart
Retrieve the items from the cart screen and show the items there
Before you navigate store the items like below
AsyncStorage.setItem(
'Items',
JSON.stringify(updated.filter((item) => item.selected))
).then(() => {
navigation.navigate('Cart', {
items: updated.filter((item) => item.selected),
});
});
The cart screen would be something like below
function Cart({ navigation, route }) {
const [data,setData]=useState([]);
React.useEffect(() => {
async function fetchMyAPI() {
const value = await AsyncStorage.getItem('Items');
setData(JSON.parse(value));
}
fetchMyAPI();
}, []);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button title="Go back" onPress={() => navigation.goBack()} />
<FlatList
data={data}
renderItem={RenderItem}
/>
</View>
);
}
Working Example
https://snack.expo.io/#guruparan/cartexample

expo camera show black screen for first time : React-Native

I have Created Project with expo-camera which on click of button opens camera. However first time when i click that button only black screen is render, after reopening the screen, and clicking the same button, the Camera UI is render on Screen.
Problem
I don't know why it show black screen first. The Problem only exist in android devices.
Link to Expo Snack Try this example on android devices.
import React, { useState, useEffect, useContext } from 'react';
import {
SafeAreaView,
View,
Text,
Dimensions,
ImageBackground,
Image,
Alert,
} from 'react-native';
import { Camera } from 'expo-camera';
import { Entypo, Ionicons, FontAwesome } from '#expo/vector-icons';
import { Surface, Button, TextInput } from 'react-native-paper';
const { width, height } = Dimensions.get('window');
let cameraRef;
const PickImage = ({ navigation }) => {
const [hasPermission, setHasPermission] = useState(null);
const [type, setType] = useState(Camera.Constants.Type.back);
const [isCameraUiOn, setIsCameraUiOn] = useState(false);
const [isCapturing, setIsCapturing] = useState(false);
const [flashMode, setFlashMode] = useState(true);
const [capturePhoto, setCapturePhoto] = useState(null);
const snap = async () => {
if (cameraRef) {
let photo = await cameraRef.takePictureAsync({
quality: 0.5,
});
setCapturePhoto(photo.uri);
setIsCapturing(false);
setIsCameraUiOn(false);
}
};
const getCameraPermission = async () => {
const { status } = await Camera.requestPermissionsAsync();
setHasPermission(status === 'granted');
};
useEffect(() => {
getCameraPermission();
}, []);
if (hasPermission === null) {
return <View />;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
if (isCameraUiOn) {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<Camera
style={{ flex: 1 }}
type={type}
ref={(ref) => (cameraRef = ref)}
flashMode={
flashMode
? Camera.Constants.FlashMode.on
: Camera.Constants.FlashMode.off
}>
<Entypo
name="cross"
color="#FFF"
size={50}
onPress={() => setIsCameraUiOn(false)}
/>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
display: 'flex',
justifyContent: 'space-evenly',
alignItems: 'flex-end',
flexDirection: 'row',
zIndex: 9999,
}}>
<Ionicons
name="md-reverse-camera"
color="#FFF"
size={35}
onPress={() => {
setType(
type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back
);
}}
/>
{isCapturing ? (
<FontAwesome name="circle" color="#FFF" size={60} />
) : (
<FontAwesome
name="circle-o"
color="#FFF"
size={60}
onPress={() => {
setIsCapturing(true);
snap();
}}
/>
)}
<Ionicons
name="ios-flash"
color={flashMode ? 'gold' : '#FFF'}
size={35}
onPress={() => setFlashMode(!flashMode)}
/>
</View>
</Camera>
</View>
</SafeAreaView>
);
} else {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ margin: 20 }}>
<Text
style={{
fontSize: 25,
fontWeight: '600',
}}>
Report Cattles with Ease !!
</Text>
<Text
style={{
marginVertical: 10,
}}>
Our System uses, cloud based fancy image detection algorithm to
process your image.
</Text>
</View>
<View
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}>
<Button
style={{
width: width * 0.5,
}}
icon="camera"
mode="contained"
onPress={() => setIsCameraUiOn(true)}>
Press me
</Button>
</View>
</SafeAreaView>
);
}
};
export default PickImage;
Link to snack Expo
im with the same problem rn, some people suggested asking for permission before rendering

Categories

Resources