I am creating a feature to capture pictures with a height/width set and save them in the gallery. At my current stage I can take a photo and save it to the gallery, the only problem is that the saved photo is not the height and width I previously set.
It seems like something simple, but I don't know what I am overlooking.
App.js
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, SafeAreaView, Image, TouchableOpacity } from 'react-native';
import { useEffect, useRef, useState } from 'react';
import { FontAwesome } from "#expo/vector-icons";
import { Camera } from 'expo-camera';
import { shareAsync } from 'expo-sharing';
import * as MediaLibrary from 'expo-media-library';
import styles from "./styles.js";
export default function App() {
let cameraRef = useRef();
const [hasCameraPermission, setHasCameraPermission] = useState();
const [hasMediaLibraryPermission, setHasMediaLibraryPermission] = useState();
const [photo, setPhoto] = useState();
useEffect(() => {
(async () => {
const cameraPermission = await Camera.requestCameraPermissionsAsync();
const mediaLibraryPermission = await MediaLibrary.requestPermissionsAsync();
setHasCameraPermission(cameraPermission.status === "granted");
setHasMediaLibraryPermission(mediaLibraryPermission.status === "granted");
})();
}, []);
if (hasCameraPermission === undefined) {
return <Text>Requesting permissions...</Text>
} else if (!hasCameraPermission) {
return <Text>Permission for camera not granted. Please change this in settings.</Text>
}
let takePic = async () => {
let options = {
quality: 1,
base64: true,
exif: false
};
};
if (photo) {
let savePhoto = () => {
MediaLibrary.saveToLibraryAsync(photo.uri).then(() => {
setPhoto(undefined);
});
};
return (
<SafeAreaView style={styles.container}>
<Image style={styles.responsiveImage} source={{ uri: "data:image/jpg;base64," + photo.base64 }} resizeMode="contain"/>
{hasMediaLibraryPermission ?
<TouchableOpacity style={styles.buttonSave} onPress={savePhoto}>
<FontAwesome name="save" size={23} color="#fff"></FontAwesome>
</TouchableOpacity> : undefined}
</SafeAreaView>
);
}
return (
<SafeAreaView style={styles.container}>
<Camera style={styles.camera} ref={cameraRef}>
<View style={styles.buttonContainer}>
<TouchableOpacity style={styles.buttonCamera} onPress={takePic}>
<FontAwesome name="camera" size={27} color="#fff"></FontAwesome>
</TouchableOpacity>
</View>
<StatusBar style="auto" />
</Camera>
</SafeAreaView>
);
}
style.js
import { StyleSheet } from "react-native"
const styles = StyleSheet.create({
responsiveImage: {
width: '80%',
height: 400,
},
});
export default styles
Related
I have a context that contains an array, this context has a function that updates a certain value in that array:
import React, { createContext, useState } from 'react'
export const SliderValueContext = createContext()
export function SliderValueProvider({ children }) {
const [intensity, setIntensity] = useState([
{
EXAMPLE0: 0,
},
{
EXAMPLE1: 0,
},
{
EXAMPLE2: 0,
},
])
const updateCertainIntensity = (value, index) => {
console.log('Index: ' + index)
console.log('Value: ' + value)
let newIntensity = [...intensity]
newIntensity[index] = value
setIntensity(newIntensity)
}
return (
<SliderValueContext.Provider
value={{intensity, updateCertainIntensity}}>
{children}
</SliderValueContext.Provider>
)
}
I have a basic StackNavigator with both of my screens:
import React from 'react'
import { createStackNavigator } from '#react-navigation/stack'
import Index from './index'
import SliderScreen from './screen'
const Stack = createStackNavigator()
export default function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen name='Index' component={Index}/>
<Stack.Screen name='SliderScreen' component={SliderScreen}/>
</Stack.Navigator>
)
}
This is how my index looks like:
import React from 'react'
import {
Button
} from 'react-native'
import { useNavigation } from '#react-navigation/native'
import { SliderValueProvider } from './context'
export default function Index() {
const navigation = useNavigation()
return (
<SliderValueProvider>
<Button title='YOU' onPress={() => navigation.navigate('SliderScreen')}></Button>
</SliderValueProvider>
)
}
App.js
export default function App() {
return (
<NavigationContainer>
<MyStack>
</MyStack>
</NavigationContainer>
)
}
Custom Slider component:
export default function SliderGroup({ id, text, borderColor }) {
const { updateCertainIntensity } = useContext(SliderValueContext)
return (
<View style={[styles.slider_container, { borderColor: borderColor }]}>
<View style={styles.slider_container_text}>
<Text style={styles.text_style}> {text} </Text>
{/* <Text style={styles.number_style}> </Text> */}
</View>
<View style={styles.slider_container_slider}>
<Slider
onValueChange={(value) => updateCertainIntensity(value, id)}
step={1}
minimumValue={0}
maximumValue={5}
maximumTrackTintColor='rgb(255, 255, 255)'
/>
</View>
</View>
)
}
Problem: Whenever I try to access the useContext in my custom Slider component, it says that the context is undefined undefined is not an object (evaluating useContext.updateCertainIntensity) .Other contexts however, work just fine, but they are not using objects, just simple strings. Does it have to do with using an object in useState()?
You aren't wrapping your app inside the context you just created.
In your App.jsx
<NavigationContainer>
<SliderValueProvider> {/* this one is going to feed its children with data */}
<MyStack /> {/* this will be fed by the parent component */}
</SliderValueProvider>
</NavigationContainer>
My code is :
import React, { useEffect } from "react";
import * as ImagePicker from "expo-image-picker";
import Screen from "./app/components/Screen";
export default function App() {
async function permisionFunction() {
const result = await ImagePicker.getCameraPermissionsAsync();
if (!result.granted) {
console.log(result);
alert("need access to gallery for this app to work");
}
}
useEffect(() => {
permisionFunction();
}, []);
return <Screen></Screen>;
}
I denied the permissions for camera when it was promted for the first time.
Now whenever I opens the app always need access to gallery for this app to work this message is shown up. for android.
I tried by giving all the permissions to the expo app in settings but still same msg appears.
How can I solve this.
Use expo-cameramodule to access device camera.
I have curated the working example of small app with which you can access pictures from gallery as well as device camera.
Working App: Expo Snack
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View, Button, Image } from 'react-native';
import { Camera } from 'expo-camera';
import * as ImagePicker from 'expo-image-picker';
export default function Add({ navigation }) {
const [cameraPermission, setCameraPermission] = useState(null);
const [galleryPermission, setGalleryPermission] = useState(null);
const [camera, setCamera] = useState(null);
const [imageUri, setImageUri] = useState(null);
const [type, setType] = useState(Camera.Constants.Type.back);
const permisionFunction = async () => {
// here is how you can get the camera permission
const cameraPermission = await Camera.requestPermissionsAsync();
setCameraPermission(cameraPermission.status === 'granted');
const imagePermission = await ImagePicker.getMediaLibraryPermissionsAsync();
console.log(imagePermission.status);
setGalleryPermission(imagePermission.status === 'granted');
if (
imagePermission.status !== 'granted' &&
cameraPermission.status !== 'granted'
) {
alert('Permission for media access needed.');
}
};
useEffect(() => {
permisionFunction();
}, []);
const takePicture = async () => {
if (camera) {
const data = await camera.takePictureAsync(null);
console.log(data.uri);
setImageUri(data.uri);
}
};
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [1, 1],
quality: 1,
});
console.log(result);
if (!result.cancelled) {
setImageUri(result.uri);
}
};
return (
<View style={styles.container}>
<View style={styles.cameraContainer}>
<Camera
ref={(ref) => setCamera(ref)}
style={styles.fixedRatio}
type={type}
ratio={'1:1'}
/>
</View>
<Button title={'Take Picture'} onPress={takePicture} />
<Button title={'Gallery'} onPress={pickImage} />
{imageUri && <Image source={{ uri: imageUri }} style={{ flex: 1 }} />}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
cameraContainer: {
flex: 1,
flexDirection: 'row',
},
fixedRatio: {
flex: 1,
aspectRatio: 1,
},
button: {
flex: 0.1,
padding: 10,
alignSelf: 'flex-end',
alignItems: 'center',
},
});
It's mention in doc Configuration.
In managed apps, Camera requires Permissions.CAMERA. Video recording requires Permissions.AUDIO_RECORDING.
I have the same problem... I'm using expo SDK 42 and after a denied answer the permissions request does not trigger again anymore.
Anyway, You have some mistakes in your code, you have to watch the status property of the permissions response.
this is how to check the response status
const requestPermissions = async () => {
try {
const {
status,
} = await ImagePicker.requestMediaLibraryPermissionsAsync();
console.log('status lib', status);
setHasPickerPermission(status === 'granted');
} catch (error) {
console.log('error', error);
}
try {
const { status } = await ImagePicker.requestCameraPermissionsAsync();
console.log('status camera', status);
setHasCameraPermission(status === 'granted');
} catch (error) {
console.log('error', error);
}
};
useEffect(() => {
requestPermissions();
}, []);
If the user has denied the camera permission the first time, the second time you request permission with requestCameraPermissionsAsync() the answer will always be "denied" unless the user manually changes the permission in the app settings.
import { Linking } from "react-native";
import { useCameraPermissions } from "expo-image-picker";
export default function App() {
const [status, requestPermissions] = useCameraPermissions();
const requestPermissionAgain = () => {
Linking.openSettings();
}
useEffect(() => {
if (!status?.granted) requestPermissions();
}, []);
}
I’m trying to make a prototype application that over and over
1- record a video with the camera for x seconds
2- displays this video
For this I use the components Camera from expo-camera and Video from expo-av
For this I have two views :
I use in my code the stateSequence property and the sequencer() function which displays alternately the view with the Camera component which films for x seconds , and the video view which allows me to display the video.
Sequencer() is triggered with setInterval( this.sequencer , 10000) found in the componentWillMount()
I can switch alternately from a View with the Camera component to a View with the Video component.
To record a video with the Camera component I use recordAsync(), but I get the following error:
Unhandled promise rejection: Error: Camera is not running
I’m using an android phone for my tests.
Can’t you help me
this is my code
import { StyleSheet, Text, View ,TouchableOpacity} from 'react-native';
import * as Permissions from 'expo-permissions';
import { Camera } from 'expo-camera';
import { Video } from 'expo-av';
import { Logs } from 'expo';
export default class SequenceViewer extends Component {
constructor(props) {
super(props);
this.state = {
stateSequence: "SHOOT ",
hasCameraPermission: null,
type: Camera.Constants.Type.front,
}
this.recordVideo = this.recordVideo.bind(this)
}
sequencer = () => {
if(this.state.stateSequence==="WATCH"){
this.setState({ stateSequence: "SHOOT",})
this.recordVideo(); // Error message Camera is not running
} else {
this.setState({stateSequence: "WATCH"})
}
}
async componentWillMount() {
let rollStatus = await Permissions.askAsync(Permissions.CAMERA_ROLL);
let cameraResponse = await Permissions.askAsync(Permissions.CAMERA)
if (rollStatus.status=='granted'){
if (cameraResponse.status == 'granted' ){
let audioResponse = await Permissions.askAsync(Permissions.AUDIO_RECORDING);
if (audioResponse.status == 'granted'){
this.setState({ permissionsGranted: true });
setInterval( this.sequencer , 10000);
}
}
}
}
recordVideo = async () => {
if(this.state.cameraIsRecording){
this.setState({cameraIsRecording:false})
this.camera.stopRecording();
}
else {
this.setState({cameraIsRecording:true})
if (this.camera) {
let record = await this.camera.recordAsync(quality='480p',maxDuration=5,mute=true).then( data =>{
this.setState( {recVideoUri :data.uri})
})
}
}
};
render() {
const { hasCameraPermission } = this.state
if(this.state.stateSequence=="WATCH")
{
return(
<View style={styles.container}>
<Video
source={{ uri:this.state.recVideoUri }}
rate={1.0}
volume={1.0}
isMuted={false}
resizeMode="cover"
shouldPlay
isLooping
style={{ width: 300, height: 300 }}
ref={(ref) => { this.player = ref }}
/>
</View>
)
} else
{
return(
<View style={{ flex: 1 }}>
<Camera style={{ flex: 1 }} type={this.state.type} ref={ref => {this.camera = ref; }}></Camera>
</View>
)
}
}
}
const styles = StyleSheet.create({
viewerText: {
fontSize: 20,
fontWeight: 'bold',
},
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Thank you
I had the same problem, my solution was by default camera type have to be "back" and you could change to "front" by:
componentDidMount = () => {
this.props.navigation.addListener('didFocus', async () => {
await setTimeout(() => {
this.setState({ cameraType: Camera.Constants.Type.front })
}, 100)
});
}
I was getting the "Camera is not running" error when i changed screens. So for functional components instead of withNavigationFocus(Camera) use this method:
import { useIsFocused } from '#react-navigation/native';
function MyComponent() {
const isFocused = useIsFocused()
return (
<View>
{ isFocused && <RNCamera /> }
</View>
)
}
I am developing an app That contain an image uploader. I found some code on internet that can upload image. And it worked partially. Which means When i press the choose image button, it opens gallery and i am able to select and crop image. And after cropping when i select ok nothing happen. It just show the image and its not uploading to the firebase cloud. Here is my code.
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button,
Image,
ActivityIndicator,
TouchableOpacity
} from 'react-native';
import * as firebase from 'firebase';
import RNFetchBlob from 'react-native-fetch-blob';
import ImagePicker from 'react-native-image-crop-picker';
export default class RNF extends Component {
constructor (props) {
super(props);
this.state = {
loading: false,
dp: null
};
}
openPicker () {
this.setState({ loading: true });
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
// const { uid } = this.state.user
const uid = '12345';
ImagePicker.openPicker({
width: 300,
height: 300,
cropping: true,
mediaType: 'photo'
}).then(image => {
const imagePath = image.path;
let uploadBlob = null;
const imageRef = firebase.storage().ref(uid).child('dp.jpg');
let mime = 'image/jpg';
fs.readFile(imagePath, 'base64')
.then((data) => {
// console.log(data);
return Blob.build(data, { type: `${mime};BASE64` });
})
.then((blob) => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime });
})
.then(() => {
uploadBlob.close();
return imageRef.getDownloadURL();
})
.then((url) => {
let userData = {};
// userData[dpNo] = url
// firebase.database().ref('users').child(uid).update({ ...userData})
let obj = {};
obj['loading'] = false;
obj['dp'] = url;
this.setState(obj);
})
.catch((error) => {
console.log(error);
});
})
.catch((error) => {
console.log(error);
});
}
render () {
const dpr = this.state.dp ? (<TouchableOpacity onPress={ () => this.openPicker() }><Image
style={{ width: 100, height: 100, margin: 5 }}
source={{ uri: this.state.dp }}
/></TouchableOpacity>) : (<Button
onPress={ () => this.openPicker() }
title={ 'Change Picture' }
/>);
const dps = this.state.loading ? <ActivityIndicator animating={this.state.loading} /> : (<View style={styles.container}>
<View style={{ flexDirection: 'row' }}>
{ dpr }
</View>
</View>);
return (
<View style={styles.container}>
{ dps }
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5
}
});
AppRegistry.registerComponent('RNF', () => RNF);
I am trying to fetch data from firebase database and show it in a Picker. This project fetch data from firebase Database table named category and show it in a React native picker. But picker showing an Error. I tried so many solutions, but the problem only key or value will be fetched from the db. I want both
This is my Firebase Db. And below is my code
import React from 'react';
import { StyleSheet, Text, View, TextInput, Picker } from 'react-native';
import DateTimePicker from 'react-native-modal-datetime-picker';
import moment from 'moment';
import * as firebase from 'firebase';
import {firebaseConfig} from './ApiKeys';
if (!firebase.apps.length) { firebase.initializeApp(firebaseConfig); }
console.ignoredYellowBox = ['Setting a timer',];
var pickerArr = [];
export default class App extends React.Component {
constructor(props){
super(props)
this.state=({
isDateTimePickerVisible: false,
selecteddate:'Date',
category:0,
snapshotList:{},
})
}
componentDidMount() {
this._loadInitialState();
}
_loadInitialState = () => {
//====================================
firebase.database().ref('/category').once('value').then((snapshot)=> {
this.setState({category:snapshot})
console.log(this.state.category);
})
//====================================
};
loadUserTypes() {
var snapshot = this.state.category;
snapshot.forEach(userSnapshot => {
var k = userSnapshot.key;
var name = userSnapshot.val();
pickerArr.push(<Picker.Item label={userSnapshot.key} value={userSnapshot.val()}/>);
console.log("k="+ k +" "+"name="+name); //Showing Data correctly
});
return pickerArr;
}
_showDateTimePicker = () => this.setState({ isDateTimePickerVisible: true });
_hideDateTimePicker = () => this.setState({ isDateTimePickerVisible: false });
_handleDatePicked = (pickeddate) => {
day = pickeddate.getDate();
month = pickeddate.getMonth();
year = pickeddate.getFullYear();
console.log('A date has been picked: ' + day + '-' + month + '-' + year);
exdate= moment(pickeddate).format('HH:mm')
this.setState({selecteddate : exdate})
this._hideDateTimePicker();
console.log("cat "+ this.state.category.val())
};
onFocus = () => {
this._handleDatePicked();
}
render() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<Text
onPress={ () => this._showDateTimePicker() }
value={this.state.selecteddate}
>{this.state.selecteddate}</Text>
{/* //--------------------------------------DateTimePicker */}
<DateTimePicker
isVisible={this.state.isDateTimePickerVisible}
onConfirm={this._handleDatePicked}
onCancel={this._hideDateTimePicker}
mode={'time'}
datePickerModeAndroid={'spinner'}
/>
{/* //-------------------------------------- */}
<Picker
selectedValue={this.state.language}
style={{height: 50, width: 100}}
onValueChange={(itemValue, itemIndex) =>
this.setState({language: itemValue})
}>
{/* -------------------Dynamic Picker Data------------------ */}
<Picker.Item label='Salle de sport' value='default'/>
{this.loadUserTypes()}
{/* -------------------------------------------------------- */}
</Picker>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});