cordova-plugin-local-notifications-continued 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/FUNDING.yml +1 -0
- package/.github/ISSUE_TEMPLATE/report_issue.yml +126 -0
- package/CHANGELOG.md +358 -0
- package/LICENSE +202 -0
- package/README.md +1531 -0
- package/images/android-actions-with-input-clicked.png +0 -0
- package/images/android-actions-with-input-not-clicked.png +0 -0
- package/images/android-actions.png +0 -0
- package/images/android-alarms-and-reminders-in-app-settings.png +0 -0
- package/images/android-alarms-and-reminders-setting.png +0 -0
- package/images/android-app-hibernation-notification.png +0 -0
- package/images/android-app-hibernation-settings-android-12.png +0 -0
- package/images/android-app-hibernation-settings-android-13-14.png +0 -0
- package/images/android-app-hibernation-settings-android-15.png +0 -0
- package/images/android-attachments-image-folded.png +0 -0
- package/images/android-attachments-image-unfolded.png +0 -0
- package/images/android-chat.png +0 -0
- package/images/android-icon.svg +19 -0
- package/images/android-inbox.png +0 -0
- package/images/android-notification-example.png +0 -0
- package/images/android-progress.png +0 -0
- package/images/android-request-permission.png +0 -0
- package/images/android-stack.png +0 -0
- package/images/apple-icon.svg +1 -0
- package/images/cordova-app-notified-logo.png +0 -0
- package/images/ios-actions-with-input.png +0 -0
- package/images/ios-actions.png +0 -0
- package/images/ios-attachments-image-folded.png +0 -0
- package/images/ios-attachments-image-unfolded.png +0 -0
- package/images/ios-notification.png +0 -0
- package/images/ios-request-permission.png +0 -0
- package/images/logo.png +0 -0
- package/package.json +53 -0
- package/plugin.xml +266 -0
- package/src/android/ClickActivity.java +72 -0
- package/src/android/LocalNotification.java +779 -0
- package/src/android/Manager.java +327 -0
- package/src/android/Notification.java +844 -0
- package/src/android/Options.java +956 -0
- package/src/android/OptionsTrigger.java +104 -0
- package/src/android/action/Action.java +214 -0
- package/src/android/action/ActionGroup.java +135 -0
- package/src/android/build/localnotification.gradle +29 -0
- package/src/android/receiver/ClearReceiver.java +61 -0
- package/src/android/receiver/RestoreReceiver.java +70 -0
- package/src/android/receiver/TriggerReceiver.java +70 -0
- package/src/android/trigger/TriggerHandler.java +195 -0
- package/src/android/trigger/TriggerHandlerAt.java +63 -0
- package/src/android/trigger/TriggerHandlerEvery.java +257 -0
- package/src/android/trigger/TriggerHandlerIn.java +69 -0
- package/src/android/util/AssetUtil.java +385 -0
- package/src/android/util/CallbackContextUtil.java +88 -0
- package/src/android/util/PluginFileProvider.java +34 -0
- package/src/android/xml/shared_files_provider_paths.xml +38 -0
- package/src/ios/APPLocalNotification.h +56 -0
- package/src/ios/APPLocalNotification.m +650 -0
- package/src/ios/APPNotificationCategory.h +28 -0
- package/src/ios/APPNotificationCategory.m +107 -0
- package/src/ios/APPNotificationContent.h +32 -0
- package/src/ios/APPNotificationContent.m +122 -0
- package/src/ios/APPNotificationOptions.h +42 -0
- package/src/ios/APPNotificationOptions.m +689 -0
- package/src/ios/UNNotificationRequest+APPLocalNotification.h +32 -0
- package/src/ios/UNNotificationRequest+APPLocalNotification.m +100 -0
- package/src/ios/UNUserNotificationCenter+APPLocalNotification.h +60 -0
- package/src/ios/UNUserNotificationCenter+APPLocalNotification.m +344 -0
- package/www/local-notification.js +1104 -0
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Apache 2.0 License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Sebastian Katzer 2017
|
|
5
|
+
*
|
|
6
|
+
* This file contains Original Code and/or Modifications of Original Code
|
|
7
|
+
* as defined in and that are subject to the Apache License
|
|
8
|
+
* Version 2.0 (the 'License'). You may not use this file except in
|
|
9
|
+
* compliance with the License. Please obtain a copy of the License at
|
|
10
|
+
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
|
|
11
|
+
* file.
|
|
12
|
+
*
|
|
13
|
+
* The Original Code and all software distributed under the License are
|
|
14
|
+
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
15
|
+
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
16
|
+
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
18
|
+
* Please see the License for the specific language governing rights and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
#import "APPNotificationOptions.h"
|
|
23
|
+
#import "UNUserNotificationCenter+APPLocalNotification.h"
|
|
24
|
+
|
|
25
|
+
@import CoreLocation;
|
|
26
|
+
@import UserNotifications;
|
|
27
|
+
|
|
28
|
+
// Maps these crap where Sunday is the 1st day of the week
|
|
29
|
+
static NSInteger WEEKDAYS[8] = { 0, 2, 3, 4, 5, 6, 7, 1 };
|
|
30
|
+
|
|
31
|
+
@interface APPNotificationOptions ()
|
|
32
|
+
|
|
33
|
+
// The dictionary which contains all notification properties
|
|
34
|
+
@property(nonatomic, retain) NSDictionary* dict;
|
|
35
|
+
|
|
36
|
+
@end
|
|
37
|
+
|
|
38
|
+
@implementation APPNotificationOptions : NSObject
|
|
39
|
+
|
|
40
|
+
@synthesize dict;
|
|
41
|
+
|
|
42
|
+
#pragma mark -
|
|
43
|
+
#pragma mark Initialization
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Initialize by using the given property values.
|
|
47
|
+
* @param dictionary A key-value property map.
|
|
48
|
+
* @return [ APPNotificationOptions ]
|
|
49
|
+
*/
|
|
50
|
+
- (id) initWithDict:(NSDictionary*)dictionary
|
|
51
|
+
{
|
|
52
|
+
self = [self init];
|
|
53
|
+
self.dict = dictionary;
|
|
54
|
+
return self;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#pragma mark -
|
|
58
|
+
#pragma mark Properties
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The ID for the notification.
|
|
62
|
+
*
|
|
63
|
+
* @return [ NSNumber* ]
|
|
64
|
+
*/
|
|
65
|
+
- (NSNumber*) id
|
|
66
|
+
{
|
|
67
|
+
NSInteger id = [dict[@"id"] integerValue];
|
|
68
|
+
|
|
69
|
+
return [NSNumber numberWithInteger:id];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The ID for the notification.
|
|
74
|
+
*
|
|
75
|
+
* @return [ NSString* ]
|
|
76
|
+
*/
|
|
77
|
+
- (NSString*) identifier
|
|
78
|
+
{
|
|
79
|
+
return [NSString stringWithFormat:@"%@", self.id];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The title for the notification.
|
|
84
|
+
*
|
|
85
|
+
* @return [ NSString* ]
|
|
86
|
+
*/
|
|
87
|
+
- (NSString*) title
|
|
88
|
+
{
|
|
89
|
+
return dict[@"title"];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The subtitle for the notification.
|
|
94
|
+
*
|
|
95
|
+
* @return [ NSString* ]
|
|
96
|
+
*/
|
|
97
|
+
- (NSString*) subtitle
|
|
98
|
+
{
|
|
99
|
+
NSArray *parts = [self.title componentsSeparatedByString:@"\n"];
|
|
100
|
+
|
|
101
|
+
return parts.count < 2 ? @"" : [parts objectAtIndex:1];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The text for the notification.
|
|
106
|
+
*
|
|
107
|
+
* @return [ NSString* ]
|
|
108
|
+
*/
|
|
109
|
+
- (NSString*) text
|
|
110
|
+
{
|
|
111
|
+
return dict[@"text"];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Don't show a notification, make no sound, no vibration, when app is in foreground
|
|
116
|
+
*
|
|
117
|
+
* @return [ BOOL ]
|
|
118
|
+
*/
|
|
119
|
+
- (BOOL) silent
|
|
120
|
+
{
|
|
121
|
+
return [dict[@"silent"] boolValue];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Show notification in foreground.
|
|
126
|
+
*
|
|
127
|
+
* @return [ BOOL ]
|
|
128
|
+
*/
|
|
129
|
+
- (BOOL) iOSForeground
|
|
130
|
+
{
|
|
131
|
+
return [dict[@"iOSForeground"] boolValue];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The badge number for the notification.
|
|
136
|
+
* 0 removes the badge, -1 don't changes the badge
|
|
137
|
+
*
|
|
138
|
+
* @return [ int ]
|
|
139
|
+
*/
|
|
140
|
+
- (int) badgeNumber
|
|
141
|
+
{
|
|
142
|
+
return [dict[@"badgeNumber"] intValue];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The category of the notification.
|
|
147
|
+
*
|
|
148
|
+
* @return [ NSString* ]
|
|
149
|
+
*/
|
|
150
|
+
- (NSString*) actionGroupId
|
|
151
|
+
{
|
|
152
|
+
id actions = dict[@"actions"];
|
|
153
|
+
|
|
154
|
+
return ([actions isKindOfClass:NSString.class]) ? actions : kAPPGeneralCategory;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* The sound file for the notification.
|
|
159
|
+
*
|
|
160
|
+
* @return [ UNNotificationSound* ]
|
|
161
|
+
*/
|
|
162
|
+
- (UNNotificationSound*) sound
|
|
163
|
+
{
|
|
164
|
+
NSString* soundPath = dict[@"sound"];
|
|
165
|
+
|
|
166
|
+
if (soundPath == NULL || [soundPath length] == 0 ) return NULL;
|
|
167
|
+
|
|
168
|
+
if ([soundPath isEqualToString:@"default"]) {
|
|
169
|
+
return [UNNotificationSound defaultSound];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Change file:// to www/ for assets
|
|
173
|
+
if ([soundPath hasPrefix:@"file://"]) {
|
|
174
|
+
soundPath = [self soundPathForAsset:soundPath];
|
|
175
|
+
|
|
176
|
+
// Gets the file name from the path
|
|
177
|
+
} else if ([soundPath hasPrefix:@"res:"]) {
|
|
178
|
+
soundPath = [self soundNameForResource:soundPath];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return [UNNotificationSound soundNamed:soundPath];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Additional content to attach.
|
|
187
|
+
*
|
|
188
|
+
* @return [ UNNotificationSound* ]
|
|
189
|
+
*/
|
|
190
|
+
- (NSArray<UNNotificationAttachment *> *) attachments
|
|
191
|
+
{
|
|
192
|
+
NSArray* attachmentsPaths = dict[@"attachments"];
|
|
193
|
+
NSMutableArray* attachments = [[NSMutableArray alloc] init];
|
|
194
|
+
|
|
195
|
+
if (!attachmentsPaths) return attachments;
|
|
196
|
+
|
|
197
|
+
for (NSString* path in attachmentsPaths) {
|
|
198
|
+
UNNotificationAttachment* attachment = [UNNotificationAttachment attachmentWithIdentifier:path
|
|
199
|
+
URL:[self urlForAttachmentPath:path]
|
|
200
|
+
options:NULL
|
|
201
|
+
error:NULL];
|
|
202
|
+
|
|
203
|
+
if (attachment) {
|
|
204
|
+
[attachments addObject:attachment];
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return attachments;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
#pragma mark -
|
|
212
|
+
#pragma mark Public
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Specify how and when to trigger the notification.
|
|
216
|
+
*
|
|
217
|
+
* @return [ UNNotificationTrigger* ]
|
|
218
|
+
*/
|
|
219
|
+
- (UNNotificationTrigger*) trigger
|
|
220
|
+
{
|
|
221
|
+
NSString* type = [self valueForTriggerOption:@"type"];
|
|
222
|
+
|
|
223
|
+
if ([type isEqualToString:@"location"]) return [self triggerWithRegion];
|
|
224
|
+
if (![type isEqualToString:@"calendar"]) NSLog(@"Unknown type: %@", type);
|
|
225
|
+
if ([self isRepeating]) return [self repeatingTrigger];
|
|
226
|
+
|
|
227
|
+
return [self nonRepeatingTrigger];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* The notification's user info dict.
|
|
232
|
+
*
|
|
233
|
+
* @return [ NSDictionary* ]
|
|
234
|
+
*/
|
|
235
|
+
- (NSDictionary*) userInfo
|
|
236
|
+
{
|
|
237
|
+
if (dict[@"updatedAt"]) {
|
|
238
|
+
NSMutableDictionary* data = [dict mutableCopy];
|
|
239
|
+
|
|
240
|
+
[data removeObjectForKey:@"updatedAt"];
|
|
241
|
+
|
|
242
|
+
return data;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return dict;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#pragma mark -
|
|
249
|
+
#pragma mark Private
|
|
250
|
+
|
|
251
|
+
- (id) valueForTriggerOption:(NSString*)key
|
|
252
|
+
{
|
|
253
|
+
return dict[@"trigger"][key];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* The date when to fire the notification.
|
|
258
|
+
*
|
|
259
|
+
* @return [ NSDate* ]
|
|
260
|
+
*/
|
|
261
|
+
- (NSDate*) triggerDate
|
|
262
|
+
{
|
|
263
|
+
double timestamp = [[self valueForTriggerOption:@"at"] doubleValue];
|
|
264
|
+
|
|
265
|
+
return [NSDate dateWithTimeIntervalSince1970:(timestamp / 1000)];
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* If the notification shall be repeating.
|
|
270
|
+
*
|
|
271
|
+
* @return [ BOOL ]
|
|
272
|
+
*/
|
|
273
|
+
- (BOOL) isRepeating
|
|
274
|
+
{
|
|
275
|
+
id every = [self valueForTriggerOption:@"every"];
|
|
276
|
+
|
|
277
|
+
if ([every isKindOfClass:NSString.class])
|
|
278
|
+
return ((NSString*) every).length > 0;
|
|
279
|
+
|
|
280
|
+
if ([every isKindOfClass:NSDictionary.class])
|
|
281
|
+
return ((NSDictionary*) every).count > 0;
|
|
282
|
+
|
|
283
|
+
return every > 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Non repeating trigger.
|
|
288
|
+
*
|
|
289
|
+
* @return [ UNTimeIntervalNotificationTrigger* ]
|
|
290
|
+
*/
|
|
291
|
+
- (UNNotificationTrigger*) nonRepeatingTrigger
|
|
292
|
+
{
|
|
293
|
+
if ([self valueForTriggerOption:@"at"]) {
|
|
294
|
+
return [self triggerWithDateMatchingComponents:NO];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:[self timeInterval] repeats:NO];
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Repeating trigger.
|
|
302
|
+
*
|
|
303
|
+
* @return [ UNNotificationTrigger* ]
|
|
304
|
+
*/
|
|
305
|
+
- (UNNotificationTrigger*) repeatingTrigger
|
|
306
|
+
{
|
|
307
|
+
id every = [self valueForTriggerOption:@"every"];
|
|
308
|
+
|
|
309
|
+
if ([every isKindOfClass:NSString.class])
|
|
310
|
+
return [self triggerWithDateMatchingComponents:YES];
|
|
311
|
+
|
|
312
|
+
if ([every isKindOfClass:NSDictionary.class])
|
|
313
|
+
return [self triggerWithCustomDateMatchingComponents];
|
|
314
|
+
|
|
315
|
+
return [self triggerWithTimeInterval];
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* A trigger based on a calendar time defined by the user.
|
|
320
|
+
*
|
|
321
|
+
* @return [ UNTimeIntervalNotificationTrigger* ]
|
|
322
|
+
*/
|
|
323
|
+
- (UNTimeIntervalNotificationTrigger*) triggerWithTimeInterval
|
|
324
|
+
{
|
|
325
|
+
double seconds = [self convertTicksToSeconds:[[self valueForTriggerOption:@"every"] doubleValue]
|
|
326
|
+
unit:[self valueForTriggerOption:@"unit"]];
|
|
327
|
+
|
|
328
|
+
if (seconds < 60) {
|
|
329
|
+
NSLog(@"time interval must be at least 60 sec if repeating");
|
|
330
|
+
seconds = 60;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:seconds
|
|
334
|
+
repeats:YES];
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* A repeating trigger based on a calendar time intervals defined by the plugin.
|
|
339
|
+
*
|
|
340
|
+
* @return [ UNCalendarNotificationTrigger* ]
|
|
341
|
+
*/
|
|
342
|
+
- (UNCalendarNotificationTrigger*) triggerWithDateMatchingComponents:(BOOL)repeats
|
|
343
|
+
{
|
|
344
|
+
NSDateComponents *date = [[self calendarWithMondayAsFirstDay] components:[self repeatInterval]
|
|
345
|
+
fromDate:[self triggerDate]];
|
|
346
|
+
|
|
347
|
+
date.timeZone = [NSTimeZone defaultTimeZone];
|
|
348
|
+
|
|
349
|
+
return [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:date
|
|
350
|
+
repeats:repeats];
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* A repeating trigger based on a calendar time intervals defined by the user.
|
|
355
|
+
*
|
|
356
|
+
* @return [ UNCalendarNotificationTrigger* ]
|
|
357
|
+
*/
|
|
358
|
+
- (UNCalendarNotificationTrigger*) triggerWithCustomDateMatchingComponents
|
|
359
|
+
{
|
|
360
|
+
NSDateComponents *date = [self customDateComponents];
|
|
361
|
+
date.calendar = [self calendarWithMondayAsFirstDay];
|
|
362
|
+
date.timeZone = [NSTimeZone defaultTimeZone];
|
|
363
|
+
|
|
364
|
+
return [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:date
|
|
365
|
+
repeats:YES];
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* A repeating trigger based on a location region.
|
|
370
|
+
*
|
|
371
|
+
* @return [ UNLocationNotificationTrigger* ]
|
|
372
|
+
*/
|
|
373
|
+
- (UNLocationNotificationTrigger*) triggerWithRegion
|
|
374
|
+
{
|
|
375
|
+
NSArray* center = [self valueForTriggerOption:@"center"];
|
|
376
|
+
double radius = [[self valueForTriggerOption:@"radius"] doubleValue];
|
|
377
|
+
BOOL single = [[self valueForTriggerOption:@"single"] boolValue];
|
|
378
|
+
|
|
379
|
+
CLLocationCoordinate2D coord =
|
|
380
|
+
CLLocationCoordinate2DMake([center[0] doubleValue], [center[1] doubleValue]);
|
|
381
|
+
|
|
382
|
+
CLCircularRegion* region =
|
|
383
|
+
[[CLCircularRegion alloc] initWithCenter:coord
|
|
384
|
+
radius:radius
|
|
385
|
+
identifier:self.identifier];
|
|
386
|
+
|
|
387
|
+
region.notifyOnEntry = [[self valueForTriggerOption:@"notifyOnEntry"] boolValue];
|
|
388
|
+
region.notifyOnExit = [[self valueForTriggerOption:@"notifyOnExit"] boolValue];
|
|
389
|
+
|
|
390
|
+
return [UNLocationNotificationTrigger triggerWithRegion:region
|
|
391
|
+
repeats:!single];
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* The time interval between the next fire date and now.
|
|
396
|
+
*
|
|
397
|
+
* @return [ double ]
|
|
398
|
+
*/
|
|
399
|
+
- (double) timeInterval
|
|
400
|
+
{
|
|
401
|
+
double ticks = [[self valueForTriggerOption:@"in"] doubleValue];
|
|
402
|
+
NSString* unit = [self valueForTriggerOption:@"unit"];
|
|
403
|
+
double seconds = [self convertTicksToSeconds:ticks unit:unit];
|
|
404
|
+
|
|
405
|
+
return MAX(0.01f, seconds);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* The repeat interval for the notification.
|
|
410
|
+
*
|
|
411
|
+
* @return [ NSCalendarUnit ]
|
|
412
|
+
*/
|
|
413
|
+
- (NSCalendarUnit) repeatInterval
|
|
414
|
+
{
|
|
415
|
+
NSString* interval = [self valueForTriggerOption:@"every"];
|
|
416
|
+
NSCalendarUnit units = NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
|
|
417
|
+
|
|
418
|
+
if ([interval isEqualToString:@"minute"])
|
|
419
|
+
return NSCalendarUnitSecond;
|
|
420
|
+
|
|
421
|
+
if ([interval isEqualToString:@"hour"])
|
|
422
|
+
return NSCalendarUnitMinute|NSCalendarUnitSecond;
|
|
423
|
+
|
|
424
|
+
if ([interval isEqualToString:@"day"])
|
|
425
|
+
return NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
|
|
426
|
+
|
|
427
|
+
if ([interval isEqualToString:@"week"])
|
|
428
|
+
return NSCalendarUnitWeekday|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
|
|
429
|
+
|
|
430
|
+
if ([interval isEqualToString:@"month"])
|
|
431
|
+
return NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
|
|
432
|
+
|
|
433
|
+
if ([interval isEqualToString:@"year"])
|
|
434
|
+
return NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
|
|
435
|
+
|
|
436
|
+
return units;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* The repeat interval for the notification.
|
|
441
|
+
*
|
|
442
|
+
* @return [ NSDateComponents* ]
|
|
443
|
+
*/
|
|
444
|
+
- (NSDateComponents*) customDateComponents
|
|
445
|
+
{
|
|
446
|
+
NSDateComponents* date = [[NSDateComponents alloc] init];
|
|
447
|
+
NSDictionary* every = [self valueForTriggerOption:@"every"];
|
|
448
|
+
|
|
449
|
+
date.second = 0;
|
|
450
|
+
|
|
451
|
+
for (NSString* key in every) {
|
|
452
|
+
long value = [[every valueForKey:key] longValue];
|
|
453
|
+
|
|
454
|
+
if ([key isEqualToString:@"minute"]) {
|
|
455
|
+
date.minute = value;
|
|
456
|
+
} else
|
|
457
|
+
if ([key isEqualToString:@"hour"]) {
|
|
458
|
+
date.hour = value;
|
|
459
|
+
} else
|
|
460
|
+
if ([key isEqualToString:@"day"]) {
|
|
461
|
+
date.day = value;
|
|
462
|
+
} else
|
|
463
|
+
if ([key isEqualToString:@"weekday"]) {
|
|
464
|
+
date.weekday = WEEKDAYS[value];
|
|
465
|
+
} else
|
|
466
|
+
if ([key isEqualToString:@"weekdayOrdinal"]) {
|
|
467
|
+
date.weekdayOrdinal = value;
|
|
468
|
+
} else
|
|
469
|
+
if ([key isEqualToString:@"week"]) {
|
|
470
|
+
date.weekOfYear = value;
|
|
471
|
+
} else
|
|
472
|
+
if ([key isEqualToString:@"weekOfMonth"]) {
|
|
473
|
+
date.weekOfMonth = value;
|
|
474
|
+
} else
|
|
475
|
+
if ([key isEqualToString:@"month"]) {
|
|
476
|
+
date.month = value;
|
|
477
|
+
} else
|
|
478
|
+
if ([key isEqualToString:@"quarter"]) {
|
|
479
|
+
date.quarter = value;
|
|
480
|
+
} else
|
|
481
|
+
if ([key isEqualToString:@"year"]) {
|
|
482
|
+
date.year = value;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return date;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Converts file:// to www/ for assets.
|
|
491
|
+
* @param path A relative assets file path.
|
|
492
|
+
* @return [ NSString* ]
|
|
493
|
+
*/
|
|
494
|
+
- (NSString*) soundPathForAsset:(NSString*)path
|
|
495
|
+
{
|
|
496
|
+
return [path stringByReplacingOccurrencesOfString:@"file://" withString:@"www/"];
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Convert a ressource path to an valid sound name attribute.
|
|
501
|
+
* @param path A relative ressource file path.
|
|
502
|
+
* @return [ NSString* ]
|
|
503
|
+
*/
|
|
504
|
+
- (NSString*) soundNameForResource:(NSString*)path
|
|
505
|
+
{
|
|
506
|
+
return [path pathComponents].lastObject;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* URL for the specified attachment path.
|
|
511
|
+
* @param path Absolute/relative path or a base64 data.
|
|
512
|
+
* @return [ NSURL* ]
|
|
513
|
+
*/
|
|
514
|
+
- (NSURL*) urlForAttachmentPath:(NSString*)path
|
|
515
|
+
{
|
|
516
|
+
if ([path hasPrefix:@"file:///"]) return [self urlForFile:path];
|
|
517
|
+
if ([path hasPrefix:@"res:"]) return [self urlForResource:path];
|
|
518
|
+
if ([path hasPrefix:@"www"] || [path hasPrefix:@"file://"]) return [self urlForAsset:path];
|
|
519
|
+
if ([path hasPrefix:@"base64:"]) return [self urlFromBase64:path];
|
|
520
|
+
|
|
521
|
+
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) NSLog(@"File not found: %@", path);
|
|
522
|
+
|
|
523
|
+
return [NSURL fileURLWithPath:path];
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* URL to an absolute file path.
|
|
528
|
+
* @return [ NSURL* ]
|
|
529
|
+
*/
|
|
530
|
+
- (NSURL*) urlForFile:(NSString*)absoluteFilePath
|
|
531
|
+
{
|
|
532
|
+
absoluteFilePath = [absoluteFilePath stringByReplacingOccurrencesOfString:@"file://" withString:@""];
|
|
533
|
+
|
|
534
|
+
if (![[NSFileManager defaultManager] fileExistsAtPath:absoluteFilePath]) {
|
|
535
|
+
NSLog(@"File not found: %@", absoluteFilePath);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return [NSURL fileURLWithPath:absoluteFilePath];
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* URL to a resource file.
|
|
543
|
+
* @param path A relative file path.
|
|
544
|
+
* @return [ NSURL* ]
|
|
545
|
+
*/
|
|
546
|
+
- (NSURL*) urlForResource:(NSString*)path
|
|
547
|
+
{
|
|
548
|
+
if ([path isEqualToString:@"res://icon"]) path = @"res://AppIcon60x60@3x.png";
|
|
549
|
+
|
|
550
|
+
NSString* absPath = [path stringByReplacingOccurrencesOfString:@"res:/"
|
|
551
|
+
withString:@""];
|
|
552
|
+
|
|
553
|
+
absPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:absPath];
|
|
554
|
+
|
|
555
|
+
if (![[NSFileManager defaultManager] fileExistsAtPath:absPath]) NSLog(@"File not found: %@", absPath);
|
|
556
|
+
|
|
557
|
+
return [NSURL fileURLWithPath:absPath];
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* URL to an asset file.
|
|
562
|
+
* @param path A relative www file path.
|
|
563
|
+
* @return [ NSURL* ]
|
|
564
|
+
*/
|
|
565
|
+
- (NSURL*) urlForAsset:(NSString*)path
|
|
566
|
+
{
|
|
567
|
+
NSString *absoluteAssetPath = [NSString stringWithFormat:@"%@/%@",
|
|
568
|
+
[[NSBundle mainBundle] bundlePath],
|
|
569
|
+
[path stringByReplacingOccurrencesOfString:@"file://"
|
|
570
|
+
withString:@"www/"]];
|
|
571
|
+
|
|
572
|
+
if (![[NSFileManager defaultManager] fileExistsAtPath:absoluteAssetPath]) {
|
|
573
|
+
NSLog(@"File not found: %@", absoluteAssetPath);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return [NSURL fileURLWithPath:absoluteAssetPath];
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* URL for a base64 encoded string.
|
|
581
|
+
* @param base64String Base64 encoded string.
|
|
582
|
+
* @return [ NSURL* ]
|
|
583
|
+
*/
|
|
584
|
+
- (NSURL*) urlFromBase64:(NSString*)base64String
|
|
585
|
+
{
|
|
586
|
+
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^base64:[^/]+.."
|
|
587
|
+
options:NSRegularExpressionCaseInsensitive
|
|
588
|
+
error:Nil];
|
|
589
|
+
|
|
590
|
+
NSString *dataString = [regex stringByReplacingMatchesInString:base64String
|
|
591
|
+
options:0
|
|
592
|
+
range:NSMakeRange(0, [base64String length])
|
|
593
|
+
withTemplate:@""];
|
|
594
|
+
|
|
595
|
+
NSData* data = [[NSData alloc] initWithBase64EncodedString:dataString
|
|
596
|
+
options:0];
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
return [self urlForData:data withFileName:[self basenameFromAttachmentPath:base64String]];
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Extract the attachments basename.
|
|
604
|
+
* @param path The file path or base64 data.
|
|
605
|
+
* @return [ NSString* ]
|
|
606
|
+
*/
|
|
607
|
+
- (NSString*) basenameFromAttachmentPath:(NSString*)path
|
|
608
|
+
{
|
|
609
|
+
if ([path hasPrefix:@"base64:"]) {
|
|
610
|
+
NSString* pathWithoutPrefix = [path stringByReplacingOccurrencesOfString:@"base64:"
|
|
611
|
+
withString:@""];
|
|
612
|
+
|
|
613
|
+
return [pathWithoutPrefix substringToIndex:[pathWithoutPrefix rangeOfString:@"//"].location];
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
return path;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Write the data into a temp file.
|
|
621
|
+
* @param data The data to save to file.
|
|
622
|
+
* @param filename The name of the file.
|
|
623
|
+
* @return [ NSURL* ]
|
|
624
|
+
*/
|
|
625
|
+
- (NSURL*) urlForData:(NSData*)data withFileName:(NSString*) filename
|
|
626
|
+
{
|
|
627
|
+
[[NSFileManager defaultManager] createDirectoryAtPath:NSTemporaryDirectory()
|
|
628
|
+
withIntermediateDirectories:YES
|
|
629
|
+
attributes:NULL
|
|
630
|
+
error:NULL];
|
|
631
|
+
|
|
632
|
+
NSString* absPath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
|
|
633
|
+
|
|
634
|
+
if (![[NSFileManager defaultManager] fileExistsAtPath:absPath]) NSLog(@"File not found: %@", absPath);
|
|
635
|
+
|
|
636
|
+
NSURL* url = [NSURL fileURLWithPath:absPath];
|
|
637
|
+
[data writeToURL:url atomically:NO];
|
|
638
|
+
|
|
639
|
+
return url;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Convert the amount of ticks into seconds.
|
|
644
|
+
* @param ticks The amount of ticks.
|
|
645
|
+
* @param unit The unit of the ticks (minute, hour, day, ...)
|
|
646
|
+
* @return [ double ] Amount of ticks in seconds.
|
|
647
|
+
*/
|
|
648
|
+
- (double) convertTicksToSeconds:(double)ticks unit:(NSString*)unit
|
|
649
|
+
{
|
|
650
|
+
if ([unit isEqualToString:@"second"]) {
|
|
651
|
+
return ticks;
|
|
652
|
+
} else if ([unit isEqualToString:@"minute"]) {
|
|
653
|
+
return ticks * 60;
|
|
654
|
+
} else if ([unit isEqualToString:@"hour"]) {
|
|
655
|
+
return ticks * 60 * 60;
|
|
656
|
+
} else if ([unit isEqualToString:@"day"]) {
|
|
657
|
+
return ticks * 60 * 60 * 24;
|
|
658
|
+
} else if ([unit isEqualToString:@"week"]) {
|
|
659
|
+
return ticks * 60 * 60 * 24 * 7;
|
|
660
|
+
} else if ([unit isEqualToString:@"month"]) {
|
|
661
|
+
return ticks * 60 * 60 * 24 * 30.438;
|
|
662
|
+
} else if ([unit isEqualToString:@"quarter"]) {
|
|
663
|
+
return ticks * 60 * 60 * 24 * 91.313;
|
|
664
|
+
} else if ([unit isEqualToString:@"year"]) {
|
|
665
|
+
return ticks * 60 * 60 * 24 * 365;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return 0;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Instance if a calendar where the monday is the first day of the week.
|
|
673
|
+
* @return [ NSCalendar* ]
|
|
674
|
+
*/
|
|
675
|
+
- (NSCalendar*) calendarWithMondayAsFirstDay
|
|
676
|
+
{
|
|
677
|
+
NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierISO8601];
|
|
678
|
+
calendar.firstWeekday = 2;
|
|
679
|
+
calendar.minimumDaysInFirstWeek = 1;
|
|
680
|
+
return calendar;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* String representation of this Object
|
|
685
|
+
*/
|
|
686
|
+
- (NSString *)description {
|
|
687
|
+
return [NSString stringWithFormat: @"%@", dict];
|
|
688
|
+
}
|
|
689
|
+
@end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Apache 2.0 License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Sebastian Katzer 2017
|
|
5
|
+
*
|
|
6
|
+
* This file contains Original Code and/or Modifications of Original Code
|
|
7
|
+
* as defined in and that are subject to the Apache License
|
|
8
|
+
* Version 2.0 (the 'License'). You may not use this file except in
|
|
9
|
+
* compliance with the License. Please obtain a copy of the License at
|
|
10
|
+
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
|
|
11
|
+
* file.
|
|
12
|
+
*
|
|
13
|
+
* The Original Code and all software distributed under the License are
|
|
14
|
+
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
15
|
+
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
16
|
+
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
18
|
+
* Please see the License for the specific language governing rights and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
#import "APPNotificationOptions.h"
|
|
23
|
+
|
|
24
|
+
@import UserNotifications;
|
|
25
|
+
|
|
26
|
+
@interface UNNotificationRequest (APPLocalNotification)
|
|
27
|
+
|
|
28
|
+
- (APPNotificationOptions*) options;
|
|
29
|
+
- (BOOL) wasUpdated;
|
|
30
|
+
- (NSString*) encodeToJSON;
|
|
31
|
+
|
|
32
|
+
@end
|