I am playing some audio files in react native. For progress of the audio file (Duration), I am showing slider for status of the audio file and for forward and reverse the duration.
But, According to audio duration, It is not keep on moving the position (like timer).
https://www.npmjs.com/package/react-native-slider
getInfo = async () => {
try {
const info = await SoundPlayer.getInfo();
// console.log('getInfo', info); // {duration: 12.416, currentTime: 7.691}
const currentTime = get(info, 'currentTime');
this.setState({ currentDuration: currentTime });
} catch (e) {
console.log('There is no song playing', e);
}
}
getProgress = (e) => {
console.log('getProgress calling');
this.getInfo();
this.setState({
currentTime: this.state.currentDuration,
});
}
<Slider
maximumValue={parseFloat(totalLength)}
minimumTrackTintColor="color"
maximumTractTintColor="color"
step={1}
value={currentTime}
onSlidingComplete={value => this.onValueChange(value)}
style={styles.slider}
thumbTintColor="red"
trackLength={parseFloat(totalLength)}
// onSlidingStart={() => this.setState({ paused: true })}
currentPosition={currentTime}
onProgress={e => this.getProgress(e)}
/>
It has to move slider value automatically according to audio duration
Any suggestions?
You'll need a counter to update the progress bar each second
timer = null;
durationCounter = () => {
this.timer = setInterval(async () => {
const info = await SoundPlayer.getInfo();
this.setState({
currentTime: info.currentTime
});
}, 1000);
};
componentDidMount = () => {
SoundPlayer.onFinishedLoading(async success => {
this.durationCounter();
});
}
componentWillMount = () => {
this.timer && clearInterval(this.timer);
};
Related
I want to create a function inside my components that detect when the app is in the background for 30 seconds, I want to dispatch a logout action or close the apps. is that possible if we do that in react native?
I'm using hooks
Thanks,
update :
I'm using the wowandy's solution but the thing is if user close the apps for less than 10 seconds and then open the app again, the dispatch command will still be executed in 30 seconds. is there any way to cancel the timeout ?
useEffect(() => {
let timeout;
const subscription = AppState.addEventListener('change', (nextAppState) => {
clearTimeout(timeout);
if (appState.current === 'background') {
timeout = setTimeout(() => dispatch(removeDataLogin()), 30000);
}
appState.current = nextAppState;
});
return () => {
subscription.remove();
clearTimeout(timeout);
};
}, []);
Update 3
So I tried to use Michael Bahl's solution as commented below. it works great with timestamp.
useEffect(() => {
let start;
let end;
const subscription = AppState.addEventListener("change", nextAppState => {
if (
appState.current.match(/inactive|background/) &&
nextAppState === "active"
) {
end = new Date()
let ms = moment(end).diff(moment(start))
if (Number(ms) >= 30000) {
dispatch(removeDataLogin())
} else {
}
} else {
start = new Date()
console.log('start diff :', start)
}
appState.current = nextAppState;
setAppStateVisible(appState.current);
console.log("AppState", appState.current);
});
return () => {
subscription.remove();
};
}, []);
update 3 Im using Michael Bahl's solution so I created a timestamp that check the difference between inactive and active screens, then dispatch the redux action
useEffect(() => {
let start;
let end;
const subscription = AppState.addEventListener("change", nextAppState => {
if (
appState.current.match(/inactive|background/) &&
nextAppState === "active"
) {
console.log('end =====')
console.log('start diff == ', start)
end = new Date()
console.log('end diff ===', end)
let ms = moment(end).diff(moment(start))
console.log('different : ', ms)
console.log(typeof ms)
if (Number(ms) >= 30000) {
console.log('harusnya logout')
dispatch(removeDataLogin())
} else {
console.log(ms, 'masuk sini')
}
} else {
start = new Date()
console.log('start diff :', start)
}
appState.current = nextAppState;
setAppStateVisible(appState.current);
console.log("AppState", appState.current);
});
return () => {
subscription.remove();
};
}, []);
You can handle app state using AppState and close it with BackHandler
See example:
import React, {useRef, useEffect} from 'react';
import {AppState, BackHandler} from 'react-native';
const App = () => {
const appState = useRef(AppState.currentState);
useEffect(() => {
let timeout;
const subscription = AppState.addEventListener('change', (nextAppState) => {
clearTimeout(timeout);
if (appState.current === 'background') {
timeout = setTimeout(() => BackHandler.exitApp(), 30000);
}
appState.current = nextAppState;
});
return () => {
subscription.remove();
clearTimeout(timeout);
};
}, []);
// TODO
return /* TODO */;
};
I'm trying to create a firestore listener, which handles changes on my collection. After some research, I implement the feature as below.
useEffect(() => {
const firebaseApp = getFirebaseApp();
const db = firestore(firebaseApp);
const handleSnapshotChanges = ( snapshot: FirebaseFirestoreTypes.QuerySnapshot<FirebaseFirestoreTypes.DocumentData> ) => {
const changes = snapshot.docChanges();
changes.forEach((change) => {
if (change.type === "added") {
console.log(change.doc);
console.log(change.type);
}
if (change.type === "modified") {
console.log("Doc modified");
}
if (change.type === "removed") {
console.log("Remove doc");
}
});
};
const query = db.collection("history");
const unsubscribe = query.onSnapshot(handleSnapshotChanges, (err) =>
console.log(err)
);
return () => {
unsubscribe();
};
}, []);
If I doing so, every time I enter the screen where I put the above useEffect, firestore keeps loading all documents in the collection and marks them as added. How can I implement this function properly.
This exitAlert is call after android button is press, I want to disable exit after the toast is close, since the toast has no close event, I am using timeout to disable it, obviously the code below does not disable second press exit:
const exitAlert = () => {
const duration = 3 * 1000;
showToast('Press again to exit', duration, 'top');
BackHandler.addEventListener('hardwareBackPress', () => {
BackHandler.exitApp();
});
setTimeout(() => BackHandler.removeEventListener('hardwareBackPress', () => {}),
duration);
}
Okay this works:
let pressTwice = true;
const duration = 3 * 1000;
showToast('Confirm exit', duration, 'top');
BackHandler.addEventListener('hardwareBackPress', () => {
if (pressTwice) {
BackHandler.exitApp();
}
});
setTimeout(function() {
pressTwice = false;
}, duration);
This may work
componentDidMount(){
let oncePressed = false;
const duration = 3 * 1000;
BackHandler.addEventListener('hardwareBackPress', () => {
if(oncePressed){
oncePressed = false;
BackHandler.exitApp();
}else{
showToast('Press again to exit', duration, 'top');
oncePressed = true
setTimeout(() => BackHandler.removeEventListener('hardwareBackPress', () => {
oncePressed = true
}),
duration);
}
});
}
I have an async function where I load my data and update state:
constructor(props) {
super(props);
this.state = {
userData: {},
isDateTimePickerVisible: false,
};
}
componentDidMount() {
this.getUser();
}
getUser = async () => {
const { navigation } = this.props;
const tenantID = navigation.getParam('userID', '0');
await this.props.getUserByID(tenantID); // Wait for action to complete
this.setState({
userData: this.props.userData
});
};
Then I use the state data to populate the Input value of my render(). However, I added a DateTimePicker to my component where opens the DateTimePicker in the onFocus Input:
<Input
style={styles.valueText}
onFocus={this.showDateTimePicker}
value={getFormattedDate(EndDate)}
/>
<DateTimePicker
isVisible={this.state.isDateTimePickerVisible}
onConfirm={this.handleDatePicked}
onCancel={this.hideDateTimePicker}
date={EndDate}
/>
The methods to handle the show/hide/update date:
showDateTimePicker = () => {
this.setState({
isDateTimePickerVisible: true
});
};
hideDateTimePicker = () => {
this.setState({
isDateTimePickerVisible: false
});
};
handleDatePicked = date => {
const obj = { ...this.state.userData };
obj.LeaseStartDate = date;
this.setState({
userData: obj
});
this.hideDateTimePicker();
};
When I first open the page, it is doesn't have any data in the this.state.userData. But, if I delete the methods 'showDateTimePicker' and 'hideDateTimePicker' the this.state.userData has the data when I first load the page. Why is it happening?
Thanks
Even if I leave the methods without the setState, it does work. However, if I remove these methods it just work.
showDateTimePicker = () => {
};
hideDateTimePicker = () => {
};
I have two components, in first components storing data in asyncstorage, in second component display data, when install app and save data does not get data from asyncstorage, when open app second time data are displayed.
storeData = async (item, messave, messrem) => {
const checkarary = this.state.favorite;
if(checkarary.some(e => e.name === item.name)) {
const value = this.state.favorite;
const position = value.filter((lists) => lists.id !== item.id);
this.setState({
favorite: position
}, () => {
try {
AsyncStorage.setItem('favoriti', JSON.stringify(this.state.favorite), () => {
Toast.show({
text: messrem,
buttonText: "Okay",
duration: 3000,
type: "danger"
});
});
} catch (error) {
}
});
} else {
this.setState({
favorite: [...this.state.favorite, item]
}, () => {
try {
AsyncStorage.setItem('favoriti', JSON.stringify(this.state.favorite), () => {
// AsyncStorage.getItem('favoriti', (err, result) => {
// console.log(result);
// });
Toast.show({
text: messave,
buttonText: "Okay",
duration: 3000,
type: "success"
});
});
} catch (error) {
}
});
}
};
Getting data in second component
_retrieveData = async () => {
try {
AsyncStorage.getItem('favoriti').then((value) => {
const parsed = JSON.parse(value);
this.setState({ favorite: parsed })
})
} catch (error) {
}
};
componentDidMount() {
this._retrieveData();
setTimeout(() => {
this.setState({
loading: false,
})
}, 2000)
};
componentDidUpdate() {
this._retrieveData();
};
How fix this issue, is there some solution. Can I set Item and reload app when install app or somthing else.
Use this
componentWillMount() {
this._retrieveData();
setTimeout(() => {
this.setState({
loading: false,
})
}, 2000)
};
instead of
componentDidMount() {
this._retrieveData();
setTimeout(() => {
this.setState({
loading: false,
})
}, 2000)
};
As componentWillMount is called after constructor is called for class and componentDidMount is called after screen is once rendered.