LocalNotification in Xamarin Forms not always received - xamarin.forms

I’m developing a mobile app in Xamarin Forms.
I have develop local notifications using the latest versione of
https://github.com/thudugala/Plugin.LocalNotification
Many times notifications work great, but sometimes notifications are not received/sended or sometimes notifications are recevied all together in a wrong moment compared to the scheduled time.
Most of the tests were made on iOS on real devices.
The code I use is more or less this:
var notification = new NotificationRequest
{
NotificationId = idNotific,
Title = "myApp",
Description = txt,
ReturningData = "myData",
Schedule =
{
NotifyTime = timeToTake,
RepeatType = NotificationRepeat.TimeInterval,
NotifyRepeatInterval = new TimeSpan(intervalDays,0,0,0)
}
};
LocalNotificationCenter.Current.Show(notification);
if (Device.RuntimePlatform == Device.iOS)
{
var notificationNext = new NotificationRequest
{
NotificationId = idNotific,
Title = "myApp",
Description = txt,
ReturningData = "myData",
Schedule =
{
NotifyTime = timeToTake,
}
};
LocalNotificationCenter.Current.Show(notificationNext);
}
For iOS, using TimeInterval, I had to add an extra schedule because otherwise the first notification is not sended.
The “idNotific” is a big integer number, “timeToTake” is a DateTime and “intervalDays” is a small integer.
I'm trying to figure out why they sometimes don't work properly.
I tried to understand if there is a something different from when notifications work and from then don't work, but apparently it's all the same.
Do you have any suggestions? Do you need more info?
Thanks
Luca

Related

sqlite3 seems to be slow

im currently writing a electron App. I wanted to use a SQLite Datebase to store some data. I got a Code like this:
var startTime = performance.now()
let sql = `UPDATE entry
SET
title = "someData",
url = "someData",
username = "someData",
password = "someData",
email = "someData",
note = "someData",
dateOfLastModification = "someData"
WHERE id=someId;`;
this.database.run(sql, (err, data) => {
if (err) {
console.log(err);
} else {
var endTime = performance.now()
console.log(`Call to updateEntry took ${endTime - startTime} milliseconds`)
}
});
Every time i call this code it, it needs more than 200ms. Isnt this too long for such a easy Query? I got other Queries that need nearly the same time. So if i got a behavior in my app that executes three Queries the user have to wait nearly 1 sec.
Any tips what im doing wrong?

Xamarin Forms - Geofencing with Shiny not triggering when in geofence

I have created a xamarin forms application and one of the requirements is as follows: The user should be able to press a button and create a geofence. When the geofence is created, the application constantly checks if the user is in a geofence. It that's true, the mobile app should show a notification sayinf: you have entered geofence.
I use Shiny to implement the feature based on this tutorial: "https://allancritchie.net/posts/shiny-geofencing".
But the problem is that it isn't doing anything. I have set the geofence 50 meters from my house, and the radius for checking to 200 meter, so when I build the app, a couple of seconds/minuts I should receive a nofitication right? Or do I need to go out of the fence first and then in? How can I fix this issue...
my code:
// shiny doesn't usually manage your viewmodels, so we'll do this for now
var geofences = ShinyHost.Resolve<IGeofenceManager>();
var notifications = ShinyHost.Resolve<INotificationManager>();
Register = new Command(async () =>
{
// this is really only required on iOS, but do it to be safe
var access = await notifications.RequestAccess();
if (access == AccessState.Available)
{
await geofences.StartMonitoring(new GeofenceRegion(
"CN Tower - Toronto, Canada",
new Position(52.079779, 4.337133),
Distance.FromMeters(200)
)
{
NotifyOnEntry = true,
NotifyOnExit = true,
SingleUse = false
});
}
});
public class GeofenceDelegate : IGeofenceDelegate
{
private readonly INotificationManager _notifications;
public GeofenceDelegate(INotificationManager notifications)
{
_notifications = notifications;
}
public async Task OnStatusChanged(GeofenceState newStatus, GeofenceRegion region)
{
if (newStatus == GeofenceState.Entered)
{
await GeofenceEntered(region);
}
else if (newStatus == GeofenceState.Exited)
{
await GeofenceLeft(region);
}
}
}
I have exactly the same code as the tutorial, and the geofence is created when I click a button if I debug it. So everything looks fine to me..
I had a similar issue and just assumed that when you start inside a fence it won't recognize you as entering/or exiting since you are already inside it.
I had to walk out/in of the created fence to trigger the 'OnStatusChanged' method.
Important to note is, that it wouldn't enter the method unless my app activated the phones GPS-system (e.g. re-requesting the current position periodically), but im not sure if that is caused by my old ass phone (running Android6.1) or if it is mend to work that way.
Also note, that i didn't use the shiny.notifications and just showed a popup when the method was run (for testing purposes) like this:
public async Task OnStatusChanged(GeofenceState newStatus, GeofenceRegion region)
{
await Application.Current.MainPage.DisplayAlert(newStatus.ToString(), $"{region.Identifier}", "Ok");
}
Hope this helps ;)

Initiate Appmaker Document Approval from Google Drive

I've customized Document Management System template in Appmaker as per my needs. Now instead of going to Appmaker every time to initiate an approval I want to provide functionality to initiate the workflow from Google Drive.So users can select file for Approval directly from Google Drive.
My question is is there any Rest call or something via which I can initiate DMS workflow from Third party app?
Well I found a way out to achieve the result.
Steps:
Drive API provides a way to add your App in 'Open With' menu in Google Drive.
So I've created my custom app and deployed it. This app will simply receive params from Google Drive 'Open with' menu and pass it to Appmaker Document Approval System.
In Appmaker Create request page parse if request contains these params, if yes then select files using these params.
This way my users can initiate the Document Approval Workflow from Google Drive.
References :
How to add/list your App in Google Drive
Step by Step video guideline to Create and publish your App
Code:
'Open With' App code for redirecting users from Google Drive to Appmaker.
code.gs:
var AUTHORIZE_URL = 'https://accounts.google.com/o/oauth2/auth';
var TOKEN_URL = 'https://accounts.google.com/o/oauth2/token';
var REDIRECT_URL= ScriptApp.getService().getUrl();
var tokenPropertyName = 'GOOGLE_OAUTH_TOKEN';
var CLIENT_ID = 'your client id';
var CLIENT_SECRET = 'your client secrect';
function doGet(e) {
var HTMLToOutput;
if(e.parameters.state){
var state = JSON.parse(e.parameters.state);
if(state.action === 'create'){
HTMLToOutput = "<html><h1>Creation Of Docs Not supported by this App!</h1></html>";
}
else {
var id = state.exportIds;
var file = DriveApp.getFileById(id);
//append params to your appmaker URL
var url = 'yourappmaker published url'+'?param1='+file.getName()+'&param2='+file.getUrl()+'#AddRequest';
HTMLToOutput = HtmlService.createHtmlOutput('<html><script>'
+'window.close = function(){window.setTimeout(function(){google.script.host.close()},9)};'
+'var a = document.createElement("a"); a.href="'+url+'"; a.target="_blank";'
+'if(document.createEvent){'
+' var event=document.createEvent("MouseEvents");'
+' if(navigator.userAgent.toLowerCase().indexOf("firefox")>-1){window.document.body.append(a)}'
+' event.initEvent("click",true,true); a.dispatchEvent(event);'
+'}else{ a.click() }'
+'close();'
+'</script>'
// Offer URL as clickable link in case above code fails.
+'<body style="word-break:break-word;font-family:sans-serif;">Failed to open automatically. Click here to proceed.</body>'
+'<script>google.script.host.setHeight(40);google.script.host.setWidth(410)</script>'
+'</html>')
.setWidth( 90 ).setHeight( 1 );
}
}
else if(e.parameters.code){//if we get "code" as a parameter in, then this is a callback. we can make this more explicit
getAndStoreAccessToken(e.parameters.code);
HTMLToOutput = '<html><h1>App is installed, you can close this window now or navigate to your Google Drive.</h1></html>';
}
else {//we are starting from scratch or resetting
HTMLToOutput = "<html><h1>Install this App into your Google Drive!</h1><a href='"+getURLForAuthorization()+"'>click here to start</a></html>";
}
console.log(getURLForAuthorization());
return HtmlService.createHtmlOutput(HTMLToOutput);
}
function getURLForAuthorization(){
return AUTHORIZE_URL + '?response_type=code&client_id='+CLIENT_ID+'&redirect_uri='+REDIRECT_URL +
'&scope=https://www.googleapis.com/auth/drive.install https://www.googleapis.com/auth/userinfo.email';
}
function getAndStoreAccessToken(code){
var parameters = { method : 'post',
payload : 'client_id='+CLIENT_ID+'&client_secret='+CLIENT_SECRET+'&grant_type=authorization_code&redirect_uri='+REDIRECT_URL+'&code=' + code};
var response = UrlFetchApp.fetch(TOKEN_URL,parameters).getContentText();
var tokenResponse = JSON.parse(response);
UserProperties.setProperty(tokenPropertyName, tokenResponse.access_token);
}
function getUrlFetchOptions() {
return {'contentType' : 'application/json',
'headers' : {'Authorization' : 'Bearer ' + UserProperties.getProperty(tokenPropertyName),
'Accept' : 'application/json'}};
}
//naive check, not using for now, use refresh tokens and add proper checking
function isTokenValid() {
return UserProperties.getProperty(tokenPropertyName);
}
In Document workflow 'Create Request' page, add event to onAttach() method. Write below function,
//client side
function checkIfRedirected(widget)
{
// console.log(location.origin);
google.script.url.getLocation(function(location) {
var params = location.parameter;
var param1 = params.param1;
var param2 = params.param2;
widget.datasource.item.DocumentName = param1;
widget.datasource.item.DocumentUrl = param2;
widget.datasource.item.Owner = app.user.email;
});
}

onCreate send email to self in AppMaker?

Still learning about app maker and found this presentation at Google I/O '17 "Build Powerful Custom Apps Fast with App Maker on G Suite"
At timestamp 15.24 sec some code is shown on the screen showing how to send an email to yourself once someone creates a new item can.
https://youtu.be/Q84HQgI3Dd8?t=15m27s
Question
Can anyone advise where and how this code can be implemented its pretty cool and would be a great feature to add when a record is created
Thanks in advance and no worries if you cant help
You are looking for model events:
https://developers.google.com/appmaker/models/events
In App Maker models typically have onCreate, onSave, onLoad, onDelete events. It is the best place to handle email notifications. Here is a link to App Script email API:
https://developers.google.com/apps-script/reference/mail/mail-app
I strongly recommend you to go to the Codelab for App Maker. The section Building a form to send an email describes the whole process.
The steps to highlight are:
Step 11 - Set the onClick property of the button as a custom action with the code:
var widgets = widget.parent.descendants;
var to = widgets.To.value;
var subject = widgets.Subject.value;
var msg = widgets.Msg.value;
widgets.EmailStatus.text = 'Sending email...';
SendEmail(to, subject, msg)
Step 13 - Add the following ClientScript code:
function clearEmailForm(){
var formWidgets = app.pages.Basic.descendants;
formWidgets.EmailStatus.text = "";
formWidgets.Msg.value = "";
formWidgets.To.value = "";
formWidgets.Subject.value = "";
}
function SendEmail(To, Subject, Msg){
var status = app.pages.Basic.descendants.EmailStatus;
google.script.run.withSuccessHandler(function(result) {
status.text = 'Email sent...';
clearEmailForm();
})
.SendEmail(To, Subject, Msg);
}
Step 14 - Now add the corresponding code to the ServerScript.
function SendEmail(to, subject, msg){
MailApp.sendEmail(to, subject , msg);
}

angularFire startAt querying and binding deletes new data

The application shows work-shifts for certain time-period. firebaseConn.getShifts is the API-function to get the shiftData for the given time period.
versions:
firebase: 2.0.6
angularFire: 0.9.0 (confirmed with 0.8.2 also)
This is my firebase schema:
And this is the code:
.factory('watchers', function(bunch-of-dependencies) {
var unbindShifts = function() {};
var inited = false;
var shifts = {};
... some irrelevant code in between ...
function initShifts() {
unbindShifts();
shifts.object = firebaseConn.getShifts( false, from, to, $scope );
$scope.shifts = shifts.object;
shifts.object.$bindTo($scope, "shifts").then(function(unbind) {
unbindShifts = unbind;
});
}
The firebase-queries (that have worked fine before adding the unbind / bind and possibly time-based querying might cause issues too):
firebaseConn.getShifts = function(asArray, from, to, scope) {
return cacheRequest(FBURL + "shifts", asArray, [from, to]);
};
function cacheRequest(url, asArray, limits) {
var type = asArray ? "array" : "object";
var startAt = limits ? limits[0] : undefined;
var endAt = limits ? limits[1] : undefined;
var retObj, FBRef;
cached[url] = cached[url] || {};
/* If there are limits-parameters we don't cache at all atm. Since those queries should be checked differently than static urls */
if(!limits && cached[url][type]) {
FBRef = cached[url][type];
} else {
FBRef = cached[url][type] = createFBRef(url, startAt, endAt);
}
if(asArray) {
retObj = FBRef.$asArray();
} else {
retObj = FBRef.$asObject();
}
return retObj;
}
function createFBRef(resourceURL, startAt, endAt) {
var modifiedObject = $firebase( createRef( resourceURL ).orderByKey().startAt(startAt).endAt(endAt) );
return modifiedObject;
}
function createRef(resourceURL) {
return new Firebase( resourceURL );
}
Now I have located the problem to be with the query limiting. If the from and to Dates are undefined, this works without problems. But I need to be able to limit the amount of data, since loading many years of workshift-data, to show a weeks time, won't be good :).
The actual problem is not displaying and fetching the data, everything works fine, it's related to the times and re-binding.
If I do any changes to e.g. "20150115"-table. For example I add another "groups"-child there. When i unbind and rebind, the whole "20150115"-table gets deleted and this holds true only to the latest changes. If I add multiple child to different dates e.g. "20150113", "20150114", "20150115" and the latest change is in "20150115" and then I unbind + re-bind another time from firebase, all the other root-paths will stay as they are, but the latest change in "20150115" will make the whole tree deleted.
I hope I make myself clear, so for safety I try to explain it again in simpler way.
- Changes to 1. "20150113", 2. "20150114", 3. "20150115" through the app.
- Changing timeline from UI causes: unbind + re-bind
- As a side-effect the whole "20150114" tree gets deleted.
The problem is somehow related to advanced querying with orderByKey().startAt(startAt).endAt(endAt) and binding.
Also for additional info. The data which is added through the UI gets added to the firebase database, but when the re-binding happens, the data is deleted from the database. Specifically on rebind, unbinding causes no issues, if I delay rebinding with timeout.
EDIT:
I have found the source of the actual issue. After the new binding is in place and everything seems to be in order, there is an angular watch event that kicks in. The event tries to save the last change user made before re-binding.
So if I have and active timeline for december (20141201 - 20141230) and I change "20141225"-data. Then change the timeline to 20150101 - 20150130, causing unbind and rebind (or manually fetching new data). There will be an event, after the binding has been done and everything seems to be in order, trying to save 20141225 data to either the new timeline (20150101 - 20150130) or the old one, not sure which one. This causes the firebase to actually delete the whole 20141225-tree, instead of saving the data.
The new data makes it into your Firebase fine, which you can see by either checking your Firebase dashboard or by running a quick snippet like this in your browser's dev console:
new Firebase("https://firebaseurl").once('value', function(s) { console.log(s.val()); })
The data even makes it back into your application. The only problem is that Angular doesn't know that new data has arrived, so it doesn't update the view with the new data.
Normally AngularFire's $asObject and $asArray methods take care of notifying AngularJS when new data arrives from Firebase. But since you are constantly creating new queries, you'll have to take care of that yourself.
There are a few ways to signal the new data to AngularJS and I'm definitely not an expert on which one is best. But if you add $scope.$apply(); to your setDays function it works:
function setDays(ref) {
var FBRange = setFBRange(ref, from, to);
var days;
unbindDays();
days = $firebase(FBRange).$asObject();
$scope.days = days;
days.$bindTo($scope, "days").then(function(unbind) {
unbindDays = unbind;
// As a result of the new binding entry gets mysteriously deleted from firebase
});
$scope.$apply(); // Tell AngularJS about the new data, so that it updates the view
function setFBRange(ref, from, to) {
return ref.orderByKey().startAt(""+from).endAt(from + to + "");
}
}
Updated Plunkr with this change (and some others to help in debugging): http://plnkr.co/edit/YZtkzUNtjQUCcw4xb2mj?p=preview

Resources