Commit 7648e407 by Sebastián Katzer

Support actions (iOS)

parent 657ce684
......@@ -35,6 +35,9 @@
// Request permission to show notifications
- (void) request:(CDVInvokedUrlCommand*)command;
// Register/update an action group
- (void) registerCategory:(CDVInvokedUrlCommand*)command;
// Schedule notifications
- (void) schedule:(CDVInvokedUrlCommand*)command;
//// Update set of notifications
......
......@@ -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 Private
......@@ -513,6 +532,8 @@
__weak APPLocalNotification* weakSelf = self;
UNNotificationRequest* request = notification.request;
[_center addNotificationCategory:notification.category];
[_center addNotificationRequest:request withCompletionHandler:^(NSError* e) {
__strong APPLocalNotification* strongSelf = weakSelf;
[strongSelf fireEvent:@"add" notification:request];
......
......@@ -30,5 +30,6 @@
- (id) initWithOptions:(NSDictionary*)dict;
- (APPNotificationOptions*) options;
- (UNNotificationRequest*) request;
- (UNNotificationCategory*) category;
@end
......@@ -23,7 +23,6 @@
#import "APPNotificationContent.h"
#import "APPNotificationOptions.h"
#import "UNUserNotificationCenter+APPLocalNotification.h"
#import <objc/runtime.h>
@import UserNotifications;
......@@ -67,7 +66,7 @@ static char optionsKey;
self.sound = options.sound;
self.badge = options.badge;
self.attachments = options.attachments;
self.categoryIdentifier = kAPPGeneralCategory;
self.categoryIdentifier = options.categoryId;
}
#pragma mark -
......@@ -107,6 +106,25 @@ static char optionsKey;
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 Private
......
......@@ -27,13 +27,15 @@
@property (readonly, getter=id) NSNumber* id;
@property (readonly, getter=identifier) NSString* identifier;
@property (readonly, getter=categoryId) NSString* categoryId;
@property (readonly, getter=title) NSString* title;
@property (readonly, getter=subtitle) NSString* subtitle;
@property (readonly, getter=badge) NSNumber* badge;
@property (readonly, getter=text) NSString* text;
@property (readonly, getter=sound) UNNotificationSound* sound;
@property (readonly, getter=attachments) NSArray<UNNotificationAttachment *> * attachments;
@property (readonly, getter=userInfo) NSDictionary* userInfo;
@property (readonly, getter=actions) NSArray<UNNotificationAction *> * actions;
@property (readonly, getter=attachments) NSArray<UNNotificationAttachment *> * attachments;
- (id) initWithDict:(NSDictionary*)dict;
- (UNNotificationTrigger*) trigger;
......
......@@ -22,6 +22,7 @@
*/
#import "APPNotificationOptions.h"
#import "UNUserNotificationCenter+APPLocalNotification.h"
@import UserNotifications;
......@@ -51,6 +52,8 @@
self = [self init];
self.dict = dictionary;
[self actions];
return self;
}
......@@ -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.
*
* @return [ UNNotificationSound* ]
......@@ -150,19 +165,12 @@
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* paths = [dict objectForKey:@"attachments"];
......@@ -188,6 +196,47 @@
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 Public
......@@ -226,6 +275,19 @@
#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.
*
* @return [ BOOL ]
......@@ -301,7 +363,7 @@
initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *date = [cal components:[self repeatInterval]
fromDate:[self fireDate]];
fromDate:[self triggerDate]];
date.timeZone = [NSTimeZone defaultTimeZone];
......@@ -335,7 +397,7 @@
*/
- (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) {
@property (readonly, getter=getNotifications) NSArray* localNotifications;
@property (readonly, getter=getNotificationIds) NSArray* localNotificationIds;
// Register general notification category to listen for dismiss actions
- (void) registerGeneralNotificationCategory;
// Add the specified category to the list of categories
- (void) addNotificationCategory:(UNNotificationCategory*)category;
// List of all notification IDs from given type
- (NSArray*) getNotificationIdsByType:(APPNotificationType)type;
......
......@@ -48,7 +48,34 @@ NSString * const kAPPGeneralCategory = @"GENERAL";
intentIdentifiers:@[]
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 -
......
......@@ -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.
*
* @return [ Object ]
......
......@@ -20,14 +20,16 @@ var exec = require('cordova/exec'),
// Default values
exports._defaults = {
text: '',
title: '',
sound: 'res://platform_default',
badge: undefined,
id: 0,
data: undefined,
every: undefined,
at: undefined
id: 0,
text: '',
title: '',
sound: 'res://platform_default',
badge: undefined,
data: undefined,
every: undefined,
at: undefined,
actions: undefined,
actionGroupId: undefined
};
// Listener
......@@ -149,10 +151,53 @@ exports.convertProperties = function (options) {
options.data = JSON.stringify(options.data);
}
if (options.actions) {
this.convertActions(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.
*
* @param [ Function ] fn The function to be exec as the callback.
......
......@@ -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.
*
* @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