1// Copyright 2018-present 650 Industries. All rights reserved.
2
3#import <EXNotifications/EXNotificationPresentationModule.h>
4
5#import <EXNotifications/EXNotificationBuilder.h>
6#import <EXNotifications/EXNotificationSerializer.h>
7#import <EXNotifications/EXNotificationCenterDelegate.h>
8
9@interface EXNotificationPresentationModule ()
10
11@property (nonatomic, weak) id<EXNotificationBuilder> notificationBuilder;
12
13// Remove once presentNotificationAsync is removed
14@property (nonatomic, strong) NSCountedSet<NSString *> *presentedNotifications;
15@property (nonatomic, weak) id<EXNotificationCenterDelegate> notificationCenterDelegate;
16
17@end
18
19@implementation EXNotificationPresentationModule
20
21EX_EXPORT_MODULE(ExpoNotificationPresenter);
22
23// Remove once presentNotificationAsync is removed
24- (instancetype)init
25{
26  if (self = [super init]) {
27    _presentedNotifications = [NSCountedSet set];
28  }
29  return self;
30}
31
32# pragma mark - Exported methods
33
34// Remove once presentNotificationAsync is removed
35EX_EXPORT_METHOD_AS(presentNotificationAsync,
36                    presentNotificationWithIdentifier:(NSString *)identifier
37                    notification:(NSDictionary *)notificationSpec
38                    resolve:(EXPromiseResolveBlock)resolve
39                    reject:(EXPromiseRejectBlock)reject)
40{
41  UNNotificationContent *content = [_notificationBuilder notificationContentFromRequest:notificationSpec];
42  UNNotificationTrigger *trigger = nil;
43  UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
44  [_presentedNotifications addObject:identifier];
45  __weak EXNotificationPresentationModule *weakSelf = self;
46  [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
47    if (error) {
48      // If there was no error, willPresentNotification: callback will remove the identifier from the set
49      [weakSelf.presentedNotifications removeObject:identifier];
50      NSString *message = [NSString stringWithFormat:@"Notification could not have been presented: %@", error.description];
51      reject(@"ERR_NOTIF_PRESENT", message, error);
52    } else {
53      resolve(identifier);
54    }
55  }];
56}
57
58EX_EXPORT_METHOD_AS(getPresentedNotificationsAsync,
59                    getPresentedNotificationsAsyncWithResolve:(EXPromiseResolveBlock)resolve
60                    reject:(EXPromiseRejectBlock)reject)
61{
62  [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
63    resolve([self serializeNotifications:notifications]);
64  }];
65}
66
67
68EX_EXPORT_METHOD_AS(dismissNotificationAsync,
69                    dismissNotificationWithIdentifier:(NSString *)identifier
70                    resolve:(EXPromiseResolveBlock)resolve
71                    reject:(EXPromiseRejectBlock)reject)
72{
73  [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[identifier]];
74  resolve(nil);
75}
76
77EX_EXPORT_METHOD_AS(dismissAllNotificationsAsync,
78                    dismissAllNotificationsWithResolver:(EXPromiseResolveBlock)resolve
79                    reject:(EXPromiseRejectBlock)reject)
80{
81  [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
82  resolve(nil);
83}
84
85# pragma mark - EXModuleRegistryConsumer
86
87- (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry
88{
89  _notificationBuilder = [moduleRegistry getModuleImplementingProtocol:@protocol(EXNotificationBuilder)];
90
91  // Remove once presentNotificationAsync is removed
92  id<EXNotificationCenterDelegate> notificationCenterDelegate = (id<EXNotificationCenterDelegate>)[moduleRegistry getSingletonModuleForName:@"NotificationCenterDelegate"];
93  [notificationCenterDelegate addDelegate:self];
94}
95
96// Remove once presentNotificationAsync is removed
97# pragma mark - EXNotificationsDelegate
98
99- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
100{
101  UNNotificationPresentationOptions presentationOptions = UNNotificationPresentationOptionNone;
102
103  NSString *identifier = notification.request.identifier;
104  if ([_presentedNotifications containsObject:identifier]) {
105    [_presentedNotifications removeObject:identifier];
106    // TODO(iOS 14): use UNNotificationPresentationOptionList and UNNotificationPresentationOptionBanner
107    presentationOptions = UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge;
108  }
109
110  completionHandler(presentationOptions);
111}
112
113# pragma mark - Helpers
114
115- (NSArray * _Nonnull)serializeNotifications:(NSArray<UNNotification *> * _Nonnull)notifications
116{
117  NSMutableArray *serializedNotifications = [NSMutableArray new];
118  for (UNNotification *notification in notifications) {
119    [serializedNotifications addObject:[EXNotificationSerializer serializedNotification:notification]];
120  }
121  return serializedNotifications;
122}
123
124@end
125