React-native-sound: setSpeakerphoneOn doesn't work - react-native-sound

I looked up documentation for setSpeakerphoneOn at https://github.com/zmxv/react-native-sound/wiki/API, where it states that you just need to pass a boolean value into it. What I'm trying to achieve is to have a toggle button for switching on and off setSpeakerphoneOn for voicemail files.
Here's the snippet of my code:
...
play = async () => {
if (this.sound) {
this.sound.play(this.playComplete)
this.setState({playState: 'playing'})
} else {
const { id, userCredential, contentUrl } = this.props
const voiceMailURL = `${contentUrl}/content/voicemail/get?msgId=${id}&token=${userCredential.access_token}`
this.sound = new Sound(voiceMailURL, '', (error) => {
if (error) {
Alert.alert('Notice', 'audio file error. (Error code : 1)')
this.setState({playState: 'paused'})
} else {
this.setState({playState: 'playing', duration: this.sound.getDuration()})
this.state.useEarPiece ? this.sound.setSpeakerphoneOn(true) : this.sound.setSpeakerphoneOn(true)
this.sound.play(this.playComplete)
}
})
}
}
playComplete = (success) => {
if (this.sound) {
if (success) {
} else {
Alert.alert('Notice', 'audio file error. (Error code : 2)')
}
this.setState({playState: 'paused', playSeconds: 0})
this.sound.setCurrentTime(0)
}
}
toggleUseEarPiece = () => {
this.setState({
useEarPiece: !this.state.useEarPiece
})
}
render () {
...
<View style={{flexDirection: 'row', justifyContent: 'center'}}>
{this.state.playState === 'playing' &&
<TouchableOpacity style={{marginHorizontal: 20}} onPress={this.pause}>
<Icon color='#000' name='ios-pause' size={20} type='ionicon' />
</TouchableOpacity>}
{this.state.playState === 'paused' &&
<TouchableOpacity style={{marginHorizontal: 20}} onPress={this.play}>
<Icon color='#000' name='md-play' size={20} type='ionicon' />
</TouchableOpacity>}
</View>
...
<TouchableOpacity onPress={this.toggleUseEarPiece}>{speaker}</TouchableOpacity>
}

You're going to giggle, but this line in your code may be at fault:
this.state.useEarPiece ? this.sound.setSpeakerphoneOn(true) : this.sound.setSpeakerphoneOn(true);

Related

How to show Timeout for 25000 ms if API does not give data using redux?

I am new to react and redux. I have implemented API fetching using redux but not sure where should i put code for Timeout if API does not give gives data for particular time. everything is working fine I am getting data too..only thing i stuck is how to show timeout. Is there any way to do that? Thanks in advance :)
reducer.js
export const GET_REPOS = 'my-awesome-app/repos/LOAD';
export const GET_REPOS_SUCCESS = 'my-awesome-app/repos/LOAD_SUCCESS';
export const GET_REPOS_FAIL = 'my-awesome-app/repos/LOAD_FAIL';
const initialState = {
repos: [],
loading: false,
error: null
};
export default function reducer(state = initialState , action) {
switch (action.type) {
case GET_REPOS:
return { ...state, loading: true };
case GET_REPOS_SUCCESS:
return { ...state, loading: false, repos: action.payload.data };
case GET_REPOS_FAIL:
return {
...state,
loading: false,
error: 'Error while fetching repositories',
};
default:
return state;
}
}
export function listRepos(photos) {
return {
type: GET_REPOS,
payload: {
request: {
url: `photos/`
}
}
};
}
export function listThumb(albumId) {
return {
type: GET_REPOS,
payload: {
request: {
url: `photos?albumId=${albumId}`
}
}
};
}
home.js
import React, { Component } from 'react';
import { ActivityIndicator } from 'react-native-paper';
import { View, Text, FlatList, StyleSheet, TouchableOpacity } from 'react-native';
import { connect } from 'react-redux';
import styles from '../HomeComponent/style';
import { Ionicons } from '#expo/vector-icons';
import { listRepos } from '../../../reducer';
import ErrorAlert from '../../common/ErrorAlertComponent/errorAlert';
class Home extends Component {
componentDidMount() {
this.props.listRepos('');
}
FlatListItemSeparator = () => (
<View style={styles.flatListItemSeparator} />
)
renderItem = ({ item }) => (
<View style={styles.listRowContainer}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('ThumbnailViewScreen', {
albumID: item.id,
})} style={styles.listRow}>
<View style={styles.listTextNavVIew}>
<Text style={styles.albumTitle}> {item.title} </Text>
<Ionicons name='md-arrow-dropright' style={styles.detailArrow} />
</View>
</TouchableOpacity>
</View>
);
render() {
const { error, loading, products } = this.props;
if (error) {
return <ErrorAlert />;
}
if (loading) {
return (
<View style={{ flex: 1, paddingTop: 30 }}>
<ActivityIndicator animating={true} size='large' />
</View>
);
}
const { repos } = this.props;
return (
<View style={styles.MainContainer} >
<FlatList
styles={styles.container}
data={repos}
renderItem={this.renderItem}
ItemSeparatorComponent={this.FlatListItemSeparator}
/>
</View>
);
}
}
const mapStateToProps = state => {
let storedRepositories = state.repos.map(repo => ({ key: repo.id.toString(), ...repo }));
return {
repos: storedRepositories,
loading: state.loading,
error: state.error
};
};
const mapDispatchToProps = {
listRepos
};
export default connect(mapStateToProps, mapDispatchToProps)(Home);
Firstly you should create entry point for your axios. For example:
import axios from 'axios/index';
const api = axios.create({
baseURL: 'site.com',
timeout: 25000,
});
export default api;
And import it where you do api calls:
import api from 'yourDirectory';
And use this entry point:
api.get(url)
If request time is too long axios throws timeout error after 25000ms

How to save and display and image in react-native?

I have a question in react-native. Im using a module called "react-native-image-picker" to pick an image and display it on my app.
Now what i want is to store it somewhere (database, or local storage) and when i open again the app, the image that i choosed should be there. But i dont know what is the best option to do it.
I've already tryied to read some stuff like react-native-fs and fetch-blob but it doesnt help me, i guess.
What is the best option to do it?
Thank you.
First, renders view according to condition. For example if image is available then simply display the image else display TouchableOpacity which will help use to select pictures :
import React, { Component } from React;
import { View, TouchableOpacity, Text, Image } from 'react-native';
import ImagePicker from 'react-native-image-picker';
import AsyncStorage from '#react-native-community/async-storage';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isImageAvailable: false,
profilePic: null
}
}
componentDidMount = () => {
this.getImage();
}
getImage = async () => {
const profilePic = await AsyncStorage.getItem("profilePic");
if (profilePic) {
this.setState({
isImageAvailable: true,
profilePic: JSON.parse(profilePic)
});
}
}
selectProfilePic = () => {
const options = {
title: 'Select Avatar',
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
const source = { uri: response.uri };
// You can also display the image using data:
// const source = { uri: 'data:image/jpeg;base64,' + response.data };
AsyncStorage.setItem("profilePic", JSON.stringify(source));
this.setState({
profilePic: source,
isImageAvailable: true
});
}
});
}
render() {
return (
<View>
{
this.state.isImageAvailable && (
<Image source={this.state.profilePic} style={{ width: 200, height: 200 }} />
)
}
{
!this.state.isImageAvailable && (
<TouchableOpacity onPress={this.selectProfilePic}>
<Text>Choose Profile Pic</Text>
</TouchableOpacity>
)
}
</View>
)
}
}
Hope it will help you.
You can use realmdb as an aternative to Asyncstorage.

Error when trying to update in react-redux

I am trying to update my data in redux but I get an error when I have more than one value in the state.
How I am transferring data into the AllPalletes component below:
<Route exact path='/' render ={(routeProps) => <AllPalletes data = {this.props.palleteNames} />} />
The AllPalletes component, where I am setting up the edit form:
class connectingPalletes extends Component {
render () {
console.log(this.props)
return (
<div>
<Menu inverted>
<Menu.Item header>Home</Menu.Item>
<Menu.Item as = {Link} to = '/createpalette'>Create a Palette</Menu.Item>
</Menu>
<Container>
<Card.Group itemsPerRow={4}>
{this.props.data.map((card) => {
let cardName = card.Name.replace(/\s+/g, '-').toLowerCase()
return (
<Card key = {card._id}>
<Image src = 'https://images.pexels.com/photos/1212406/pexels-photo-1212406.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500' wrapped ui={false}/>
<Card.Content>
<Grid>
<Grid.Column floated = 'left' width ={7}>
{card.edit? (
<PaletteEditForm {...card}/>
) : (
<Card.Header as = {Link} to = {`/palette/${cardName}`}>{card.Name}</Card.Header>
)}
</Grid.Column>
<Grid.Column floated = 'right' width = {5}>
<Icon name = 'pencil' />
<Icon name = 'trash' onClick = {() => this.props.dispatch(removePalette({id: card._id}))}/>
</Grid.Column>
</Grid>
</Card.Content>
</Card>
)
})}
</Card.Group>
<Divider></Divider>
<Divider hidden></Divider>
<Grid centered columns={1}>
<Button as = {Link} to = '/testing'>Go Back</Button>
</Grid>
</Container>
</div>
)
}
}
const AllPalletes = connect()(connectingPalletes)
export default AllPalletes
And here is the edit form:
class EditForm extends Component {
constructor(props) {
super(props)
this.state = {
paletteName: this.props.Name
}
}
handleChange = (e) => {
const val = e.target.value,
s_name = e.target.name
this.setState (() => {
return {
[s_name]: val,
}
})
}
handleSubmit = () => {
let updates = {Name: this.state.paletteName, edit: false}
this.props.dispatch(editPalette(this.props._id, updates))
}
render() {
console.log(this.props)
return (
<Form onSubmit = {this.handleSubmit}>
<Input type = 'text' name = 'paletteName' value = {this.state.paletteName} onChange={this.handleChange} />
</Form>
)
}
}
const PaletteEditForm = connect()(EditForm)
export default PaletteEditForm
My Reducer:
import uuid from 'uuid/v1'
const paletteDefault = [{
Name: "Material UI",
myArray: [],
_id: uuid(),
edit: false
}, {
Name: "Splash UI",
myArray: [],
_id: uuid(),
edit: true
}]
const PaletteReducers = (state = paletteDefault, action) => {
console.log(action)
switch(action.type) {
case 'ADD_PALETTE':
return [...state, action.palette]
case 'REMOVE_PALETTE':
return state.filter(x => x._id !== action.id)
case 'EDIT_PALETTE':
return state.map((palette) => {
if(palette._id === action.id) {
return {
...palette,
...action.updates
}
}
})
default:
return state
}
}
export default PaletteReducers
My Action
// EDIT_PALETTE
const editPalette = (id, updates) => ({
type: 'EDIT_PALETTE',
id,
updates
})
export {addPalette, removePalette, editPalette}
I have a feeling that the problem could be in how I have set up the reducer case.
The edit dispatch only works when I have one value in the state. Otherwise, I am getting this error:
Uncaught TypeError: Cannot read property 'Name' of undefined
at AllPalletes.js:23
Please help..
I found the error. I had not give a return value in the 'EDIT_PALETTE' case, after the if-statement. It was
case 'EDIT_PALETTE':
return state.map((palette) => {
if(palette._id === action.id) {
return {
...palette,
...action.updates
}
}
})
And instead should be:
case 'EDIT_PALETTE':
return state.map((palette) => {
if(palette._id === action.id) {
return {
...palette,
...action.updates
}
}
return palette
})

Adding an image in React native

I got this code, and im supposed to add 3 different images to each row.
class SubRatingRowGroup extends Component {
onRatingPressed(elementName, rating) {
const cat = _.find(this.props.categories_tree.categories, {
name: elementName
});
cat.rating = rating;
this.props.setSubRatings(cat, rating);
}
handleClick = () => {
this.props.setCategories( this.props.categories_tree.categories);
this.props.openSubCategory(this.props.categories_tree, this.props.editable)
}
render() {
if (this.props.categories_tree && this.props.categories_tree.categories) {
let subRatingRows = [];
subRatingRows = this.props.categories_tree.categories.map((category, key) => (
<View style={{ flex: 1}} key={key}>
<View style={styles.ratingButtonRow}>
<View style={styles.buttonNameText} >
<Button title={category.name} onPress={this.handleClick} />
</View>
</View>
</View>
));
return (
<View >
{subRatingRows }
</View>);
}
return renderLoadingSpinner();
}
}
This will end with me rendering 3 rows with :
Enviromental
Social
Cultural
and i need 3 different backgrounds on these rows, i'm kinda new so i'm not sure what to do here. Would appreciate any help!

React Native Lottie View Animation Play/Pause Issue

I'm using React Native Lottie Wrapper to show animation on screen.
I need a functionality to play/pause/resume animation.
Here is my a part of my code:
...
constructor(props) {
super(props);
this.state = {
progress: new Animated.Value(0)
};
}
static navigationOptions = {
title: "Details",
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
headerTruncatedBackTitle: 'List'
};
componentDidMount() {
this.animation.play();
}
playLottie() {
console.log('play');
}
pauseLottie() {
console.log('pause');
}
render() {
return (
<View>
<Animation
ref={animation => { this.animation = animation; }}
source={require('../../../../assets/anim/balloons.json')}
style={{height: 300, width: '100%'}}
loop={false}
progress={this.state.progress}
/>
<Text>Course with id: {this.props.navigation.state.params.courseId}</Text>
<Button
onPress={this.playLottie}
title="Play Lottie"
color="#841584"
accessibilityLabel="Play video"
/>
<Button
onPress={this.pauseLottie}
title="Pause Lottie"
color="#841584"
accessibilityLabel="Pause video"
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
...
The animation is playing well but I can't pause it and resume it.
Does anyone have a solution for this problem?
P.S. I have tried to use this.animation in pauseLottie() method but it said that is undefined.
Thank you in advance!
You can pause and play Lottie animation by changing the speed prop, where speed={0} puts LottieView component in pause and speed={1} plays it at normal speed.
Here is an example:
playAnimation = () => {
this.setState({speed: 1})
}
pauseAnimation = () => {
this.setState({speed: 0})
}
<LottieView
source={this.state.sourceAnimation}
speed={this.state.speed} />
You have to set the state from the play/pause functions. In order to access the state of the Component, you have to bind the function to the component class:
First option in your constructor:
constructor(props) {
super(props);
this.playLottie.bind(this);
this.pauseLottie.bind(this);
}
or second option when declaring inside class use the es6 function syntax:
playLottie = () => {
...
}
pauseLottie = () => {
...
}
Inside those function call setState and add the value you want to set it to. In your case I would:
playLottie = () => {
this.setState({ progress: true })
}
pauseLottie = () => {
this.setState({ progress: false })
}
It is important you bind those two functions to your class component, because you will not be able to access component props. Thats why it is throwing you an error setState is not a function
Your render looks good ;)
for me it didn't work well: we have to add setValue(0), then we need to improve pause/restart to maintain the playing speed and change easing function to avoid slow re-start. Let's also add looping:
constructor(props) {
super(props);
this.playLottie.bind(this);
this.pauseLottie.bind(this);
this.state = {
progress: new Animated.Value(0),
pausedProgress: 0
};
}
playLottie = () => {
Animated.timing(this.state.progress, {
toValue: 1,
duration: (10000 * (1 - this.state.pausedProgress)),
easing: Easing.linear,
}).start((value) => {
if (value.finished) this.restartAnimation();
});
}
restartAnimation = () => {
this.state.progress.setValue(0);
this.setState({ pausedProgress: 0 });
this.playAnimation();
}
pauseLottie = () => {
this.state.progress.stopAnimation(this.realProgress);
}
realProgress = (value) => {
console.log(value);
this.setState({ pausedProgress: value });
};
...
(Now) For me, it's working fine! Play and pause option work as expected.
If you use an Lottie animation that contains a loop you can control it all with the LottieView api built in. (if you are using a file that has the animation)
import Lottie from 'lottie-react-native'
const ref = useRef<AnimatedLottieView>()
const pause = () => {
ref.current.pause()
}
const resume = () => {
ref.current.resume()
}
const reset = () => {
ref.current.reset()
}
<Lottie
ref={ref}
source={source}
resizeMode={resizeMode}
loop={true}
duration={duration}
autoPlay={true}
onAnimationFinish={onFinish}
/>

Resources