Commit 5b7238a2 by Sebastián Katzer

Update to latest dev

parent e62fff29
{
"_args": [
[
{
"raw": "cordova-windows@~5.0.0",
"scope": null,
"escapedName": "cordova-windows",
"name": "cordova-windows",
"rawSpec": "~5.0.0",
"spec": ">=5.0.0 <5.1.0",
"type": "range"
},
"/Users/sebastian/Documents/github/cordova-example-local-notifications/node_modules"
]
],
"_from": "cordova-windows@>=5.0.0 <5.1.0",
"_from": "cordova-windows@^5.0.0",
"_id": "cordova-windows@5.0.0",
"_inCache": true,
"_inBundle": false,
"_integrity": "sha1-fWRTk+byEstL0XFWcZlFSEzudf4=",
"_location": "/cordova-windows",
"_nodeVersion": "7.2.0",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/cordova-windows-5.0.0.tgz_1486749384153_0.040384991792961955"
},
"_npmUser": {
"name": "kotikov.vladimir",
"email": "kotikov.vladimir@gmail.com"
},
"_npmVersion": "3.10.9",
"_phantomChildren": {},
"_requested": {
"raw": "cordova-windows@~5.0.0",
"scope": null,
"escapedName": "cordova-windows",
"type": "range",
"registry": true,
"raw": "cordova-windows@^5.0.0",
"name": "cordova-windows",
"rawSpec": "~5.0.0",
"spec": ">=5.0.0 <5.1.0",
"type": "range"
"escapedName": "cordova-windows",
"rawSpec": "^5.0.0",
"saveSpec": null,
"fetchSpec": "^5.0.0"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/cordova-windows/-/cordova-windows-5.0.0.tgz",
"_shasum": "7d645393e6f212cb4bd17156719945484cee75fe",
"_shrinkwrap": null,
"_spec": "cordova-windows@~5.0.0",
"_where": "/Users/sebastian/Documents/github/cordova-example-local-notifications/node_modules",
"_spec": "cordova-windows@^5.0.0",
"_where": "/Users/sebastian/Documents/github/cordova-example-local-notifications",
"author": {
"name": "Apache Software Foundation"
},
......@@ -75,6 +51,7 @@
"shelljs": "^0.5.3",
"winjs": "^4.4.0"
},
"deprecated": false,
"description": "cordova-windows release",
"devDependencies": {
"istanbul": "^0.4.0",
......@@ -82,11 +59,6 @@
"jshint": "^2.8.0",
"rewire": "^2.5.1"
},
"directories": {},
"dist": {
"shasum": "7d645393e6f212cb4bd17156719945484cee75fe",
"tarball": "https://registry.npmjs.org/cordova-windows/-/cordova-windows-5.0.0.tgz"
},
"homepage": "https://github.com/apache/cordova-windows#readme",
"keywords": [
"windows",
......@@ -95,60 +67,7 @@
],
"license": "Apache-2.0",
"main": "template/cordova/Api.js",
"maintainers": [
{
"name": "apachebuilds",
"email": "root@apache.org"
},
{
"name": "bowserj",
"email": "bowserj@apache.org"
},
{
"name": "cmarcelk",
"email": "cmarcelk@gmail.com"
},
{
"name": "filmaj",
"email": "maj.fil@gmail.com"
},
{
"name": "kamrik",
"email": "kamrik@gmail.com"
},
{
"name": "kotikov.vladimir",
"email": "kotikov.vladimir@gmail.com"
},
{
"name": "nikhilkh",
"email": "nikhil.khandelwal@gmail.com"
},
{
"name": "purplecabbage",
"email": "purplecabbage@gmail.com"
},
{
"name": "sgrebnov",
"email": "sergei.grebnov@gmail.com"
},
{
"name": "shazron",
"email": "shazron@gmail.com"
},
{
"name": "stevegill",
"email": "stevengill97@gmail.com"
},
{
"name": "timbarham",
"email": "npmjs@barhams.info"
}
],
"name": "cordova-windows",
"optionalDependencies": {},
"readme": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements. See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership. The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License. You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied. See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n\n#Apache Cordova for Windows\n\n[![Build status](https://ci.appveyor.com/api/projects/status/19h1fq0lyvwtei05/branch/master)](https://ci.appveyor.com/project/Humbedooh/cordova-windows/branch/master)\n[![Build Status](https://travis-ci.org/apache/cordova-windows.svg?branch=master)](https://travis-ci.org/apache/cordova-windows)\n[![codecov.io](https://codecov.io/github/apache/cordova-windows/coverage.svg?branch=master)](https://codecov.io/github/apache/cordova-windows?branch=master)\n\nThis repo contains the code for an [Apache Cordova](http://cordova.apache.org) platform that allows you to build applications that target Windows 10, and Windows 8.1, as well as Windows Phone 8.1. An Apache Cordova based applications is written in HTML, CSS and JavaScript.\n\n(Warning: Windows 8 has been deprecated, please update your applications to target Windows 8.1 or above)\n\n[Apache Cordova](http://cordova.apache.org) is a project of [The Apache Software Foundation (ASF)](http://apache.org)\n\n#Requirements\n### Windows 10, Windows 8.1, Windows Phone 8.1\n\nHost OS: Windows 8.1 or Windows 10\n\nInstall the tools: [Visual Studio 2015](http://www.visualstudio.com/downloads)\n\n### Windows 8.1,Windows Phone 8.1\n\nHost OS: Windows 8.1\n\nInstall the tools: [Visual Studio 2013 Express](http://www.visualstudio.com/downloads/download-visual-studio-vs#d-express-windows-8).\n\n#Getting started\nThe best way to use this is to install the [Cordova CLI](https://www.npmjs.com/package/cordova), create a project, add the windows platform, and run the app:\n\n\tnpm install -g cordova\n\tcordova create test\n\tcordova platform add windows\n\tcordova run windows\n\n#Getting logs from Windows Store applications\nYou can get your JavaScript logs as well as Windows logs related to your Windows Store application by running the following command from your app directory:\n\n\tplatforms\\windows\\cordova\\log\n\nIn most cases, this command requires administrator privileges. However, if you want to gather logs without admin privileges, you may need to manually enable logging channel via Event Viewer:\n\n\tStart -> Run -> eventvwr\n\tView -> Show Analytic and Debug Logs\n\tApplications and Services Logs -> Microsoft -> Windows -> AppHost -> AppTracing -> Enable Log\n\nPlease note that the log command is supported only for Windows Store applications and cannot get logs from Windows Phone application.\n\n#Report Issues\nReport them at the [Apache Cordova Issue Tracker](https://issues.apache.org/jira/browse/CB). Create a user account, use `windows` as the component.\n\n#Further Reading\n- [Windows Platform Guide](http://cordova.apache.org/docs/en/edge/guide_platforms_win8_index.md.html#Windows%208%20Platform%20Guide)\n- [Apache Cordova Documentation](http://docs.cordova.io)\n",
"readmeFilename": "README.md",
"repository": {
"type": "git",
"url": "git+https://github.com/apache/cordova-windows.git"
......
......@@ -2,4 +2,22 @@
<Bucket
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "../../../cordova-plugin-local-notifications/src/ios/APPNotificationContent.m"
timestampString = "526314552.870829"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "102"
endingLineNumber = "102"
landmarkName = "-request"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>
......@@ -26,9 +26,9 @@
@interface APPLocalNotification : CDVPlugin <UNUserNotificationCenterDelegate>
// Set launchDetails object
- (void) launchDetails:(CDVInvokedUrlCommand*)command;
- (void) launch:(CDVInvokedUrlCommand*)command;
// Execute all queued events
- (void) deviceready:(CDVInvokedUrlCommand*)command;
- (void) ready:(CDVInvokedUrlCommand*)command;
// Check permission to show notifications
- (void) check:(CDVInvokedUrlCommand*)command;
......@@ -40,8 +40,8 @@
// Schedule notifications
- (void) schedule:(CDVInvokedUrlCommand*)command;
//// Update set of notifications
//- (void) update:(CDVInvokedUrlCommand*)command;
// Update set of notifications
- (void) update:(CDVInvokedUrlCommand*)command;
// Clear notifications by id
- (void) clear:(CDVInvokedUrlCommand*)command;
// Clear all notifications
......
......@@ -30,6 +30,7 @@
@property (readonly, getter=subtitle) NSString* subtitle;
@property (readonly, getter=badge) NSNumber* badge;
@property (readonly, getter=text) NSString* text;
@property (readonly, getter=silent) BOOL silent;
@property (readonly, getter=sound) UNNotificationSound* sound;
@property (readonly, getter=userInfo) NSDictionary* userInfo;
@property (readonly, getter=actions) NSArray<UNNotificationAction *> * actions;
......
......@@ -61,18 +61,6 @@
#pragma mark Properties
/**
* The type for the notification.
*
* @return [ NSString* ]
*/
- (NSString*) triggerType
{
NSString* type = [dict objectForKey:@"trigger"];
return type.length ? type : @"normal";
}
/**
* The ID for the notification.
*
* @return [ NSNumber* ]
......@@ -127,6 +115,16 @@
}
/**
* Show notification in foreground.
*
* @return [ BOOL ]
*/
- (BOOL) silent
{
return [[dict objectForKey:@"silent"] boolValue];
}
/**
* The badge number for the notification.
*
* @return [ NSNumber* ]
......@@ -280,12 +278,12 @@
*/
- (UNNotificationTrigger*) trigger
{
NSString* type = [self triggerType];
NSString* type = [self valueForTriggerOption:@"type"];
if ([type isEqualToString:@"location"])
return [self triggerWithRegion];
if (![type isEqualToString:@"date"])
if (![type isEqualToString:@"calendar"])
NSLog(@"Unknown type: %@", type);
if ([self isRepeating])
......@@ -315,6 +313,11 @@
#pragma mark -
#pragma mark Private
- (id) valueForTriggerOption:(NSString*)key
{
return [[dict objectForKey:@"trigger"] objectForKey:key];
}
/**
* The date when to fire the notification.
*
......@@ -322,8 +325,7 @@
*/
- (NSDate*) triggerDate
{
double timestamp = [[dict objectForKey:@"at"]
doubleValue];
double timestamp = [[self valueForTriggerOption:@"at"] doubleValue];
return [NSDate dateWithTimeIntervalSince1970:timestamp];
}
......@@ -335,7 +337,7 @@
*/
- (BOOL) isRepeating
{
id every = [dict objectForKey:@"every"];
id every = [self valueForTriggerOption:@"every"];
if ([every isKindOfClass:NSString.class])
return ((NSString*) every).length > 0;
......@@ -364,7 +366,7 @@
*/
- (UNNotificationTrigger*) repeatingTrigger
{
id every = [dict objectForKey:@"every"];
id every = [self valueForTriggerOption:@"every"];
if ([every isKindOfClass:NSString.class])
return [self triggerWithDateMatchingComponents];
......@@ -382,7 +384,7 @@
*/
- (UNTimeIntervalNotificationTrigger*) triggerWithTimeInterval
{
long interval = [[dict objectForKey:@"every"] longValue];
long interval = [[self valueForTriggerOption:@"every"] longValue];
if (interval < 60) {
NSLog(@"time interval must be at least 60 if repeating");
......@@ -438,8 +440,8 @@
*/
- (UNLocationNotificationTrigger*) triggerWithRegion
{
NSArray* center = [dict objectForKey:@"center"];
double radius = [[dict objectForKey:@"radius"] doubleValue];
NSArray* center = [self valueForTriggerOption:@"center"];
double radius = [[self valueForTriggerOption:@"radius"] doubleValue];
CLLocationCoordinate2D coord =
CLLocationCoordinate2DMake([center[0] doubleValue], [center[1] doubleValue]);
......@@ -449,8 +451,8 @@
radius:radius
identifier:self.identifier];
region.notifyOnEntry = [[dict objectForKey:@"notifyOnEntry"] boolValue];
region.notifyOnExit = [[dict objectForKey:@"notifyOnExit"] boolValue];
region.notifyOnEntry = [[self valueForTriggerOption:@"notifyOnEntry"] boolValue];
region.notifyOnExit = [[self valueForTriggerOption:@"notifyOnExit"] boolValue];
return [UNLocationNotificationTrigger triggerWithRegion:region repeats:YES];
}
......@@ -472,7 +474,7 @@
*/
- (NSCalendarUnit) repeatInterval
{
NSString* interval = [dict objectForKey:@"every"];
NSString* interval = [self valueForTriggerOption:@"every"];
NSCalendarUnit units = NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
if ([interval isEqualToString:@"minute"])
......@@ -504,7 +506,7 @@
- (NSDateComponents*) customDateComponents
{
NSDateComponents* date = [[NSDateComponents alloc] init];
NSDictionary* every = [dict objectForKey:@"every"];
NSDictionary* every = [self valueForTriggerOption:@"every"];
for (NSString* key in every) {
long value = [[every valueForKey:key] longValue];
......
......@@ -27,6 +27,8 @@
// The options provided by the plug-in
- (APPNotificationOptions*) options;
// If the notification was updated
- (BOOL) wasUpdated;
// Encode the user info dict to JSON
- (NSString*) encodeToJSON;
......
......@@ -65,6 +65,16 @@ static char optionsKey;
}
/**
* If the notification was updated.
*
* @return [ BOOL ]
*/
- (BOOL) wasUpdated
{
return [self.content userInfo][@"updatedAt"] != NULL;
}
/**
* Encode the user info dict to JSON.
*/
- (NSString*) encodeToJSON
......
......@@ -28,7 +28,8 @@ extern NSString * const kAPPGeneralCategory;
typedef NS_ENUM(NSUInteger, APPNotificationType) {
NotifcationTypeAll = 0,
NotifcationTypeScheduled = 1,
NotifcationTypeTriggered = 2
NotifcationTypeTriggered = 2,
NotifcationTypeUnknown = 3
};
#define APPNotificationType_DEFINED
......@@ -44,15 +45,10 @@ typedef NS_ENUM(NSUInteger, APPNotificationType) {
// List of all notification IDs from given type
- (NSArray*) getNotificationIdsByType:(APPNotificationType)type;
// Find out if notification with ID exists
- (BOOL) notificationExist:(NSNumber*)id;
// Find out if notification with ID and type exists
- (BOOL) notificationExist:(NSNumber*)id type:(APPNotificationType)type;
// Find notification by ID
- (UNNotificationRequest*) getNotificationWithId:(NSNumber*)id;
// Find notification by ID and type
- (UNNotificationRequest*) getNotificationWithId:(NSNumber*)id andType:(APPNotificationType)type;
// Find notification type by ID
- (APPNotificationType) getTypeOfNotificationWithId:(NSNumber*)id;
// Property list from all local notifications
- (NSArray*) getNotificationOptions;
......@@ -60,8 +56,6 @@ typedef NS_ENUM(NSUInteger, APPNotificationType) {
- (NSArray*) getNotificationOptionsById:(NSArray*)ids;
// Property list from all local notifications with type constraint
- (NSArray*) getNotificationOptionsByType:(APPNotificationType)type;
// Property list from given local notifications with type constraint
- (NSArray*) getNotificationOptionsByType:(APPNotificationType)type andId:(NSArray*)ids;
// Clear specified notfication
- (void) clearNotification:(UNNotificationRequest*)notification;
......
......@@ -185,29 +185,6 @@ NSString * const kAPPGeneralCategory = @"GENERAL";
return ids;
}
/*
* If the notification with the specified ID does exists.
*
* @param id
* Notification ID
*/
- (BOOL) notificationExist:(NSNumber*)id
{
return [self getNotificationWithId:id] != NULL;
}
/* If the notification with specified ID and type exists.
*
* @param id
* Notification ID
* @param type
* Notification life cycle type
*/
- (BOOL) notificationExist:(NSNumber*)id type:(APPNotificationType)type
{
return [self getNotificationWithId:id andType:type] != NULL;
}
/**
* Find notification by ID.
*
......@@ -216,34 +193,39 @@ NSString * const kAPPGeneralCategory = @"GENERAL";
*/
- (UNNotificationRequest*) getNotificationWithId:(NSNumber*)id
{
return [self getNotificationWithId:id andType:NotifcationTypeAll];
}
/*
* Find notification by ID and type.
*
* @param id
* Notification ID
* @param type
* Notification life cycle type
*/
- (UNNotificationRequest*) getNotificationWithId:(NSNumber*)id andType:(APPNotificationType)type
{
NSArray* notifications = [self getNotificationsByType:type];
NSArray* notifications = [self getNotifications];
for (UNNotificationRequest* notification in notifications)
{
NSString* fid = [NSString stringWithFormat:@"%@", notification.options.id];
if ([fid isEqualToString:[id stringValue]]) {
return notification;
}
}
return NULL;
}
/**
* Find notification type by ID
*/
- (APPNotificationType) getTypeOfNotificationWithId:(NSNumber*)id
{
NSArray* ids = [self getNotificationIdsByType:NotifcationTypeTriggered];
if ([ids containsObject:id])
return NotifcationTypeTriggered;
ids = [self getNotificationIdsByType:NotifcationTypeScheduled];
if ([ids containsObject:id])
return NotifcationTypeScheduled;
return NotifcationTypeUnknown;
}
/**
* List of properties from all notifications.
*/
- (NSArray*) getNotificationOptions
......@@ -278,29 +260,16 @@ NSString * const kAPPGeneralCategory = @"GENERAL";
*/
- (NSArray*) getNotificationOptionsById:(NSArray*)ids
{
return [self getNotificationOptionsByType:NotifcationTypeAll andId:ids];
}
/**
* List of properties from given local notifications.
*
* @param type
* Notification life cycle type
* @param ids
* Notification IDs
*/
- (NSArray*) getNotificationOptionsByType:(APPNotificationType)type andId:(NSArray*)ids
{
NSArray* notifications = [self getNotificationsByType:type];
NSArray* notifications = [self getNotifications];
NSMutableArray* options = [[NSMutableArray alloc] init];
for (UNNotificationRequest* notification in notifications)
{
if ([ids containsObject:notification.options.id]) {
[options addObject:notification.options.userInfo];
}
}
return options;
}
......
......@@ -84,41 +84,38 @@ exports.schedule = function (msgs, callback, scope, args) {
}
};
// /**
// * Update existing notifications specified by IDs in options.
// *
// * @param {Object} notifications
// * The notification properties to update
// * @param {Function} callback
// * A function to be called after the notification has been updated
// * @param {Object?} scope
// * The scope for the callback function
// * @param {Object?} args
// * skipPermission:true schedules the notifications immediatly without
// * registering or checking for permission
// */
// exports.update = function (msgs, callback, scope, args) {
// var fn = function(granted) {
// if (!granted) return;
// var notifications = Array.isArray(msgs) ? msgs : [msgs];
// for (var i = 0; i < notifications.length; i++) {
// var notification = notifications[i];
// this.convertProperties(notification);
// }
// this.exec('update', notifications, callback, scope);
// };
// if (args && args.skipPermission) {
// fn.call(this, true);
// } else {
// this.registerPermission(fn, this);
// }
// };
/**
* Schedule notifications.
*
* @param [ Array ] notifications The notifications to schedule.
* @param [ Function ] callback The function to be exec as the callback.
* @param [ Object ] scope The callback function's scope.
* @param [ Object ] args Optional flags how to schedule.
*
* @return [ Void ]
*/
exports.update = function (msgs, callback, scope, args) {
var fn = function(granted) {
if (!granted) return;
var notifications = Array.isArray(msgs) ? msgs : [msgs];
for (var i = 0; i < notifications.length; i++) {
var notification = notifications[i];
this.convertProperties(notification);
}
this.exec('update', notifications, callback, scope);
};
if (args && args.skipPermission) {
fn.call(this, true);
} else {
this.requestPermission(fn, this);
}
};
/**
* Clear the specified notifications by id.
......
......@@ -29,14 +29,14 @@ exports._defaults = {
text: '',
title: '',
sound: 'res://platform_default',
trigger: 'date',
badge: undefined,
data: undefined,
every: undefined,
at: undefined,
icon: undefined,
trigger: { type: 'calendar' },
actions: [],
actionGroupId: undefined,
attachments: []
attachments: [],
progressBar: false
};
// Listener
......@@ -59,12 +59,6 @@ exports.applyPlatformSpecificOptions = function () {
defaults.led = undefined;
defaults.color = undefined;
break;
case 'iOS':
defaults.region = undefined;
defaults.radius = undefined;
defaults.notifyOnEntry = true;
defaults.notifyOnExit = false;
break;
}
};
......@@ -78,7 +72,6 @@ exports.applyPlatformSpecificOptions = function () {
exports.mergeWithDefaults = function (options) {
var defaults = this.getDefaults();
options.at = this.getValueFor(options, 'at', 'firstAt', 'date');
options.text = this.getValueFor(options, 'text', 'message');
options.data = this.getValueFor(options, 'data', 'json');
......@@ -90,10 +83,6 @@ exports.mergeWithDefaults = function (options) {
options.autoClear = false;
}
if (options.at === undefined || options.at === null) {
options.at = new Date();
}
for (var key in defaults) {
if (options[key] === null || options[key] === undefined) {
if (options.hasOwnProperty(key) && ['data','sound'].indexOf(key) > -1) {
......@@ -106,7 +95,7 @@ exports.mergeWithDefaults = function (options) {
for (key in options) {
if (!defaults.hasOwnProperty(key)) {
delete options[key];
// delete options[key];
console.warn('Unknown property: ' + key);
}
}
......@@ -149,21 +138,13 @@ exports.convertProperties = function (options) {
}
}
if (options.at) {
if (typeof options.at == 'object') {
options.at = options.at.getTime();
}
options.at = Math.round(options.at/1000);
}
if (typeof options.data == 'object') {
options.data = JSON.stringify(options.data);
}
if (options.actions) {
this.convertActions(options);
}
this.convertTrigger(options);
this.convertActions(options);
this.convertProgressBar(options);
return options;
};
......@@ -199,6 +180,82 @@ exports.convertActions = function (options) {
options.category = (options.category || 'DEFAULT_GROUP').toString();
options.actions = actions;
return options;
};
/**
* Convert the passed values for the trigger to their required type.
*
* @param [ Map ] options Set of custom values.
*
* @return [ Map ] Interaction object with trigger spec.
*/
exports.convertTrigger = function (options) {
var cfg = options.trigger,
isDate = Date.prototype.isPrototypeOf(cfg),
isObject = Object.prototype.isPrototypeOf(cfg),
trigger = !isDate && isObject ? cfg : {},
date = this.getValueFor(trigger, 'at', 'firstAt', 'date');
if (!trigger.type) {
trigger.type = trigger.center ? 'location' : 'calendar';
}
var isCal = trigger.type == 'calendar';
if (isCal && !date) {
date = this.getValueFor(options, 'at', 'firstAt', 'date') || new Date();
}
if (isCal) {
date = typeof date == 'object' ? date.getTime() : date;
trigger.at = Math.round(date / 1000);
}
if (isCal && !trigger.every && options.every) {
trigger.every = options.every;
}
if (!trigger.count && device.platform == 'windows') {
trigger.count = trigger.every ? 5 : 1;
}
if (trigger.every && device.platform == 'windows') {
trigger.every = trigger.every.toString();
}
if (!isCal) {
trigger.notifyOnEntry = !!trigger.notifyOnEntry;
trigger.notifyOnExit = trigger.notifyOnExit === true;
trigger.radius = trigger.radius || 5;
}
delete options.every;
delete options.at;
delete options.firstAt;
delete options.date;
options.trigger = trigger;
return options;
};
/**
* Convert the passed values for the progressBar to their required type.
*
* @param [ Map ] options Set of custom values.
*
* @return [ Map ] Interaction object with trigger spec.
*/
exports.convertProgressBar = function (options) {
var cfg = options.progressBar;
if (typeof cfg === 'boolean') {
options.progressBar = { enabled: cfg };
}
return options;
};
/**
......@@ -306,13 +363,13 @@ exports.exec = function (action, args, callback, scope) {
channel.deviceready.subscribe(function () {
// Device is ready now, the listeners are registered
// and all queued events can be executed.
exports.exec('deviceready');
exports.exec('ready');
});
// Called before 'deviceready' event
channel.onCordovaReady.subscribe(function () {
// Set launchDetails object
exports.exec('launchDetails');
exports.exec('launch');
// Device plugin is ready now
channel.onCordovaInfoReady.subscribe(function () {
// Merge platform specifics into defaults
......
......@@ -58,22 +58,19 @@ exports.schedule = function (notifications, callback, scope, args) {
this.core.schedule(notifications, callback, scope, args);
};
// /**
// * Update existing notifications specified by IDs in options.
// *
// * @param {Object} notifications
// * The notification properties to update
// * @param {Function} callback
// * A function to be called after the notification has been updated
// * @param {Object?} scope
// * The scope for the callback function
// * @param {Object?} args
// * skipPermission:true schedules the notifications immediatly without
// * registering or checking for permission
// */
// exports.update = function (notifications, callback, scope, args) {
// this.core.update(notifications, callback, scope, args);
// };
/**
* Update notifications.
*
* @param [ Array ] notifications The notifications to schedule.
* @param [ Function ] callback The function to be exec as the callback.
* @param [ Object ] scope The callback function's scope.
* @param [ Object ] args Optional flags how to schedule.
*
* @return [ Void ]
*/
exports.update = function (notifications, callback, scope, args) {
this.core.update(notifications, callback, scope, args);
};
/**
* Clear the specified notifications by id.
......
......@@ -51,32 +51,34 @@ var app = {
},
// Initialize plugin
pluginInitialize: function() {
document.getElementById('granted').onclick = app.hasPermission;
document.getElementById('request').onclick = app.askPermission;
document.getElementById('sched_single').onclick = app.scheduleSingle;
document.getElementById('sched_multi').onclick = app.scheduleMultiple;
document.getElementById('sched_delayed').onclick = app.scheduleDelayed;
document.getElementById('sched_interval').onclick = app.scheduleInterval;
document.getElementById('sched_actions').onclick = app.scheduleActions;
document.getElementById('clear_single').onclick = app.clearSingle;
document.getElementById('clear_multi').onclick = app.clearMulti;
document.getElementById('clear_all').onclick = app.clearAll;
document.getElementById('cancel_single').onclick = app.cancelSingle;
document.getElementById('cancel_multi').onclick = app.cancelMulti;
document.getElementById('cancel_all').onclick = app.cancelAll;
document.getElementById('present?').onclick = app.isPresent;
document.getElementById('scheduled?').onclick = app.isScheduled;
document.getElementById('triggered?').onclick = app.isTriggered;
document.getElementById('type').onclick = app.type;
document.getElementById('ids').onclick = app.ids;
document.getElementById('scheduled_ids').onclick = app.scheduledIds;
document.getElementById('triggered_ids').onclick = app.triggeredIds;
document.getElementById('scheduled_nots').onclick = app.scheduledNots;
document.getElementById('triggered_nots').onclick = app.triggeredNots;
document.getElementById('notification').onclick = app.notification;
document.getElementById('multiple_nots').onclick = app.multipleNots;
document.getElementById('notifications').onclick = app.notifications;
document.getElementById('defaults').onclick = app.setDefaultTitle;
document.getElementById('granted').onclick = app.hasPermission;
document.getElementById('request').onclick = app.askPermission;
document.getElementById('sched_single').onclick = app.scheduleSingle;
document.getElementById('sched_multi').onclick = app.scheduleMultiple;
document.getElementById('sched_delayed').onclick = app.scheduleDelayed;
document.getElementById('sched_interval').onclick = app.scheduleInterval;
document.getElementById('sched_actions').onclick = app.scheduleActions;
document.getElementById('update_text').onclick = app.update;
document.getElementById('update_interval').onclick = app.updateInterval;
document.getElementById('clear_single').onclick = app.clearSingle;
document.getElementById('clear_multi').onclick = app.clearMulti;
document.getElementById('clear_all').onclick = app.clearAll;
document.getElementById('cancel_single').onclick = app.cancelSingle;
document.getElementById('cancel_multi').onclick = app.cancelMulti;
document.getElementById('cancel_all').onclick = app.cancelAll;
document.getElementById('present?').onclick = app.isPresent;
document.getElementById('scheduled?').onclick = app.isScheduled;
document.getElementById('triggered?').onclick = app.isTriggered;
document.getElementById('type').onclick = app.type;
document.getElementById('ids').onclick = app.ids;
document.getElementById('scheduled_ids').onclick = app.scheduledIds;
document.getElementById('triggered_ids').onclick = app.triggeredIds;
document.getElementById('scheduled_nots').onclick = app.scheduledNots;
document.getElementById('triggered_nots').onclick = app.triggeredNots;
document.getElementById('notification').onclick = app.notification;
document.getElementById('multiple_nots').onclick = app.multipleNots;
document.getElementById('notifications').onclick = app.notifications;
document.getElementById('defaults').onclick = app.setDefaultTitle;
var details = cordova.plugins.notification.local.launchDetails;
......@@ -100,7 +102,8 @@ var app = {
scheduleSingle: function () {
cordova.plugins.notification.local.schedule({
id: 1,
text: 'Test Message 1',
title: 'Test Message',
text: 'My first notification',
icon: 'http://3.bp.blogspot.com/-Qdsy-GpempY/UU_BN9LTqSI/AAAAAAAAAMA/LkwLW2yNBJ4/s1600/supersu.png',
smallIcon: 'res://cordova',
sound: null,
......@@ -131,25 +134,25 @@ var app = {
var now = new Date().getTime(),
_5_sec_from_now = new Date(now + 5 * 1000);
var sound = device.platform == 'Android' ? 'file://sound.mp3' : 'file://beep.caf';
var sound = device.platform != 'iOS' ? 'file://sound.mp3' : 'file://beep.caf';
cordova.plugins.notification.local.schedule({
id: 1,
title: 'Scheduled with delay',
text: 'Test Message 1',
at: _5_sec_from_now,
trigger: _5_sec_from_now,
sound: sound,
badge: 12
});
},
// Schedule a repeating notification
scheduleInterval: function () {
var sound = device.platform == 'Android' ? 'file://sound.mp3' : 'file://beep.caf';
var sound = device.platform != 'iOS' ? 'file://sound.mp3' : 'file://beep.caf';
cordova.plugins.notification.local.schedule({
id: 1,
text: 'Scheduled every minute',
every: 'minute',
trigger: { every: 'minute' },
sound: sound,
icon: 'res://icon',
smallIcon: 'res://ic_popup_sync'
......@@ -160,6 +163,7 @@ var app = {
cordova.plugins.notification.local.schedule({
title: 'Local Notification Plugin',
text: 'Made by appPlant from Leipzig/Germany',
icon: 'file://img/avatar.jpg?crop=cirlce',
attachments: ['file://img/logo.png'],
actionGroupId: 'like-dislike',
actions: [{
......@@ -181,6 +185,27 @@ var app = {
}]
});
},
// Update notification text
update: function () {
cordova.plugins.notification.local.update({
id: 1,
title: 'Updated Message 1',
text: 'New icon :)',
icon: 'res://icon',
color: 'FF0000',
attachments: ['file://img/logo.png'],
data: { updated: true }
});
},
// Update trigger interval
updateInterval: function () {
cordova.plugins.notification.local.update({
id: 1,
title: 'Updated Message 1',
text: 'Triggeres every minute',
every: 'minute'
});
},
// Clear a single notification
clearSingle: function () {
cordova.plugins.notification.local.clear(1, app.ids);
......@@ -298,7 +323,7 @@ var app = {
});
cordova.plugins.notification.local.on('update', function (obj) {
console.log('update', arguments);
// showToast('updated: ' + obj.id);
showToast('updated: ' + obj.id);
});
cordova.plugins.notification.local.on('trigger', function (obj) {
console.log('trigger', arguments);
......@@ -371,7 +396,7 @@ showWinDialog = function (text) {
};
if (window.hasOwnProperty('Windows')) {
alert = function (msg) { new Windows.UI.Popups.MessageDialog(msg).showAsync(); };
alert = showWinDialog;
}
app.initialize();
......@@ -84,41 +84,38 @@ exports.schedule = function (msgs, callback, scope, args) {
}
};
// /**
// * Update existing notifications specified by IDs in options.
// *
// * @param {Object} notifications
// * The notification properties to update
// * @param {Function} callback
// * A function to be called after the notification has been updated
// * @param {Object?} scope
// * The scope for the callback function
// * @param {Object?} args
// * skipPermission:true schedules the notifications immediatly without
// * registering or checking for permission
// */
// exports.update = function (msgs, callback, scope, args) {
// var fn = function(granted) {
// if (!granted) return;
// var notifications = Array.isArray(msgs) ? msgs : [msgs];
// for (var i = 0; i < notifications.length; i++) {
// var notification = notifications[i];
// this.convertProperties(notification);
// }
// this.exec('update', notifications, callback, scope);
// };
// if (args && args.skipPermission) {
// fn.call(this, true);
// } else {
// this.registerPermission(fn, this);
// }
// };
/**
* Schedule notifications.
*
* @param [ Array ] notifications The notifications to schedule.
* @param [ Function ] callback The function to be exec as the callback.
* @param [ Object ] scope The callback function's scope.
* @param [ Object ] args Optional flags how to schedule.
*
* @return [ Void ]
*/
exports.update = function (msgs, callback, scope, args) {
var fn = function(granted) {
if (!granted) return;
var notifications = Array.isArray(msgs) ? msgs : [msgs];
for (var i = 0; i < notifications.length; i++) {
var notification = notifications[i];
this.convertProperties(notification);
}
this.exec('update', notifications, callback, scope);
};
if (args && args.skipPermission) {
fn.call(this, true);
} else {
this.requestPermission(fn, this);
}
};
/**
* Clear the specified notifications by id.
......
......@@ -29,14 +29,14 @@ exports._defaults = {
text: '',
title: '',
sound: 'res://platform_default',
trigger: 'date',
badge: undefined,
data: undefined,
every: undefined,
at: undefined,
icon: undefined,
trigger: { type: 'calendar' },
actions: [],
actionGroupId: undefined,
attachments: []
attachments: [],
progressBar: false
};
// Listener
......@@ -59,12 +59,6 @@ exports.applyPlatformSpecificOptions = function () {
defaults.led = undefined;
defaults.color = undefined;
break;
case 'iOS':
defaults.region = undefined;
defaults.radius = undefined;
defaults.notifyOnEntry = true;
defaults.notifyOnExit = false;
break;
}
};
......@@ -78,7 +72,6 @@ exports.applyPlatformSpecificOptions = function () {
exports.mergeWithDefaults = function (options) {
var defaults = this.getDefaults();
options.at = this.getValueFor(options, 'at', 'firstAt', 'date');
options.text = this.getValueFor(options, 'text', 'message');
options.data = this.getValueFor(options, 'data', 'json');
......@@ -90,10 +83,6 @@ exports.mergeWithDefaults = function (options) {
options.autoClear = false;
}
if (options.at === undefined || options.at === null) {
options.at = new Date();
}
for (var key in defaults) {
if (options[key] === null || options[key] === undefined) {
if (options.hasOwnProperty(key) && ['data','sound'].indexOf(key) > -1) {
......@@ -106,7 +95,7 @@ exports.mergeWithDefaults = function (options) {
for (key in options) {
if (!defaults.hasOwnProperty(key)) {
delete options[key];
// delete options[key];
console.warn('Unknown property: ' + key);
}
}
......@@ -149,21 +138,13 @@ exports.convertProperties = function (options) {
}
}
if (options.at) {
if (typeof options.at == 'object') {
options.at = options.at.getTime();
}
options.at = Math.round(options.at/1000);
}
if (typeof options.data == 'object') {
options.data = JSON.stringify(options.data);
}
if (options.actions) {
this.convertActions(options);
}
this.convertTrigger(options);
this.convertActions(options);
this.convertProgressBar(options);
return options;
};
......@@ -199,6 +180,82 @@ exports.convertActions = function (options) {
options.category = (options.category || 'DEFAULT_GROUP').toString();
options.actions = actions;
return options;
};
/**
* Convert the passed values for the trigger to their required type.
*
* @param [ Map ] options Set of custom values.
*
* @return [ Map ] Interaction object with trigger spec.
*/
exports.convertTrigger = function (options) {
var cfg = options.trigger,
isDate = Date.prototype.isPrototypeOf(cfg),
isObject = Object.prototype.isPrototypeOf(cfg),
trigger = !isDate && isObject ? cfg : {},
date = this.getValueFor(trigger, 'at', 'firstAt', 'date');
if (!trigger.type) {
trigger.type = trigger.center ? 'location' : 'calendar';
}
var isCal = trigger.type == 'calendar';
if (isCal && !date) {
date = this.getValueFor(options, 'at', 'firstAt', 'date') || new Date();
}
if (isCal) {
date = typeof date == 'object' ? date.getTime() : date;
trigger.at = Math.round(date / 1000);
}
if (isCal && !trigger.every && options.every) {
trigger.every = options.every;
}
if (!trigger.count && device.platform == 'windows') {
trigger.count = trigger.every ? 5 : 1;
}
if (trigger.every && device.platform == 'windows') {
trigger.every = trigger.every.toString();
}
if (!isCal) {
trigger.notifyOnEntry = !!trigger.notifyOnEntry;
trigger.notifyOnExit = trigger.notifyOnExit === true;
trigger.radius = trigger.radius || 5;
}
delete options.every;
delete options.at;
delete options.firstAt;
delete options.date;
options.trigger = trigger;
return options;
};
/**
* Convert the passed values for the progressBar to their required type.
*
* @param [ Map ] options Set of custom values.
*
* @return [ Map ] Interaction object with trigger spec.
*/
exports.convertProgressBar = function (options) {
var cfg = options.progressBar;
if (typeof cfg === 'boolean') {
options.progressBar = { enabled: cfg };
}
return options;
};
/**
......@@ -306,13 +363,13 @@ exports.exec = function (action, args, callback, scope) {
channel.deviceready.subscribe(function () {
// Device is ready now, the listeners are registered
// and all queued events can be executed.
exports.exec('deviceready');
exports.exec('ready');
});
// Called before 'deviceready' event
channel.onCordovaReady.subscribe(function () {
// Set launchDetails object
exports.exec('launchDetails');
exports.exec('launch');
// Device plugin is ready now
channel.onCordovaInfoReady.subscribe(function () {
// Merge platform specifics into defaults
......
......@@ -58,22 +58,19 @@ exports.schedule = function (notifications, callback, scope, args) {
this.core.schedule(notifications, callback, scope, args);
};
// /**
// * Update existing notifications specified by IDs in options.
// *
// * @param {Object} notifications
// * The notification properties to update
// * @param {Function} callback
// * A function to be called after the notification has been updated
// * @param {Object?} scope
// * The scope for the callback function
// * @param {Object?} args
// * skipPermission:true schedules the notifications immediatly without
// * registering or checking for permission
// */
// exports.update = function (notifications, callback, scope, args) {
// this.core.update(notifications, callback, scope, args);
// };
/**
* Update notifications.
*
* @param [ Array ] notifications The notifications to schedule.
* @param [ Function ] callback The function to be exec as the callback.
* @param [ Object ] scope The callback function's scope.
* @param [ Object ] args Optional flags how to schedule.
*
* @return [ Void ]
*/
exports.update = function (notifications, callback, scope, args) {
this.core.update(notifications, callback, scope, args);
};
/**
* Clear the specified notifications by id.
......
......@@ -13,4 +13,10 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebuggerFlavor>AppHostDeviceDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)|$(UseDotNetNativeToolchain)'=='Release|x86|true'">
<DebuggerFlavor>AppHostDeviceDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup>
<AutoRefresh>false</AutoRefresh>
</PropertyGroup>
</Project>
\ No newline at end of file
......@@ -13,4 +13,22 @@
</ItemGroup>
<Import Condition="Exists('$(MSBuildThisFileDirectory)CordovaAppDebug.projitems') And '$(Configuration)'=='Debug'" Project="CordovaAppDebug.projitems" />
<Import Condition="Exists('$(MSBuildThisFileDirectory)CordovaAppRelease.projitems') And '$(Configuration)'!='Debug'" Project="CordovaAppRelease.projitems" />
<ItemGroup>
<Reference Condition="'$(Platform)'=='x86'" Include="LocalNotificationProxy">
<HintPath>plugins/cordova-plugin-local-notifications/x86/LocalNotificationProxy.winmd</HintPath>
<IsWinMDFile>true</IsWinMDFile>
</Reference>
</ItemGroup>
<ItemGroup>
<Reference Condition="'$(Platform)'=='x64'" Include="LocalNotificationProxy">
<HintPath>plugins/cordova-plugin-local-notifications/x64/LocalNotificationProxy.winmd</HintPath>
<IsWinMDFile>true</IsWinMDFile>
</Reference>
</ItemGroup>
<ItemGroup>
<Reference Condition="'$(Platform)'=='ARM'" Include="LocalNotificationProxy">
<HintPath>plugins/cordova-plugin-local-notifications/ARM/LocalNotificationProxy.winmd</HintPath>
<IsWinMDFile>true</IsWinMDFile>
</Reference>
</ItemGroup>
</Project>
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.15
VisualStudioVersion = 15.0.26730.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CordovaApp", "CordovaApp", "{3A47E08D-7EA5-4F3F-AA6D-1D4A41F26944}"
EndProject
......@@ -113,14 +113,14 @@ Global
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Debug|x64.Build.0 = Debug|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Debug|x86.ActiveCfg = Debug|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Debug|x86.Build.0 = Debug|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|Any CPU.ActiveCfg = Publish|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|Any CPU.Build.0 = Publish|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|ARM.ActiveCfg = Publish|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|ARM.Build.0 = Publish|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|x64.ActiveCfg = Publish|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|x64.Build.0 = Publish|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|x86.ActiveCfg = Publish|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|x86.Build.0 = Publish|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|Any CPU.ActiveCfg = Release|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|Any CPU.Build.0 = Release|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|ARM.ActiveCfg = Release|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|ARM.Build.0 = Release|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|x64.ActiveCfg = Release|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|x64.Build.0 = Release|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|x86.ActiveCfg = Release|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Publish|x86.Build.0 = Release|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Release|Any CPU.Build.0 = Release|Any CPU
{FB381278-F4AD-4703-A12A-C43EE0B231BD}.Release|ARM.ActiveCfg = Release|Any CPU
......@@ -139,4 +139,7 @@ Global
{F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1} = {3A47E08D-7EA5-4F3F-AA6D-1D4A41F26944}
{FB381278-F4AD-4703-A12A-C43EE0B231BD} = {3A47E08D-7EA5-4F3F-AA6D-1D4A41F26944}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AD3B56BE-BD21-4EFF-B8E4-BA2F4F33DD21}
EndGlobalSection
EndGlobal
......@@ -21,7 +21,9 @@
<uap:DefaultTile ShortName="NotificationExample" Square310x310Logo="images\Square310x310Logo.png" Square71x71Logo="images\Square71x71Logo.png" Wide310x150Logo="images\Wide310x150Logo.png">
</uap:DefaultTile>
<uap:InitialRotationPreference>
<uap:Rotation Preference="portrait" />
<uap:Rotation Preference="landscape" />
<uap:Rotation Preference="landscapeFlipped" />
</uap:InitialRotationPreference>
</uap:VisualElements>
<uap:ApplicationContentUriRules>
......
......@@ -84,41 +84,38 @@ exports.schedule = function (msgs, callback, scope, args) {
}
};
// /**
// * Update existing notifications specified by IDs in options.
// *
// * @param {Object} notifications
// * The notification properties to update
// * @param {Function} callback
// * A function to be called after the notification has been updated
// * @param {Object?} scope
// * The scope for the callback function
// * @param {Object?} args
// * skipPermission:true schedules the notifications immediatly without
// * registering or checking for permission
// */
// exports.update = function (msgs, callback, scope, args) {
// var fn = function(granted) {
// if (!granted) return;
// var notifications = Array.isArray(msgs) ? msgs : [msgs];
// for (var i = 0; i < notifications.length; i++) {
// var notification = notifications[i];
// this.convertProperties(notification);
// }
// this.exec('update', notifications, callback, scope);
// };
// if (args && args.skipPermission) {
// fn.call(this, true);
// } else {
// this.registerPermission(fn, this);
// }
// };
/**
* Schedule notifications.
*
* @param [ Array ] notifications The notifications to schedule.
* @param [ Function ] callback The function to be exec as the callback.
* @param [ Object ] scope The callback function's scope.
* @param [ Object ] args Optional flags how to schedule.
*
* @return [ Void ]
*/
exports.update = function (msgs, callback, scope, args) {
var fn = function(granted) {
if (!granted) return;
var notifications = Array.isArray(msgs) ? msgs : [msgs];
for (var i = 0; i < notifications.length; i++) {
var notification = notifications[i];
this.convertProperties(notification);
}
this.exec('update', notifications, callback, scope);
};
if (args && args.skipPermission) {
fn.call(this, true);
} else {
this.requestPermission(fn, this);
}
};
/**
* Clear the specified notifications by id.
......
......@@ -29,14 +29,14 @@ exports._defaults = {
text: '',
title: '',
sound: 'res://platform_default',
trigger: 'date',
badge: undefined,
data: undefined,
every: undefined,
at: undefined,
icon: undefined,
trigger: { type: 'calendar' },
actions: [],
actionGroupId: undefined,
attachments: []
attachments: [],
progressBar: false
};
// Listener
......@@ -59,12 +59,6 @@ exports.applyPlatformSpecificOptions = function () {
defaults.led = undefined;
defaults.color = undefined;
break;
case 'iOS':
defaults.region = undefined;
defaults.radius = undefined;
defaults.notifyOnEntry = true;
defaults.notifyOnExit = false;
break;
}
};
......@@ -78,7 +72,6 @@ exports.applyPlatformSpecificOptions = function () {
exports.mergeWithDefaults = function (options) {
var defaults = this.getDefaults();
options.at = this.getValueFor(options, 'at', 'firstAt', 'date');
options.text = this.getValueFor(options, 'text', 'message');
options.data = this.getValueFor(options, 'data', 'json');
......@@ -90,10 +83,6 @@ exports.mergeWithDefaults = function (options) {
options.autoClear = false;
}
if (options.at === undefined || options.at === null) {
options.at = new Date();
}
for (var key in defaults) {
if (options[key] === null || options[key] === undefined) {
if (options.hasOwnProperty(key) && ['data','sound'].indexOf(key) > -1) {
......@@ -106,7 +95,7 @@ exports.mergeWithDefaults = function (options) {
for (key in options) {
if (!defaults.hasOwnProperty(key)) {
delete options[key];
// delete options[key];
console.warn('Unknown property: ' + key);
}
}
......@@ -149,21 +138,13 @@ exports.convertProperties = function (options) {
}
}
if (options.at) {
if (typeof options.at == 'object') {
options.at = options.at.getTime();
}
options.at = Math.round(options.at/1000);
}
if (typeof options.data == 'object') {
options.data = JSON.stringify(options.data);
}
if (options.actions) {
this.convertActions(options);
}
this.convertTrigger(options);
this.convertActions(options);
this.convertProgressBar(options);
return options;
};
......@@ -199,6 +180,82 @@ exports.convertActions = function (options) {
options.category = (options.category || 'DEFAULT_GROUP').toString();
options.actions = actions;
return options;
};
/**
* Convert the passed values for the trigger to their required type.
*
* @param [ Map ] options Set of custom values.
*
* @return [ Map ] Interaction object with trigger spec.
*/
exports.convertTrigger = function (options) {
var cfg = options.trigger,
isDate = Date.prototype.isPrototypeOf(cfg),
isObject = Object.prototype.isPrototypeOf(cfg),
trigger = !isDate && isObject ? cfg : {},
date = this.getValueFor(trigger, 'at', 'firstAt', 'date');
if (!trigger.type) {
trigger.type = trigger.center ? 'location' : 'calendar';
}
var isCal = trigger.type == 'calendar';
if (isCal && !date) {
date = this.getValueFor(options, 'at', 'firstAt', 'date') || new Date();
}
if (isCal) {
date = typeof date == 'object' ? date.getTime() : date;
trigger.at = Math.round(date / 1000);
}
if (isCal && !trigger.every && options.every) {
trigger.every = options.every;
}
if (!trigger.count && device.platform == 'windows') {
trigger.count = trigger.every ? 5 : 1;
}
if (trigger.every && device.platform == 'windows') {
trigger.every = trigger.every.toString();
}
if (!isCal) {
trigger.notifyOnEntry = !!trigger.notifyOnEntry;
trigger.notifyOnExit = trigger.notifyOnExit === true;
trigger.radius = trigger.radius || 5;
}
delete options.every;
delete options.at;
delete options.firstAt;
delete options.date;
options.trigger = trigger;
return options;
};
/**
* Convert the passed values for the progressBar to their required type.
*
* @param [ Map ] options Set of custom values.
*
* @return [ Map ] Interaction object with trigger spec.
*/
exports.convertProgressBar = function (options) {
var cfg = options.progressBar;
if (typeof cfg === 'boolean') {
options.progressBar = { enabled: cfg };
}
return options;
};
/**
......@@ -306,13 +363,13 @@ exports.exec = function (action, args, callback, scope) {
channel.deviceready.subscribe(function () {
// Device is ready now, the listeners are registered
// and all queued events can be executed.
exports.exec('deviceready');
exports.exec('ready');
});
// Called before 'deviceready' event
channel.onCordovaReady.subscribe(function () {
// Set launchDetails object
exports.exec('launchDetails');
exports.exec('launch');
// Device plugin is ready now
channel.onCordovaInfoReady.subscribe(function () {
// Merge platform specifics into defaults
......
......@@ -58,22 +58,19 @@ exports.schedule = function (notifications, callback, scope, args) {
this.core.schedule(notifications, callback, scope, args);
};
// /**
// * Update existing notifications specified by IDs in options.
// *
// * @param {Object} notifications
// * The notification properties to update
// * @param {Function} callback
// * A function to be called after the notification has been updated
// * @param {Object?} scope
// * The scope for the callback function
// * @param {Object?} args
// * skipPermission:true schedules the notifications immediatly without
// * registering or checking for permission
// */
// exports.update = function (notifications, callback, scope, args) {
// this.core.update(notifications, callback, scope, args);
// };
/**
* Update notifications.
*
* @param [ Array ] notifications The notifications to schedule.
* @param [ Function ] callback The function to be exec as the callback.
* @param [ Object ] scope The callback function's scope.
* @param [ Object ] args Optional flags how to schedule.
*
* @return [ Void ]
*/
exports.update = function (notifications, callback, scope, args) {
this.core.update(notifications, callback, scope, args);
};
/**
* Clear the specified notifications by id.
......
......@@ -51,32 +51,34 @@ var app = {
},
// Initialize plugin
pluginInitialize: function() {
document.getElementById('granted').onclick = app.hasPermission;
document.getElementById('request').onclick = app.askPermission;
document.getElementById('sched_single').onclick = app.scheduleSingle;
document.getElementById('sched_multi').onclick = app.scheduleMultiple;
document.getElementById('sched_delayed').onclick = app.scheduleDelayed;
document.getElementById('sched_interval').onclick = app.scheduleInterval;
document.getElementById('sched_actions').onclick = app.scheduleActions;
document.getElementById('clear_single').onclick = app.clearSingle;
document.getElementById('clear_multi').onclick = app.clearMulti;
document.getElementById('clear_all').onclick = app.clearAll;
document.getElementById('cancel_single').onclick = app.cancelSingle;
document.getElementById('cancel_multi').onclick = app.cancelMulti;
document.getElementById('cancel_all').onclick = app.cancelAll;
document.getElementById('present?').onclick = app.isPresent;
document.getElementById('scheduled?').onclick = app.isScheduled;
document.getElementById('triggered?').onclick = app.isTriggered;
document.getElementById('type').onclick = app.type;
document.getElementById('ids').onclick = app.ids;
document.getElementById('scheduled_ids').onclick = app.scheduledIds;
document.getElementById('triggered_ids').onclick = app.triggeredIds;
document.getElementById('scheduled_nots').onclick = app.scheduledNots;
document.getElementById('triggered_nots').onclick = app.triggeredNots;
document.getElementById('notification').onclick = app.notification;
document.getElementById('multiple_nots').onclick = app.multipleNots;
document.getElementById('notifications').onclick = app.notifications;
document.getElementById('defaults').onclick = app.setDefaultTitle;
document.getElementById('granted').onclick = app.hasPermission;
document.getElementById('request').onclick = app.askPermission;
document.getElementById('sched_single').onclick = app.scheduleSingle;
document.getElementById('sched_multi').onclick = app.scheduleMultiple;
document.getElementById('sched_delayed').onclick = app.scheduleDelayed;
document.getElementById('sched_interval').onclick = app.scheduleInterval;
document.getElementById('sched_actions').onclick = app.scheduleActions;
document.getElementById('update_text').onclick = app.update;
document.getElementById('update_interval').onclick = app.updateInterval;
document.getElementById('clear_single').onclick = app.clearSingle;
document.getElementById('clear_multi').onclick = app.clearMulti;
document.getElementById('clear_all').onclick = app.clearAll;
document.getElementById('cancel_single').onclick = app.cancelSingle;
document.getElementById('cancel_multi').onclick = app.cancelMulti;
document.getElementById('cancel_all').onclick = app.cancelAll;
document.getElementById('present?').onclick = app.isPresent;
document.getElementById('scheduled?').onclick = app.isScheduled;
document.getElementById('triggered?').onclick = app.isTriggered;
document.getElementById('type').onclick = app.type;
document.getElementById('ids').onclick = app.ids;
document.getElementById('scheduled_ids').onclick = app.scheduledIds;
document.getElementById('triggered_ids').onclick = app.triggeredIds;
document.getElementById('scheduled_nots').onclick = app.scheduledNots;
document.getElementById('triggered_nots').onclick = app.triggeredNots;
document.getElementById('notification').onclick = app.notification;
document.getElementById('multiple_nots').onclick = app.multipleNots;
document.getElementById('notifications').onclick = app.notifications;
document.getElementById('defaults').onclick = app.setDefaultTitle;
var details = cordova.plugins.notification.local.launchDetails;
......@@ -100,7 +102,8 @@ var app = {
scheduleSingle: function () {
cordova.plugins.notification.local.schedule({
id: 1,
text: 'Test Message 1',
title: 'Test Message',
text: 'My first notification',
icon: 'http://3.bp.blogspot.com/-Qdsy-GpempY/UU_BN9LTqSI/AAAAAAAAAMA/LkwLW2yNBJ4/s1600/supersu.png',
smallIcon: 'res://cordova',
sound: null,
......@@ -131,25 +134,25 @@ var app = {
var now = new Date().getTime(),
_5_sec_from_now = new Date(now + 5 * 1000);
var sound = device.platform == 'Android' ? 'file://sound.mp3' : 'file://beep.caf';
var sound = device.platform != 'iOS' ? 'file://sound.mp3' : 'file://beep.caf';
cordova.plugins.notification.local.schedule({
id: 1,
title: 'Scheduled with delay',
text: 'Test Message 1',
at: _5_sec_from_now,
trigger: _5_sec_from_now,
sound: sound,
badge: 12
});
},
// Schedule a repeating notification
scheduleInterval: function () {
var sound = device.platform == 'Android' ? 'file://sound.mp3' : 'file://beep.caf';
var sound = device.platform != 'iOS' ? 'file://sound.mp3' : 'file://beep.caf';
cordova.plugins.notification.local.schedule({
id: 1,
text: 'Scheduled every minute',
every: 'minute',
trigger: { every: 'minute' },
sound: sound,
icon: 'res://icon',
smallIcon: 'res://ic_popup_sync'
......@@ -160,6 +163,7 @@ var app = {
cordova.plugins.notification.local.schedule({
title: 'Local Notification Plugin',
text: 'Made by appPlant from Leipzig/Germany',
icon: 'file://img/avatar.jpg?crop=cirlce',
attachments: ['file://img/logo.png'],
actionGroupId: 'like-dislike',
actions: [{
......@@ -181,6 +185,27 @@ var app = {
}]
});
},
// Update notification text
update: function () {
cordova.plugins.notification.local.update({
id: 1,
title: 'Updated Message 1',
text: 'New icon :)',
icon: 'res://icon',
color: 'FF0000',
attachments: ['file://img/logo.png'],
data: { updated: true }
});
},
// Update trigger interval
updateInterval: function () {
cordova.plugins.notification.local.update({
id: 1,
title: 'Updated Message 1',
text: 'Triggeres every minute',
every: 'minute'
});
},
// Clear a single notification
clearSingle: function () {
cordova.plugins.notification.local.clear(1, app.ids);
......@@ -298,7 +323,7 @@ var app = {
});
cordova.plugins.notification.local.on('update', function (obj) {
console.log('update', arguments);
// showToast('updated: ' + obj.id);
showToast('updated: ' + obj.id);
});
cordova.plugins.notification.local.on('trigger', function (obj) {
console.log('trigger', arguments);
......@@ -371,7 +396,7 @@ showWinDialog = function (text) {
};
if (window.hasOwnProperty('Windows')) {
alert = function (msg) { new Windows.UI.Popups.MessageDialog(msg).showAsync(); };
alert = showWinDialog;
}
app.initialize();
......@@ -23,7 +23,41 @@
var LocalNotification = LocalNotificationProxy.LocalNotification,
ActivationKind = Windows.ApplicationModel.Activation.ActivationKind;
var impl = new LocalNotificationProxy.LocalNotificationProxy();
var impl = new LocalNotificationProxy.LocalNotificationProxy(),
queue = [],
ready = false;
/**
* Set launchDetails object.
*
* @param [ Function ] success Success callback
* @param [ Function ] error Error callback
* @param [ Array ] args Interface arguments
*
* @return [ Void ]
*/
exports.launch = function (success, error, args) {
var plugin = cordova.plugins.notification.local;
if (args.length === 0 || plugin.launchDetails) return;
plugin.launchDetails = { id: args[0], action: args[1] };
};
/**
* To execute all queued events.
*
* @return [ Void ]
*/
exports.ready = function () {
ready = true;
for (var i = 0; i < queue.length; i++) {
exports.fireEvent.apply(exports, queue[i]);
}
queue = [];
};
/**
* Check permission to show notifications.
......@@ -61,42 +95,45 @@ exports.request = function (success, error) {
* @return [ Void ]
*/
exports.schedule = function (success, error, args) {
var options = [], actions = [];
var options = [];
for (var i = 0, props, opts; i < args.length; i++) {
props = args[i];
opts = new LocalNotification.Options();
for (var prop in opts) {
if (prop != 'actions' && props[prop]) opts[prop] = props[prop];
}
for (var j = 0, action, btn; j < props.actions.length; j++) {
action = props.actions[j];
opts = exports.parseOptions(props);
options.push(opts);
}
if (!action.type || action.type == 'button') {
btn = new LocalNotification.Button();
} else
if (action.type == 'input') {
btn = new LocalNotification.Input();
}
impl.schedule(options);
for (prop in btn) {
if (action[prop]) btn[prop] = action[prop];
}
for (i = 0; i < options.length; i++) {
exports.fireEvent('add', options[i]);
}
actions.push(btn);
}
success();
};
opts.actions = actions;
/**
* Update notifications.
*
* @param [ Function ] success Success callback
* @param [ Function ] error Error callback
* @param [ Array ] args Interface arguments
*
* @return [ Void ]
*/
exports.update = function (success, error, args) {
var options = [];
for (var i = 0, props, opts; i < args.length; i++) {
props = args[i];
opts = exports.parseOptions(props);
options.push(opts);
}
impl.schedule(options);
impl.update(options);
for (i = 0; i < options.length; i++) {
exports.fireEvent('add', options[i]);
exports.fireEvent('update', options[i]);
}
success();
......@@ -299,6 +336,10 @@ exports.clicked = function (xml, input) {
meta.text = input.first().current.value;
}
if (!ready) {
exports.launch(null, null, [toast.id, event]);
}
exports.fireEvent(event, toast, meta);
};
......@@ -315,6 +356,11 @@ exports.fireEvent = function (event, toast, data) {
var meta = Object.assign({ event: event }, data),
plugin = cordova.plugins.notification.local.core;
if (!ready) {
queue.push(arguments);
return;
}
if (toast) {
plugin.fireEvent(event, exports.clone(toast), meta);
} else {
......@@ -364,6 +410,109 @@ exports.clone = function (obj) {
return clone;
};
/**
* Parse notification spec into an instance of prefered type.
*
* @param [ Object ] obj The notification options map.
*
* @return [ LocalNotification.Options ]
*/
exports.parseOptions = function (obj) {
var opts = new LocalNotification.Options(),
ignore = ['progressBar', 'actions', 'trigger'];
for (var prop in opts) {
if (!ignore.includes(prop) && obj[prop]) {
opts[prop] = obj[prop];
}
}
var progressBar = exports.parseProgressBar(obj);
opts.progressBar = progressBar;
var trigger = exports.parseTrigger(obj);
opts.trigger = trigger;
var actions = exports.parseActions(obj);
opts.actions = actions;
return opts;
};
/**
* Parse trigger spec into instance of prefered type.
*
* @param [ Object ] obj The notification options map.
*
* @return [ LocalNotification.Trigger ]
*/
exports.parseTrigger = function (obj) {
var trigger = new LocalNotification.Trigger(),
spec = obj.trigger, val;
if (!spec) return trigger;
for (var prop in trigger) {
val = spec[prop];
if (!val) continue;
trigger[prop] = prop == 'every' ? val.toString() : val;
}
return trigger;
};
/**
* Parse action specs into instances of prefered types.
*
* @param [ Object ] obj The notification options map.
*
* @return [ Array<LocalNotification.Action> ]
*/
exports.parseActions = function (obj) {
var actions = [];
if (!obj.actions) return actions;
for (var i = 0, action, btn; i < obj.actions.length; i++) {
action = obj.actions[i];
if (!action.type || action.type == 'button') {
btn = new LocalNotification.Button();
} else
if (action.type == 'input') {
btn = new LocalNotification.Input();
}
for (var prop in btn) {
if (action[prop]) btn[prop] = action[prop];
}
actions.push(btn);
}
return actions;
};
/**
* Parse progressBar specs into instances of prefered types.
*
* @param [ Object ] obj The notification options map.
*
* @return [ LocalNotification.ProgressBar ]
*/
exports.parseProgressBar = function (obj) {
var bar = new LocalNotification.ProgressBar(),
spec = obj.progressBar;
if (!spec) return bar;
for (var prop in bar) {
if (spec[prop]) bar[prop] = spec[prop];
}
return bar;
};
// Handle onclick event
document.addEventListener('activated', function (e) {
if (e.kind == ActivationKind.toastNotification) {
......
......@@ -84,41 +84,38 @@ exports.schedule = function (msgs, callback, scope, args) {
}
};
// /**
// * Update existing notifications specified by IDs in options.
// *
// * @param {Object} notifications
// * The notification properties to update
// * @param {Function} callback
// * A function to be called after the notification has been updated
// * @param {Object?} scope
// * The scope for the callback function
// * @param {Object?} args
// * skipPermission:true schedules the notifications immediatly without
// * registering or checking for permission
// */
// exports.update = function (msgs, callback, scope, args) {
// var fn = function(granted) {
// if (!granted) return;
// var notifications = Array.isArray(msgs) ? msgs : [msgs];
// for (var i = 0; i < notifications.length; i++) {
// var notification = notifications[i];
// this.convertProperties(notification);
// }
// this.exec('update', notifications, callback, scope);
// };
// if (args && args.skipPermission) {
// fn.call(this, true);
// } else {
// this.registerPermission(fn, this);
// }
// };
/**
* Schedule notifications.
*
* @param [ Array ] notifications The notifications to schedule.
* @param [ Function ] callback The function to be exec as the callback.
* @param [ Object ] scope The callback function's scope.
* @param [ Object ] args Optional flags how to schedule.
*
* @return [ Void ]
*/
exports.update = function (msgs, callback, scope, args) {
var fn = function(granted) {
if (!granted) return;
var notifications = Array.isArray(msgs) ? msgs : [msgs];
for (var i = 0; i < notifications.length; i++) {
var notification = notifications[i];
this.convertProperties(notification);
}
this.exec('update', notifications, callback, scope);
};
if (args && args.skipPermission) {
fn.call(this, true);
} else {
this.requestPermission(fn, this);
}
};
/**
* Clear the specified notifications by id.
......
......@@ -29,14 +29,14 @@ exports._defaults = {
text: '',
title: '',
sound: 'res://platform_default',
trigger: 'date',
badge: undefined,
data: undefined,
every: undefined,
at: undefined,
icon: undefined,
trigger: { type: 'calendar' },
actions: [],
actionGroupId: undefined,
attachments: []
attachments: [],
progressBar: false
};
// Listener
......@@ -59,12 +59,6 @@ exports.applyPlatformSpecificOptions = function () {
defaults.led = undefined;
defaults.color = undefined;
break;
case 'iOS':
defaults.region = undefined;
defaults.radius = undefined;
defaults.notifyOnEntry = true;
defaults.notifyOnExit = false;
break;
}
};
......@@ -78,7 +72,6 @@ exports.applyPlatformSpecificOptions = function () {
exports.mergeWithDefaults = function (options) {
var defaults = this.getDefaults();
options.at = this.getValueFor(options, 'at', 'firstAt', 'date');
options.text = this.getValueFor(options, 'text', 'message');
options.data = this.getValueFor(options, 'data', 'json');
......@@ -90,10 +83,6 @@ exports.mergeWithDefaults = function (options) {
options.autoClear = false;
}
if (options.at === undefined || options.at === null) {
options.at = new Date();
}
for (var key in defaults) {
if (options[key] === null || options[key] === undefined) {
if (options.hasOwnProperty(key) && ['data','sound'].indexOf(key) > -1) {
......@@ -106,7 +95,7 @@ exports.mergeWithDefaults = function (options) {
for (key in options) {
if (!defaults.hasOwnProperty(key)) {
delete options[key];
// delete options[key];
console.warn('Unknown property: ' + key);
}
}
......@@ -149,21 +138,13 @@ exports.convertProperties = function (options) {
}
}
if (options.at) {
if (typeof options.at == 'object') {
options.at = options.at.getTime();
}
options.at = Math.round(options.at/1000);
}
if (typeof options.data == 'object') {
options.data = JSON.stringify(options.data);
}
if (options.actions) {
this.convertActions(options);
}
this.convertTrigger(options);
this.convertActions(options);
this.convertProgressBar(options);
return options;
};
......@@ -199,6 +180,82 @@ exports.convertActions = function (options) {
options.category = (options.category || 'DEFAULT_GROUP').toString();
options.actions = actions;
return options;
};
/**
* Convert the passed values for the trigger to their required type.
*
* @param [ Map ] options Set of custom values.
*
* @return [ Map ] Interaction object with trigger spec.
*/
exports.convertTrigger = function (options) {
var cfg = options.trigger,
isDate = Date.prototype.isPrototypeOf(cfg),
isObject = Object.prototype.isPrototypeOf(cfg),
trigger = !isDate && isObject ? cfg : {},
date = this.getValueFor(trigger, 'at', 'firstAt', 'date');
if (!trigger.type) {
trigger.type = trigger.center ? 'location' : 'calendar';
}
var isCal = trigger.type == 'calendar';
if (isCal && !date) {
date = this.getValueFor(options, 'at', 'firstAt', 'date') || new Date();
}
if (isCal) {
date = typeof date == 'object' ? date.getTime() : date;
trigger.at = Math.round(date / 1000);
}
if (isCal && !trigger.every && options.every) {
trigger.every = options.every;
}
if (!trigger.count && device.platform == 'windows') {
trigger.count = trigger.every ? 5 : 1;
}
if (trigger.every && device.platform == 'windows') {
trigger.every = trigger.every.toString();
}
if (!isCal) {
trigger.notifyOnEntry = !!trigger.notifyOnEntry;
trigger.notifyOnExit = trigger.notifyOnExit === true;
trigger.radius = trigger.radius || 5;
}
delete options.every;
delete options.at;
delete options.firstAt;
delete options.date;
options.trigger = trigger;
return options;
};
/**
* Convert the passed values for the progressBar to their required type.
*
* @param [ Map ] options Set of custom values.
*
* @return [ Map ] Interaction object with trigger spec.
*/
exports.convertProgressBar = function (options) {
var cfg = options.progressBar;
if (typeof cfg === 'boolean') {
options.progressBar = { enabled: cfg };
}
return options;
};
/**
......@@ -306,13 +363,13 @@ exports.exec = function (action, args, callback, scope) {
channel.deviceready.subscribe(function () {
// Device is ready now, the listeners are registered
// and all queued events can be executed.
exports.exec('deviceready');
exports.exec('ready');
});
// Called before 'deviceready' event
channel.onCordovaReady.subscribe(function () {
// Set launchDetails object
exports.exec('launchDetails');
exports.exec('launch');
// Device plugin is ready now
channel.onCordovaInfoReady.subscribe(function () {
// Merge platform specifics into defaults
......
......@@ -58,22 +58,19 @@ exports.schedule = function (notifications, callback, scope, args) {
this.core.schedule(notifications, callback, scope, args);
};
// /**
// * Update existing notifications specified by IDs in options.
// *
// * @param {Object} notifications
// * The notification properties to update
// * @param {Function} callback
// * A function to be called after the notification has been updated
// * @param {Object?} scope
// * The scope for the callback function
// * @param {Object?} args
// * skipPermission:true schedules the notifications immediatly without
// * registering or checking for permission
// */
// exports.update = function (notifications, callback, scope, args) {
// this.core.update(notifications, callback, scope, args);
// };
/**
* Update notifications.
*
* @param [ Array ] notifications The notifications to schedule.
* @param [ Function ] callback The function to be exec as the callback.
* @param [ Object ] scope The callback function's scope.
* @param [ Object ] args Optional flags how to schedule.
*
* @return [ Void ]
*/
exports.update = function (notifications, callback, scope, args) {
this.core.update(notifications, callback, scope, args);
};
/**
* Clear the specified notifications by id.
......
{
"name": "de.appplant.cordova.plugin.local-notification",
"cordova_name": "Cordova LocalNotification Plugin",
"version": "0.8.5",
"name": "cordova-plugin-local-notifications",
"version": "0.0.0",
"description": "Schedules and queries for local notifications",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"cordova": {
"id": "cordova-plugin-local-notifications",
"platforms": [
"ios",
"windows"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/katzer/cordova-plugin-local-notifications.git#ios10"
"url": "git+https://github.com/katzer/cordova-plugin-local-notifications.git#x"
},
"keywords": [
"appplant",
"notification",
"local notification",
"cordova",
"user notification",
"ecosystem:cordova",
"cordova-android",
"cordova-ios",
"cordova-windows"
],
"platforms": [
"ios",
"android",
"windows"
],
"engines": [
{
"name": "cordova",
......@@ -37,14 +34,14 @@
{
"name": "cordova-windows",
"version": ">=4.2.0"
},
{
"name": "apple-ios",
"version": ">=10.0.0"
}
],
"dependencies": {
"cordova-plugin-device": "*",
"cordova-plugin-app-event": ">=1.1.0"
},
"author": "Sebastián Katzer",
"license": "Apache-2.0",
"license": "Apache 2.0",
"bugs": {
"url": "https://github.com/katzer/cordova-plugin-local-notifications/issues"
},
......
......@@ -26,9 +26,9 @@
@interface APPLocalNotification : CDVPlugin <UNUserNotificationCenterDelegate>
// Set launchDetails object
- (void) launchDetails:(CDVInvokedUrlCommand*)command;
- (void) launch:(CDVInvokedUrlCommand*)command;
// Execute all queued events
- (void) deviceready:(CDVInvokedUrlCommand*)command;
- (void) ready:(CDVInvokedUrlCommand*)command;
// Check permission to show notifications
- (void) check:(CDVInvokedUrlCommand*)command;
......@@ -40,8 +40,8 @@
// Schedule notifications
- (void) schedule:(CDVInvokedUrlCommand*)command;
//// Update set of notifications
//- (void) update:(CDVInvokedUrlCommand*)command;
// Update set of notifications
- (void) update:(CDVInvokedUrlCommand*)command;
// Clear notifications by id
- (void) clear:(CDVInvokedUrlCommand*)command;
// Clear all notifications
......
......@@ -47,13 +47,12 @@
*
* @return [ Void ]
*/
- (void) launchDetails:(CDVInvokedUrlCommand*)command
- (void) launch:(CDVInvokedUrlCommand*)command
{
if (!_launchDetails)
return;
NSString* js;
js = [NSString stringWithFormat:
@"cordova.plugins.notification.local.launchDetails = {id:%@, action:'%@'}",
_launchDetails[0], _launchDetails[1]];
......@@ -68,7 +67,7 @@
*
* @return [ Void ]
*/
- (void) deviceready:(CDVInvokedUrlCommand*)command
- (void) ready:(CDVInvokedUrlCommand*)command
{
deviceready = YES;
......@@ -104,60 +103,36 @@
}];
}
///**
// * Update a set of notifications.
// *
// * @param properties
// * A dict of properties for each notification
// */
//- (void) update:(CDVInvokedUrlCommand*)command
//{
// NSArray* notifications = command.arguments;
//
// [self.commandDelegate runInBackground:^{
// if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
// for (NSDictionary* options in notifications) {
// NSNumber* id = [options objectForKey:@"id"];
// UNNotificationRequest* notification;
//
// notification = [_center getNotificationWithId:id];
//
// if (!notification)
// continue;
//
// // [self updateNotification:[notification copy]
// // withOptions:options];
// //
// // [self fireEvent:@"update" notification:notification];
// //
// // if (notifications.count > 1) {
// // [NSThread sleepForTimeInterval:0.01];
// // }
// }
// } else {
// for (NSDictionary* options in notifications) {
// NSNumber* id = [options objectForKey:@"id"];
// UILocalNotification* notification;
//
// notification = [_app localNotificationWithId:id];
//
// if (!notification)
// continue;
//
// [self updateLocalNotification:[notification copy]
// withOptions:options];
//
// [self fireEvent:@"update" localnotification:notification];
//
// if (notifications.count > 1) {
// [NSThread sleepForTimeInterval:0.01];
// }
// }
// }
//
// [self execCallback:command];
// }];
//}
/**
* Update notifications.
*
* @param [Array<Hash>] properties A list of key-value properties.
*
* @return [ Void ]
*/
- (void) update:(CDVInvokedUrlCommand*)command
{
NSArray* notifications = command.arguments;
[self.commandDelegate runInBackground:^{
for (NSDictionary* options in notifications) {
NSNumber* id = [options objectForKey:@"id"];
UNNotificationRequest* notification;
notification = [_center getNotificationWithId:id];
if (!notification)
continue;
[self updateNotification:[notification copy]
withOptions:options];
[self fireEvent:@"update" notification:notification];
}
[self execCallback:command];
}];
}
/**
* Clear notifications by id.
......@@ -264,7 +239,7 @@
default:
type = @"unknown";
}
CDVPluginResult* result;
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsString:type];
......@@ -340,11 +315,11 @@
NSArray* notifications;
notifications = [_center getNotificationOptionsById:ids];
CDVPluginResult* result;
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsDictionary:[notifications firstObject]];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
......@@ -476,36 +451,46 @@
/**
* Schedule the local notification.
*
* @param [ APPNotificationContent* ] notification The notification to schedule.
*
* @return [ Void ]
*/
- (void) scheduleNotification:(APPNotificationContent*)notification
{
__weak APPLocalNotification* weakSelf = self;
UNNotificationRequest* request = notification.request;
NSString* event = [notification.request wasUpdated] ? @"update" : @"add";
[_center addNotificationCategory:notification.category];
[_center addNotificationRequest:request withCompletionHandler:^(NSError* e) {
__strong APPLocalNotification* strongSelf = weakSelf;
[strongSelf fireEvent:@"add" notification:request];
[strongSelf fireEvent:event notification:request];
}];
}
///**
// * Update the local notification.
// */
//- (void) updateNotification:(UILocalNotification*)notification
// withOptions:(NSDictionary*)newOptions
//{APPNotificationRequest*
// NSMutableDictionary* options = [notification.userInfo mutableCopy];
//
// [options addEntriesFromDictionary:newOptions];
// [options setObject:[NSDate date] forKey:@"updatedAt"];
//
//// notification = [[UILocalNotification alloc]
//// initWithOptions:options];
////
//// [self scheduleLocalNotification:notification];
//}
/**
* Update the local notification.
*
* @param [ UNNotificationRequest* ] notification The notification to update.
* @param [ NSDictionary* ] options The options to update.
*
* @return [ Void ]
*/
- (void) updateNotification:(UNNotificationRequest*)notification
withOptions:(NSDictionary*)newOptions
{
NSMutableDictionary* options = [notification.content.userInfo mutableCopy];
[options addEntriesFromDictionary:newOptions];
[options setObject:[NSDate date] forKey:@"updatedAt"];
APPNotificationContent*
newNotification = [[APPNotificationContent alloc] initWithOptions:options];
[self scheduleNotification:newNotification];
}
#pragma mark -
#pragma mark UNUserNotificationCenterDelegate
......@@ -517,8 +502,15 @@
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
{
[self fireEvent:@"trigger" notification:notification.request];
completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
if (![notification.request wasUpdated]) {
[self fireEvent:@"trigger" notification:notification.request];
}
if (notification.request.options.silent) {
completionHandler(UNNotificationPresentationOptionNone);
} else {
completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
}
}
/**
......
......@@ -30,6 +30,7 @@
@property (readonly, getter=subtitle) NSString* subtitle;
@property (readonly, getter=badge) NSNumber* badge;
@property (readonly, getter=text) NSString* text;
@property (readonly, getter=silent) BOOL silent;
@property (readonly, getter=sound) UNNotificationSound* sound;
@property (readonly, getter=userInfo) NSDictionary* userInfo;
@property (readonly, getter=actions) NSArray<UNNotificationAction *> * actions;
......
......@@ -61,18 +61,6 @@
#pragma mark Properties
/**
* The type for the notification.
*
* @return [ NSString* ]
*/
- (NSString*) triggerType
{
NSString* type = [dict objectForKey:@"trigger"];
return type.length ? type : @"normal";
}
/**
* The ID for the notification.
*
* @return [ NSNumber* ]
......@@ -127,6 +115,16 @@
}
/**
* Show notification in foreground.
*
* @return [ BOOL ]
*/
- (BOOL) silent
{
return [[dict objectForKey:@"silent"] boolValue];
}
/**
* The badge number for the notification.
*
* @return [ NSNumber* ]
......@@ -280,12 +278,12 @@
*/
- (UNNotificationTrigger*) trigger
{
NSString* type = [self triggerType];
NSString* type = [self valueForTriggerOption:@"type"];
if ([type isEqualToString:@"location"])
return [self triggerWithRegion];
if (![type isEqualToString:@"date"])
if (![type isEqualToString:@"calendar"])
NSLog(@"Unknown type: %@", type);
if ([self isRepeating])
......@@ -315,6 +313,11 @@
#pragma mark -
#pragma mark Private
- (id) valueForTriggerOption:(NSString*)key
{
return [[dict objectForKey:@"trigger"] objectForKey:key];
}
/**
* The date when to fire the notification.
*
......@@ -322,8 +325,7 @@
*/
- (NSDate*) triggerDate
{
double timestamp = [[dict objectForKey:@"at"]
doubleValue];
double timestamp = [[self valueForTriggerOption:@"at"] doubleValue];
return [NSDate dateWithTimeIntervalSince1970:timestamp];
}
......@@ -335,7 +337,7 @@
*/
- (BOOL) isRepeating
{
id every = [dict objectForKey:@"every"];
id every = [self valueForTriggerOption:@"every"];
if ([every isKindOfClass:NSString.class])
return ((NSString*) every).length > 0;
......@@ -364,7 +366,7 @@
*/
- (UNNotificationTrigger*) repeatingTrigger
{
id every = [dict objectForKey:@"every"];
id every = [self valueForTriggerOption:@"every"];
if ([every isKindOfClass:NSString.class])
return [self triggerWithDateMatchingComponents];
......@@ -382,7 +384,7 @@
*/
- (UNTimeIntervalNotificationTrigger*) triggerWithTimeInterval
{
long interval = [[dict objectForKey:@"every"] longValue];
long interval = [[self valueForTriggerOption:@"every"] longValue];
if (interval < 60) {
NSLog(@"time interval must be at least 60 if repeating");
......@@ -438,8 +440,8 @@
*/
- (UNLocationNotificationTrigger*) triggerWithRegion
{
NSArray* center = [dict objectForKey:@"center"];
double radius = [[dict objectForKey:@"radius"] doubleValue];
NSArray* center = [self valueForTriggerOption:@"center"];
double radius = [[self valueForTriggerOption:@"radius"] doubleValue];
CLLocationCoordinate2D coord =
CLLocationCoordinate2DMake([center[0] doubleValue], [center[1] doubleValue]);
......@@ -449,8 +451,8 @@
radius:radius
identifier:self.identifier];
region.notifyOnEntry = [[dict objectForKey:@"notifyOnEntry"] boolValue];
region.notifyOnExit = [[dict objectForKey:@"notifyOnExit"] boolValue];
region.notifyOnEntry = [[self valueForTriggerOption:@"notifyOnEntry"] boolValue];
region.notifyOnExit = [[self valueForTriggerOption:@"notifyOnExit"] boolValue];
return [UNLocationNotificationTrigger triggerWithRegion:region repeats:YES];
}
......@@ -472,7 +474,7 @@
*/
- (NSCalendarUnit) repeatInterval
{
NSString* interval = [dict objectForKey:@"every"];
NSString* interval = [self valueForTriggerOption:@"every"];
NSCalendarUnit units = NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
if ([interval isEqualToString:@"minute"])
......@@ -504,7 +506,7 @@
- (NSDateComponents*) customDateComponents
{
NSDateComponents* date = [[NSDateComponents alloc] init];
NSDictionary* every = [dict objectForKey:@"every"];
NSDictionary* every = [self valueForTriggerOption:@"every"];
for (NSString* key in every) {
long value = [[every valueForKey:key] longValue];
......
......@@ -27,6 +27,8 @@
// The options provided by the plug-in
- (APPNotificationOptions*) options;
// If the notification was updated
- (BOOL) wasUpdated;
// Encode the user info dict to JSON
- (NSString*) encodeToJSON;
......
......@@ -65,6 +65,16 @@ static char optionsKey;
}
/**
* If the notification was updated.
*
* @return [ BOOL ]
*/
- (BOOL) wasUpdated
{
return [self.content userInfo][@"updatedAt"] != NULL;
}
/**
* Encode the user info dict to JSON.
*/
- (NSString*) encodeToJSON
......
......@@ -22,7 +22,41 @@
var LocalNotification = LocalNotificationProxy.LocalNotification,
ActivationKind = Windows.ApplicationModel.Activation.ActivationKind;
var impl = new LocalNotificationProxy.LocalNotificationProxy();
var impl = new LocalNotificationProxy.LocalNotificationProxy(),
queue = [],
ready = false;
/**
* Set launchDetails object.
*
* @param [ Function ] success Success callback
* @param [ Function ] error Error callback
* @param [ Array ] args Interface arguments
*
* @return [ Void ]
*/
exports.launch = function (success, error, args) {
var plugin = cordova.plugins.notification.local;
if (args.length === 0 || plugin.launchDetails) return;
plugin.launchDetails = { id: args[0], action: args[1] };
};
/**
* To execute all queued events.
*
* @return [ Void ]
*/
exports.ready = function () {
ready = true;
for (var i = 0; i < queue.length; i++) {
exports.fireEvent.apply(exports, queue[i]);
}
queue = [];
};
/**
* Check permission to show notifications.
......@@ -60,42 +94,45 @@ exports.request = function (success, error) {
* @return [ Void ]
*/
exports.schedule = function (success, error, args) {
var options = [], actions = [];
var options = [];
for (var i = 0, props, opts; i < args.length; i++) {
props = args[i];
opts = new LocalNotification.Options();
for (var prop in opts) {
if (prop != 'actions' && props[prop]) opts[prop] = props[prop];
}
for (var j = 0, action, btn; j < props.actions.length; j++) {
action = props.actions[j];
opts = exports.parseOptions(props);
options.push(opts);
}
if (!action.type || action.type == 'button') {
btn = new LocalNotification.Button();
} else
if (action.type == 'input') {
btn = new LocalNotification.Input();
}
impl.schedule(options);
for (prop in btn) {
if (action[prop]) btn[prop] = action[prop];
}
for (i = 0; i < options.length; i++) {
exports.fireEvent('add', options[i]);
}
actions.push(btn);
}
success();
};
opts.actions = actions;
/**
* Update notifications.
*
* @param [ Function ] success Success callback
* @param [ Function ] error Error callback
* @param [ Array ] args Interface arguments
*
* @return [ Void ]
*/
exports.update = function (success, error, args) {
var options = [];
for (var i = 0, props, opts; i < args.length; i++) {
props = args[i];
opts = exports.parseOptions(props);
options.push(opts);
}
impl.schedule(options);
impl.update(options);
for (i = 0; i < options.length; i++) {
exports.fireEvent('add', options[i]);
exports.fireEvent('update', options[i]);
}
success();
......@@ -298,6 +335,10 @@ exports.clicked = function (xml, input) {
meta.text = input.first().current.value;
}
if (!ready) {
exports.launch(null, null, [toast.id, event]);
}
exports.fireEvent(event, toast, meta);
};
......@@ -314,6 +355,11 @@ exports.fireEvent = function (event, toast, data) {
var meta = Object.assign({ event: event }, data),
plugin = cordova.plugins.notification.local.core;
if (!ready) {
queue.push(arguments);
return;
}
if (toast) {
plugin.fireEvent(event, exports.clone(toast), meta);
} else {
......@@ -363,6 +409,109 @@ exports.clone = function (obj) {
return clone;
};
/**
* Parse notification spec into an instance of prefered type.
*
* @param [ Object ] obj The notification options map.
*
* @return [ LocalNotification.Options ]
*/
exports.parseOptions = function (obj) {
var opts = new LocalNotification.Options(),
ignore = ['progressBar', 'actions', 'trigger'];
for (var prop in opts) {
if (!ignore.includes(prop) && obj[prop]) {
opts[prop] = obj[prop];
}
}
var progressBar = exports.parseProgressBar(obj);
opts.progressBar = progressBar;
var trigger = exports.parseTrigger(obj);
opts.trigger = trigger;
var actions = exports.parseActions(obj);
opts.actions = actions;
return opts;
};
/**
* Parse trigger spec into instance of prefered type.
*
* @param [ Object ] obj The notification options map.
*
* @return [ LocalNotification.Trigger ]
*/
exports.parseTrigger = function (obj) {
var trigger = new LocalNotification.Trigger(),
spec = obj.trigger, val;
if (!spec) return trigger;
for (var prop in trigger) {
val = spec[prop];
if (!val) continue;
trigger[prop] = prop == 'every' ? val.toString() : val;
}
return trigger;
};
/**
* Parse action specs into instances of prefered types.
*
* @param [ Object ] obj The notification options map.
*
* @return [ Array<LocalNotification.Action> ]
*/
exports.parseActions = function (obj) {
var actions = [];
if (!obj.actions) return actions;
for (var i = 0, action, btn; i < obj.actions.length; i++) {
action = obj.actions[i];
if (!action.type || action.type == 'button') {
btn = new LocalNotification.Button();
} else
if (action.type == 'input') {
btn = new LocalNotification.Input();
}
for (var prop in btn) {
if (action[prop]) btn[prop] = action[prop];
}
actions.push(btn);
}
return actions;
};
/**
* Parse progressBar specs into instances of prefered types.
*
* @param [ Object ] obj The notification options map.
*
* @return [ LocalNotification.ProgressBar ]
*/
exports.parseProgressBar = function (obj) {
var bar = new LocalNotification.ProgressBar(),
spec = obj.progressBar;
if (!spec) return bar;
for (var prop in bar) {
if (spec[prop]) bar[prop] = spec[prop];
}
return bar;
};
// Handle onclick event
document.addEventListener('activated', function (e) {
if (e.kind == ActivationKind.toastNotification) {
......
......@@ -30,22 +30,27 @@ namespace LocalNotificationProxy.LocalNotification
/// Initializes a new instance of the <see cref="Builder"/> class.
/// </summary>
/// <param name="options">Notification properties to set.</param>
internal Builder(Options options)
public Builder(Options options)
{
this.Content = new Notification(options);
}
/// <summary>
/// Gets content
/// Gets the content.
/// </summary>
public Notification Content { get; private set; }
/// <summary>
/// Gets options
/// Gets the options.
/// </summary>
private Options Options { get => this.Content.Options; }
/// <summary>
/// Gets the trigger.
/// </summary>
private Trigger Trigger { get => this.Options.Trigger; }
/// <summary>
/// Build a toast notification specified by the options.
/// </summary>
/// <returns>A fully configured toast notification instance.</returns>
......@@ -53,6 +58,7 @@ namespace LocalNotificationProxy.LocalNotification
{
var toast = this.InitToast();
this.AddProgressBarToToast(toast);
this.AddAttachmentsToToast(toast);
this.AddActionsToToast(toast);
......@@ -60,6 +66,17 @@ namespace LocalNotificationProxy.LocalNotification
}
/// <summary>
/// If there is at least one more toast variant to build.
/// </summary>
/// <returns>True if there are more toasts to build.</returns>
public bool HasNext() => this.Trigger.Count > this.Trigger.Occurrence;
/// <summary>
/// Moves the flag to the next toast variant.
/// </summary>
public void MoveNext() => this.Trigger.Occurrence += this.HasNext() ? 1 : 0;
/// <summary>
/// Gets the initialize skeleton for a toast notification.
/// </summary>
/// <returns>Basic skeleton with sound, image and text.</returns>
......@@ -87,7 +104,7 @@ namespace LocalNotificationProxy.LocalNotification
}
},
AppLogoOverride = this.Content.Image
AppLogoOverride = this.Content.Icon
}
},
......@@ -100,6 +117,20 @@ namespace LocalNotificationProxy.LocalNotification
}
/// <summary>
/// Adds optional progress bar to the toast.
/// </summary>
/// <param name="toast">Tho toast to extend for.</param>
private void AddProgressBarToToast(ToastContent toast)
{
var progressBar = this.Content.ProgressBar;
if (progressBar != null)
{
toast.Visual.BindingGeneric.Children.Add(progressBar);
}
}
/// <summary>
/// Adds attachments to the toast.
/// </summary>
/// <param name="toast">Tho toast to extend for.</param>
......@@ -137,21 +168,17 @@ namespace LocalNotificationProxy.LocalNotification
{
var xml = toast.GetXml();
var at = this.Content.Date;
ScheduledToastNotification notification;
var notification = new ScheduledToastNotification(xml, at);
if (this.Content.IsRepeating())
{
var interval = this.Content.Interval;
notification = new ScheduledToastNotification(xml, at, interval, 5);
}
else
notification.Id = this.Content.Id;
notification.Tag = this.Options.Id.ToString();
notification.SuppressPopup = this.Options.Silent;
if (this.Trigger.Occurrence > 1)
{
notification = new ScheduledToastNotification(xml, at);
notification.Group = notification.Tag;
}
notification.Id = this.Options.ID.ToString();
notification.Tag = notification.Id;
return notification;
}
}
......
......@@ -46,8 +46,40 @@ namespace LocalNotificationProxy.LocalNotification
{
foreach (Options options in notifications)
{
var toast = new Builder(options).Build();
ToastNotifier.AddToSchedule(toast);
var builder = new Builder(options);
ScheduledToastNotification toast;
do
{
toast = builder.Build();
ToastNotifier.AddToSchedule(toast);
builder.MoveNext();
} while (builder.HasNext());
}
}
/// <summary>
/// Update notifications.
/// </summary>
/// <param name="notifications">List of key-value properties</param>
public void Update([ReadOnlyArray] Options[] notifications)
{
foreach (Options options in notifications)
{
var bar = options.ProgressBar;
if (!bar.Enabled)
{
continue;
}
var data = new NotificationData { SequenceNumber = 0 };
data.Values["progress.value"] = bar.Value.ToString();
data.Values["progress.status"] = bar.Status.ToString();
data.Values["progress.description"] = bar.Description.ToString();
ToastNotifier.Update(data, options.Id.ToString());
}
}
......@@ -98,29 +130,29 @@ namespace LocalNotificationProxy.LocalNotification
public List<Options> Cancel(int[] ids)
{
var scheduled = ToastNotifier.GetScheduledToastNotifications();
var tags = new List<int>(ids);
var toRemove = new List<int>(ids);
var toClear = new List<int>(ids);
var toasts = new List<Options>();
foreach (var toast in scheduled)
{
var id = int.Parse(toast.Tag);
if (tags.Contains(id))
if (toRemove.Contains(id))
{
tags.Remove(id);
toasts.Add(new Notification(toast).Options);
toClear.Remove(id);
ToastNotifier.RemoveFromSchedule(toast);
}
if (tags.Count == 0)
{
break;
if (!this.IsPhantom(toast))
{
toasts.Add(new Notification(toast).Options);
}
}
}
if (tags.Count > 0)
if (toClear.Count > 0)
{
toasts.AddRange(this.Clear(tags.ToArray()));
toasts.AddRange(this.Clear(toClear.ToArray()));
}
return toasts;
......@@ -165,7 +197,10 @@ namespace LocalNotificationProxy.LocalNotification
foreach (var toast in toasts)
{
ids.Add(int.Parse(toast.Tag));
if (!this.IsPhantom(toast))
{
ids.Add(int.Parse(toast.Tag));
}
}
}
......@@ -175,7 +210,10 @@ namespace LocalNotificationProxy.LocalNotification
foreach (var toast in toasts)
{
ids.Add(int.Parse(toast.Tag));
if (!this.IsPhantom(toast))
{
ids.Add(int.Parse(toast.Tag));
}
}
}
......@@ -206,7 +244,10 @@ namespace LocalNotificationProxy.LocalNotification
foreach (var toast in toasts)
{
notifications.Add(new Notification(toast));
if (!this.IsPhantom(toast))
{
notifications.Add(new Notification(toast));
}
}
}
......@@ -216,7 +257,10 @@ namespace LocalNotificationProxy.LocalNotification
foreach (var toast in toasts)
{
notifications.Add(new Notification(toast));
if (!this.IsPhantom(toast))
{
notifications.Add(new Notification(toast));
}
}
}
......@@ -358,5 +402,25 @@ namespace LocalNotificationProxy.LocalNotification
return Notification.Type.Unknown;
}
/// <summary>
/// If the specified toast is only for internal reason.
/// </summary>
/// <param name="toast">The toast notification to test for.</param>
/// <returns>True if its an internal ("phantom") one.</returns>
private bool IsPhantom(ToastNotification toast)
{
return toast.Group.Length > 0;
}
/// <summary>
/// If the specified toast is only for internal reason.
/// </summary>
/// <param name="toast">The toast notification to test for.</param>
/// <returns>True if its an internal ("phantom") one.</returns>
private bool IsPhantom(ScheduledToastNotification toast)
{
return toast.Group.Length > 0;
}
}
}
......@@ -49,9 +49,17 @@
All, Scheduled, Triggered, Unknown
}
/// <summary>
/// Gets the wrapped notification options.
/// </summary>
public Options Options { get; private set; }
/// <summary>
/// Gets the unique identifier for the toast.
/// </summary>
public string Id => $"{this.Options.Id}#{this.Options.Trigger.Occurrence}";
/// <summary>
/// Gets a ToastAudio object based on the specified sound uri.
/// </summary>
public ToastAudio Sound
......@@ -93,12 +101,12 @@
/// <summary>
/// Gets a GenericAppLogo object based on the specified icon uri.
/// </summary>
public ToastGenericAppLogo Image
public ToastGenericAppLogo Icon
{
get
{
var image = new ToastGenericAppLogo();
var path = this.Options.Image;
var path = this.Options.Icon;
if (path == null || path.StartsWith("res://logo"))
{
......@@ -254,15 +262,43 @@
}
/// <summary>
/// Gets the progress bar widget.
/// </summary>
public AdaptiveProgressBar ProgressBar
{
get
{
var bar = this.Options.ProgressBar;
if (!bar.Enabled)
{
return null;
}
return new AdaptiveProgressBar()
{
Title = bar.Title,
Value = new BindableProgressBarValue("progress.value"),
ValueStringOverride = new BindableString("progress.description"),
Status = new BindableString("progress.status")
};
}
}
/// <summary>
/// Gets the date when to trigger the notification.
/// </summary>
public DateTime Date
{
get
{
var date = DateTimeOffset.FromUnixTimeMilliseconds(this.Options.At * 1000).LocalDateTime;
var trigger = this.Options.Trigger;
var time = trigger.At;
var date = DateTimeOffset.FromUnixTimeMilliseconds(time * 1000).LocalDateTime;
var minDate = DateTime.Now.AddSeconds(0.1);
date = date.AddTicks(this.Interval.Ticks * (trigger.Occurrence - 1));
return (date < minDate) ? minDate : date;
}
}
......@@ -274,16 +310,38 @@
{
get
{
switch (this.Options.Every)
var every = this.Options.Trigger.Every;
switch (every)
{
case null:
case "":
return TimeSpan.Zero;
case "second":
return new TimeSpan(TimeSpan.TicksPerSecond);
case "minute":
return new TimeSpan(TimeSpan.TicksPerMinute);
case "hour":
return new TimeSpan(TimeSpan.TicksPerHour);
case "day":
return new TimeSpan(TimeSpan.TicksPerDay);
default:
return TimeSpan.Zero;
case "week":
return new TimeSpan(TimeSpan.TicksPerDay * 7);
case "month":
return new TimeSpan(TimeSpan.TicksPerDay * 31);
case "quarter":
return new TimeSpan(TimeSpan.TicksPerHour * 2190);
case "year":
return new TimeSpan(TimeSpan.TicksPerDay * 365);
}
try
{
return TimeSpan.FromSeconds(60 * int.Parse(every));
}
catch
{
return TimeSpan.Zero;
}
}
}
......@@ -296,16 +354,5 @@
{
return this.Options.GetXml();
}
/// <summary>
/// If the notification shall be repeating.
/// </summary>
/// <returns>True if the Every property has some value.</returns>
public bool IsRepeating()
{
var every = this.Options.Every;
return every != null && every.Length > 0 && !every.Equals("0");
}
}
}
......@@ -33,7 +33,7 @@ namespace LocalNotificationProxy.LocalNotification
/// <summary>
/// Gets or sets notification ID.
/// </summary>
public int ID { get; set; }
public int Id { get; set; } = 0;
/// <summary>
/// Gets or sets notification title.
......@@ -58,17 +58,17 @@ namespace LocalNotificationProxy.LocalNotification
/// <summary>
/// Gets or sets the notification image.
/// </summary>
public string Image { get; set; }
public string Icon { get; set; }
/// <summary>
/// Gets or sets the notification fire date.
/// Gets or sets a value indicating whether the popup shall be visible.
/// </summary>
public long At { get; set; }
public bool Silent { get; set; } = false;
/// <summary>
/// Gets or sets the notification repeat interval.
/// Gets or sets the notification trigger.
/// </summary>
public string Every { get; set; }
public Trigger Trigger { get; set; }
/// <summary>
/// Gets or sets the notification user data.
......@@ -86,6 +86,11 @@ namespace LocalNotificationProxy.LocalNotification
public IAction[] Actions { get; set; }
/// <summary>
/// Gets or sets the notification progress bar.
/// </summary>
public ProgressBar ProgressBar { get; set; }
/// <summary>
/// Deserializes the XML string into an instance of Options.
/// </summary>
/// <param name="identifier">The serialized instance of Options as an xml string.</param>
......@@ -98,9 +103,8 @@ namespace LocalNotificationProxy.LocalNotification
var options = new Options();
var node = doc.DocumentElement;
options.ID = int.Parse(node.GetAttribute("id"));
options.Id = int.Parse(node.GetAttribute("id"));
options.Badge = int.Parse(node.GetAttribute("badge"));
options.At = int.Parse(node.GetAttribute("at"));
if (node.GetAttributeNode("text") != null)
{
......@@ -119,17 +123,22 @@ namespace LocalNotificationProxy.LocalNotification
if (node.GetAttributeNode("image") != null)
{
options.Image = node.GetAttribute("image");
options.Icon = node.GetAttribute("image");
}
if (node.GetAttributeNode("every") != null)
if (node.GetAttributeNode("data") != null)
{
options.Every = node.GetAttribute("every");
options.Data = node.GetAttribute("data");
}
if (node.GetAttributeNode("data") != null)
if (node.GetAttributeNode("attachments") != null)
{
options.Data = node.GetAttribute("data");
options.Attachments = node.GetAttribute("attachments").Split(',');
}
if (node.GetAttributeNode("silent") != null)
{
options.Silent = true;
}
if (node.GetAttributeNode("action") != null)
......@@ -158,9 +167,8 @@ namespace LocalNotificationProxy.LocalNotification
{
var node = new XmlDocument().CreateElement("options");
node.SetAttribute("id", this.ID.ToString());
node.SetAttribute("id", this.Id.ToString());
node.SetAttribute("badge", this.Badge.ToString());
node.SetAttribute("at", this.At.ToString());
if (this.Title != null)
{
......@@ -177,19 +185,24 @@ namespace LocalNotificationProxy.LocalNotification
node.SetAttribute("sound", this.Sound);
}
if (this.Image != null)
if (this.Icon != null)
{
node.SetAttribute("image", this.Image);
node.SetAttribute("image", this.Icon);
}
if (this.Every != null)
if (this.Data != null)
{
node.SetAttribute("every", this.Every);
node.SetAttribute("data", this.Data);
}
if (this.Data != null)
if (this.Attachments != null)
{
node.SetAttribute("data", this.Data);
node.SetAttribute("attachments", string.Join(",", this.Attachments));
}
if (this.Silent)
{
node.SetAttribute("silent", "1");
}
if (action != null)
......
/*
* Apache 2.0 License
*
* Copyright (c) Sebastian Katzer 2017
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*/
namespace LocalNotificationProxy.LocalNotification
{
public sealed class ProgressBar
{
/// <summary>
/// Gets or sets a value indicating whether the notification has a progress bar.
/// </summary>
public bool Enabled { get; set; } = false;
/// <summary>
/// Gets or sets the title.
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the value.
/// </summary>
public double Value { get; set; } = 0;
/// <summary>
/// Gets or sets the status.
/// </summary>
public string Status { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the description.
/// </summary>
public string Description { get; set; } = string.Empty;
}
}
/*
* Apache 2.0 License
*
* Copyright (c) Sebastian Katzer 2017
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*/
namespace LocalNotificationProxy.LocalNotification
{
public sealed class Trigger
{
/// <summary>
/// Gets trigger type.
/// </summary>
public string Type { get; } = "calendar";
/// <summary>
/// Gets or sets trigger date.
/// </summary>
public long At { get; set; }
/// <summary>
/// Gets or sets trigger count.
/// </summary>
public int Count { get; set; } = 1;
/// <summary>
/// Gets trigger occurrence.
/// </summary>
public int Occurrence { get; internal set; } = 1;
/// <summary>
/// Gets or sets trigger interval.
/// </summary>
public string Every { get; set; }
}
}
......@@ -50,6 +50,15 @@ namespace LocalNotificationProxy
}
/// <summary>
/// Update notifications.
/// </summary>
/// <param name="notifications">List of key-value properties</param>
public void Update([ReadOnlyArray] Options[] notifications)
{
this.manager.Update(notifications);
}
/// <summary>
/// Clear the notifications specified by id.
/// </summary>
/// <param name="ids">The IDs of the notification to clear.</param>
......
......@@ -118,6 +118,8 @@
<Compile Include="LocalNotification\Input.cs" />
<Compile Include="LocalNotification\Manager.cs" />
<Compile Include="LocalNotification\Options.cs" />
<Compile Include="LocalNotification\ProgressBar.cs" />
<Compile Include="LocalNotification\Trigger.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
......
......@@ -1208,7 +1208,7 @@
</member>
<member name="P:Microsoft.Toolkit.Uwp.Notifications.ToastActivationOptions.AfterActivationBehavior">
<summary>
Not supported on Windows: Specifies the behavior that the toast should use when the user invokes this action. Note that this option only works on <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastButton"/> and <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastContextMenuItem"/>.
New in Fall Creators Update: Specifies the behavior that the toast should use when the user invokes this action. Note that this option only works on <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastButton"/> and <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastContextMenuItem"/>. Desktop-only, supported in builds 16251 or higher.
</summary>
</member>
<member name="T:Microsoft.Toolkit.Uwp.Notifications.IToastBindingGenericChild">
......
......@@ -1208,7 +1208,7 @@
</member>
<member name="P:Microsoft.Toolkit.Uwp.Notifications.ToastActivationOptions.AfterActivationBehavior">
<summary>
Not supported on Windows: Specifies the behavior that the toast should use when the user invokes this action. Note that this option only works on <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastButton"/> and <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastContextMenuItem"/>.
New in Fall Creators Update: Specifies the behavior that the toast should use when the user invokes this action. Note that this option only works on <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastButton"/> and <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastContextMenuItem"/>. Desktop-only, supported in builds 16251 or higher.
</summary>
</member>
<member name="T:Microsoft.Toolkit.Uwp.Notifications.IToastBindingGenericChild">
......
......@@ -1208,7 +1208,7 @@
</member>
<member name="P:Microsoft.Toolkit.Uwp.Notifications.ToastActivationOptions.AfterActivationBehavior">
<summary>
Not supported on Windows: Specifies the behavior that the toast should use when the user invokes this action. Note that this option only works on <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastButton"/> and <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastContextMenuItem"/>.
New in Fall Creators Update: Specifies the behavior that the toast should use when the user invokes this action. Note that this option only works on <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastButton"/> and <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastContextMenuItem"/>. Desktop-only, supported in builds 16251 or higher.
</summary>
</member>
<member name="T:Microsoft.Toolkit.Uwp.Notifications.IToastBindingGenericChild">
......
......@@ -1208,7 +1208,7 @@
</member>
<member name="P:Microsoft.Toolkit.Uwp.Notifications.ToastActivationOptions.AfterActivationBehavior">
<summary>
Not supported on Windows: Specifies the behavior that the toast should use when the user invokes this action. Note that this option only works on <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastButton"/> and <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastContextMenuItem"/>.
New in Fall Creators Update: Specifies the behavior that the toast should use when the user invokes this action. Note that this option only works on <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastButton"/> and <see cref="T:Microsoft.Toolkit.Uwp.Notifications.ToastContextMenuItem"/>. Desktop-only, supported in builds 16251 or higher.
</summary>
</member>
<member name="T:Microsoft.Toolkit.Uwp.Notifications.IToastBindingGenericChild">
......
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\bin\ARM\Debug\LocalNotificationProxy.winmd
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\bin\ARM\Debug\LocalNotificationProxy.pdb
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\bin\ARM\Debug\LocalNotificationProxy.pri
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\bin\ARM\Debug\Microsoft.Toolkit.Uwp.Notifications.dll
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\bin\ARM\Debug\Microsoft.Toolkit.Uwp.Notifications.pdb
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\bin\ARM\Debug\Microsoft.Toolkit.Uwp.Notifications.xml
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\bin\ARM\Debug\Microsoft.Toolkit.Uwp.Notifications.pri
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\obj\ARM\Debug\LocalNotificationProxy.csprojResolveAssemblyReference.cache
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\obj\ARM\Debug\LocalNotificationProxy.csproj.CoreCompileInputs.cache
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\obj\ARM\Debug\LocalNotificationProxy.winmd
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\obj\ARM\Debug\LocalNotificationProxy.pdb
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\obj\ARM\Debug\LocalNotificationProxy.winmdobj
......@@ -16,8 +22,3 @@ Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotifica
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\obj\ARM\Debug\qualifiers.txt
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\obj\ARM\Debug\qualifiers.txt.intermediate
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\obj\ARM\Debug\MultipleQualifiersPerDimensionFound.txt
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\bin\ARM\Debug\Microsoft.Toolkit.Uwp.Notifications.dll
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\bin\ARM\Debug\Microsoft.Toolkit.Uwp.Notifications.pdb
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\bin\ARM\Debug\Microsoft.Toolkit.Uwp.Notifications.xml
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\bin\ARM\Debug\Microsoft.Toolkit.Uwp.Notifications.pri
Z:\Documents\github\cordova-plugin-local-notifications\src\windows\LocalNotificationProxy\LocalNotificationProxy\obj\ARM\Debug\LocalNotificationProxy.csprojResolveAssemblyReference.cache
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment