Commit 6c99242e authored by yogevbd's avatar yogevbd

Splits requestPermissionsWithCategories to two functions

parent 8099dbfc
#import "RCTConvert+RNNotifications.h" #import "RCTConvert+RNNotifications.h"
@implementation RCTConvert (UIUserNotificationActivationMode)
RCT_ENUM_CONVERTER(UIUserNotificationActivationMode, (@{
@"foreground": @(UIUserNotificationActivationModeForeground),
@"background": @(UIUserNotificationActivationModeBackground)
}), UIUserNotificationActivationModeForeground, integerValue)
@end
@implementation RCTConvert (UNNotificationActionOptions) @implementation RCTConvert (UNNotificationActionOptions)
+ (UNNotificationActionOptions)UNUserNotificationActionOptions:(id)json { + (UNNotificationActionOptions)UNUserNotificationActionOptions:(id)json {
......
...@@ -32,8 +32,12 @@ RCT_EXPORT_MODULE(); ...@@ -32,8 +32,12 @@ RCT_EXPORT_MODULE();
#pragma mark - JS interface #pragma mark - JS interface
RCT_EXPORT_METHOD(requestPermissionsWithCategories:(NSArray *)json) { RCT_EXPORT_METHOD(requestPermissions) {
[_commandsHandler requestPermissionsWithCategories:json]; [_commandsHandler requestPermissions];
}
RCT_EXPORT_METHOD(setCategories:(NSArray *)categories) {
[_commandsHandler setCategories:categories];
} }
RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
......
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
- (instancetype)init; - (instancetype)init;
- (void)requestPermissionsWithCategories:(NSArray *)json; - (void)requestPermissions;
- (void)setCategories:(NSArray *)categories;
- (void)getInitialNotification:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; - (void)getInitialNotification:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
......
...@@ -13,8 +13,12 @@ ...@@ -13,8 +13,12 @@
return self; return self;
} }
- (void)requestPermissionsWithCategories:(NSArray *)json { - (void)requestPermissions {
[_notificationCenter requestPermissionsWithCategories:json]; [_notificationCenter requestPermissions];
}
- (void)setCategories:(NSArray *)categories {
[_notificationCenter setCategories:categories];
} }
- (void)getInitialNotification:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - (void)getInitialNotification:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
......
...@@ -10,7 +10,9 @@ typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError ...@@ -10,7 +10,9 @@ typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError
- (void)isRegisteredForRemoteNotifications:(RCTPromiseResolveBlock)resolve; - (void)isRegisteredForRemoteNotifications:(RCTPromiseResolveBlock)resolve;
- (void)requestPermissionsWithCategories:(NSArray *)json; - (void)requestPermissions;
- (void)setCategories:(NSArray *)json;
- (void)checkPermissions:(RCTPromiseResolveBlock)resolve; - (void)checkPermissions:(RCTPromiseResolveBlock)resolve;
......
...@@ -3,16 +3,7 @@ ...@@ -3,16 +3,7 @@
@implementation RNNotificationCenter @implementation RNNotificationCenter
- (void)requestPermissionsWithCategories:(NSArray *)json { - (void)requestPermissions {
NSMutableSet<UNNotificationCategory *>* categories = nil;
if ([json count] > 0) {
categories = [NSMutableSet new];
for (NSDictionary* categoryJson in json) {
[categories addObject:[RCTConvert UNMutableUserNotificationCategory:categoryJson]];
}
}
[[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:categories];
UNAuthorizationOptions authOptions = (UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert); UNAuthorizationOptions authOptions = (UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert);
[UNUserNotificationCenter.currentNotificationCenter requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) { [UNUserNotificationCenter.currentNotificationCenter requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error && granted) { if (!error && granted) {
...@@ -27,6 +18,18 @@ ...@@ -27,6 +18,18 @@
}]; }];
} }
- (void)setCategories:(NSArray *)json {
NSMutableSet<UNNotificationCategory *>* categories = nil;
if ([json count] > 0) {
categories = [NSMutableSet new];
for (NSDictionary* categoryJson in json) {
[categories addObject:[RCTConvert UNMutableUserNotificationCategory:categoryJson]];
}
}
[[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:categories];
}
- (void)sendLocalNotification:(NSDictionary *)notification withId:(NSString *)notificationId { - (void)sendLocalNotification:(NSDictionary *)notification withId:(NSString *)notificationId {
UNNotificationRequest* localNotification = [RCTConvert UNNotificationRequest:notification withId:notificationId]; UNNotificationRequest* localNotification = [RCTConvert UNNotificationRequest:notification withId:notificationId];
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:localNotification withCompletionHandler:nil]; [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:localNotification withCompletionHandler:nil];
......
...@@ -25,33 +25,43 @@ ...@@ -25,33 +25,43 @@
_notificationCenter = [UNUserNotificationCenter currentNotificationCenter]; _notificationCenter = [UNUserNotificationCenter currentNotificationCenter];
} }
- (void)testRequestPermissionsWithCategories_userAuthorizedPermissions { - (void)testRequestPermissions_userAuthorizedPermissions {
NSArray* json = @[@{@"identifier": @"identifier"}];
UNAuthorizationOptions authOptions = (UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert); UNAuthorizationOptions authOptions = (UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert);
UNNotificationSettings* settings = [UNNotificationSettings new]; UNNotificationSettings* settings = [UNNotificationSettings new];
[settings setValue:@(UNAuthorizationStatusAuthorized) forKey:@"authorizationStatus"]; [settings setValue:@(UNAuthorizationStatusAuthorized) forKey:@"authorizationStatus"];
[[_notificationCenter expect] setNotificationCategories:[OCMArg any]];
[[_notificationCenter expect] requestAuthorizationWithOptions:authOptions completionHandler:[OCMArg invokeBlockWithArgs:@(YES), [NSNull null], nil]]; [[_notificationCenter expect] requestAuthorizationWithOptions:authOptions completionHandler:[OCMArg invokeBlockWithArgs:@(YES), [NSNull null], nil]];
[[_notificationCenter expect] getNotificationSettingsWithCompletionHandler:[OCMArg invokeBlockWithArgs:settings, nil]]; [[_notificationCenter expect] getNotificationSettingsWithCompletionHandler:[OCMArg invokeBlockWithArgs:settings, nil]];
[[(id)[UIApplication sharedApplication] expect] registerForRemoteNotifications]; [[(id)[UIApplication sharedApplication] expect] registerForRemoteNotifications];
[_uut requestPermissionsWithCategories:json]; [_uut requestPermissions];
[_notificationCenter verify]; [_notificationCenter verify];
} }
- (void)testRequestPermissionsWithCategories_userDeniedPermissions { - (void)testRequestPermissions_userDeniedPermissions {
NSArray* json = @[@{@"identifier": @"identifier"}];
UNAuthorizationOptions authOptions = (UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert); UNAuthorizationOptions authOptions = (UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert);
UNNotificationSettings* settings = [UNNotificationSettings new]; UNNotificationSettings* settings = [UNNotificationSettings new];
[settings setValue:@(UNAuthorizationStatusDenied) forKey:@"authorizationStatus"]; [settings setValue:@(UNAuthorizationStatusDenied) forKey:@"authorizationStatus"];
[[_notificationCenter expect] setNotificationCategories:[OCMArg any]];
[[_notificationCenter expect] requestAuthorizationWithOptions:authOptions completionHandler:[OCMArg invokeBlockWithArgs:@(YES), [NSNull null], nil]]; [[_notificationCenter expect] requestAuthorizationWithOptions:authOptions completionHandler:[OCMArg invokeBlockWithArgs:@(YES), [NSNull null], nil]];
[[_notificationCenter expect] getNotificationSettingsWithCompletionHandler:[OCMArg invokeBlockWithArgs:settings, nil]]; [[_notificationCenter expect] getNotificationSettingsWithCompletionHandler:[OCMArg invokeBlockWithArgs:settings, nil]];
[[(id)[UIApplication sharedApplication] reject] registerForRemoteNotifications]; [[(id)[UIApplication sharedApplication] reject] registerForRemoteNotifications];
[_uut requestPermissionsWithCategories:json]; [_uut requestPermissions];
[_notificationCenter verify];
}
- (void)testSetCategories_shouldSetCategories {
NSArray* json = @[@{@"identifier": @"categoryId", @"actions": @[@{@"identifier" : @"actionId", @"activationMode": @"foreground"}]}];
[[_notificationCenter expect] setNotificationCategories:[OCMArg checkWithBlock:^BOOL(NSMutableSet<UNNotificationCategory *>* categories) {
UNNotificationCategory* category = categories.allObjects.firstObject;
UNNotificationAction* action = category.actions.firstObject;
return ([category.identifier isEqualToString:@"categoryId"] &&
[action.identifier isEqualToString:@"actionId"] &&
action.options == UNNotificationActionOptionForeground);
}]];
[_uut setCategories:json];
[_notificationCenter verify]; [_notificationCenter verify];
} }
......
...@@ -2,7 +2,7 @@ import { NativeCommandsSender } from './adapters/NativeCommandsSender'; ...@@ -2,7 +2,7 @@ import { NativeCommandsSender } from './adapters/NativeCommandsSender';
import { NativeEventsReceiver } from './adapters/NativeEventsReceiver'; import { NativeEventsReceiver } from './adapters/NativeEventsReceiver';
import { Commands } from './commands/Commands'; import { Commands } from './commands/Commands';
import { EventsRegistry } from './events/EventsRegistry'; import { EventsRegistry } from './events/EventsRegistry';
import { Notification } from './interfaces/Notification'; import { Notification, NotificationCategory } from './interfaces/Notification';
export class NotificationsRoot { export class NotificationsRoot {
private readonly nativeEventsReceiver: NativeEventsReceiver; private readonly nativeEventsReceiver: NativeEventsReceiver;
...@@ -22,14 +22,21 @@ export class NotificationsRoot { ...@@ -22,14 +22,21 @@ export class NotificationsRoot {
/** /**
* Request permissions to send remote notifications - iOS only * Request permissions to send remote notifications - iOS only
*/ */
public requestPermissions(): Promise<any> { public requestPermissions() {
return this.commands.requestPermissions(); return this.commands.requestPermissions();
} }
/**
* registerPushKit
*/
public registerPushKit() {
return this.commands.registerPushKit();
}
/** /**
* Reset the app to a new layout * Reset the app to a new layout
*/ */
public localNotification(notification: Notification): Promise<any> { public localNotification(notification: Notification) {
return this.commands.sendLocalNotification(notification); return this.commands.sendLocalNotification(notification);
} }
...@@ -40,6 +47,71 @@ export class NotificationsRoot { ...@@ -40,6 +47,71 @@ export class NotificationsRoot {
return this.commands.getInitialNotification(); return this.commands.getInitialNotification();
} }
/**
* setCategories
*/
public setCategories(categories: [NotificationCategory?]) {
this.commands.setCategories(categories);
}
/**
* getBadgesCount
*/
public getBadgeCount(): Promise<number> {
return this.commands.getBadgeCount();
}
/**
* setBadgeCount
* @param count number of the new badge count
*/
public setBadgeCount(count: number) {
return this.commands.setBadgeCount(count);
}
/**
* cancelLocalNotification
*/
public cancelLocalNotification(notificationId: string) {
return this.commands.cancelLocalNotification(notificationId);
}
/**
* cancelAllLocalNotifications
*/
public cancelAllLocalNotifications() {
this.commands.cancelAllLocalNotifications();
}
/**
* isRegisteredForRemoteNotifications
*/
public isRegisteredForRemoteNotifications(): Promise<any> {
this.commands.isRegisteredForRemoteNotifications();
}
/**
* checkPermissions
*/
public checkPermissions() {
return this.commands.checkPermissions();
}
/**
* removeAllDeliveredNotifications
*/
public removeAllDeliveredNotifications() {
return this.commands.removeAllDeliveredNotifications();
}
/**
* removeDeliveredNotifications
* @param identifiers Array of notification identifiers
*/
public removeDeliveredNotifications(identifiers: Array<string>) {
return this.commands.removeDeliveredNotifications(identifiers);
}
/** /**
* Obtain the events registry instance * Obtain the events registry instance
*/ */
......
import { NativeModules } from 'react-native'; import { NativeModules } from 'react-native';
import { Notification } from '../interfaces/Notification'; import { Notification, NotificationCategory, NotificationPermissions } from '../interfaces/Notification';
interface NativeCommandsModule { interface NativeCommandsModule {
getInitialNotification(): Promise<any>; getInitialNotification(): Promise<Notification>;
localNotification(notification: Notification, id: string): Promise<Notification>; localNotification(notification: Notification, id: string): void;
requestPermissionsWithCategories(categories: any): Promise<any>; requestPermissions(): void;
abandonPermissions(): Promise<any>; abandonPermissions(): void;
registerPushKit(): void;
getBadgeCount(): Promise<number>;
setBadgeCount(count: number): void;
cancelLocalNotification(notificationId: string): void;
cancelAllLocalNotifications(): void;
isRegisteredForRemoteNotifications(): Promise<boolean>;
checkPermissions(): Promise<NotificationPermissions>;
removeDeliveredNotifications(identifiers: Array<string>): void;
removeAllDeliveredNotifications(): void;
setCategories(categories: [NotificationCategory?]): void;
} }
export class NativeCommandsSender { export class NativeCommandsSender {
...@@ -23,10 +33,50 @@ export class NativeCommandsSender { ...@@ -23,10 +33,50 @@ export class NativeCommandsSender {
} }
requestPermissions() { requestPermissions() {
return this.nativeCommandsModule.requestPermissionsWithCategories([]); return this.nativeCommandsModule.requestPermissions();
} }
abandonPermissions() { abandonPermissions() {
return this.nativeCommandsModule.abandonPermissions(); return this.nativeCommandsModule.abandonPermissions();
} }
registerPushKit() {
return this.nativeCommandsModule.registerPushKit();
}
setCategories(categories: [NotificationCategory?]) {
this.nativeCommandsModule.setCategories(categories);
}
getBadgeCount(): Promise<number> {
return this.nativeCommandsModule.getBadgeCount();
}
setBadgeCount(count: number) {
this.nativeCommandsModule.setBadgeCount(count);
}
cancelLocalNotification(notificationId: string) {
this.nativeCommandsModule.cancelLocalNotification(notificationId);
}
cancelAllLocalNotifications() {
this.nativeCommandsModule.cancelAllLocalNotifications();
}
isRegisteredForRemoteNotifications(): Promise<any> {
return this.nativeCommandsModule.isRegisteredForRemoteNotifications();
}
checkPermissions() {
return this.nativeCommandsModule.checkPermissions();
}
removeAllDeliveredNotifications() {
return this.nativeCommandsModule.removeAllDeliveredNotifications();
}
removeDeliveredNotifications(identifiers: Array<string>) {
return this.nativeCommandsModule.removeDeliveredNotifications(identifiers);
}
} }
...@@ -3,7 +3,7 @@ import { mock, verify, instance, deepEqual, when, anything, anyString } from 'ts ...@@ -3,7 +3,7 @@ import { mock, verify, instance, deepEqual, when, anything, anyString } from 'ts
import { Commands } from './Commands'; import { Commands } from './Commands';
import { NativeCommandsSender } from '../adapters/NativeCommandsSender'; import { NativeCommandsSender } from '../adapters/NativeCommandsSender';
import { Notification } from '../interfaces/Notification'; import { Notification, NotificationCategory, NotificationPermissions } from '../interfaces/Notification';
describe('Commands', () => { describe('Commands', () => {
let uut: Commands; let uut: Commands;
...@@ -18,7 +18,7 @@ describe('Commands', () => { ...@@ -18,7 +18,7 @@ describe('Commands', () => {
}); });
describe('getInitialNotification', () => { describe('getInitialNotification', () => {
it('sends getInitialNotification to native', () => { it('sends to native', () => {
uut.getInitialNotification(); uut.getInitialNotification();
verify(mockedNativeCommandsSender.getInitialNotification()).called(); verify(mockedNativeCommandsSender.getInitialNotification()).called();
}); });
...@@ -33,24 +33,129 @@ describe('Commands', () => { ...@@ -33,24 +33,129 @@ describe('Commands', () => {
}); });
describe('requestPermissions', () => { describe('requestPermissions', () => {
it('sends requestPermissions to native', () => { it('sends to native', () => {
uut.requestPermissions(); uut.requestPermissions();
verify(mockedNativeCommandsSender.requestPermissions()).called(); verify(mockedNativeCommandsSender.requestPermissions()).called();
}); });
}); });
describe('registerPushKit', () => {
it('sends to native', () => {
uut.registerPushKit();
verify(mockedNativeCommandsSender.registerPushKit()).called();
});
});
describe('setCategories', () => {
it('sends to native', () => {
const emptyCategoriesArray: [NotificationCategory?] = [];
uut.setCategories(emptyCategoriesArray);
verify(mockedNativeCommandsSender.setCategories(emptyCategoriesArray)).called();
});
it('sends to native with categories', () => {
const category: NotificationCategory = {identifier: 'id', actions: []};
const categoriesArray: [NotificationCategory] = [category];
uut.setCategories(categoriesArray);
verify(mockedNativeCommandsSender.setCategories(categoriesArray)).called();
});
});
describe('abandonPermissions', () => { describe('abandonPermissions', () => {
it('sends abandonPermissions to native', () => { it('sends to native', () => {
uut.abandonPermissions(); uut.abandonPermissions();
verify(mockedNativeCommandsSender.abandonPermissions()).called(); verify(mockedNativeCommandsSender.abandonPermissions()).called();
}); });
}); });
describe('sendLocalNotification', () => { describe('sendLocalNotification', () => {
it('sends sendLocalNotification to native', () => { it('sends to native', () => {
const notification: Notification = {data: {}, alert: 'alert'}; const notification: Notification = {data: {}, alert: 'alert'};
uut.sendLocalNotification(notification); uut.sendLocalNotification(notification);
verify(mockedNativeCommandsSender.sendLocalNotification(notification, 'id')).called(); verify(mockedNativeCommandsSender.sendLocalNotification(notification, 'id')).called();
}); });
}); });
describe('getBadgeCount', () => {
it('sends to native', () => {
uut.getBadgeCount();
verify(mockedNativeCommandsSender.getBadgeCount()).called();
});
});
describe('setBadgeCount', () => {
it('sends to native', () => {
uut.setBadgeCount(10);
verify(mockedNativeCommandsSender.setBadgeCount(10)).called();
});
});
describe('cancelLocalNotification', () => {
it('sends to native', () => {
uut.cancelLocalNotification("notificationId");
verify(mockedNativeCommandsSender.cancelLocalNotification("notificationId")).called();
});
});
describe('cancelAllLocalNotifications', () => {
it('sends to native', () => {
uut.cancelAllLocalNotifications();
verify(mockedNativeCommandsSender.cancelAllLocalNotifications()).called();
});
});
describe('isRegisteredForRemoteNotifications', () => {
it('sends to native', () => {
uut.isRegisteredForRemoteNotifications();
verify(mockedNativeCommandsSender.isRegisteredForRemoteNotifications()).called();
});
it('return positive response from native', async () => {
when(mockedNativeCommandsSender.isRegisteredForRemoteNotifications()).thenResolve(
true
);
const isRegistered = await uut.isRegisteredForRemoteNotifications();
verify(mockedNativeCommandsSender.isRegisteredForRemoteNotifications()).called();
expect(isRegistered).toEqual(true);
});
it('return negative response from native', async () => {
when(mockedNativeCommandsSender.isRegisteredForRemoteNotifications()).thenResolve(
false
);
const isRegistered = await uut.isRegisteredForRemoteNotifications();
expect(isRegistered).toEqual(false);
});
});
describe('checkPermissions', () => {
it('sends to native', () => {
uut.checkPermissions();
verify(mockedNativeCommandsSender.checkPermissions()).called();
});
it('return negative response from native', async () => {
const expectedPermissions: NotificationPermissions = {badge: false, alert: true, sound: false};
when(mockedNativeCommandsSender.checkPermissions()).thenResolve(
expectedPermissions
);
const permissions = await uut.checkPermissions();
expect(permissions).toEqual(expectedPermissions);
});
});
describe('removeAllDeliveredNotifications', () => {
it('sends to native', () => {
uut.removeAllDeliveredNotifications();
verify(mockedNativeCommandsSender.removeAllDeliveredNotifications()).called();
});
});
describe('removeDeliveredNotifications', async () => {
it('sends to native', () => {
const identifiers: Array<string> = ["id1", "id2"];
uut.removeDeliveredNotifications(identifiers);
verify(mockedNativeCommandsSender.removeDeliveredNotifications(identifiers)).called();
});
});
}); });
import * as _ from 'lodash'; import * as _ from 'lodash';
import { NativeCommandsSender } from '../adapters/NativeCommandsSender'; import { NativeCommandsSender } from '../adapters/NativeCommandsSender';
import { Notification } from '../interfaces/Notification'; import { Notification, NotificationCategory, NotificationPermissions } from '../interfaces/Notification';
export class Commands { export class Commands {
constructor( constructor(
...@@ -27,4 +27,44 @@ export class Commands { ...@@ -27,4 +27,44 @@ export class Commands {
const result = this.nativeCommandsSender.abandonPermissions(); const result = this.nativeCommandsSender.abandonPermissions();
return result; return result;
} }
public registerPushKit() {
this.nativeCommandsSender.registerPushKit();
}
public setCategories(categories: [NotificationCategory?]) {
this.nativeCommandsSender.setCategories(categories);
}
public getBadgeCount(): Promise<number> {
return this.nativeCommandsSender.getBadgeCount();
}
public setBadgeCount(count: number) {
this.nativeCommandsSender.setBadgeCount(count);
}
public cancelLocalNotification(notificationId: string) {
this.nativeCommandsSender.cancelLocalNotification(notificationId);
}
public cancelAllLocalNotifications() {
this.nativeCommandsSender.cancelAllLocalNotifications();
}
public isRegisteredForRemoteNotifications(): Promise<boolean> {
return this.nativeCommandsSender.isRegisteredForRemoteNotifications();
}
public checkPermissions(): Promise<NotificationPermissions> {
return this.nativeCommandsSender.checkPermissions();
}
public removeAllDeliveredNotifications() {
this.nativeCommandsSender.removeAllDeliveredNotifications();
}
public removeDeliveredNotifications(identifiers: Array<string>) {
return this.nativeCommandsSender.removeDeliveredNotifications(identifiers);
}
} }
...@@ -6,3 +6,28 @@ export interface Notification { ...@@ -6,3 +6,28 @@ export interface Notification {
type?: string; type?: string;
thread?: string; thread?: string;
} }
export interface NotificationPermissions {
badge: boolean;
alert: boolean;
sound: boolean;
}
export interface NotificationCategory {
identifier: string
actions: [NotificationAction?];
}
export interface NotificationTextInput {
buttonTitle: string;
placeholder: string;
}
export interface NotificationAction {
identifier: string;
activationMode: 'foreground' | 'authenticationRequired' | 'destructive';
title: string;
authenticationRequired: boolean;
textInput: NotificationTextInput
}
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