Skip to content

Commit

Permalink
feat(ios): extract settings into PushPluginSettings
Browse files Browse the repository at this point in the history
  • Loading branch information
erisu committed Sep 17, 2024
1 parent 8bae799 commit b6b0691
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 113 deletions.
3 changes: 3 additions & 0 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,11 @@

<source-file src="src/ios/AppDelegate+notification.m"/>
<source-file src="src/ios/PushPlugin.m"/>
<source-file src="src/ios/PushPluginSettings.m"/>

<header-file src="src/ios/AppDelegate+notification.h"/>
<header-file src="src/ios/PushPlugin.h"/>
<header-file src="src/ios/PushPluginSettings.h"/>

<framework src="PushKit.framework"/>

Expand Down
131 changes: 18 additions & 113 deletions src/ios/PushPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/

#import "PushPlugin.h"
#import "PushPluginSettings.h"
#import "AppDelegate+notification.h"

@import Firebase;
Expand Down Expand Up @@ -121,9 +122,10 @@ - (void)unsubscribe:(CDVInvokedUrlCommand *)command {

- (void)init:(CDVInvokedUrlCommand *)command {
NSMutableDictionary* options = [command.arguments objectAtIndex:0];
NSMutableDictionary* iosOptions = [options objectForKey:@"ios"];
id voipArg = [iosOptions objectForKey:@"voip"];
if (([voipArg isKindOfClass:[NSString class]] && [voipArg isEqualToString:@"true"]) || [voipArg boolValue]) {
[[PushPluginSettings sharedInstance] updateSettingsWithOptions:[options objectForKey:@"ios"]];
PushPluginSettings *settings = [PushPluginSettings sharedInstance];

if ([settings voipEnabled]) {
[self.commandDelegate runInBackground:^ {
NSLog(@"[PushPlugin] VoIP set to true");

Expand All @@ -142,114 +144,34 @@ - (void)init:(CDVInvokedUrlCommand *)command {
[self.commandDelegate runInBackground:^ {
NSLog(@"[PushPlugin] register called");
self.callbackId = command.callbackId;

NSArray* topics = [iosOptions objectForKey:@"topics"];
[self setFcmTopics:topics];
self.isInline = NO;
self.fcmTopics = [settings fcmTopics];
self.forceShow = [settings forceShowEnabled];
self.clearBadge = [settings clearBadgeEnabled];
if (self.clearBadge) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}

UNAuthorizationOptions authorizationOptions = UNAuthorizationOptionNone;

id badgeArg = [iosOptions objectForKey:@"badge"];
id soundArg = [iosOptions objectForKey:@"sound"];
id alertArg = [iosOptions objectForKey:@"alert"];
id criticalArg = [iosOptions objectForKey:@"critical"];
id clearBadgeArg = [iosOptions objectForKey:@"clearBadge"];
id forceShowArg = [iosOptions objectForKey:@"forceShow"];

if (([badgeArg isKindOfClass:[NSString class]] && [badgeArg isEqualToString:@"true"]) || [badgeArg boolValue])
{
if ([settings badgeEnabled]) {
authorizationOptions |= UNAuthorizationOptionBadge;
}

if (([soundArg isKindOfClass:[NSString class]] && [soundArg isEqualToString:@"true"]) || [soundArg boolValue])
{
if ([settings soundEnabled]) {
authorizationOptions |= UNAuthorizationOptionSound;
}

if (([alertArg isKindOfClass:[NSString class]] && [alertArg isEqualToString:@"true"]) || [alertArg boolValue])
{
if ([settings alertEnabled]) {
authorizationOptions |= UNAuthorizationOptionAlert;
}

if (@available(iOS 12.0, *))
{
if ((([criticalArg isKindOfClass:[NSString class]] && [criticalArg isEqualToString:@"true"]) || [criticalArg boolValue]))
{
if ([settings criticalEnabled]) {
authorizationOptions |= UNAuthorizationOptionCriticalAlert;
}
}

if (clearBadgeArg == nil || ([clearBadgeArg isKindOfClass:[NSString class]] && [clearBadgeArg isEqualToString:@"false"]) || ![clearBadgeArg boolValue]) {
NSLog(@"[PushPlugin] register: setting badge to false");
clearBadge = NO;
} else {
NSLog(@"[PushPlugin] register: setting badge to true");
clearBadge = YES;
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}
NSLog(@"[PushPlugin] register: clear badge is set to %d", clearBadge);

if (forceShowArg == nil || ([forceShowArg isKindOfClass:[NSString class]] && [forceShowArg isEqualToString:@"false"]) || ![forceShowArg boolValue]) {
NSLog(@"[PushPlugin] register: setting forceShow to false");
forceShow = NO;
} else {
NSLog(@"[PushPlugin] register: setting forceShow to true");
forceShow = YES;
}

isInline = NO;

NSLog(@"[PushPlugin] register: better button setup");
// setup action buttons
NSMutableSet<UNNotificationCategory *> *categories = [[NSMutableSet alloc] init];
id categoryOptions = [iosOptions objectForKey:@"categories"];
if (categoryOptions != nil && [categoryOptions isKindOfClass:[NSDictionary class]]) {
for (id key in categoryOptions) {
NSLog(@"[PushPlugin] categories: key %@", key);
id category = [categoryOptions objectForKey:key];

id yesButton = [category objectForKey:@"yes"];
UNNotificationAction *yesAction;
if (yesButton != nil && [yesButton isKindOfClass:[NSDictionary class]]) {
yesAction = [self createAction: yesButton];
}
id noButton = [category objectForKey:@"no"];
UNNotificationAction *noAction;
if (noButton != nil && [noButton isKindOfClass:[NSDictionary class]]) {
noAction = [self createAction: noButton];
}
id maybeButton = [category objectForKey:@"maybe"];
UNNotificationAction *maybeAction;
if (maybeButton != nil && [maybeButton isKindOfClass:[NSDictionary class]]) {
maybeAction = [self createAction: maybeButton];
}

// Identifier to include in your push payload and local notification
NSString *identifier = key;

NSMutableArray<UNNotificationAction *> *actions = [[NSMutableArray alloc] init];
if (yesButton != nil) {
[actions addObject:yesAction];
}
if (noButton != nil) {
[actions addObject:noAction];
}
if (maybeButton != nil) {
[actions addObject:maybeAction];
}

UNNotificationCategory *notificationCategory = [UNNotificationCategory categoryWithIdentifier:identifier
actions:actions
intentIdentifiers:@[]
options:UNNotificationCategoryOptionNone];

NSLog(@"[PushPlugin] Adding category %@", key);
[categories addObject:notificationCategory];
}
}
[self handleNotificationSettingsWithAuthorizationOptions:[NSNumber numberWithInteger:authorizationOptions]];

UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center setNotificationCategories:categories];
[self handleNotificationSettingsWithAuthorizationOptions:[NSNumber numberWithInteger:authorizationOptions]];
[center setNotificationCategories:[settings categories]];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleNotificationSettings:)
Expand Down Expand Up @@ -291,23 +213,6 @@ - (void)init:(CDVInvokedUrlCommand *)command {
}
}

- (UNNotificationAction *)createAction:(NSDictionary *)dictionary {
NSString *identifier = [dictionary objectForKey:@"callback"];
NSString *title = [dictionary objectForKey:@"title"];
UNNotificationActionOptions options = UNNotificationActionOptionNone;

id mode = [dictionary objectForKey:@"foreground"];
if (mode != nil && (([mode isKindOfClass:[NSString class]] && [mode isEqualToString:@"true"]) || [mode boolValue])) {
options |= UNNotificationActionOptionForeground;
}
id destructive = [dictionary objectForKey:@"destructive"];
if (destructive != nil && (([destructive isKindOfClass:[NSString class]] && [destructive isEqualToString:@"true"]) || [destructive boolValue])) {
options |= UNNotificationActionOptionDestructive;
}

return [UNNotificationAction actionWithIdentifier:identifier title:title options:options];
}

- (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
if (self.callbackId == nil) {
NSLog(@"[PushPlugin] Unexpected call to didRegisterForRemoteNotificationsWithDeviceToken, ignoring: %@", deviceToken);
Expand Down
28 changes: 28 additions & 0 deletions src/ios/PushPluginSettings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// PushPluginSettings.h
// cordovaTest
//
// Created by Erisu on 2024/09/14.
//

#import <Foundation/Foundation.h>
#import <UserNotifications/UserNotifications.h>

@interface PushPluginSettings : NSObject

@property (nonatomic, readonly) BOOL badgeEnabled;
@property (nonatomic, readonly) BOOL soundEnabled;
@property (nonatomic, readonly) BOOL alertEnabled;
@property (nonatomic, readonly) BOOL criticalEnabled;
@property (nonatomic, readonly) BOOL clearBadgeEnabled;
@property (nonatomic, readonly) BOOL forceShowEnabled;
@property (nonatomic, readonly) BOOL voipEnabled;

@property (nonatomic, readonly, strong) NSArray *fcmTopics;
@property (nonatomic, readonly, strong) NSSet<UNNotificationCategory *> *categories;

+ (instancetype)sharedInstance;

- (void)updateSettingsWithOptions:(NSDictionary *)options;

@end
179 changes: 179 additions & 0 deletions src/ios/PushPluginSettings.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//
// PushPluginSettings.m
// cordovaTest
//
// Created by Erisu on 2024/09/14.
//

#import "PushPluginSettings.h"

@interface PushPluginSettings ()

@property (nonatomic, strong) NSMutableDictionary *settingsDictionary;

@end

@implementation PushPluginSettings

+ (instancetype)sharedInstance {
static PushPluginSettings *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] initWithDefaults];
});
return sharedInstance;
}

- (instancetype)initWithDefaults {
self = [super init];
if (self) {
self.settingsDictionary = [@{
@"badge" : @(NO),
@"sound" : @(NO),
@"alert" : @(NO),
@"critical" : @(NO),
@"clearBadge" : @(NO),
@"forceShow" : @(NO),
@"voip" : @(NO),
@"fcmTopics" : @[],
@"categories" : [NSSet set]
} mutableCopy];
}
return self;
}

- (void)updateSettingsWithOptions:(NSDictionary *)options {
for (NSString *key in options) {
if ([self.settingsDictionary objectForKey:key]) {
// Overrides the default setting if defined and apply the correct formatting based on the key.
if ([key isEqualToString:@"fcmTopics"]) {
self.settingsDictionary[key] = [self parseArrayOption:key fromOptions:options withDefault:nil];
} else if ([key isEqualToString:@"categories"]) {
self.settingsDictionary[key] = [self parseCategoriesFromOptions:options[key]];
} else {
self.settingsDictionary[key] = @([self parseOption:key fromOptions:options withDefault:NO]);
}
} else {
NSLog(@"[PushPlugin] Settings: Invalid option key: %@", key);
}
}

NSLog(@"[PushPlugin] Settings: %@", self.settingsDictionary);
}

- (BOOL)parseOption:(NSString *)key fromOptions:(NSDictionary *)options withDefault:(BOOL)defaultValue {
id option = [options objectForKey:key];
if ([option isKindOfClass:[NSString class]]) {
return [option isEqualToString:@"true"];
}
if ([option respondsToSelector:@selector(boolValue)]) {
return [option boolValue];
}
return defaultValue;
}

- (NSArray *)parseArrayOption:(NSString *)key fromOptions:(NSDictionary *)options withDefault:(NSArray *)defaultValue {
id option = [options objectForKey:key];
if ([option isKindOfClass:[NSArray class]]) {
return (NSArray *)option;
}
return defaultValue;
}

- (NSSet<UNNotificationCategory *> *)parseCategoriesFromOptions:(NSDictionary *)categoryOptions {
NSMutableSet<UNNotificationCategory *> *categoriesSet = [[NSMutableSet alloc] init];
if (categoryOptions != nil && [categoryOptions isKindOfClass:[NSDictionary class]]) {
for (id key in categoryOptions) {
NSDictionary *category = [categoryOptions objectForKey:key];
UNNotificationCategory *notificationCategory = [self createCategoryFromDictionary:category withIdentifier:key];
if (notificationCategory) {
[categoriesSet addObject:notificationCategory];
}
}
}
return categoriesSet;
}

- (UNNotificationCategory *)createCategoryFromDictionary:(NSDictionary *)category withIdentifier:(NSString *)identifier {
NSMutableArray<UNNotificationAction *> *actions = [[NSMutableArray alloc] init];

UNNotificationAction *yesAction = [self createActionFromDictionary:[category objectForKey:@"yes"]];
if (yesAction)
[actions addObject:yesAction];

UNNotificationAction *noAction = [self createActionFromDictionary:[category objectForKey:@"no"]];
if (noAction)
[actions addObject:noAction];

UNNotificationAction *maybeAction = [self createActionFromDictionary:[category objectForKey:@"maybe"]];
if (maybeAction)
[actions addObject:maybeAction];

return [UNNotificationCategory categoryWithIdentifier:identifier actions:actions intentIdentifiers:@[] options:UNNotificationCategoryOptionNone];
}

- (UNNotificationAction *)createActionFromDictionary:(NSDictionary *)dictionary {
if (![dictionary isKindOfClass:[NSDictionary class]]) {
return nil;
}

NSString *identifier = [dictionary objectForKey:@"identifier"];
NSString *title = [dictionary objectForKey:@"title"];

if (!title || !identifier) {
return nil;
}

UNNotificationActionOptions options = UNNotificationActionOptionNone;
id foreground = [dictionary objectForKey:@"foreground"];
if (foreground != nil && (([foreground isKindOfClass:[NSString class]] && [foreground isEqualToString:@"true"]) || [foreground boolValue])) {
options |= UNNotificationActionOptionForeground;
}

id destructive = [dictionary objectForKey:@"destructive"];
if (destructive != nil && (([destructive isKindOfClass:[NSString class]] && [destructive isEqualToString:@"true"]) || [destructive boolValue])) {
options |= UNNotificationActionOptionDestructive;
}

return [UNNotificationAction actionWithIdentifier:identifier title:title options:options];
}

#pragma mark - Getters for individual settings

- (BOOL)badgeEnabled {
return [self.settingsDictionary[@"badge"] boolValue];
}

- (BOOL)soundEnabled {
return [self.settingsDictionary[@"sound"] boolValue];
}

- (BOOL)alertEnabled {
return [self.settingsDictionary[@"alert"] boolValue];
}

- (BOOL)criticalEnabled {
return [self.settingsDictionary[@"critical"] boolValue];
}

- (BOOL)clearBadgeEnabled {
return [self.settingsDictionary[@"clearBadge"] boolValue];
}

- (BOOL)forceShowEnabled {
return [self.settingsDictionary[@"forceShow"] boolValue];
}

- (BOOL)voipEnabled {
return [self.settingsDictionary[@"voip"] boolValue];
}

- (NSArray *)fcmTopics {
return self.settingsDictionary[@"fcmTopics"];
}

- (NSSet<UNNotificationCategory *> *)categories {
return self.settingsDictionary[@"categories"];
}

@end

0 comments on commit b6b0691

Please sign in to comment.