Preventing every push notification being executed iOS titanium - ios

If I get multiple push notifications whilst app is in foreground. The callback method will execute every push notification one by one.
callback : function(e) {
if (e.inBackground == 1) {
//came from background - do something.
} else {
// Titanium.UI.iPhone.setAppBadge(null);
//check type, if it is chat.
if (type == 'chat') {
//check if window is already opened or not, if so fire event handler
if (currentWindow == '_chatWindow') {
//update view directly after entering app from the background. Fire event handler
Ti.App.fireEvent('_updateChat', {});
} else if (currentWindow == '_messages') {
//refresh messages screen if on messages screen and chat message arrives
//update view directly after entering app from the background. Fire event handler
Ti.App.fireEvent('_updateMessages', {});
} else {
//display local notification
}
}
If the push notification has come from the background it is easy to deal with, as the push notification that is activated is the one the user chooses to swipe. However, if multiple push notifications come into the foreground and say it's chat, it will execute them multiple times.
How can I handle push notifications in the foreground better? Thanks
Update:
tried this code without much luck
Ti.App.addEventListener('_displayNotification', function(e) {
//store all push notifications in array
var pushArray = [];
var countPushNotifications;
//currentTime to cross reference
var currentTime = new Date();
if (currentTime - Alloy.Globals.pushTime < 3000) {
//do something
pushArray.add(e.PushNotificationData);
} else {
//after 3 seconds remove event handler
//fire event to filter array and process notification, reset time for next event
Alloy.Globals.pushTime = null;
Ti.App.removeEventListener('_displayNotification', {});
}
//first push notification, will be the current time
if(Alloy.Globals.pushTime==null){
Alloy.Globals.pushTime = currentTime;
}
});
Trying to get all the push notifications inside the array, for further filtering.
Update 2:
if (Alloy.Globals.countPushNotificationsFlag == 1) {
Alloy.Globals.countPushNotificationsFlag = null;
setTimeout(function() {
Ti.App.fireEvent('_displayNotification', {
PushMessage : message
});
}, 6000);
} else {
Alloy.Globals.countPushNotificationsFlag = 1;
Ti.App.fireEvent('_displayNotification', {
PushMessage : message
});
}
I have tried to execute push notifications alternatively.
1st notification - fires instantly.
2nd notification - fires after 6 seconds.
3rd notification - instantly.
4th notification - fires after 6 seconds.
and so on...
however the code only works for
notification 1 and 2.
Fails when it hits the 3rd notification.

you can check if Push is received in foreground or background using inBackground Property of push here is the documentation
Hope it helps.

I haven't got the Titanium experience to give you actual code, but this is the approach you need to take:
When you receive a notification, check to see if a (global) boolean receivedNotification is false
If it is false, set it to true, store the event into a global and schedule a setTimeout function for, say, 3 seconds, to process the event and reset receivedNotification to false
If receivedNotification is true, update the global event to the newer notification
In the process event method that is triggered via the timer your will do what you currently do in the first section of code.
This will ensure that the event is processed no longer than 3 seconds after it is received and that events will be processed, at most, once every three seconds.
Your code looks pretty close, except you are trying to fire the first event immediately and then subsequent events after a delay. Unfortunately I don't believe that this is possible, because you have no way of seeing if there are events queued immediately. I think that you are always going to have to incur the delay, but you can tune the delay to find a balance between responsiveness and reduced API calls -
if (Alloy.Globals.countPushNotificationsFlag == null) {
Alloy.Globals.countPushNotificationsFlag = 1;
Alloy.Globals.messageToPush=message;
setTimeout(function() {
Alloy.Globals.countPushNotificationsFlag = null;
Ti.App.fireEvent('_displayNotification', {
PushMessage : Alloy.Globals.messageToPush
});
}, 3000);
}
else {
Alloy.Globals.messageToPush=message;
}

Related

Send Local Notification when Timer reaches zero SwiftUI

Learning SwiftUI. I have an app that counts down timers from 30 min. As the timer doesn't work when the app is in the background, I have used user notification to get the current time app goes into the background and the time it comes to the foreground and subtracts the difference between those two times from the countdown timer I have going on so it reflects the time that has passed. Everything works fine. However, I need to be able to send a notification when the timer reaches zero.
As the timer is suspended every time the app goes into the background and the difference between how much time has passed is only calculated when the app comes into the foreground, I'm not able to find a way to send a notification when the timer reaches zero ( as the difference is only calculated when the app is in the foreground ) which negates the whole point of sending notification to let the user know the timer has ended.
Is there a way to figure out how to send a notification when the timer has reached zero without the app coming into the foreground? or any way to keep the timer running in the background so I can check if the timer has reached zero to send a notification?
Snippet of the code:
HStack {
// some code
}
.onReceive(NotificationCenter.default.publisher(
for: UIScene.didEnterBackgroundNotification)) { _ in
if isTimerStarted {
movingToBackground()
}
}
.onReceive(NotificationCenter.default.publisher(
for: UIScene.didActivateNotification)) { _ in
if isTimerStarted {
movingToForeground()
}
}
// the functions created:
func movingToBackground() {
print("Moving to the background")
notificationDate = Date()
fbManager.pause()
}
func movingToForeground() {
print("Moving to the foreground")
let deltaTime: Int = Int(Date().timeIntervalSince(notificationDate))
let deltaTimefill : Double = Double(deltaTime) / Double(300)
fbManager.breakElapsed -= deltaTime
if fbManager.breakElapsed <= 0 {
notify.sendNotification(
date: Date(),
type: "time",
timeInterval: 5,
title: "AppName+",
body: "Your timer has ended")
}
fbManager.breakFill += deltaTimefill
fbManager.startBreak()
}
Let me know if you need more code.
You can queue up the notification at any time, with the date parameter set to when you want it to be displayed.

Zendesk web widget status not correctly updating and button not hiding

I'm loading the Zendesk web widget into a page, and this is the event handler for when it's loaded in
scriptElement.onload = function () {
zE(function () {
$zopim(function () {
$zopim.livechat.button.setHideWhenOffline(true);
$zopim.livechat.setOnStatus(function (status) {
console.log('status',status);
status === 'online' ? $zopim.livechat.button.show() : $zopim.livechat.button.hide();
});
$zopim.livechat.setStatus('offline');
});
});
};
It has the setOnStatus event handler which should trigger anytime the status changes. It seems to be triggered once when the page initially loads in. You'd expect it to be triggered as well everytime I call the setStatus method, but that's not the case. Where I log the status, it's always just 'online', and it only happens once.
What I'm trying to do is force the button to disappear when the status is offline. Yet setting the status to 'offline' doesn't hide the button, just displays the offline version (i.e. a button which lets me send an offline message, rather than a live chat).
I thought the setHideWhenOffline method might have helped, but that doesn't seem to make any difference in this case.
Any ideas?
Actually I found the solution I needed here, this prevents the offline button appearing.
window.zESettings = {
webWidget: {
contactForm: {
suppress: true
}
}
};
https://developer.zendesk.com/embeddables/docs/widget/settings#suppress

How can I know when UNUserNotificationCenter's removeAllPendingNotificationRequests() has completed?

The iOS docs say that UNUserNotificationCenter's removeAllPendingNotificationRequests() is asynchronous.
What I want to do is this:
Call removeAllPendingNotificationRequests() to get rid of all my scheduled notifications
Schedule a bunch of new notifications, some of which may or may not have the same IDs as what was there previously
But since the documentation says that the method is asynchronously running on another thread (and there is no completion callback parameter) I'm worried that sometimes, depending on the vagaries of threads and timing and whatnot, that step #1 will still be going as I am creating things in step 2 and therefore it will also kill some of the new notifications I'm making.
This kind of stuff is a little tricky to test manually, since it depends on timing. So I'm curious is anyone knows if this is something I should be worried about or not...
In documentation for add notification I found this:
Calling -addNotificationRequest: will replace an existing notification
request with the same identifier.
Maybe the solution would be something like this:
Create new notification requests
Get all pending and filter out only the ones that will not be replaced
Delete not replaced
Add all new notifications
let center = UNUserNotificationCenter.current()
// Create new requests
let newRequests: [UNNotificationRequest] = [...]
let identifiersForNew: [String] = newRequests.map { $0.identifier }
center.getPendingNotificationRequests { pendingRequests in
// Get all pending notification requests and filter only the ones that will not be replaced
let toDelete = pendingRequests.filter { !identifiersForNew.contains($0.identifier) }
let identifiersToDelete = toDelete.map { $0.identifier }
// Delete notifications that will not be replaced
center.removePendingNotificationRequests(withIdentifiers: identifiersToDelete)
// Add all new requests
for request in newRequests {
center.add(request, withCompletionHandler: nil)
}
}
I have the same case as you and up to know I don't have a problem with this code:
center.getPendingNotificationRequests(completionHandler: { notifications in
var notificationIds:[String] = []
for notification in notifications {
if notification.identifier != "something_taht_I_dont_dismiss"{
notificationIds.append(notification.identifier)
}
}
self.center.removePendingNotificationRequests(withIdentifiers: notificationIds)
createAllNewNotifications()
})
If you want to double check all if the pending notifications are removed you can create simple recursion method for checking.
func removeAllNotificationsSafe() {
center.removeAllPendingNotificationRequests()
checkNotificationsAreRemoved()
}
func checkNotificationsAreRemoved() {
center.getPendingNotificationRequests(completionHandler: { notifications in
if notifications.count > 0 {
self.checkNotificationsAreRemoved()
} else {
self.doWhathverYouWant()
}
}
}
I don't believe this is needed, because all the actions of UNUserNotificationCenter will be synchronized between each other.

Cannot delete local notifications in Appcelerator Titanium for iOS

I developed an app for a client in which the user can set local notifications. The issue is when the user tries to delete the alarm/notification from their list, the notification still fires (for repeating alarms). I've tried to cancel all notifications on load and then setting each one notification up again as well as other methods, but nothing seems to work. Is there a solution to this? Has anyone else experienced this? It should be a pretty basic task to accomplish.
Here's the code I'm using to remove the notification from the server db as well as from within the phone's local notification storage:
tbl.addEventListener('delete',function(e){
var rowIndex = e.rowIndex;
tbl.deleteRow(rowIndex);
var appReq = Ti.Network.createHTTPClient();
appReq.open('POST', app.appurl + 'actions.php');
//LOAD
appReq.onload = function(){
Ti.API.info(this.responseText);
var appResp = JSON.parse(this.responseText);//JSON resp
if(appResp.rsp == 'OK')
{
app.alarms[e.rowData.cancel_id].cancel();
view.getAlarms();
}else
{
alert(appResp.msg);
}
};
//ERROR
appReq.onerror = function(e){
Ti.API.info(e.error);
};
//DATA
var data = {
id:e.rowData.id,
action:'removealarm'
};
//SEND
Ti.API.info('sending: ' + JSON.stringify(data));
appReq.send(data);
});
**NOTE: This code seemed to work for my device but not the client's, I just need to make sure this would be the proper method.
To cancel all pending notifications, call the Ti.App.iOS.cancelAllLocalNotifications() method.

Why Cordova resume event is not firing in power lock mode / Sleep mode in iOS using sencha

In my application if user lock the mobile.I need to navigate to login screen.I have implemented resume event to navigate login screen if user unlock the device.can anybody tell Why Cordova resume event is not firing in power lock mode / Sleep mode in iOS
is there any other event i need to use in lock mode?
P.S It is working in minimizing the app and maximizing the app
Although in IOS a resume event is fired when minimizing or maximizing an app by pressing the home button, it appears that a resume event is not fired when "closing" or "staring" the app by pressing the power button at least in IOS.
A possible JS-solution might be to check for inactivity. Let's say when an app has not not received any events triggered by an user for some time(30 seconds and if no real pause-event has been fired since) for instance click/touch-events then it can be assumed that the app can still execute some code(so it's still in foreground) and is "paused":
// threshold for inactivity state
var idleTimeout = 30000;
// variable that holds the time in seconds, which indicates how long the app has not received certain events
var timeInSecondsPassed = 0;
// interval instance
var intervalInstance = null;
// variable to handle the transition from "pause" to "resume" state
var inPauseState = false;
function startPauseListener() {
timeInSecondsPassed = 0;
var resetPassedTime = function(){
timeInSecondsPassed = 0;
// has the app reached the "pause" state and
// currently receiving certain events -> the "resume" state is reached
if(inPauseState){
inPauseState = false;
// the "resume" state is reached here
// so the same code might be executed here as it is in the resume-listener
}
};
document.ontouchstart = resetPassedTime;
document.onclick = resetPassedTime;
document.onscroll = resetPassedTime;
document.onkeypress = resetPassedTime;
intervalInstance = setInterval(checkPauseState,1000);
}
function clearPauseListener() {
clearInterval(intervalInstance);
timeInSecondsPassed = 0;
}
function checkPauseState() {
timeInSecondsPassed += 1000;
if (timeInSecondsPassed >= idleTimeout) {
inPauseState = true;
timeInSecondsPassed = 0;
// run further code here to handle "pause" state
// at this point it is assumed as soon as the app receives click/touch-events again a "resume" state is reached.
}
}
function onDeviceReady() {
// handle android devices so that the interval is stopped when a real pause event is fired and started when a real resume event is fired
document.addEventListener("resume", function(){
startPauseListener();
// your actual code to handle real resume events
}, false);
document.addEventListener("pause", function(){
clearPauseListener();
}, false);
}
It has to be noted that when the app is really paused so a pause event is fired the code above is not run in IOS but in android so that's why you might have to handle this szenario in android differently by taking advandage of both resume and pause-Listener for in android when the app is minimized by the home button the interval would still be executed and consumes CPU in the background.
And please also note that it's only a kind of concept-code and not tested in any device!!!
Hope this helps.
There's an iOS-specific event called active that "detects when users disable the Lock button to unlock the device with the app running in the foreground".
Check the documentation at the bottom of the resume doc page:
https://cordova.apache.org/docs/en/5.1.1/cordova/events/events.resume.html

Resources