Skip to content

Commit b28a99c

Browse files
ghivertNaturalclar
andauthored
Add ability to repeat notifications like on iOS (#268)
Co-authored-by: Jesse Katsumata <jesse.katsumata@gmail.com> Co-authored-by: Jesse Katsumata <niconico.clarinet@gmail.com>
1 parent c79a50e commit b28a99c

File tree

4 files changed

+86
-17
lines changed

4 files changed

+86
-17
lines changed

README.md

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,14 +324,47 @@ request is an object containing:
324324
- `body` : The message displayed in the notification alert.
325325
- `badge` The number to display as the app's icon badge. Setting the number to 0 removes the icon badge.
326326
- `fireDate` : The date and time when the system should deliver the notification.
327-
- `repeats` : Sets notification to repeat daily. Must be used with fireDate.
327+
- `repeats` : Sets notification to repeat. Must be used with fireDate and repeatsComponent.
328+
- `repeatsComponent`: An object indicating which parts of fireDate should be repeated.
328329
- `sound` : The sound played when the notification is fired.
329330
- `category` : The category of this notification, required for actionable notifications.
330331
- `isSilent` : If true, the notification will appear without sound.
331332
- `isCritical` : If true, the notification sound be played even when the device is locked, muted, or has Do Not Disturb enabled.
332333
- `criticalSoundVolume` : A number between 0 and 1 for volume of critical notification. Default volume will be used if not specified.
333334
- `userInfo` : An object containing additional notification data.
334335

336+
request.repeatsComponent is an object containing (each field is optionnal):
337+
338+
- `month`: Will repeat every selected month in your fireDate.
339+
- `day`: Will repeat every selected day in your fireDate.
340+
- `hour`: Will repeat every selected hour in your fireDate.
341+
- `minute`: Will repeat every selected minute in your fireDate.
342+
- `second`: Will repeat every selected second in your fireDate.
343+
- `nanosecond`: Will repeat every selected nanosecond in your fireDate.
344+
345+
For example, let’s say you want to have a notification repeating every day at 23:54, starting tomorrow, you will use something like this:
346+
347+
```javascript
348+
const getCorrectDate = () => {
349+
const date = new Date();
350+
date.setDate(date.getDate() + 1);
351+
date.setHours(23);
352+
date.setMinutes(54);
353+
return date;
354+
};
355+
356+
PushNotificationIOS.addNotificationRequest({
357+
fireDate: getCorrectDate(),
358+
repeats: true,
359+
repeatsComponent: {
360+
hour: true,
361+
minute: true,
362+
},
363+
});
364+
```
365+
366+
If you want to repeat every time the clock reach 54 minutes (like 00:54, 01:54, and so on), just switch hour to false. Every field is used to indicate at what time the notification should be repeated, exactly like you could do on iOS.
367+
335368
---
336369

337370
### `setNotificationCategories()`

ios/RCTConvert+Notification.m

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -93,25 +93,32 @@ @implementation RCTConvert (UNNotificationRequest)
9393
+ (UNNotificationRequest *)UNNotificationRequest:(id)json
9494
{
9595
NSDictionary<NSString *, id> *details = [self NSDictionary:json];
96-
96+
9797
BOOL isSilent = [RCTConvert BOOL:details[@"isSilent"]];
9898
BOOL isCritical = [RCTConvert BOOL:details[@"isCritical"]];
9999
float criticalSoundVolume = [RCTConvert float:details[@"criticalSoundVolume"]];
100100
NSString* identifier = [RCTConvert NSString:details[@"id"]];
101-
102-
101+
103102
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
104-
content.title= [RCTConvert NSString:details[@"title"]];
105-
content.subtitle= [RCTConvert NSString:details[@"subtitle"]];
106-
content.body =[RCTConvert NSString:details[@"body"]];
107-
content.badge = [RCTConvert NSNumber:details[@"badge"]];
103+
content.title = [RCTConvert NSString:details[@"title"]];
104+
content.subtitle = [RCTConvert NSString:details[@"subtitle"]];
105+
content.body = [RCTConvert NSString:details[@"body"]];
106+
content.badge = [RCTConvert NSNumber:details[@"badge"]];
108107
content.categoryIdentifier = [RCTConvert NSString:details[@"category"]];
109108

110109
NSString* threadIdentifier = [RCTConvert NSString:details[@"threadId"]];
111110
if (threadIdentifier){
112111
content.threadIdentifier = threadIdentifier;
113112
}
114113

114+
NSDictionary<NSString *, id> *userDateComps = [RCTConvert NSDictionary:details[@"repeatsComponent"]];
115+
BOOL month = [RCTConvert BOOL:userDateComps[@"month"]];
116+
BOOL day = [RCTConvert BOOL:userDateComps[@"day"]];
117+
BOOL hour = [RCTConvert BOOL:userDateComps[@"hour"]];
118+
BOOL minute = [RCTConvert BOOL:userDateComps[@"minute"]];
119+
BOOL second = [RCTConvert BOOL:userDateComps[@"second"]];
120+
BOOL nanosecond = [RCTConvert BOOL:userDateComps[@"nanosecond"]];
121+
115122
content.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]];
116123
if (!isSilent) {
117124
if (isCritical) {
@@ -122,18 +129,31 @@ + (UNNotificationRequest *)UNNotificationRequest:(id)json
122129
}
123130
} else {
124131
content.sound = [RCTConvert NSString:details[@"sound"]] ? [UNNotificationSound soundNamed:[RCTConvert NSString:details[@"sound"]]] : [UNNotificationSound defaultSound];
125-
}
132+
}```
126133
}
127134

128135
NSDate* fireDate = [RCTConvert NSDate:details[@"fireDate"]];
129136
BOOL repeats = [RCTConvert BOOL:details[@"repeats"]];
130-
NSDateComponents *triggerDate = fireDate ? [[NSCalendar currentCalendar]
131-
components:NSCalendarUnitYear +
132-
NSCalendarUnitMonth + NSCalendarUnitDay +
133-
NSCalendarUnitHour + NSCalendarUnitMinute +
134-
NSCalendarUnitSecond + NSCalendarUnitTimeZone
135-
fromDate:fireDate] : nil;
136-
137+
NSCalendarUnit defaultDateComponents =
138+
NSCalendarUnitYear |
139+
NSCalendarUnitMonth |
140+
NSCalendarUnitDay |
141+
NSCalendarUnitHour |
142+
NSCalendarUnitMinute |
143+
NSCalendarUnitSecond;
144+
NSCalendarUnit repeatDateComponents =
145+
(month ? NSCalendarUnitMonth : 0) |
146+
(day ? NSCalendarUnitDay : 0) |
147+
(hour ? NSCalendarUnitHour : 0) |
148+
(minute ? NSCalendarUnitMinute : 0) |
149+
(second ? NSCalendarUnitSecond : 0) |
150+
(nanosecond ? NSCalendarUnitNanosecond : 0);
151+
NSDateComponents *triggerDate = fireDate
152+
? [[NSCalendar currentCalendar]
153+
components:(repeats ? repeatDateComponents : defaultDateComponents) | NSCalendarUnitTimeZone
154+
fromDate:fireDate]
155+
: nil;
156+
137157
UNCalendarNotificationTrigger* trigger = triggerDate ? [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:triggerDate repeats:repeats] : nil;
138158

139159
UNNotificationRequest* notification = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];

js/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,12 @@ class PushNotificationIOS {
146146
request.fireDate instanceof Date
147147
? {...request, fireDate: request.fireDate.toISOString()}
148148
: request;
149+
const finalRequest = {
150+
...handledRequest,
151+
repeatsComponent: request.repeatsComponent || {},
152+
};
149153

150-
RNCPushNotificationIOS.addNotificationRequest(handledRequest);
154+
RNCPushNotificationIOS.addNotificationRequest(finalRequest);
151155
}
152156

153157
/**

js/types.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ export type NotificationRequest = {|
4545
* Must be used with fireDate.
4646
*/
4747
repeats?: boolean,
48+
/**
49+
* Define what components should be used in the fireDate during repeats.
50+
* Must be used with repeats and fireDate.
51+
*/
52+
repeatsComponent?: {
53+
month?: boolean,
54+
day?: boolean,
55+
hour?: boolean,
56+
minute?: boolean,
57+
second?: boolean,
58+
nanosecond?: boolean,
59+
},
4860
/**
4961
* Sets notification to be silent
5062
*/

0 commit comments

Comments
 (0)