Reputation: 471
What I want is to display a Image if user does not interact with the app for 1 minute. I have tried implementing it by setting timers on all the user events like onPress onSwipe etc on all the elements. But handling those is a complex process. Then I tried out using InteractionManager but that also didn't work out. What I want to know is there any way I can get to know if any user event has occurred?
Upvotes: 10
Views: 16641
Reputation: 872
I created module react-native-inactivity
for this purpose. By using this module you can actually get if the app is inactive for 1 minute. You can use in this way.
import ReactNativeInactivity from "react-native-inactivity";
export default function App() {
const [showImage, setShowImage] = React.useState(false);
return (
<View style={{ flex: 1 }}>
<ReactNativeInactivity
isActive={true}
onInactive={() => setShowImage(true)}
timeForInactivity={60000} //1 mint in ms
restartTimerOnActivityAfterExpiration={false}
loop={false}
style={{ flex: 1, justifyContent: "center", alignItems: "center", backgroundColor: "grey" }}>
<YOUR_NAV_HERE/>
</ReactNativeInactivity>
{ showImage ? <YourImage /> : null }
</View>
);
}
You can also manage other props according to your requirement. Even After showing the image you can actually deactivate the timer through state if you wish.
If this solution helped you just thumbs up and give me a star at repository. For more refer to: https://www.npmjs.com/package/react-native-inactivity
Upvotes: 0
Reputation: 341
Here is how I implemented inactive listener with react-navigation Custom Navigator. I used react-native PanResponder to detect touch activities. Since this is mounted to the root of the app, there won't be any issues with mounting setTimout in multiple places.
import React, {useCallback, useEffect, useRef} from 'react';
import {useKeycloak} from '@react-keycloak/native';
import {
NavigationHelpersContext,
useNavigationBuilder,
StackRouter,
} from '@react-navigation/native';
import {View, PanResponder} from 'react-native';
const CustomNavigator = ({initialRouteName, children, screenOptions}) => {
const {state, navigation, descriptors} = useNavigationBuilder(StackRouter, {
children,
screenOptions,
initialRouteName,
});
const [keycloak] = useKeycloak();
const timerId = useRef(false);
useEffect(() => {
resetInactivityTimeout();
}, [resetInactivityTimeout]);
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponderCapture: () => {
resetInactivityTimeout();
},
}),
).current;
const resetInactivityTimeout = useCallback(() => {
clearTimeout(timerId.current);
timerId.current = setTimeout(() => {
// action after user has been detected idle
// ex: logout from the app
}, 30000);
}, []);
return (
<NavigationHelpersContext.Provider value={navigation}>
<View style={{flex: 1}} {...panResponder.panHandlers}>
{descriptors[state.routes[state.index].key].render()}
</View>
</NavigationHelpersContext.Provider>
);
};
export default CustomNavigator;
Upvotes: 3
Reputation: 471
Finally, I did it using PanResponder. And It works flawlessly. It takes key presses ans swipes and drags.
Expo Link : https://snack.expo.io/Sy8ulr8B-
Here is my code:
import React, { Component } from 'react';
import { Button, PanResponder, View, StyleSheet,TouchableOpacity, Text , Image} from 'react-native';
export default class App extends Component {
state = {
show : false
};
_panResponder = {};
timer = 0;
componentWillMount() {
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => {
this.resetTimer()
return true
},
onMoveShouldSetPanResponder: () => true,
onStartShouldSetPanResponderCapture: () => { this.resetTimer() ; return false},
onMoveShouldSetPanResponderCapture: () => false,
onPanResponderTerminationRequest: () => true,
onShouldBlockNativeResponder: () => false,
});
this.timer = setTimeout(()=>this.setState({show:true}),5000)
}
resetTimer(){
clearTimeout(this.timer)
if(this.state.show)
this.setState({show:false})
this.timer = setTimeout(()=>this.setState({show:true}),5000)
}
render() {
return (
<View
style={styles.container}
collapsable={false}
{...this._panResponder.panHandlers}>
{
this.state.show ? <Text style={{fontSize:30}}>Timer Expired : 5sec</Text> : null
}
<TouchableOpacity>
<Image style={{width: 300, height: 300}} source={{uri: 'https://facebook.github.io/react/img/logo_og.png'}} />
</TouchableOpacity>
<Button
title="Here is a button for some reason"
onPress={() => {}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
}
});
Upvotes: 13