How to detect hold and fastforward event in react native TVEventHandler - android

I am new to React Native. I want to know how can implement press and hold event for seek.
I am able to get fastForward and press right events in React native layer by using below code.
_enableTVEventHandler() {
this._tvEventHandler = new TVEventHandler();
this._tvEventHandler.enable(this, function(cmp, evt) {
if (evt && evt.eventType === 'right') {
cmp.setState({board: cmp.state.board.move(2)});
} else if(evt && evt.eventType === 'up') {
cmp.setState({board: cmp.state.board.move(1)});
} else if(evt && evt.eventType === 'left') {
cmp.setState({board: cmp.state.board.move(0)});
} else if(evt && evt.eventType === 'down') {
cmp.setState({board: cmp.state.board.move(3)});
} else if(evt && evt.eventType === 'playPause') {
cmp.restartGame();
}
});
}
Not able to get the hold fastforward or hold and right event to detect seek event. I am not sure it if its possible in RN layer. If not then how can i do the same in Android layer.
Thanks in advance

you could try something like this where eventKeyAction is an integer value that represents button press(down/up).where "key up" is 1, "key down" is 0.
so you could use that to serve your purpose
const [isfastForwarding, setisfastForwarding] = useState(false);
const _enableTVEventHandler = () => {
_tvEventHandler = new TVEventHandler();
_tvEventHandler.enable(this, (cmp, { eventType, eventKeyAction }) => {
// eventKeyAction is an integer value representing button press(key down) and release(key up). "key up" is 1, "key down" is 0.
if (eventType === "fastForward" && eventKeyAction === 0) {
setisfastForwarding(true);
}
if (eventType === "fastForward" && eventKeyAction === 1) {
setisfastForwarding(false);
}
});
};
you can also add some delay if you wish to

Related

How to achieve custom BackHandler behavior only under a certain condition?

I have a flatlist in my application and I want to enable a user to mark a particular list item as selected on Long press and provide a delete button to remove multiple items in one go. These are the behaviors I expect.
If no items in the flatlist are selected, pressing an item opens a new screen with item details and back button takes you back to the flatlist.
If no items are selected, long pressing an item marks it as selected. Every item pressed after any particular item is selected is marked as selected instead of opening the details screen.
Items which are already selected and then pressed become unselected.
If any number of items are selected, a delete button is rendered and pressing the back button unselects all items.
I have been able to achieve most of the first three behaviors but I am completly lost with the Back Handler. Here is my component with only the relevant code for brevity. Only the state array which contains the items selected for deletion and the listItem which is used as the RenderItem prop for the flatlist is shown.
const Home = (props) => {
const [deleteItems, setDeleteItems] = useState([]);
const renderItem = ({ item }) => {
let bb_OR_ub = item.useBy ? 'Use By ' : 'Best Before '
let exp_check = CheckExp(item, 1);
let listStyle = {};
if (exp_check === -1)
listStyle = { backgroundColor: '#ff9ea5' }
else if (exp_check === 0)
listStyle = { backgroundColor: '#fff185' }
if (deleteItems.indexOf(item.name) != -1) {
listStyle = { opacity: 0.3 }
}
return (
<ListItem
containerStyle={listStyle}
badge={
exp_check !== 1 ?
exp_check === -1 ? { status: 'error', value: `!` } : {
status: 'warning'
} : null
}
title={item.name}
subtitle={bb_OR_ub + item.date}
bottomDivider
leftAvatar={{ source: require('../shared/cexp.png'), imageProps: { resizeMode: 'contain' } }}
onPress={() => {
if (deleteItems.length == 0)
navigate('ExpiryDetails', { item })
else {
setDeleteItems([...deleteItems, item.name])
}
}}
onLongPress={() => {
if (deleteItems.indexOf(item.name) == -1 || deleteItems.length == 0) {
setDeleteItems([...deleteItems, item.name])
}
else {
setDeleteItems(deleteItems.filter(el => el != item.name))
}
}} />
);
}
The BackHandler provided by react-native allows you to subscribe to back button being pressed. The callback provided to backhandler can provide either true (when the default behavior should not trigger) or false (when the default behavior is allowed to continue).
For your case, we want to have custom behavior on back when there are items selected, at that moment we want to unselect all items.
I adjusted your code to introdcue the BackHandler and unselect any items on back being pressed
const Home = (props) => {
const [deleteItems, setDeleteItems] = useState([]);
// Subscribe to BackHandler once the component is mounted
// or when deletedItems changes
useEffect(() => {
const handler = BackHandler.addEventListener('hardwareBackPress', () => {
// If no deleted items: we return false
if (!deletedItems.length) {
return false;
}
// clear the selected items, and indicate that the back if handled
setDeletedItems([]);
return true;
});
// unsubscribe when component unmounts
return () => {
handler.remove();
};
}, [deletedItems]);
const renderItem = ({ item }) => {
let bb_OR_ub = item.useBy ? 'Use By ' : 'Best Before '
let exp_check = CheckExp(item, 1);
let listStyle = {};
if (exp_check === -1)
listStyle = { backgroundColor: '#ff9ea5' }
else if (exp_check === 0)
listStyle = { backgroundColor: '#fff185' }
if (deleteItems.indexOf(item.name) != -1) {
listStyle = { opacity: 0.3 }
}
return (
<ListItem
containerStyle={listStyle}
badge={
exp_check !== 1 ?
exp_check === -1 ? { status: 'error', value: `!` } : {
status: 'warning'
} : null
}
title={item.name}
subtitle={bb_OR_ub + item.date}
bottomDivider
leftAvatar={{ source: require('../shared/cexp.png'), imageProps: { resizeMode: 'contain' } }}
onPress={() => {
if (deleteItems.length == 0)
navigate('ExpiryDetails', { item })
else {
setDeleteItems([...deleteItems, item.name])
}
}}
onLongPress={() => {
if (deleteItems.indexOf(item.name) == -1 || deleteItems.length == 0) {
setDeleteItems([...deleteItems, item.name])
}
else {
setDeleteItems(deleteItems.filter(el => el != item.name))
}
}} />
);
}

React Native: Active state in AppState listener getting triggered when component mounts

I have set up a listener for AppState in React Native to know when my app switches from background to foreground so I can show a splash screen.
useEffect(() => {
AppState.addEventListener('change', handleAppStateChange);
},[])
const handleAppStateChange = newState => {
if (newState === 'active') {
RNBootSplash.show();
}
};
The problem is, and this only happens when I compile a release APK, for some reason it works fine in debug, the splash screen is showing each time the component mounts, while it should only trigger when the app is switched into the active state from background. Any help?
Using React Native 61.5
Try this way :
const [appState, setAppState] = React.useState(AppState.currentState)
useEffect(() => {
AppState.addEventListener('change', handleAppStateChange)
setAppState(AppState.currentState)
return AppState.removeEventListener('change')
},[])
const handleAppStateChange = newState => {
if (appState.match(/inactive|background/) && newState === 'active') {
console.log('App has come to the foreground!')
// Show the splash screen
RNBootSplash.show()
} else {
console.log('App has gone to the background!')
// do something in background
}
setAppState(newState)
}
Only thing that worked was using refs
const latestAppState = React.useRef(AppState.currentState)
const handleAppStateChange = newState => {
if (latestAppState.current.match(/inactive|background/) && newState === 'active') {
RNBootSplash.show();
}
latestAppState.current = newState
}

Delay access to property in ionic 2 class

I have a non static traduction file that I periodically get from a server. I cannont change the format of the file.
When I a new page is instanciate in my Ionic App I set this.traductions from a value in storage. See constructor below :
constructor(storage: Storage, public navCtrl: NavController, public navParams: NavParams, public commandeService: CommandeService, public alertCtrl: AlertController, public translate: TranslateService) {
this.categorie = this.navParams.get('categorie');
storage.get('boissons').then((StringBoissons) => {
var boissons: Array<any> = JSON.parse(StringBoissons);
this.boissons = boissons.filter(
(value) => {
return value.tboi_id == this.categorie.tboi_id;
});
}
);
storage.get('traductions').then((val) => {
this.traductions = JSON.parse(val);
});
this.commande = commandeService.getCommande();
this.translate = translate;
}
Then my View call getTraduction(...)
getTraduction(table, champ, id, objet) {
var traduction = this.traductions.find( (value) => {
return value.trad_table == table && value.trad_champ == champ && value.trad_code_langue == this.translate.currentLang && value.trad_id_item == objet[id];
});
if ( traduction && traduction.trad_texte )
return traduction.trad_texte;
else
return objet[champ];
}
Everything works fine in browser preview but on device I get a
Cannot call method 'find' of null
at t.getTraduction
I think it is due to asynchronous results but I can't quite get my head around it and figure how to solve this.
Thanks in advance for any insight
OK quite dumb question actually Sylvain :
You should have put your getTraduction function in a provider.
#Injectable()
export class TraductionDynaService {
traductions;
constructor(
public storage: Storage,
public http: Http,
public translate: TranslateService,
) {
storage.get('traductions').then((val) => {
this.traductions = JSON.parse(val);
});
}
getTraduction(table, champ, id, objet) {
var traduction = this.traductions.find( (value) => {
return value.trad_table == table && value.trad_champ == champ && value.trad_code_langue == this.translate.currentLang && value.trad_id_item == objet[id];
});
if ( traduction && traduction.trad_texte )
return traduction.trad_texte;
else
return objet[champ];
}
}
And it worked like a charm. getTraduction(...) could even return a promise to handle when traduction is null or undefined...

Appcelerator Android Camera always make application force close

I make an apps using Appcelerator (Titanium SDK).
and I have a problem when open camera, I already set camera permission in tiapp.xml.
And I've try use a source from kitchen Sink titanium.
Here's my code
var win;
function fireUpTheCamera() {
if (Ti.Platform.osname === 'android'|| Ti.Platform.osname == "iphone" || Ti.Platform.osname == 'ipad') {
win.removeEventListener('focus', fireUpTheCamera);
}
Titanium.Media.showCamera({
success:function(event) {
var cropRect = event.cropRect;
var image = event.media;
Ti.API.debug('Our type was: '+event.mediaType);
if(event.mediaType == Ti.Media.MEDIA_TYPE_PHOTO)
{
var imageView = Ti.UI.createImageView({
width:win.width,
height:win.height,
image:event.media
});
win.add(imageView);
}
else
{
alert("got the wrong type back ="+event.mediaType);
}
},
cancel:function() {
},
error:function(error) {
// create alert
var a = Titanium.UI.createAlertDialog({title:'Camera'});
// set message
if (error.code == Titanium.Media.NO_CAMERA)
{
a.setMessage('Please run this test on device');
}
else
{
a.setMessage('Unexpected error: ' + error.code);
}
// show alert
a.show();
},
saveToPhotoGallery:true,
allowEditing:true,
mediaTypes:[Ti.Media.MEDIA_TYPE_PHOTO]
});
}
function cam_basic(_args) {
win = Titanium.UI.createWindow({
title:_args.title
});
if (Ti.Platform.osname === 'android'|| Ti.Platform.osname == "iphone" || Ti.Platform.osname == 'ipad') {
win.addEventListener('focus', fireUpTheCamera);
} else {
fireUpTheCamera();
}
return win;
};
module.exports = cam_basic;
when I finish capture picture and press the OK button, it's always restart application without any error message, also in the log.
I'm using SDK 6.0.0GA.
Please give me some help, and what's wrong with my code.
Before firing up the camera you have to ask the end user for permissions. I'm using this snippet and it works with Ti-5.4.0.
if(Ti.Media.hasCameraPermissions())
fireUpTheCamera();
else
{
Ti.Media.requestCameraPermissions(function(permission)
{
if(permission.success)
fireUpTheCamera();
else
alert('Please Provide permission first');
});
}
Since Titanium sdk 5.1 you need to request runtime permission as well to use the camera.
See here: http://docs.appcelerator.com/platform/latest/#!/api/Titanium.Media-method-requestCameraPermissions

Why the the httpInterceptor got rejected when the App starts even when there is network?

I'm using the following code to show a message when there is no network. It works well when testing the app in airplane mode. However, it always shows the popup even when there is network when the app code start (rejection.status === 0). How to workaround it?
.config(function($provide, $httpProvider) {
$provide.factory('httpInterceptor', function($q, $injector) {
return {
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
var interactiveService = $injector.get('interactiveService');
if (rejection.status === 0 || rejection.status === -1) {
interactiveService.showPopup('The internet is disconnected on your device.' + rejection.status);
}
return $q.reject(rejection);
}
};
});
$httpProvider.interceptors.push('httpInterceptor');
})
If it helps try this
.config(function($provide, $httpProvider) {
$provide.factory('httpInterceptor', function($q, $injector) {
return {
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
var interactiveService = $injector.get('interactiveService');
/************** New code starts*******/
var networkState = navigator.connection.type;
if(networkState === Connection.NONE){
interactiveService.showPopup('The internet is disconnected on your device.' + rejection.status);
}
/************** New code ends*******/
return $q.reject(rejection);
}
};
});
$httpProvider.interceptors.push('httpInterceptor');
})

Categories

Resources