Commit 7648e407 by Sebastián Katzer

Support actions (iOS)

parent 657ce684
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
// Request permission to show notifications // Request permission to show notifications
- (void) request:(CDVInvokedUrlCommand*)command; - (void) request:(CDVInvokedUrlCommand*)command;
// Register/update an action group
- (void) registerCategory:(CDVInvokedUrlCommand*)command;
// Schedule notifications // Schedule notifications
- (void) schedule:(CDVInvokedUrlCommand*)command; - (void) schedule:(CDVInvokedUrlCommand*)command;
//// Update set of notifications //// Update set of notifications
......
...@@ -502,6 +502,25 @@ ...@@ -502,6 +502,25 @@
}]; }];
} }
/**
* Register/update an action group.
*
* @return [ Void ]
*/
- (void) registerCategory:(CDVInvokedUrlCommand *)command
{
[self.commandDelegate runInBackground:^{
NSDictionary* options = command.arguments[0];
APPNotificationContent* notification;
notification = [[APPNotificationContent alloc]
initWithOptions:options];
[_center addNotificationCategory:notification.category];
[self execCallback:command];
}];
}
#pragma mark - #pragma mark -
#pragma mark Private #pragma mark Private
...@@ -513,6 +532,8 @@ ...@@ -513,6 +532,8 @@
__weak APPLocalNotification* weakSelf = self; __weak APPLocalNotification* weakSelf = self;
UNNotificationRequest* request = notification.request; UNNotificationRequest* request = notification.request;
[_center addNotificationCategory:notification.category];
[_center addNotificationRequest:request withCompletionHandler:^(NSError* e) { [_center addNotificationRequest:request withCompletionHandler:^(NSError* e) {
__strong APPLocalNotification* strongSelf = weakSelf; __strong APPLocalNotification* strongSelf = weakSelf;
[strongSelf fireEvent:@"add" notification:request]; [strongSelf fireEvent:@"add" notification:request];
......
...@@ -30,5 +30,6 @@ ...@@ -30,5 +30,6 @@
- (id) initWithOptions:(NSDictionary*)dict; - (id) initWithOptions:(NSDictionary*)dict;
- (APPNotificationOptions*) options; - (APPNotificationOptions*) options;
- (UNNotificationRequest*) request; - (UNNotificationRequest*) request;
- (UNNotificationCategory*) category;
@end @end
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#import "APPNotificationContent.h" #import "APPNotificationContent.h"
#import "APPNotificationOptions.h" #import "APPNotificationOptions.h"
#import "UNUserNotificationCenter+APPLocalNotification.h"
#import <objc/runtime.h> #import <objc/runtime.h>
@import UserNotifications; @import UserNotifications;
...@@ -67,7 +66,7 @@ static char optionsKey; ...@@ -67,7 +66,7 @@ static char optionsKey;
self.sound = options.sound; self.sound = options.sound;
self.badge = options.badge; self.badge = options.badge;
self.attachments = options.attachments; self.attachments = options.attachments;
self.categoryIdentifier = kAPPGeneralCategory; self.categoryIdentifier = options.categoryId;
} }
#pragma mark - #pragma mark -
...@@ -107,6 +106,25 @@ static char optionsKey; ...@@ -107,6 +106,25 @@ static char optionsKey;
trigger:opts.trigger]; trigger:opts.trigger];
} }
/**
* The category for the notification with all the actions.
*
* @return [ UNNotificationCategory* ]
*/
- (UNNotificationCategory*) category
{
NSString* categoryId = self.categoryIdentifier;
NSArray* actions = self.options.actions;
if (!actions.count)
return NULL;
return [UNNotificationCategory categoryWithIdentifier:categoryId
actions:actions
intentIdentifiers:@[]
options:UNNotificationCategoryOptionCustomDismissAction];
}
#pragma mark - #pragma mark -
#pragma mark Private #pragma mark Private
......
...@@ -27,13 +27,15 @@ ...@@ -27,13 +27,15 @@
@property (readonly, getter=id) NSNumber* id; @property (readonly, getter=id) NSNumber* id;
@property (readonly, getter=identifier) NSString* identifier; @property (readonly, getter=identifier) NSString* identifier;
@property (readonly, getter=categoryId) NSString* categoryId;
@property (readonly, getter=title) NSString* title; @property (readonly, getter=title) NSString* title;
@property (readonly, getter=subtitle) NSString* subtitle; @property (readonly, getter=subtitle) NSString* subtitle;
@property (readonly, getter=badge) NSNumber* badge; @property (readonly, getter=badge) NSNumber* badge;
@property (readonly, getter=text) NSString* text; @property (readonly, getter=text) NSString* text;
@property (readonly, getter=sound) UNNotificationSound* sound; @property (readonly, getter=sound) UNNotificationSound* sound;
@property (readonly, getter=attachments) NSArray<UNNotificationAttachment *> * attachments;
@property (readonly, getter=userInfo) NSDictionary* userInfo; @property (readonly, getter=userInfo) NSDictionary* userInfo;
@property (readonly, getter=actions) NSArray<UNNotificationAction *> * actions;
@property (readonly, getter=attachments) NSArray<UNNotificationAttachment *> * attachments;
- (id) initWithDict:(NSDictionary*)dict; - (id) initWithDict:(NSDictionary*)dict;
- (UNNotificationTrigger*) trigger; - (UNNotificationTrigger*) trigger;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
*/ */
#import "APPNotificationOptions.h" #import "APPNotificationOptions.h"
#import "UNUserNotificationCenter+APPLocalNotification.h"
@import UserNotifications; @import UserNotifications;
...@@ -51,6 +52,8 @@ ...@@ -51,6 +52,8 @@
self = [self init]; self = [self init];
self.dict = dictionary; self.dict = dictionary;
[self actions];
return self; return self;
} }
...@@ -125,6 +128,18 @@ ...@@ -125,6 +128,18 @@
} }
/** /**
* The category of the notification.
*
* @return [ NSString* ]
*/
- (NSString*) categoryId
{
NSString* value = [dict objectForKey:@"actionGroupId"];
return value.length ? value : kAPPGeneralCategory;
}
/**
* The sound file for the notification. * The sound file for the notification.
* *
* @return [ UNNotificationSound* ] * @return [ UNNotificationSound* ]
...@@ -150,19 +165,12 @@ ...@@ -150,19 +165,12 @@
return [UNNotificationSound soundNamed:file]; return [UNNotificationSound soundNamed:file];
} }
/** /**
* The date when to fire the notification. * Additional content to attach.
* *
* @return [ NSDate* ] * @return [ UNNotificationSound* ]
*/ */
- (NSDate*) fireDate
{
double timestamp = [[dict objectForKey:@"at"]
doubleValue];
return [NSDate dateWithTimeIntervalSince1970:timestamp];
}
- (NSArray<UNNotificationAttachment *> *) attachments - (NSArray<UNNotificationAttachment *> *) attachments
{ {
NSArray* paths = [dict objectForKey:@"attachments"]; NSArray* paths = [dict objectForKey:@"attachments"];
...@@ -188,6 +196,47 @@ ...@@ -188,6 +196,47 @@
return attachments; return attachments;
} }
/**
* Additional actions for the notification.
*
* @return [ NSArray* ]
*/
- (NSArray<UNNotificationAction *> *) actions
{
NSArray* items = [dict objectForKey:@"actions"];
NSMutableArray* actions = [[NSMutableArray alloc] init];
if (!items)
return actions;
for (NSDictionary* item in items) {
NSString* id = [item objectForKey:@"id"];
NSString* title = [item objectForKey:@"title"];
UNNotificationActionOptions options = UNNotificationActionOptionNone;
if ([[item objectForKey:@"launch"] boolValue]) {
options = UNNotificationActionOptionForeground;
}
if ([[item objectForKey:@"ui"] isEqualToString:@"decline"]) {
options = options | UNNotificationActionOptionDestructive;
}
if ([[item objectForKey:@"needsAuth"] boolValue]) {
options = options | UNNotificationActionOptionAuthenticationRequired;
}
UNNotificationAction* action;
action = [UNNotificationAction actionWithIdentifier:id
title:title
options:options];
[actions addObject:action];
}
return actions;
}
#pragma mark - #pragma mark -
#pragma mark Public #pragma mark Public
...@@ -226,6 +275,19 @@ ...@@ -226,6 +275,19 @@
#pragma mark Private #pragma mark Private
/** /**
* The date when to fire the notification.
*
* @return [ NSDate* ]
*/
- (NSDate*) triggerDate
{
double timestamp = [[dict objectForKey:@"at"]
doubleValue];
return [NSDate dateWithTimeIntervalSince1970:timestamp];
}
/**
* If the notification shall be repeating. * If the notification shall be repeating.
* *
* @return [ BOOL ] * @return [ BOOL ]
...@@ -301,7 +363,7 @@ ...@@ -301,7 +363,7 @@
initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *date = [cal components:[self repeatInterval] NSDateComponents *date = [cal components:[self repeatInterval]
fromDate:[self fireDate]]; fromDate:[self triggerDate]];
date.timeZone = [NSTimeZone defaultTimeZone]; date.timeZone = [NSTimeZone defaultTimeZone];
...@@ -335,7 +397,7 @@ ...@@ -335,7 +397,7 @@
*/ */
- (double) timeInterval - (double) timeInterval
{ {
return MAX(0.01f, [self.fireDate timeIntervalSinceDate:[NSDate date]]); return MAX(0.01f, [self.triggerDate timeIntervalSinceDate:[NSDate date]]);
} }
/** /**
......
...@@ -38,7 +38,10 @@ typedef NS_ENUM(NSUInteger, APPNotificationType) { ...@@ -38,7 +38,10 @@ typedef NS_ENUM(NSUInteger, APPNotificationType) {
@property (readonly, getter=getNotifications) NSArray* localNotifications; @property (readonly, getter=getNotifications) NSArray* localNotifications;
@property (readonly, getter=getNotificationIds) NSArray* localNotificationIds; @property (readonly, getter=getNotificationIds) NSArray* localNotificationIds;
// Register general notification category to listen for dismiss actions
- (void) registerGeneralNotificationCategory; - (void) registerGeneralNotificationCategory;
// Add the specified category to the list of categories
- (void) addNotificationCategory:(UNNotificationCategory*)category;
// List of all notification IDs from given type // List of all notification IDs from given type
- (NSArray*) getNotificationIdsByType:(APPNotificationType)type; - (NSArray*) getNotificationIdsByType:(APPNotificationType)type;
......
...@@ -48,7 +48,34 @@ NSString * const kAPPGeneralCategory = @"GENERAL"; ...@@ -48,7 +48,34 @@ NSString * const kAPPGeneralCategory = @"GENERAL";
intentIdentifiers:@[] intentIdentifiers:@[]
options:UNNotificationCategoryOptionCustomDismissAction]; options:UNNotificationCategoryOptionCustomDismissAction];
[self setNotificationCategories:[NSSet setWithObjects:category, nil]]; [self setNotificationCategories:[NSSet setWithObject:category]];
}
/**
* Add the specified category to the list of categories.
*
* @param [ UNNotificationCategory* ] category The category to add.
*
* @return [ Void ]
*/
- (void) addNotificationCategory:(UNNotificationCategory*)category
{
if (!category)
return;
[self getNotificationCategoriesWithCompletionHandler:^(NSSet<UNNotificationCategory *> *set) {
NSMutableSet* categories = [NSMutableSet setWithSet:set];
for (UNNotificationCategory* item in categories) {
if ([category.identifier isEqualToString:item.identifier]) {
[categories removeObject:item];
break;
}
}
[categories addObject:category];
[self setNotificationCategories:categories];
}];
} }
#pragma mark - #pragma mark -
......
...@@ -397,6 +397,21 @@ exports.getAllTriggered = function (callback, scope) { ...@@ -397,6 +397,21 @@ exports.getAllTriggered = function (callback, scope) {
}; };
/** /**
* Register an group of actions by id.
*
* @param [ String ] id The Id of the group.
* @param [ Array] actions The action config settings.
* @param [ Function ] callback The function to be exec as the callback.
* @param [ Object ] scope The callback function's scope.
*
* @return [ Void ]
*/
exports.addActionGroup = function (id, actions, callback, scope) {
var config = { actionGroupId: id, actions: actions };
this.exec('registerCategory', config, callback, scope);
};
/**
* The (platform specific) default settings. * The (platform specific) default settings.
* *
* @return [ Object ] * @return [ Object ]
......
...@@ -20,14 +20,16 @@ var exec = require('cordova/exec'), ...@@ -20,14 +20,16 @@ var exec = require('cordova/exec'),
// Default values // Default values
exports._defaults = { exports._defaults = {
text: '', id: 0,
title: '', text: '',
sound: 'res://platform_default', title: '',
badge: undefined, sound: 'res://platform_default',
id: 0, badge: undefined,
data: undefined, data: undefined,
every: undefined, every: undefined,
at: undefined at: undefined,
actions: undefined,
actionGroupId: undefined
}; };
// Listener // Listener
...@@ -149,10 +151,53 @@ exports.convertProperties = function (options) { ...@@ -149,10 +151,53 @@ exports.convertProperties = function (options) {
options.data = JSON.stringify(options.data); options.data = JSON.stringify(options.data);
} }
if (options.actions) {
this.convertActions(options);
}
return options; return options;
}; };
/** /**
* Convert the passed values to their required type, modifying them
* directly for Android and passing the converted list back for iOS.
*
* @param [ Map ] options Set of custom values.
*
* @return [ Map ] Interaction object with category & actions.
*/
exports.convertActions = function (options) {
if (!options.actions)
return null;
var MAX_ACTIONS = (device.platform === 'iOS') ? 4 : 3,
actions = [];
if (options.actions.length > MAX_ACTIONS)
console.warn('Count of actions exceeded count of ' + MAX_ACTIONS);
for (var i = 0; i < options.actions.length && MAX_ACTIONS > 0; i++) {
var action = options.actions[i];
if (!action.id) {
console.warn(
'Action with title ' + action.title + ' has no id and will not be added.');
continue;
}
action.id = action.id.toString();
action.title = (action.title || action.id).toString();
actions.push(action);
MAX_ACTIONS--;
}
options.category = (options.category || 'DEFAULT_GROUP').toString();
options.actions = actions;
};
/**
* Create a callback function to get executed within a specific scope. * Create a callback function to get executed within a specific scope.
* *
* @param [ Function ] fn The function to be exec as the callback. * @param [ Function ] fn The function to be exec as the callback.
......
...@@ -277,6 +277,20 @@ exports.getAllTriggered = function (callback, scope) { ...@@ -277,6 +277,20 @@ exports.getAllTriggered = function (callback, scope) {
}; };
/** /**
* Register an group of actions by id.
*
* @param [ String ] id The Id of the group.
* @param [ Array] actions The action config settings.
* @param [ Function ] callback The function to be exec as the callback.
* @param [ Object ] scope The callback function's scope.
*
* @return [ Void ]
*/
exports.addActionGroup = function (id, actions, callback, scope) {
this.core.registerActionGroup(id, actions, callback, scope);
};
/**
* The (platform specific) default settings. * The (platform specific) default settings.
* *
* @return [ Object ] * @return [ Object ]
......
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