React Native - Cannot capture hardware back button click event - react-native

I used to react-native-navigation from the Wix for my app navigation. But it is not working properly. After authenticating the user by my application successfully navigate to the main screen, but the problem is when I pressed android back button it will navigate to the login screen again. I need to avoid that. How can I do it? Finally tried to completely exit from the application. But it also not working properly. I have tried a few solutions, but those solutions have not worked for me. Here I have attached few solutions that I have tried.
try 01 :
componentWillUnmount() {
if (Platform.OS === 'android') return
BackHandler.removeEventListener('hardwareBackPress')
}
componentWillMount() {
Alert.alert(
"Warning!",
"one")
if (Platform.OS === 'android' && this.props.login)
BackHandler.addEventListener('hardwareBackPress', () => {
Alert.alert(
"Warning!",
"two")
return true
})
}
try 01: this function working properly, but this isn't solving the problem.
try 02 :
constructor(props) {
super(props);
this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
}
onNavigatorEvent(event) {
switch (event.id) {
case "willAppear":
this.backHandler = BackHandler.addEventListener(
"hardwareBackPress",
this.handleBackPress,
Alert.alert(
event.id,
"willAppear")
);
break;
case "willDisappear":
this.backPressed = 0;
Alert.alert(
"Warning!",
"willDisappear")
this.backHandler.remove();
break;
default:
break;
}
}
handleBackPress = () => {
console.log("handleBackPress");
if (this.backPressed && this.backPressed > 0) {
if (this.props.login) {
console.log("login");
RNExitApp.exitApp();
} else {
console.log("root");
this.props.navigator.popToRoot({ animated: false });
return false;
}
}
}
try 02: In this try "onNavigatorEvent (event)" working properly. But 1st time (1st time User login to the system, until the session saved) not working, but after that any time this function working.
This is the complete code.
LoginScreen.js
this.props.navigator.push({
screen: "auxxa.LandingScreen",
passProps: { login: true },
overrideBackPress: true,
navigatorStyle: {
navBarHidden: true
}
});
LandingScreen.js
constructor(props) {
super(props);
this.state = {
size: { width, height },
tileData: null,
isLoading: true,
user_id: null,
refetching: false,
access_token: null
};
// this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
}
onNavigatorEvent(event) {
switch (event.id) {
case "willAppear":
this.backHandler = BackHandler.addEventListener(
"hardwareBackPress",
this.handleBackPress,
Alert.alert(
event.id,
"willAppear")
);
break;
case "willDisappear":
this.backPressed = 0;
Alert.alert(
"Warning!",
"willDisappear")
this.backHandler.remove();
break;
default:
break;
}
}
handleBackPress = () => {
console.log("handleBackPress");
if (this.backPressed && this.backPressed > 0) {
if (this.props.login) {
console.log("login");
// RNExitApp.exitApp();
} else {
console.log("root");
this.props.navigator.popToRoot({ animated: false });
return false;
}
}
this.backPressed = 1;
this.props.navigator.showSnackbar({
text: "Press one more time to exit",
duration: "long"
});
return true;
};
componentWillUnmount() {
if (Platform.OS === 'android') return
BackHandler.removeEventListener('hardwareBackPress')
}
componentWillMount() {
Alert.alert(
"Warning!",
"one")
if (Platform.OS === 'android' && this.props.login)
BackHandler.addEventListener('hardwareBackPress', () => {
Alert.alert(
"Warning!",
"two")
return true
})
}
//Firebase initialization
componentDidMount() {
NetInfo.isConnected.addEventListener("change", this.handleConnectionChange);
// if network connected this will change the state --
NetInfo.isConnected.fetch().done(isConnected => {
if (isConnected) {
this.setState({ status: isConnected });
this._retrieveData();
}
else {
this.setState({ refetching: false })
// Alert.alert(
// "Warning!",
// "Please check your network connection.",
// [
// {
// text: "Cancel",
// onPress: () => console.log("Cancel Pressed"),
// style: "cancel"
// },
// { text: "OK", onPress: () => console.log("OK Pressed") }
// ],
// { cancelable: false }
// end here
// );
}
});
//Push Notification implementation
if (Platform.OS == "android") {
FCM.requestPermissions();
FCM.getFCMToken().then(token => {
console.log("TOKEN (getFCMToken)", token);
});
// This method get all notification from server side.
FCM.getInitialNotification().then(notif => {
console.log("INITIAL NOTIFICATION", notif);
});
// This method give received notifications to mobile to display.
this.notificationUnsubscribe = FCM.on(FCMEvent.Notification, notif => {
console.log("a", notif);
if (notif && notif.local_notification) {
return;
}
this.sendRemote(notif);
});
// this method call when FCM token is update(FCM token update any time so will get updated token from this method)
this.refreshUnsubscribe = FCM.on(FCMEvent.RefreshToken, token => {
console.log("TOKEN (refreshUnsubscribe)", token);
this.props.onChangeToken(token);
});
}
}
//Send Notifications method
sendRemote(notif) {
console.log("send");
FCM.presentLocalNotification({
title: notif.title,
body: notif.body,
priority: "high",
click_action: notif.click_action,
show_in_foreground: true
});
}
_retrieveData = async () => {
try {
const value = await AsyncStorage.multiGet(["id", "access_token"]);
if (value !== null) {
// We have data!!
console.log(value);
this.setState({ user_id: value[0][1] });
this.setState({ access_token: value[1][1] });
this.getLandingData();
}
} catch (error) {
// Error retrieving data
}
};
refetch = () => {
this.setState({ refetching: true })
this._retrieveData()
}
// if network state change then this method will check the isConnected true, if it is false
// this will popup the alert --
handleConnectionChange = isConnected => {
this.setState({ status: isConnected });
if (!isConnected) {
// alert dialog starting here --
Alert.alert(
"Warning!",
"Please check your network connection.",
[
{
text: "Cancel",
onPress: () => console.log("Cancel Pressed"),
style: "cancel"
},
{ text: "OK", onPress: () => console.log("OK Pressed") }
],
{ cancelable: false }
// end here
);
} else {
// this.getLandingData();
this.refetch();
}
};
// network conctivity check end here --
handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
async getLandingData() {
// let user_id = 18;
let url =
Config.BASE_URL +
`api/BIMobile/GetInitiatlTiles?userId=${encodeURIComponent(
this.state.user_id
)}`;
console.log(url);
fetch(url, {
method: "GET",
headers: {
Authorization: "Bearer " + this.state.access_token
},
})
.then(response => {
return response.json();
})
.then(responseData => {
//set your data here
console.log("responseData : ", responseData.messageCode);
if (responseData.data == null) {
Alert.alert(
"Oops! Something went wrong.",
"This page did not load correctly. Please contact helpdesk.",
[
{
text: "Cancel",
isLoading: true,
onPress: () => console.log("Cancel Pressed"),
style: "cancel"
},
{ text: "OK", isLoading: true, onPress: () => console.log("OK Pressed") }
],
{ cancelable: false }
// end here
);
} else {
if (responseData.messageCode.code == 1) {
this.setState({ tileData: responseData.data, isLoading: false });
} else if (responseData.messageCode.code == 0) {
console.log(responseData.messageCode.message)
}
}
})
.catch(error => {
console.error(error);
});
}
// this function set title to the page
module1Handler = (value, title) => {
this.props.navigator.push({
screen: value,
navigatorStyle: {
navBarHidden: false
},
title: title
});
};
_onLayoutDidChange = e => {
const layout = e.nativeEvent.layout;
this.setState({ size: { width: layout.width, height: layout.height } });
};
render() {
let menuItems = [];
console.log("title Data : " + this.state.tileData);
if (this.state.isLoading) {
// setup progressbar to the view --
// when the data is fetching this will spinning --
return <ActivityIndicator style={styles.activity_indicator_view} />;
} else {
return (
<View style={{ flex: 1 }} onLayout={this._onLayoutDidChange}>
<Swiper showsButtons={false} loop={false} showsPagination={false}>
{this.state.tileData.map((array, key) => {
if (key == 0) {
return (
<MainScreen
action={(value, title) => {
this.module1Handler(value, title);
}}
array={array}
/>
);
} else {
return (
<SliderScreen
action={(value, title) => {
this.module1Handler(value, title);
}}
array={array}
/>
);
}
})}
</Swiper>
</View>
);
}
}
}
const styles = StyleSheet.create({
activity_indicator_view: {
flex: 1,
flexDirection: "row",
height: "40%",
justifyContent: "space-around",
padding: 10
}
});
Appreciate if someone could assist me to correct way. Thanks.

Related

React-native: How to change the audio speed in expo-av

I'm having trouble changing the prop: 'rate' to change the speed of the audio being played.
I'm using expo-av (https://docs.expo.dev/versions/latest/sdk/av/).
Here's my code:
import {Text, View, Alert } from 'react-native'
import * as MediaLibrary from 'expo-media-library';
import { DataProvider } from 'recyclerlistview';
import {Audio} from 'expo-av';
import { play, pause, resume, playNext } from "../misc/AudioController";
export const AudioContext = createContext()
export class AudioProvider extends Component {
constructor(props) {
super(props);
this.state = {
audioFiles: [],
permissionError: false,
dataProvider: new DataProvider((r1, r2) => r1 !== r2),
playbackObj: null,
soundObj: null,
currentAudio: {},
isPlaying: false,
currentAudioIndex: null,
playbackPosition: null,
playbackDuration: null,
rate: 2.0,
};
this.totalAudioCount = 0;
}
permissionAlert = () => {
Alert.alert("Permission Required", "This app needs to read audio files", [
{ text: "I am ready", onPress: () => this.getPermission() },
{
text: "cancel",
onPress: () => this.permissionAlert(),
},
]);
};
getAudioFiles = async () => {
const { dataProvider, audioFiles } = this.state;
let media = await MediaLibrary.getAssetsAsync({
mediaType: "audio",
});
media = await MediaLibrary.getAssetsAsync({
mediaType: "audio",
first: media.totalCount,
});
this.totalAudioCount = media.totalCount;
this.setState({
...this.state,
dataProvider: dataProvider.cloneWithRows([
...audioFiles,
...media.assets,
]),
audioFiles: [...audioFiles, ...media.assets],
});
};
loadPreviousAudio = async () => {
let previousAudio = await AsyncStorageLib.getItem("previousAudio");
let currentAudio;
let currentAudioIndex;
if (previousAudio === null) {
currentAudio = this.state.audioFiles[0];
currentAudioIndex = 0;
} else {
previousAudio = JSON.parse(previousAudio);
currentAudio = previousAudio.audio;
currentAudioIndex = previousAudio.index;
}
this.setState({ ...this.state, currentAudio, currentAudio });
};
getPermission = async () => {
// {
// "canAskAgain": true,
// "expires": "never",
// "granted": false,
// "status": "undetermined",
// }
const permission = await MediaLibrary.getPermissionsAsync();
if (permission.granted) {
this.getAudioFiles();
}
if (!permission.canAskAgain && !permission.granted) {
this.setState({ ...this.state, permissionError: true });
}
if (!permission.granted && permission.canAskAgain) {
const { status, canAskAgain } =
await MediaLibrary.requestPermissionsAsync();
if (status === "denied" && canAskAgain) {
this.permissionAlert();
}
if (status === "granted") {
this.getAudioFiles();
}
if (status === "denied" && !canAskAgain) {
this.setState({ ...this.state, permissionError: true });
}
}
};
onPlaybackStatusUpdate = async (playbackStatus) => {
console.log("hier");
if (playbackStatus.isLoaded && playbackStatus.isPlaying) {
this.updateState(this, {
playbackPosition: playbackStatus.positionMillis,
playbackDuration: playbackStatus.durationMillis,
});
}
if (playbackStatus.didJustFinish) {
const nextAudioIndex = this.state.currentAudioIndex + 1;
if (nextAudioIndex >= this.totalAudioCount) {
this.state.playbackObj.unloadAsync();
this.updateState(this, {
soundObj: null,
currentAudio: this.state.audioFiles[0],
isPlaying: false,
currentAudioIndex: 0,
playbackPosition: null,
playbackDuration: null,
});
}
const audio = this.state.audioFiles[nextAudioIndex];
const status = await playNext(this.state.playbackObj, audio.uri);
this.updateState(this, {
soundObj: status,
currentAudio: audio,
isPlaying: true,
currentAudioIndex: nextAudioIndex,
});
}
};
componentDidMount() {
this.getPermission();
if (this.state.playbackObj === null) {
this.setState({ ...this.state, playbackObj: new Audio.Sound(), });
}
}
updateState = (prevState, newState = {}) => {
this.setState({ ...prevState, ...newState });
};
render() {
const {
audioFiles,
dataProvider,
permissionError,
playbackObj,
soundObj,
currentAudio,
isPlaying,
currentAudioIndex,
playbackPosition,
playbackDuration,
rate,
} = this.state;
if (permissionError)
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Text>It looks like you haven't accepted the permission</Text>
</View>
);
return (
<AudioContext.Provider
value={{
audioFiles,
dataProvider,
playbackObj,
soundObj,
currentAudio,
isPlaying,
currentAudioIndex,
totalAudioCount: this.totalAudioCount,
playbackPosition,
playbackDuration,
rate,
updateState: this.updateState,
loadPreviousAudio: this.loadPreviousAudio,
onPlaybackStatusUpdate: this.onPlaybackStatusUpdate
}}
>
{this.props.children}
</AudioContext.Provider>
);
}
}
import {Component} from 'react';
import AsyncStorageLib from '#react-native-async-storage/async-storage';
export default AudioProvider;
and here's some more:
// play audio
// Import the react-native-sound module
import { PitchCorrectionQuality,shouldCorrectPitch, rate } from "expo-av/build/AV.types";
export const play = async (playbackObj, uri,) => {
try {
return await playbackObj.loadAsync(
{uri},
{shouldPlay: true},
);
} catch (error) {
console.log('error inside play helper method', error.message)
}
};
//pause
export const pause = async playbackObj => {
try {
// playbackObj.setRateAsync(rate = 2.0, shouldCorrectPitch = true, PitchCorrectionQuality= High);
return await playbackObj.setStatusAsync({
shouldPlay: false},
);
} catch (error) {
console.log('error inside pause helper method', error.message)
}
};
//resume
export const resume = async playbackObj => {
try {
return await playbackObj.playAsync(
);
} catch (error) {
console.log('error inside pause resume method', error.message)
}
};
//select next
export const playNext = async (playbackObj, uri) => {
try {
await playbackObj.stopAsync()
await playbackObj.unloadAsync();
return await play(playbackObj, uri);
} catch (error) {
console.log('error inside playNext helper method')
}
}
I've tried including 'rate: 2.0' inside this.state{audioFiles: [],
permissionError: false, etc.} but it didn't work.
Also I've tried doing: await playbackObj.setRateAsync() in the 2nd code snippet.
Any suggestions?
Nvm, I found the solution. Here's my updated code:
// play audio
// Import the react-native-sound module
import { PitchCorrectionQuality,shouldCorrectPitch, rate } from "expo-av/build/AV.types";
export const play = async (playbackObj, uri,) => {
try {
await playbackObj.loadAsync(
{uri},
{shouldPlay: true},
);
return await playbackObj.setStatusAsync({ rate: 0.9749090909 });
} catch (error) {
console.log('error inside play helper method', error.message)
}
};
//pause
export const pause = async playbackObj => {
try {
return await playbackObj.setStatusAsync({
shouldPlay: false,
rate: 0.9749090909,
});
} catch (error) {
console.log('error inside pause helper method', error.message)
}
};
//resume
export const resume = async playbackObj => {
try {
return await playbackObj.playAsync(
);
} catch (error) {
console.log('error inside pause resume method', error.message)
}
};
//select next
export const playNext = async (playbackObj, uri) => {
try {
await playbackObj.stopAsync()
await playbackObj.unloadAsync();
return await play(playbackObj, uri);
} catch (error) {
console.log('error inside playNext helper method')
}
}

Why is InterstitialAd not loaded after the first trigger?

I manage to get the first ad to show, but app crashed the next time I try to trigger an ad. And gives me this error: Error: InterstitialAd.show() The requested InterstitialAd has not loaded and could not be shown
In App.js
componentDidMount() {
const eventListener = interstitial.onAdEvent(type => {
if (type === AdEventType.LOADED) {
this.setState({
setLoaded: true,
});
}
});
interstitial.load();
eventListener();
}
showAds = () => {
interstitial.show();
// No advert ready to show yet
if (!this.state.loaded) {
console.log('null');
return null;
}
};
// This trigger is within another function
this.showAds();
I have a class component so I use ComponentDidMount instead of useEffect. Might that cause some troubles?
UPDATE:
this.state = {
loaded: false,
setLoaded: false,
Listener: null,
};
The above state is an attempt to redo
const [loaded, setLoaded] = useState(false);
constructor () {
super();
this.Listener=null
}
componentDidMount() {
this.Listener = interstitial.onAdEvent(type => {
if (type === AdEventType.LOADED) {
this.setState({
loaded: true,
});
}else if(type === AdEventType.CLOSED){
this.loadAd()
}
});
this.loadAd()
}
componentWillUnmount(){
if(this.Listener!==null){
this.Listener()
}
}
loadAd = () =>{
this.setState({
loaded: false,
});
interstitial.load();
}
showAds = () => {
if (!this.state.loaded) {
console.log('null');
return null;
}else{
interstitial.show();
}
};

How to Navigate to Screen after GPS been enabled?

When the User is enabled the GPS I want to navigate it to AuthScreen.js. I'm using react-native-navigation v1 but there is no feature that can navigate just to simple screen, only push and modal but I don't want to use it.
Also using this: react-native-android-location-services-dialog-box
Here are my codes:
componentDidMount() {
this.gpsLocation();
}
gpsLocation = () => {
if (Platform.OS === 'android') {
LocationServicesDialogBox.checkLocationServicesIsEnabled({
message: "<h2>Use Location?</h2> \
This app wants to change your device settings:<br/><br/>\
Use GPS for location<br/><br/>",
ok: "Yes",
cancel: "No",
style: {
backgroundColor: '#4f6d7a',
positiveButtonTextColor: '#000000',
negativeButtonTextColor: '#000000'
},
enableHighAccuracy: true,
showDialog: true,
openLocationServices: true,
preventOutSideTouch: true,
preventBackClick: true,
providerListener: true
}).then(function(success) {
console.log(success)
// return <AuthScreen/>
}).catch((error) => {
console.log(error.message);
});
};
DeviceEventEmitter.addListener('locationProviderStatusChange', function(status) {
console.log(status);
});
};
componentWillUnmount() {
LocationServicesDialogBox.stopListener();
};
render() {
if(!this.state.nextScreen) {
return (
<View style={styles.container}>
</View>
);
} else {
return <AuthScreen/>
}
};
If you really don't want to navigate, you can use the .then() callback in which you're already logging the success parameter. According to the doc, success is an object with the following structure:
{
alreadyEnabled: false,
enabled: true,
status: "enabled"
}
You just need to check if success.enabled is true and if that's the case call setState({ nextScreen : true });
Edit: Here's the code, as requested:
// MyView.js
componentDidMount()
{
this.checkOrRequestLocationPermission();
}
checkOrRequestLocationPermission()
{
if (Platform.OS === 'android')
{
LocationServicesDialogBox.checkLocationServicesIsEnabled({
// Your config
// ...
})
.then(result => {
if (result.enabled)
{
this.setState({
nextScreen : true
});
}
// The above could be replaced by this
// this.setState({
// nextScreen : result.enabled
// });
})
.catch(error => {
console.warn('Error requesting location permission ' + error);
});
}
}
render() {
if(!this.state.nextScreen) {
return (
<View style={styles.container} />
);
}
else {
return <AuthScreen/>
}
};

react native async getting data when running app first time

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.

Undefined is not an object (evaluating 'items.reduce)

Here my codes :
Voice.onSpeechStart = this.onSpeechStart.bind(this);
Voice.onSpeechRecognized = this.onSpeechRecognized.bind(this);
Voice.onSpeechResults = this.onSpeechResults.bind(this);}
componentWillUnmount() {
Voice.destroy().then(Voice.removeAllListeners);}
onSpeechStart(e) {
this.setState({
started: "√"}
);}
onSpeechRecognized(e) {
this.setState({
recognized: "√"
});
}
onSpeechResults(e) {
this.setState({results: e.value});
if(matchSorter(this.setState.results,'login now') === 'login now'){
this.props.navigation.navigate("Dashboard");
}
else {
ToastAndroid.show("Please Try Again", ToastAndroid.SHORT);
}
}
async _startRecognition(e) {
this.setState({
recognized: "",
started: "",
results: []
});
try {
await Voice.start("en-US");
} catch (e) {
console.error(e);
}
render() {
return (
<Text>Say "Login now"</Text>
<TouchableOpacity
onPress={this._startRecognition.bind(this)}>
<Text> TAP HERE </Text>}
and this error coming out :
Error Image from Android-based Mobile:
*The output of "this.setState.results" when I say login now is "blogging nowlogging nowlogin nowjogging nowlog in now".
When you tried to retrive value from state then you have to write code like : this.state.VARIBLENAME. You have this.setState.VARIBLENAME which is wrong.
Correction from your code:
if(matchSorter(this.state.results,'login now') === 'login now'){
this.props.navigation.navigate("Dashboard");
}
Your whole code:
Voice.onSpeechStart = this.onSpeechStart.bind(this);
Voice.onSpeechRecognized = this.onSpeechRecognized.bind(this);
Voice.onSpeechResults = this.onSpeechResults.bind(this);}
componentWillUnmount() {
Voice.destroy().then(Voice.removeAllListeners);}
onSpeechStart(e) {
this.setState({
started: "√"}
);}
onSpeechRecognized(e) {
this.setState({
recognized: "√"
});
}
onSpeechResults(e) {
this.setState({results: e.value});
if(matchSorter(this.state.results,'login now') === 'login now'){
this.props.navigation.navigate("Dashboard");
}
else {
ToastAndroid.show("Please Try Again", ToastAndroid.SHORT);
}
}
async _startRecognition(e) {
this.setState({
recognized: "",
started: "",
results: []
});
try {
await Voice.start("en-US");
} catch (e) {
console.error(e);
}
render() {
return (
<Text>Say "Login now"</Text>
<TouchableOpacity
onPress={this._startRecognition.bind(this)}>
<Text> TAP HERE </Text>
}
You can replace the code and it will work for you.