saveToCameraRoll is not a function - javascript

I am trying to send images which are taken using React Native Camera library to Camera Roll.
When the user presses a button the following function gets triggered:
takePicture = async function() {
if (this.camera) {
const options = { quality: 0.5, base64: true }
const data = await this.camera.takePictureAsync(options)
CameraRoll.saveToCameraRoll(data.uri)
}
}
I already know that the app sends pictures to the cache folder because after this code is executed a link to the picture is displayed:
takePicture = async function() {
if (this.camera) {
const options = { quality: 0.5, base64: true }
const data = await this.camera.takePictureAsync(options)
console.log(data.uri)
}
}
The debugger shows the following error:
Possible Unhandled Promise Rejection (id:0)
React Native Camera: TypeError: _reactNative.default.saveToCameraRoll is not a function
The code of the Cam component:
import React, {Component} from 'react';
import {StyleSheet, View} from 'react-native'
import { RNCamera } from 'react-native-camera'
import CameraRoll from 'react-native'
import ActionButton from 'react-native-action-button'
import Icon from 'react-native-vector-icons/Ionicons'
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
button: {
height: 200,
justifyContent: 'flex-end',
alignItems: 'center'
},
actionButtonIcon: {
fontSize: 20,
height: 22,
color: 'white',
},
});
export default class Cam extends Component {
constructor() {
super()
this.takePicture = this.takePicture.bind(this)
}
takePicture = async function() {
if (this.camera) {
const options = { quality: 0.5, base64: true }
const data = await this.camera.takePictureAsync(options)
CameraRoll.saveToCameraRoll(data.uri)
}
}
render() {
return (
<View style={styles.container}>
<RNCamera
ref={ref => {this.camera = ref}}
style={{
flex: 1,
width: '100%',
position: 'relative'
}}
>
</RNCamera>
<ActionButton size={80} useNativeFeedback={false} buttonColor="rgba(231,76,60,1)">
<ActionButton.Item useNativeFeedback={false} buttonColor='#9b59b6' title="Settings" onPress={this.props.switchScreen}>
<Icon name="md-create" style={styles.actionButtonIcon} />
</ActionButton.Item>
<ActionButton.Item useNativeFeedback={false} buttonColor='#1abc9c' title="Start" onPress={this.takePicture}>
<Icon name="md-done-all" style={styles.actionButtonIcon} />
</ActionButton.Item>
</ActionButton>
</View>
)
}
}

Looking at this example of how to use CameraRoll :
import {
View,
Text,
TouchableHighlight,
Modal,
StyleSheet,
Button,
CameraRoll,
Image,
Dimensions,
ScrollView,
} from 'react-native'
You have to replace :
import CameraRoll from 'react-native';
by
import { CameraRoll } from 'react-native';
(I've put it as an answer so it can be accepted and close the question)
In your code, you can mutualise the imports like :
import React, {
Component,
} from 'react';
import {
RNCamera,
} from 'react-native-camera';
import {
CameraRoll,
StyleSheet,
View,
} from 'react-native';
import ActionButton from 'react-native-action-button';
import Icon from 'react-native-vector-icons/Ionicons';

Related

Missing MEDIA_LIBRARY permissions

I making an app using react native expo, onPress I want to download a .vcf or .pdf file on specified folder which is I fetched from server. but when I click onPress I get following errors in console
I able to download Images but when it comes to .vcf or pdf file facing below error.
MediaLibrary.createAlbumAsync("xFolderName", asset);
xFolderName where Im trying to store my .vcf or .pdf file, following path is created while saving an Images same for .vcf file Android-> Pictures -> xFolderName
[Unhandled promise rejection: Error: MediaLibrary.createAlbumAsync
must be called with an asset on Android.]
at node_modules/expo-media-library/build/MediaLibrary.js:302:14 in createAlbumAsync
at node_modules/expo-media-library/build/MediaLibrary.js:295:7 in createAlbumAsync
at components/ngo/ECard.js:98:8 in FileSystem.downloadAsync.then$argument_0
[Unhandled promise rejection: Error: Missing MEDIA_LIBRARY
permissions.]
at node_modules/react-native/Libraries/BatchedBridge/NativeModules.js:106:50 in promiseMethodWrapper
at node_modules/expo-modules-core/build/NativeModulesProxy.native.js:15:23 in moduleName.methodInfo.name
at node_modules/expo-media-library/build/MediaLibrary.js:148:24 in createAssetAsync
at node_modules/expo-media-library/build/MediaLibrary.js:141:7 in createAssetAsync
at components/ngo/ECard.js:97:22 in FileSystem.downloadAsync.then$argument_0
App.js
import { Header } from "react-native/Libraries/NewAppScreen";
import { StatusBar } from "expo-status-bar";
import {
StyleSheet,
Text,
View,
Button,
Image,
TouchableOpacity,
ScrollView,
Modal,
Share,
ImageBackground,
} from "react-native";
import React, { useState } from "react";
import { API_URL } from "#env";
import { Icon, SocialIcon } from "#rneui/themed";
import * as FileSystem from "expo-file-system";
import * as Permissions from "expo-permissions";
import * as MediaLibrary from "expo-media-library";
import Toast from "react-native-root-toast";
export default function App(props) {
const [apiData, setApiData] = React.useState({
xxxname: "",
});
const downloadFile = () => {
FileSystem.downloadAsync(
`${API_URL}/xpath/xpath?slug=${apiData.slug}`,
FileSystem.documentDirectory + apiData.xname + ".vcf"
)
.then(({ uri }) => {
const asset = MediaLibrary.createAssetAsync(uri);
MediaLibrary.createAlbumAsync("xFolderName", asset);
Toast.show("Download Completed");
})
.catch((error) => {
console.error(error);
});
};
return (
<View>
<TouchableOpacity
style={styles.addButton}
onPress={() => downloadFile()}
>
<Icon
color={"white"}
name="file-download"
/>
<Text style={styles.addButtonText}>Download</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
addButton: {
width: "30%",
margin: 10,
height: 55,
backgroundColor: "#3b82f6",
borderRadius: 15,
alignItems: "center",
justifyContent: "center",
elevation: 8,
},
addButtonText: {
color: "#fff",
fontSize: 18,
},
});

React navigation content size too narrow

Hi I am implementing react navigation in a react native app, and I am following the docs on react navigation. And I when I run the code this is the result:
My question is how do I make the center content's width same as the screen.
Also, his is my first time using react native expo after switching from reactJS
Code:
navigator code:
import Login from "./Login";
import Signup from "./Signup";
import {
createAppContainer,
NavigationContainer,
NavigationNavigator,
} from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import Chat from "./Chat";
import Error from "./Error";
/**
* This is the screen stack of the navigation stack.
*/
const screens: any = {
default: { screen: Login },
signup: { screen: Signup },
chat: { screen: Chat },
Error: { screen: Error },
};
const stack: NavigationNavigator<any, any> = createStackNavigator(screens);
const container: NavigationContainer = createAppContainer(stack);
export default container;
App.tsx:
import { StatusBar } from "expo-status-bar";
import React from "react";
import { Alert, StyleSheet, Text, View } from "react-native";
import * as expoAppLoading from "expo-app-loading";
import loadFonts from "./assets/fonts/loader";
import Navigator from "./screens/navigator";
/**
* This is the main app component of the Chill&chat application.
*/
const App: React.FC = () => {
const [loading, setLoading] = React.useState(true);
const style: any = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
text: {
fontFamily: "poppinsBold",
},
});
if (loading) {
return (
<expoAppLoading.default
startAsync={async (): Promise<void> => {
await loadFonts();
}}
onFinish={(): void => {
setLoading(false);
}}
onError={(): void => {
Alert.alert("Error", "Error loading fonts");
}}
/>
);
} else {
return (
<View style={style.container}>
<Navigator />
<StatusBar style="auto" />
</View>
);
}
};
export default App;
You should be able to set the width by adding percentage dimensions to your style sheet for the desired element. This may require you do away with flex layout however, or use flex in a parent instead.
container: {
width:'100%',
},
This should solve for the width problem though.

React360-Redux:Communication between 2 roots components via redux

I have 2 root components in react360.I have the main panel with information and my products and i have my 3d model.I want to communicate one another.Μore specifically I just want to click on the product then the color from my 3d model changes.At this time, my 3d model has value from the store I have originally defined, but while the price is changing, it is not renewed in the 3d model.for example when the application starts the original color of my model is blue but when I click on the first item it does not change to red. Wrere is the problem?????before
after
client.js
import { ReactInstance } from "react-360-web";
import { Location } from "react-360-web";
function init(bundle, parent, options = {}) {
const r360 = new ReactInstance(bundle, parent, {
// Add custom options here
fullScreen: true,
...options
});
// Render your app content to the default cylinder surface
r360.renderToSurface(
r360.createRoot("Center", {
/* initial props */
}),
r360.getDefaultSurface()
);
r360.renderToLocation(
r360.createRoot("React3DView"),
r360.getDefaultLocation()
);
// Load the initial environment
r360.compositor.setBackground(r360.getAssetURL("360_world.jpg"));
}
window.React360 = { init };
index.js
import { AppRegistry } from "react-360";
import Center from "./components/center";
import React3DView from "./components/obj";
AppRegistry.registerComponent("Center", () => Center);
AppRegistry.registerComponent("React3DView", () => React3DView);
reducer
initialState = {
data: [
{ id: 1, value: "MILEPTY.png" },
{ id: 2, value: "cleveland.png" },
{ id: 3, value: "phila.png" },
{ id: 4, value: "raptors.png" },
{ id: 5, value: "rockets.png" }
],
currentinfo: "Hello.Press click on T-shirt to show information",
currentcolor: "blue"
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case "INFO":
if (action.key === 1) {
return {
...state,
currentinfo: "Milwaukee bucks",
currentcolor: "red"
};
}
if (action.key === 2) {
return {
...state,
currentinfo: "Cleveland Cavaliers",
currentcolor: "green"
};
}
if (action.key === 3) {
return { ...state, currentinfo: "Philadelphia 76xers" };
}
if (action.key === 4) {
return { ...state, currentinfo: "Toronto Raptors" };
}
if (action.key === 5) {
return { ...state, currentinfo: "Huston Rockets" };
}
default:
return state;
}
};
export default reducer;
centerPanel
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import Products from "./products";
import { connect } from "react-redux";
class CenterPanel extends React.Component {
render() {
return (
<View style={styles.panel}>
<View style={{ flex: 1, flexDirection: "row" }}>
<View
style={{
width: 250,
height: 600
}}
>
<Text style={{ marginTop: "100" }}>{this.props.currentinfo}</Text>
</View>
<View
style={{
width: 1000,
height: 600,
backgroundColor: "green"
}}
>
<View style={{ flex: 1, flexDirection: "row" }}>
{this.props.data.map(element => (
<Products
key={element.id}
value={element.value}
id={element.id}
/>
))}
</View>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
panel: {
// Fill the entire surface
width: 1000,
height: 600,
backgroundColor: "rgba(255, 255, 255, 0.4)"
}
});
const mapStateToProps = state => {
return {
data: state.data,
currentinfo: state.currentinfo
};
};
export default connect(mapStateToProps)(CenterPanel);
products
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import { connect } from "react-redux";
class Products extends React.Component {
state = {
img: this.props.value
};
render() {
return (
<View
style={styles.panelimages}
onInput={() => this.props.onText(this.props.id)}
>
<Image style={styles.images} source={asset(this.state.img)} />
</View>
);
}
}
const styles = StyleSheet.create({
panelimages: {
width: 150,
height: 150,
marginTop: 200,
backgroundColor: "white"
},
images: {
width: 150,
height: 150
}
});
const mapDispatchToProps = dispatch => {
return {
onText: id => dispatch({ type: "INFO", key: id })
};
};
export default connect(
null,
mapDispatchToProps
)(Products);
center
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import { createStore } from "redux";
import { Provider } from "react-redux";
import reducer from "../store/reducer";
import CenterPanel from "./centerPanel";
// const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
const store = createStore(reducer);
export default class Center extends React.Component {
render() {
return (
<Provider store={store}>
<CenterPanel />
</Provider>
);
}
}
objpanel
import React from "react";
import {
asset,
AppRegistry,
StyleSheet,
Text,
View,
VrButton,
Image
} from "react-360";
import Entity from "Entity";
import { connect } from "react-redux";
class Object3d extends React.Component {
render() {
return (
<View>
<Entity
source={{ obj: asset("t-shirt.obj") }}
style={{
transform: [{ translate: [-3.5, -3.5, -2.8] }],
color: this.props.currentcolor -------->here is problem
}}
/>
</View>
);
}
}
const mapStateToProps = state => {
return {
currentcolor: state.currentcolor
};
};
export default connect(mapStateToProps)(Object3d);
obj
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import { createStore } from "redux";
import { Provider } from "react-redux";
import reducer from "../store/reducer";
import Object3d from "./objpanel";
// const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
const store = createStore(reducer);
export default class React3DView extends React.Component {
render() {
return (
<Provider store={store}>
<Object3d />
</Provider>
);
}
}
I've tried to do this with redux but in the end I had more problems implementing it than it was worth. In order to implement something like that you would need to follow the code that is described here:
React 360 multi panel example
Additionally, I've implemented what you are trying to do without redux. You can look at the code in this repository and also view the production link here. Its modeled after the react 360 code.
CryptoDashboardVR repo
CryptodashboardVR Multipanel synchronization
Finally, If you still need help, check out my course on React 360. I explain the concepts used. Udemy react 360.
Hope that helps. For now, I would abandon the redux approach until maybe 2.0 comes out.

undefined is not an object (evaluating '_this.props.navigator.push')

I'm trying to navigate from Homescreen to another screen(Test).I have 'HomeScreen.js' below. Once I click on the register button, I get the above mentioned error.
I've been at this for a whole day, but can't seem to get a straight forward answer.
The error is on my 'Homescreen.js' (Attached screenshot error)
Screenshot
Error is pointing to: this.props.navigator.push under the _handleRegisterView function.
HomeScreen.js
import React from 'react';
import {
StyleSheet,
Text,
View,
AsyncStorage,
Component,
TouchableHighlight,
AppRegistry
} from 'react-native';
import Test from './Test';
import { StackNavigator } from 'react-navigation';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'SpeedHack',
};
_handleRegisterView = () => {
this.props.navigator.push({
title: 'Test',
component: Test,
backButtonTitle: 'Back'
})
//alert('Register button Pressed!.');
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight onPress={this._handleRegisterView}>
<Text style={[styles.button, styles.blueButton]}>
Register
</Text></View>
);
}
}
Test.js (Doesn't really do anything interesting, loads an image)
import React from 'react';
import { Component, StyleSheet, Text, View, Image } from 'react-native';
class Test extends React.Component {
render() {
let pic = {
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
};
return (
<View style={styles.container}>
<Text>Ssup Dude! Want some bananas?</Text>
<Image source = {pic} style = {{width: 300, height: 300}}/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
You seem to be confused. In react-navigation in order to push a screen, you do not do this.props.navigator.push, you use this.props.navigation.navigate.

Usage of navigator in react-native

I am new to react-native framework and learning how to use navigator. I tried to implement jump between two pages of APP. From "Boy" to "Girl" then back to "Boy".
Here is the code in APP.js:
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, {Component, } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
Image,
} from 'react-native';
import Boy from './Boy';
import {Navigator} from 'react-native-deprecated-custom-components';
import TabNavigator from 'react-native-tab-navigator';
export default class imooc_gp extends Component {
constructor(props){
super(props);
this.state = {
selectedTab:'tb_popular',
}
}
render() {
return (
<View style={styles.container}>
<Navigator
initialRoute = {{
title:'example',
component: Boy
}}
renderScene = {(route, navigator) =>{
let Component = route.component;
return <Component navigator = {navigator} {...route.params}/>
}}
></Navigator>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
page1 :{
flex: 1,
backgroundColor: 'red',
},
page2: {
flex: 1,
backgroundColor: 'yellow',
},
image: {
height: 22,
width: 22,
}
});
Boy.js:
import React, {Component} from 'react';
import {
View,
Text,
StyleSheet
}from 'react-native';
import Girl from './Girl';
export default class Boy extends Component{
constructor(props){
super(props);
this.state = {
word: ''
}
}
render(){
return (
<View style = {styles.container}>
<Text style = {styles.text}> I am a boy</Text>
<Text style = {styles.text}
onPress = {()=>{
this.props.navigator.push({
title:'Girl',
component: Girl,
params:{
word: 'A Rose',
onCallBack: (word)=>{
this.setState({
word: word
})
}
}
})
}}>Send girl a Rose</Text>
<Text style = {styles.text}>{this.state.word}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'gray',
justifyContent: 'center'
},
text: {
fontSize: 20,
}
})
Girl.js:
import React, {Component} from 'react';
import {
View,
Text,
StyleSheet
}from 'react-native';
export default class Girl extends Component{
constructor(props){
super(props);
this.state = {
}
}
render(){
return(
<View styles = {styles.container}>
<Text style = {styles.text}> I am a Girl</Text>
<Text style = {styles.text}>{this.state.word}</Text>
<Text style = {styles.text}
onPress = {()=>{
this.props.onCallBack('A box of chocolate')
this.props.navigator.pop()
}}>return chocolate</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'red',
justifyContent: 'center',
},
text: {
fontSize: 22
}
})
And I received the error message on iPhone emulator showed in the image:
I guess the error could be caused by wrong usage grammar of Navigator in different react-native version.
In my experience, I have found it more useful to use react-navigation library. This allows one to create a router files that lists all the pages that you want your app to navigate around; in your case, it could be Boy.js and Girl.js. Example given below:
import React from 'react';
import { StackNavigator } from 'react-navigation';
import { Boy, Girl } from '../app';
export const Screens = StackNavigator({
Boy: {
screen: Boy,
},
Girl: {
screen: Girl
}
});
And once you render the Screen component, Boy.js and Girl.js will each have access to the other screen via the "navigation.navigate" props.
So in your Boy component, rather than:
onPress = {()=>{
this.props.navigator.push({
title:'Girl',
component: Girl,
params:{
word: 'A Rose',
onCallBack: (word)=>{
this.setState({
word: word
})
}
}
})
You could simply write:
this.props.navigation.navigate("Girl")
All you would need to do is import the Girl component.
Hope this helps!

Categories

Resources