Commit c0e921c1 authored by yogevbd's avatar yogevbd

typescript WIP

parent f666b856
...@@ -109,7 +109,7 @@ ...@@ -109,7 +109,7 @@
formattedNotification[@"body"] = RCTNullIfNil(content.body); formattedNotification[@"body"] = RCTNullIfNil(content.body);
formattedNotification[@"category"] = RCTNullIfNil(content.categoryIdentifier); formattedNotification[@"category"] = RCTNullIfNil(content.categoryIdentifier);
formattedNotification[@"thread"] = RCTNullIfNil(content.threadIdentifier); formattedNotification[@"thread"] = RCTNullIfNil(content.threadIdentifier);
[formattedNotification addEntriesFromDictionary:RCTNullIfNil(RCTJSONClean(content.userInfo))]; formattedNotification[@"data"] = [NSDictionary dictionaryWithDictionary:RCTNullIfNil(RCTJSONClean(content.userInfo))];
return formattedNotification; return formattedNotification;
} }
......
...@@ -4,15 +4,11 @@ ...@@ -4,15 +4,11 @@
@implementation RNNotificationParser @implementation RNNotificationParser
+ (NSDictionary *)parseNotification:(UNNotification *)notification { + (NSDictionary *)parseNotification:(UNNotification *)notification {
NSDictionary* notificationDict = @{@"identifier": notification.request.identifier, return [RCTConvert UNNotificationPayload:notification];
@"payload": [RCTConvert UNNotificationPayload:notification]
};
return notificationDict;
} }
+ (NSDictionary *)parseNotificationResponse:(UNNotificationResponse *)response { + (NSDictionary *)parseNotificationResponse:(UNNotificationResponse *)response {
NSDictionary* responseDict = @{@"payload": [RCTConvert UNNotificationPayload:response.notification], @"identifier": response.notification.request.identifier, @"action": [self parseNotificationResponseAction:response]}; NSDictionary* responseDict = @{@"notification": [RCTConvert UNNotificationPayload:response.notification], @"identifier": response.notification.request.identifier, @"action": [self parseNotificationResponseAction:response]};
return responseDict; return responseDict;
} }
......
...@@ -6,90 +6,92 @@ import { ...@@ -6,90 +6,92 @@ import {
Button Button
} from 'react-native'; } from 'react-native';
import React, {Component} from 'react'; import React, {Component} from 'react';
import { Notifications } from '../lib/dist/index'; import { Notifications } from '../lib/dist/index';
// let upvoteAction = new NotificationAction({
// activationMode: 'background',
// title: String.fromCodePoint(0x1F44D),
// identifier: 'UPVOTE_ACTION'
// });
// let replyAction = new NotificationAction({
// activationMode: 'background',
// title: 'Reply',
// authenticationRequired: true,
// textInput: {
// buttonTitle: 'Reply now',
// placeholder: 'Insert message'
// },
// identifier: 'REPLY_ACTION'
// });
class NotificationsExampleApp extends Component { class NotificationsExampleApp extends Component {
constructor() { constructor() {
super(); super();
this.state = { this.state = {
notifications: [] notifications: []
}; };
Notifications.events().registerNotificationsReceived((notification) => { this.registerNotificationEvents();
alert(JSON.stringify(notification)); }
})
// NotificationsIOS.addEventListener('remoteNotificationsRegistered', this.onPushRegistered.bind(this));
// NotificationsIOS.addEventListener('remoteNotificationsRegistrationFailed', this.onPushRegisteredFailed.bind(this));
// NotificationsIOS.addEventListener('pushKitRegistered', this.onPushKitRegistered.bind(this)); registerNotificationEvents() {
// NotificationsIOS.registerPushKit(); Notifications.events().registerNotificationReceived((notification, completion) => {
this.setState({
notifications: [...this.state.notifications, notification.data.link]
});
// NotificationsIOS.addEventListener('notificationReceivedForeground', this.onNotificationReceivedForeground.bind(this)); completion({alert: true, sound: false, badge: false});
// NotificationsIOS.addEventListener('notificationOpened', this.onNotificationOpened.bind(this)); });
// NotificationsIOS.addEventListener('pushKitNotificationReceived', this.onPushKitNotificationReceived.bind(this));
}
async componentDidMount() { Notifications.events().registerRemoteNotificationOpened((response, completion) => {
const initialNotification = await Notifications.getInitialNotification(); this.setState({
if (initialNotification) { notifications: [...this.state.notifications, `Notification Clicked: ${response.notification.data.link}`]
this.setState({notifications: [initialNotification.getData().link, ...this.state.notifications]}); });
}
completion();
});
} }
onPushRegistered(deviceToken) { renderNotification(notification) {
console.log('Device Token Received: ' + deviceToken); return <Text>{`${notification}`}</Text>;
} }
onPushRegisteredFailed(error) { requestPermissions() {
console.log('Remote notifiction registration failed: ' + error); Notifications.requestPermissions();
} }
onPushKitRegistered(deviceToken) { setCategories() {
console.log('PushKit Token Received: ' + deviceToken); const upvoteAction = {
} activationMode: 'background',
title: String.fromCodePoint(0x1F44D),
identifier: 'UPVOTE_ACTION'
};
const replyAction = {
activationMode: 'background',
title: 'Reply',
authenticationRequired: true,
textInput: {
buttonTitle: 'Reply now',
placeholder: 'Insert message'
},
identifier: 'REPLY_ACTION'
};
const category = {
identifier: 'SOME_CATEGORY',
actions: [upvoteAction, replyAction]
};
onPushKitNotificationReceived(notification) { Notifications.setCategories([category]);
console.log('PushKit notification Received: ' + JSON.stringify(notification));
} }
onNotificationReceivedForeground(notification, completion) { sendLocalNotification() {
console.log('Notification Received Foreground with title: ' + JSON.stringify(notification)); Notifications.localNotification({
this.setState({ body: 'Local notificiation!',
notifications: [...this.state.notifications, notification.getData().link] title: 'Local Notification Title',
sound: 'chime.aiff',
category: 'SOME_CATEGORY',
userInfo: { link: 'localNotificationLink' },
}); });
}
completion({alert: notification.getData().showAlert, sound: false, badge: false}); removeAllDeliveredNotifications() {
Notifications.removeAllDeliveredNotifications();
} }
onNotificationOpened(notification, completion, action) { async componentDidMount() {
console.log('Notification Opened: ' + JSON.stringify(notification) + JSON.stringify(action)); const initialNotification = await Notifications.getInitialNotification();
this.setState({ if (initialNotification) {
notifications: [...this.state.notifications, `Notification Clicked: ${notification.getData().link}`] this.setState({notifications: [initialNotification.data.link, ...this.state.notifications]});
}); }
completion();
} }
renderNotification(notification) { componentWillUnmount() {
return <Text>{`${notification}`}</Text>;
} }
render() { render() {
...@@ -109,35 +111,6 @@ class NotificationsExampleApp extends Component { ...@@ -109,35 +111,6 @@ class NotificationsExampleApp extends Component {
</View> </View>
); );
} }
requestPermissions() {
// let cat = new NotificationCategory({
// identifier: 'SOME_CATEGORY',
// actions: [upvoteAction, replyAction]
// });
Notifications.requestPermissions(/*[cat]*/);
}
sendLocalNotification() {
Notifications.localNotification({
body: 'Local notificiation!',
title: 'Local Notification Title',
sound: 'chime.aiff',
category: 'SOME_CATEGORY',
userInfo: { link: 'localNotificationLink' },
});
}
removeAllDeliveredNotifications() {
// NotificationsIOS.removeAllDeliveredNotifications();
}
componentWillUnmount() {
// NotificationsIOS.removeEventListener('notificationReceivedForeground', this.onNotificationReceivedForeground.bind(this));
// NotificationsIOS.removeEventListener('notificationOpened', this.onNotificationOpened.bind(this));
// NotificationsIOS.removeEventListener('remoteNotificationsRegistered', this.onPushRegistered.bind(this));
// NotificationsIOS.removeEventListener('pushKitRegistered', this.onPushKitRegistered.bind(this));
}
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
50CBD3CD22F2558C00142352 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 50CBD3A922F2556900142352 /* libRCTAnimation.a */; };
50F1F0CC22CE3B4700FD5829 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F1F06022CE3A6100FD5829 /* libReact.a */; }; 50F1F0CC22CE3B4700FD5829 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F1F06022CE3A6100FD5829 /* libReact.a */; };
50F1F0CD22CE3B6300FD5829 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F1F08A22CE3AA000FD5829 /* libRCTActionSheet.a */; }; 50F1F0CD22CE3B6300FD5829 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F1F08A22CE3AA000FD5829 /* libRCTActionSheet.a */; };
50F1F0CF22CE3B6300FD5829 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F1F09522CE3ABE00FD5829 /* libRCTImage.a */; }; 50F1F0CF22CE3B6300FD5829 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F1F09522CE3ABE00FD5829 /* libRCTImage.a */; };
...@@ -27,6 +28,20 @@ ...@@ -27,6 +28,20 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
50CBD3A822F2556900142352 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 50CBD3A222F2556900142352 /* RCTAnimation.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RCTAnimation;
};
50CBD3AA22F2556900142352 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 50CBD3A222F2556900142352 /* RCTAnimation.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 2D2A28201D9B03D100D4039D;
remoteInfo = "RCTAnimation-tvOS";
};
50E49F4022D1F06C007160C1 /* PBXContainerItemProxy */ = { 50E49F4022D1F06C007160C1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
...@@ -283,6 +298,7 @@ ...@@ -283,6 +298,7 @@
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = NotificationsExampleApp/Info.plist; sourceTree = "<group>"; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = NotificationsExampleApp/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = NotificationsExampleApp/main.m; sourceTree = "<group>"; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = NotificationsExampleApp/main.m; sourceTree = "<group>"; };
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
50CBD3A222F2556900142352 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
50F1F08522CE3A9F00FD5829 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = "<group>"; }; 50F1F08522CE3A9F00FD5829 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = "<group>"; };
50F1F0A022CE3B0600FD5829 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = "<group>"; }; 50F1F0A022CE3B0600FD5829 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = "<group>"; };
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
...@@ -296,6 +312,7 @@ ...@@ -296,6 +312,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
50CBD3CD22F2558C00142352 /* libRCTAnimation.a in Frameworks */,
50F1F0D722CE3C1E00FD5829 /* libcxxreact.a in Frameworks */, 50F1F0D722CE3C1E00FD5829 /* libcxxreact.a in Frameworks */,
50F1F0D622CE3C0F00FD5829 /* libyoga.a in Frameworks */, 50F1F0D622CE3C0F00FD5829 /* libyoga.a in Frameworks */,
50F1F0CD22CE3B6300FD5829 /* libRCTActionSheet.a in Frameworks */, 50F1F0CD22CE3B6300FD5829 /* libRCTActionSheet.a in Frameworks */,
...@@ -346,6 +363,15 @@ ...@@ -346,6 +363,15 @@
name = NotificationsExampleApp; name = NotificationsExampleApp;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
50CBD3A322F2556900142352 /* Products */ = {
isa = PBXGroup;
children = (
50CBD3A922F2556900142352 /* libRCTAnimation.a */,
50CBD3AB22F2556900142352 /* libRCTAnimation.a */,
);
name = Products;
sourceTree = "<group>";
};
50F1F04D22CE3A6100FD5829 /* Products */ = { 50F1F04D22CE3A6100FD5829 /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
...@@ -444,6 +470,7 @@ ...@@ -444,6 +470,7 @@
832341AE1AAA6A7D00B99B32 /* Libraries */ = { 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
50CBD3A222F2556900142352 /* RCTAnimation.xcodeproj */,
50F1F0A022CE3B0600FD5829 /* RCTNetwork.xcodeproj */, 50F1F0A022CE3B0600FD5829 /* RCTNetwork.xcodeproj */,
D85498C21D97B31100DEEE06 /* RNNotifications.xcodeproj */, D85498C21D97B31100DEEE06 /* RNNotifications.xcodeproj */,
146833FF1AC3E56700842450 /* React.xcodeproj */, 146833FF1AC3E56700842450 /* React.xcodeproj */,
...@@ -542,6 +569,10 @@ ...@@ -542,6 +569,10 @@
ProductGroup = 50F1F08622CE3A9F00FD5829 /* Products */; ProductGroup = 50F1F08622CE3A9F00FD5829 /* Products */;
ProjectRef = 50F1F08522CE3A9F00FD5829 /* RCTActionSheet.xcodeproj */; ProjectRef = 50F1F08522CE3A9F00FD5829 /* RCTActionSheet.xcodeproj */;
}, },
{
ProductGroup = 50CBD3A322F2556900142352 /* Products */;
ProjectRef = 50CBD3A222F2556900142352 /* RCTAnimation.xcodeproj */;
},
{ {
ProductGroup = 50F1F09022CE3ABE00FD5829 /* Products */; ProductGroup = 50F1F09022CE3ABE00FD5829 /* Products */;
ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
...@@ -587,6 +618,20 @@ ...@@ -587,6 +618,20 @@
/* End PBXProject section */ /* End PBXProject section */
/* Begin PBXReferenceProxy section */ /* Begin PBXReferenceProxy section */
50CBD3A922F2556900142352 /* libRCTAnimation.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTAnimation.a;
remoteRef = 50CBD3A822F2556900142352 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
50CBD3AB22F2556900142352 /* libRCTAnimation.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTAnimation.a;
remoteRef = 50CBD3AA22F2556900142352 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
50E49F4122D1F06C007160C1 /* libjsi.a */ = { 50E49F4122D1F06C007160C1 /* libjsi.a */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = archive.ar; fileType = archive.ar;
......
...@@ -4,6 +4,7 @@ import { Commands } from './commands/Commands'; ...@@ -4,6 +4,7 @@ import { Commands } from './commands/Commands';
import { EventsRegistry } from './events/EventsRegistry'; import { EventsRegistry } from './events/EventsRegistry';
import { Notification, NotificationCategory } from './interfaces/Notification'; import { Notification, NotificationCategory } from './interfaces/Notification';
import { UniqueIdProvider } from './adapters/UniqueIdProvider'; import { UniqueIdProvider } from './adapters/UniqueIdProvider';
import { CompletionCallbackWrapper } from './adapters/CompletionCallbackWrapper';
export class NotificationsRoot { export class NotificationsRoot {
private readonly nativeEventsReceiver: NativeEventsReceiver; private readonly nativeEventsReceiver: NativeEventsReceiver;
...@@ -11,16 +12,18 @@ export class NotificationsRoot { ...@@ -11,16 +12,18 @@ export class NotificationsRoot {
private readonly commands: Commands; private readonly commands: Commands;
private readonly eventsRegistry: EventsRegistry; private readonly eventsRegistry: EventsRegistry;
private readonly uniqueIdProvider: UniqueIdProvider; private readonly uniqueIdProvider: UniqueIdProvider;
private readonly completionCallbackWrapper: CompletionCallbackWrapper;
constructor() { constructor() {
this.nativeEventsReceiver = new NativeEventsReceiver(); this.nativeEventsReceiver = new NativeEventsReceiver();
this.nativeCommandsSender = new NativeCommandsSender(); this.nativeCommandsSender = new NativeCommandsSender();
this.completionCallbackWrapper = new CompletionCallbackWrapper(this.nativeCommandsSender);
this.uniqueIdProvider = new UniqueIdProvider(); this.uniqueIdProvider = new UniqueIdProvider();
this.commands = new Commands( this.commands = new Commands(
this.nativeCommandsSender, this.nativeCommandsSender,
this.uniqueIdProvider this.uniqueIdProvider
); );
this.eventsRegistry = new EventsRegistry(this.nativeEventsReceiver); this.eventsRegistry = new EventsRegistry(this.nativeEventsReceiver, this.completionCallbackWrapper);
} }
/** /**
...@@ -45,7 +48,7 @@ export class NotificationsRoot { ...@@ -45,7 +48,7 @@ export class NotificationsRoot {
} }
/** /**
* * getInitialNotification
*/ */
public getInitialNotification(): Promise<Notification> { public getInitialNotification(): Promise<Notification> {
return this.commands.getInitialNotification(); return this.commands.getInitialNotification();
......
import { NativeCommandsSender } from './NativeCommandsSender';
import { NotificationCompletion, Notification } from '../interfaces/Notification';
import { NotificationResponse } from '../interfaces/NotificationEvents';
export class CompletionCallbackWrapper {
constructor(
private readonly nativeCommandsSender: NativeCommandsSender
) {}
public wrapReceivedCallback(callback: Function): (notification: Notification) => void {
return (notification) => {
const completion = (response: NotificationCompletion) => {
this.nativeCommandsSender.finishPresentingNotification(notification.identifier, response);
};
callback(notification, completion);
}
}
public wrapOpenedCallback(callback: Function): (response: NotificationResponse) => void {
return (response) => {
const completion = () => {
this.nativeCommandsSender.finishHandlingAction(response.notification.identifier);
};
callback(response, completion);
}
}
}
export const { NativeCommandsSender } = jest.genMockFromModule('./NativeCommandsSender');
import { NativeModules } from 'react-native'; import { NativeModules } from 'react-native';
import { Notification, NotificationCategory, NotificationPermissions } from '../interfaces/Notification'; import { Notification, NotificationCategory, NotificationPermissions, NotificationCompletion } from '../interfaces/Notification';
interface NativeCommandsModule { interface NativeCommandsModule {
getInitialNotification(): Promise<Notification>; getInitialNotification(): Promise<Notification>;
...@@ -16,6 +16,8 @@ interface NativeCommandsModule { ...@@ -16,6 +16,8 @@ interface NativeCommandsModule {
removeDeliveredNotifications(identifiers: Array<string>): void; removeDeliveredNotifications(identifiers: Array<string>): void;
removeAllDeliveredNotifications(): void; removeAllDeliveredNotifications(): void;
setCategories(categories: [NotificationCategory?]): void; setCategories(categories: [NotificationCategory?]): void;
finishPresentingNotification(notificationId: string, callback: NotificationCompletion): void;
finishHandlingAction(notificationId: string): void;
} }
export class NativeCommandsSender { export class NativeCommandsSender {
...@@ -28,7 +30,7 @@ export class NativeCommandsSender { ...@@ -28,7 +30,7 @@ export class NativeCommandsSender {
return this.nativeCommandsModule.localNotification(notification, id); return this.nativeCommandsModule.localNotification(notification, id);
} }
getInitialNotification() { getInitialNotification(): Promise<Notification> {
return this.nativeCommandsModule.getInitialNotification(); return this.nativeCommandsModule.getInitialNotification();
} }
...@@ -79,4 +81,12 @@ export class NativeCommandsSender { ...@@ -79,4 +81,12 @@ export class NativeCommandsSender {
removeDeliveredNotifications(identifiers: Array<string>) { removeDeliveredNotifications(identifiers: Array<string>) {
return this.nativeCommandsModule.removeDeliveredNotifications(identifiers); return this.nativeCommandsModule.removeDeliveredNotifications(identifiers);
} }
finishPresentingNotification(notificationId: string, notificationCompletion: NotificationCompletion): void {
this.nativeCommandsModule.finishPresentingNotification(notificationId, notificationCompletion);
}
finishHandlingAction(notificationId: string): void {
this.nativeCommandsModule.finishHandlingAction(notificationId);
}
} }
import { NativeModules, NativeEventEmitter, EventEmitter, EmitterSubscription } from 'react-native'; import { NativeModules, NativeEventEmitter, EventEmitter, EmitterSubscription } from 'react-native';
import { import {
NotificationRegisteredEvent, NotificationReceived Registered, RegistrationError, RegisteredPushKit, NotificationResponse
} from '../interfaces/NotificationEvents'; } from '../interfaces/NotificationEvents';
import { Notification } from '../interfaces/Notification';
export class NativeEventsReceiver { export class NativeEventsReceiver {
private emitter: EventEmitter; private emitter: EventEmitter;
...@@ -9,11 +10,27 @@ export class NativeEventsReceiver { ...@@ -9,11 +10,27 @@ export class NativeEventsReceiver {
this.emitter = new NativeEventEmitter(NativeModules.RNEventEmitter); this.emitter = new NativeEventEmitter(NativeModules.RNEventEmitter);
} }
public registerRemoteNotificationsRegistered(callback: (event: NotificationRegisteredEvent) => void): EmitterSubscription { public registerRemoteNotificationsRegistered(callback: (event: Registered) => void): EmitterSubscription {
return this.emitter.addListener('remoteNotificationsRegistered', callback); return this.emitter.addListener('remoteNotificationsRegistered', callback);
} }
public registerRemoteNotificationReceived(callback: (event: NotificationReceived) => void): EmitterSubscription { public registerPushKitRegistered(callback: (event: RegisteredPushKit) => void): EmitterSubscription {
return this.emitter.addListener('pushKitRegistered', callback);
}
public registerRemoteNotificationReceived(callback: (notification: Notification) => void): EmitterSubscription {
return this.emitter.addListener('notificationReceivedForeground', callback);
}
public registerPushKitNotificationReceived(callback: (event: object) => void): EmitterSubscription {
return this.emitter.addListener('notificationReceivedForeground', callback); return this.emitter.addListener('notificationReceivedForeground', callback);
} }
public registerRemoteNotificationOpened(callback: (response: NotificationResponse, completion: () => void) => void): EmitterSubscription {
return this.emitter.addListener('notificationOpened', callback);
}
public registerRemoteNotificationsRegistrationFailed(callback: (event: RegistrationError) => void): EmitterSubscription {
return this.emitter.addListener('remoteNotificationsRegistrationFailed', callback);
}
} }
import * as _ from 'lodash'; import * as _ from 'lodash';
import { mock, verify, instance, deepEqual, when, anything, anyString } from 'ts-mockito'; import { mock, verify, instance, when, anything, anyString } from 'ts-mockito';
import { Commands } from './Commands'; import { Commands } from './Commands';
import { NativeCommandsSender } from '../adapters/NativeCommandsSender'; import { NativeCommandsSender } from '../adapters/NativeCommandsSender';
...@@ -28,7 +28,7 @@ describe('Commands', () => { ...@@ -28,7 +28,7 @@ describe('Commands', () => {
}); });
it('returns a promise with the initial notification', async () => { it('returns a promise with the initial notification', async () => {
const expectedNotification: Notification = {data: {}, alert: 'alert'}; const expectedNotification: Notification = {identifier: 'id', data: {}, alert: 'alert'};
when(mockedNativeCommandsSender.getInitialNotification()).thenResolve( when(mockedNativeCommandsSender.getInitialNotification()).thenResolve(
expectedNotification expectedNotification
); );
...@@ -75,19 +75,19 @@ describe('Commands', () => { ...@@ -75,19 +75,19 @@ describe('Commands', () => {
describe('sendLocalNotification', () => { describe('sendLocalNotification', () => {
it('sends to native', () => { it('sends to native', () => {
const notification: Notification = {data: {}, alert: 'alert'}; const notification: Notification = {identifier: 'id', alert: 'alert', data: {}};
uut.sendLocalNotification(notification); uut.sendLocalNotification(notification);
verify(mockedNativeCommandsSender.sendLocalNotification(notification, anyString())).called(); verify(mockedNativeCommandsSender.sendLocalNotification(notification, anyString())).called();
}); });
it('generates unique identifier', () => { it('generates unique identifier', () => {
const notification: Notification = {data: {}, alert: 'alert'}; const notification: Notification = {identifier: 'id', data: {}, alert: 'alert'};
uut.sendLocalNotification(notification); uut.sendLocalNotification(notification);
verify(mockedNativeCommandsSender.sendLocalNotification(notification, `Notification_+UNIQUE_ID`)).called(); verify(mockedNativeCommandsSender.sendLocalNotification(notification, `Notification_+UNIQUE_ID`)).called();
}); });
it('use passed notification id', () => { it('use passed notification id', () => {
const notification: Notification = {data: {}, alert: 'alert'}; const notification: Notification = {identifier: 'id', data: {}, alert: 'alert'};
const passedId: string = "passedId"; const passedId: string = "passedId";
uut.sendLocalNotification(notification, passedId); uut.sendLocalNotification(notification, passedId);
verify(mockedNativeCommandsSender.sendLocalNotification(notification, passedId)).called(); verify(mockedNativeCommandsSender.sendLocalNotification(notification, passedId)).called();
......
...@@ -15,7 +15,7 @@ export class Commands { ...@@ -15,7 +15,7 @@ export class Commands {
return result; return result;
} }
public getInitialNotification() { public getInitialNotification(): Promise<Notification> {
const result = this.nativeCommandsSender.getInitialNotification(); const result = this.nativeCommandsSender.getInitialNotification();
return result; return result;
} }
......
import { EventsRegistry } from './EventsRegistry';
import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver.mock';
import { NotificationCompletion, Notification } from '../interfaces/Notification';
import { CompletionCallbackWrapper } from '../adapters/CompletionCallbackWrapper';
import { NativeCommandsSender } from '../adapters/NativeCommandsSender.mock';
import { NotificationResponse } from '../interfaces/NotificationEvents';
describe('EventsRegistry', () => {
let uut: EventsRegistry;
const mockNativeEventsReceiver = new NativeEventsReceiver();
const mockNativeCommandsSender = new NativeCommandsSender();
const completionCallbackWrapper = new CompletionCallbackWrapper(mockNativeCommandsSender);
beforeEach(() => {
uut = new EventsRegistry(mockNativeEventsReceiver, completionCallbackWrapper);
});
describe('registerRemoteNotificationsReceived', () => {
it('delegates to nativeEventsReceiver', () => {
const cb = jest.fn();
uut.registerNotificationReceived(cb);
expect(mockNativeEventsReceiver.registerRemoteNotificationReceived).toHaveBeenCalledTimes(1);
expect(mockNativeEventsReceiver.registerRemoteNotificationReceived).toHaveBeenCalledWith(expect.any(Function));
});
it('should wrap callback with completion block', () => {
const wrappedCallback = jest.fn();
const notification: Notification = {identifier: 'identifier', data: {}, alert: 'alert'}
uut.registerNotificationReceived(wrappedCallback);
const call = mockNativeEventsReceiver.registerRemoteNotificationReceived.mock.calls[0][0];
call(notification);
expect(wrappedCallback).toBeCalledWith(notification, expect.any(Function));
expect(wrappedCallback).toBeCalledTimes(1);
});
it('should wrap callback with completion block', () => {
const expectedNotification: Notification = {identifier: 'identifier', data: {}, alert: 'alert'}
uut.registerNotificationReceived((notification) => {
expect(notification).toEqual(expectedNotification);
});
const call = mockNativeEventsReceiver.registerRemoteNotificationReceived.mock.calls[0][0];
call(expectedNotification);
});
it('calling completion should invoke finishPresentingNotification', () => {
const notification: Notification = {identifier: 'notificationId', data: {}, alert: 'alert'}
const response: NotificationCompletion = {alert: true}
uut.registerNotificationReceived((notification, completion) => {
completion(response);
expect(mockNativeCommandsSender.finishPresentingNotification).toBeCalledWith(notification.identifier, response);
});
const call = mockNativeEventsReceiver.registerRemoteNotificationReceived.mock.calls[0][0];
call(notification);
});
});
describe('', () => {
it('delegates to nativeEventsReceiver', () => {
const cb = jest.fn();
uut.registerRemoteNotificationOpened(cb);
expect(mockNativeEventsReceiver.registerRemoteNotificationOpened).toHaveBeenCalledTimes(1);
expect(mockNativeEventsReceiver.registerRemoteNotificationOpened).toHaveBeenCalledWith(expect.any(Function));
});
it('should wrap callback with completion block', () => {
const wrappedCallback = jest.fn();
const notification: Notification = {identifier: 'identifier', data: {}, alert: 'alert'};
const response: NotificationResponse = {notification, identifier: 'responseId'};
uut.registerRemoteNotificationOpened(wrappedCallback);
const call = mockNativeEventsReceiver.registerRemoteNotificationOpened.mock.calls[0][0];
call(response);
expect(wrappedCallback).toBeCalledWith(response, expect.any(Function));
expect(wrappedCallback).toBeCalledTimes(1);
});
it('should wrap callback with completion block', () => {
const notification: Notification = {identifier: 'identifier', data: {}, alert: 'alert'}
const expectedResponse: NotificationResponse = {notification, identifier: 'responseId'}
uut.registerRemoteNotificationOpened((response) => {
expect(response).toEqual(expectedResponse);
});
const call = mockNativeEventsReceiver.registerRemoteNotificationOpened.mock.calls[0][0];
call(expectedResponse);
});
it('calling completion should invoke finishHandlingAction', () => {
const notification: Notification = {identifier: 'notificationId', data: {}, alert: 'alert'}
const expectedResponse: NotificationResponse = {identifier: 'responseId', notification};
uut.registerRemoteNotificationOpened((response, completion) => {
completion();
expect(response).toEqual(expectedResponse);
expect(mockNativeCommandsSender.finishHandlingAction).toBeCalledWith(notification.identifier);
});
const call = mockNativeEventsReceiver.registerRemoteNotificationOpened.mock.calls[0][0];
call(expectedResponse);
});
});
it('delegates registerRemoteNotificationsRegistered to nativeEventsReceiver', () => {
const cb = jest.fn();
uut.registerRemoteNotificationsRegistered(cb);
expect(mockNativeEventsReceiver.registerRemoteNotificationsRegistered).toHaveBeenCalledTimes(1);
expect(mockNativeEventsReceiver.registerRemoteNotificationsRegistered).toHaveBeenCalledWith(cb);
});
it('delegates registerPushKitRegistered to nativeEventsReceiver', () => {
const cb = jest.fn();
uut.registerPushKitRegistered(cb);
expect(mockNativeEventsReceiver.registerPushKitRegistered).toHaveBeenCalledTimes(1);
expect(mockNativeEventsReceiver.registerPushKitRegistered).toHaveBeenCalledWith(cb);
});
it('delegates registerPushKitNotificationReceived to nativeEventsReceiver', () => {
const cb = jest.fn();
uut.registerPushKitNotificationReceived(cb);
expect(mockNativeEventsReceiver.registerPushKitNotificationReceived).toHaveBeenCalledTimes(1);
expect(mockNativeEventsReceiver.registerPushKitNotificationReceived).toHaveBeenCalledWith(cb);
});
it('delegates registerRemoteNotificationsRegistrationFailed to nativeEventsReceiver', () => {
const cb = jest.fn();
uut.registerRemoteNotificationsRegistrationFailed(cb);
expect(mockNativeEventsReceiver.registerRemoteNotificationsRegistrationFailed).toHaveBeenCalledTimes(1);
expect(mockNativeEventsReceiver.registerRemoteNotificationsRegistrationFailed).toHaveBeenCalledWith(cb);
});
});
import { EventsRegistry } from './EventsRegistry';
import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver.mock';
describe('EventsRegistry', () => {
let uut: EventsRegistry;
const mockNativeEventsReceiver = new NativeEventsReceiver();
beforeEach(() => {
uut = new EventsRegistry(mockNativeEventsReceiver);
});
it('delegates registerRemoteNotificationsRegistered to nativeEventsReceiver', () => {
const cb = jest.fn();
uut.registerRemoteNotificationsRegistered(cb);
expect(mockNativeEventsReceiver.registerRemoteNotificationsRegistered).toHaveBeenCalledTimes(1);
expect(mockNativeEventsReceiver.registerRemoteNotificationsRegistered).toHaveBeenCalledWith(cb);
});
it('delegates registerRemoteNotificationsReceived to nativeEventsReceiver', () => {
const cb = jest.fn();
uut.registerNotificationReceived(cb);
expect(mockNativeEventsReceiver.registerRemoteNotificationReceived).toHaveBeenCalledTimes(1);
expect(mockNativeEventsReceiver.registerRemoteNotificationReceived).toHaveBeenCalledWith(cb);
});
});
import { EmitterSubscription } from 'react-native'; import { EmitterSubscription } from 'react-native';
import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver'; import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver';
import { import {
NotificationRegisteredEvent, Registered,
NotificationReceived RegistrationError,
RegisteredPushKit,
NotificationResponse
} from '../interfaces/NotificationEvents'; } from '../interfaces/NotificationEvents';
import { CompletionCallbackWrapper } from '../adapters/CompletionCallbackWrapper';
import { NotificationCompletion, Notification } from '../interfaces/Notification';
export class EventsRegistry { export class EventsRegistry {
constructor(private nativeEventsReceiver: NativeEventsReceiver) { } constructor(
private nativeEventsReceiver: NativeEventsReceiver,
private completionCallbackWrapper: CompletionCallbackWrapper)
{}
public registerRemoteNotificationsRegistered(callback: (event: NotificationRegisteredEvent) => void): EmitterSubscription { public registerRemoteNotificationsRegistered(callback: (event: Registered) => void): EmitterSubscription {
return this.nativeEventsReceiver.registerRemoteNotificationsRegistered(callback); return this.nativeEventsReceiver.registerRemoteNotificationsRegistered(callback);
} }
public registerNotificationReceived(callback: (event: NotificationReceived) => void): EmitterSubscription { public registerPushKitRegistered(callback: (event: RegisteredPushKit) => void): EmitterSubscription {
return this.nativeEventsReceiver.registerRemoteNotificationReceived(callback); return this.nativeEventsReceiver.registerPushKitRegistered(callback);
} }
public registerNotificationReceived(callback: (notification: Notification, completion: (response: NotificationCompletion) => void) => void): EmitterSubscription {
return this.nativeEventsReceiver.registerRemoteNotificationReceived(this.completionCallbackWrapper.wrapReceivedCallback(callback));
}
public registerPushKitNotificationReceived(callback: (event: object) => void): EmitterSubscription {
return this.nativeEventsReceiver.registerPushKitNotificationReceived(callback);
}
public registerRemoteNotificationOpened(callback: (response: NotificationResponse, completion: () => void) => void): EmitterSubscription {
return this.nativeEventsReceiver.registerRemoteNotificationOpened(this.completionCallbackWrapper.wrapOpenedCallback(callback));
}
public registerRemoteNotificationsRegistrationFailed(callback: (event: RegistrationError) => void): EmitterSubscription {
return this.nativeEventsReceiver.registerRemoteNotificationsRegistrationFailed(callback);
}
} }
export interface Notification { export interface Notification {
identifier: string;
data: object; data: object;
alert: string alert: string
sound?: string; sound?: string;
...@@ -31,3 +32,14 @@ export interface NotificationAction { ...@@ -31,3 +32,14 @@ export interface NotificationAction {
authenticationRequired: boolean; authenticationRequired: boolean;
textInput: NotificationTextInput textInput: NotificationTextInput
} }
export interface NotificationActionResponse {
identifier: string;
text: string;
}
export interface NotificationCompletion {
badge?: boolean;
alert?: boolean;
sound?: boolean;
}
import { Notification } from './Notification'; import { Notification, NotificationActionResponse } from './Notification';
export interface NotificationRegisteredEvent { export interface Registered {
deviceToken: string; deviceToken: string;
} }
export interface NotificationReceived { export interface RegistrationError {
code: string;
domain: string;
localizedDescription: string;
}
export interface RegisteredPushKit {
pushKitToken: string;
}
export interface NotificationResponse {
identifier: string;
notification: Notification; notification: Notification;
action?: NotificationActionResponse
} }
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