* Handle iOS reply action on native side * Make linter happy * Revert rn vector changes to .pbxproj Co-authored-by: Miguel Alatzar <migbot@users.noreply.github.com>
This commit is contained in:
parent
5f0df6eb49
commit
3daa365e44
6 changed files with 218 additions and 142 deletions
|
|
@ -12,7 +12,6 @@ class PushNotification {
|
|||
constructor() {
|
||||
this.onRegister = null;
|
||||
this.onNotification = null;
|
||||
this.onReply = null;
|
||||
this.deviceNotification = null;
|
||||
this.deviceToken = null;
|
||||
|
||||
|
|
@ -55,7 +54,6 @@ class PushNotification {
|
|||
configure(options) {
|
||||
this.onRegister = options.onRegister;
|
||||
this.onNotification = options.onNotification;
|
||||
this.onReply = options.onReply;
|
||||
|
||||
if (this.onRegister && this.deviceToken) {
|
||||
this.onRegister({token: this.deviceToken});
|
||||
|
|
|
|||
|
|
@ -19,14 +19,11 @@ import {t} from 'app/utils/i18n';
|
|||
const CATEGORY = 'CAN_REPLY';
|
||||
const REPLY_ACTION = 'REPLY_ACTION';
|
||||
|
||||
const replies = new Set();
|
||||
|
||||
class PushNotification {
|
||||
constructor() {
|
||||
this.deviceNotification = null;
|
||||
this.onRegister = null;
|
||||
this.onNotification = null;
|
||||
this.onReply = null;
|
||||
this.reduxStore = null;
|
||||
|
||||
NotificationsIOS.addEventListener(DEVICE_REMOTE_NOTIFICATIONS_REGISTERED_EVENT, this.onRemoteNotificationsRegistered);
|
||||
|
|
@ -48,22 +45,10 @@ class PushNotification {
|
|||
}
|
||||
};
|
||||
|
||||
handleReply = (notification, text, completion) => {
|
||||
const data = notification.getData();
|
||||
|
||||
if (this.onReply && !replies.has(data.identifier)) {
|
||||
replies.add(data.identifier);
|
||||
this.onReply(data, text, completion);
|
||||
} else {
|
||||
completion();
|
||||
}
|
||||
};
|
||||
|
||||
configure(options) {
|
||||
this.reduxStore = options.reduxStore;
|
||||
this.onRegister = options.onRegister;
|
||||
this.onNotification = options.onNotification;
|
||||
this.onReply = options.onReply;
|
||||
|
||||
this.requestNotificationReplyPermissions();
|
||||
|
||||
|
|
@ -175,18 +160,14 @@ class PushNotification {
|
|||
this.handleNotification(info, true, false);
|
||||
};
|
||||
|
||||
onNotificationOpened = (notification, completion, action) => {
|
||||
if (action.identifier === REPLY_ACTION) {
|
||||
this.handleReply(notification, action.text, completion);
|
||||
} else {
|
||||
const data = notification.getData();
|
||||
const info = {
|
||||
...data,
|
||||
message: data.body || notification.getMessage(),
|
||||
};
|
||||
this.handleNotification(info, false, true);
|
||||
completion();
|
||||
}
|
||||
onNotificationOpened = (notification, completion) => {
|
||||
const data = notification.getData();
|
||||
const info = {
|
||||
...data,
|
||||
message: data.body || notification.getMessage(),
|
||||
};
|
||||
this.handleNotification(info, false, true);
|
||||
completion();
|
||||
};
|
||||
|
||||
onRemoteNotificationsRegistered = (deviceToken) => {
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import {PostTypes} from 'mattermost-redux/action_types';
|
||||
|
||||
import PushNotificationUtils from './push_notifications';
|
||||
|
||||
jest.mock('app/init/credentials', () => ({
|
||||
getAppCredentials: jest.fn().mockReturnValue({
|
||||
username: 'device-token,current-user-id',
|
||||
password: 'token,url',
|
||||
}),
|
||||
getCurrentServerUrl: jest.fn().mockReturnValue('url'),
|
||||
}));
|
||||
|
||||
jest.mock('app/actions/views/root', () => ({
|
||||
createPostForNotificationReply: jest.fn().mockImplementation(() => {
|
||||
return () => ({error: 'error'});
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('app/selectors/i18n', () => ({
|
||||
getCurrentLocale: jest.fn().mockReturnValue('en'),
|
||||
}));
|
||||
|
||||
jest.mock('react-native-notifications', () => {
|
||||
return {
|
||||
requestPermissions: jest.fn(),
|
||||
addEventListener: jest.fn(),
|
||||
NotificationAction: jest.fn(),
|
||||
NotificationCategory: jest.fn(),
|
||||
localNotification: jest.fn(),
|
||||
getInitialNotification: jest.fn(() => Promise.resolve()),
|
||||
};
|
||||
});
|
||||
|
||||
const mockStore = configureMockStore([thunk]);
|
||||
const store = mockStore({});
|
||||
PushNotificationUtils.configure(store);
|
||||
|
||||
describe('PushNotifications', () => {
|
||||
it('should add channel_id to failed push notification reply', async () => {
|
||||
let notification = PushNotificationUtils.getNotification();
|
||||
expect(notification).toBe(null);
|
||||
|
||||
const channelID = 'channel-id';
|
||||
const data = {channel_id: channelID};
|
||||
const text = 'text';
|
||||
const completion = () => {};
|
||||
await PushNotificationUtils.onPushNotificationReply(data, text, completion);
|
||||
|
||||
const storeActions = store.getActions();
|
||||
const receivedPost = storeActions.some((action) => action.type === PostTypes.RECEIVED_POST);
|
||||
expect(receivedPost).toBe(false);
|
||||
|
||||
notification = PushNotificationUtils.getNotification();
|
||||
expect(notification.userInfo.channel_id).toBe(channelID);
|
||||
});
|
||||
});
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
00E356F31AD99517003FC87E /* MattermostTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* MattermostTests.m */; };
|
||||
0111A42B7F264BCF8CBDE3ED /* OpenSans-ExtraBoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = FBBEC29EE2D3418D9AC33BD5 /* OpenSans-ExtraBoldItalic.ttf */; };
|
||||
|
|
@ -22,6 +23,7 @@
|
|||
499F7A652354F51900E7AF6E /* OnPasteEventManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 499F7A642354F51900E7AF6E /* OnPasteEventManager.m */; };
|
||||
499F7AF1235511FD00E7AF6E /* Mattermost-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 499F7AF0235511FC00E7AF6E /* Mattermost-Regular.otf */; };
|
||||
49B4C050230C981C006E919E /* libUploadAttachments.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FABE04522137F2A00D0F595 /* libUploadAttachments.a */; };
|
||||
536CC6C323E79287002C478C /* RNNotificationEventHandler+HandleReplyAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 536CC6C123E79287002C478C /* RNNotificationEventHandler+HandleReplyAction.m */; };
|
||||
552835DCC0C24FC691EE6CAB /* Roboto-LightItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 8F0B22D2C9924FAFA7FB681C /* Roboto-LightItalic.ttf */; };
|
||||
55C6561DDBBA45929D88B6D1 /* OpenSans-BoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 32AC3D4EA79E44738A6E9766 /* OpenSans-BoldItalic.ttf */; };
|
||||
62A8448264674B4D95A5A7C2 /* OpenSans-Semibold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C78A387124874496AD2C1466 /* OpenSans-Semibold.ttf */; };
|
||||
|
|
@ -184,6 +186,8 @@
|
|||
499F7B412355141200E7AF6E /* libYoutubePlayer-in-WKWebView.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libYoutubePlayer-in-WKWebView.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
49B4BF51230C83D2006E919E /* libz.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.1.dylib; path = ../../../../../../../../../usr/lib/libz.1.dylib; sourceTree = "<group>"; };
|
||||
49D0879035464473A11A0E1C /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = "<group>"; };
|
||||
536CC6C123E79287002C478C /* RNNotificationEventHandler+HandleReplyAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "RNNotificationEventHandler+HandleReplyAction.m"; path = "Mattermost/RNNotificationEventHandler+HandleReplyAction.m"; sourceTree = "<group>"; };
|
||||
536CC6C223E79287002C478C /* RNNotificationEventHandler+HandleReplyAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "RNNotificationEventHandler+HandleReplyAction.h"; path = "Mattermost/RNNotificationEventHandler+HandleReplyAction.h"; sourceTree = "<group>"; };
|
||||
563B800AC53A447FA18F47D3 /* FontAwesome5_Solid.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome5_Solid.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf"; sourceTree = "<group>"; };
|
||||
57CB4735B7E57B50D0B50E16 /* Pods-MattermostTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MattermostTests.debug.xcconfig"; path = "Target Support Files/Pods-MattermostTests/Pods-MattermostTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
5BB993883BB9CFFBD2BEB9FC /* libPods-MattermostTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MattermostTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
|
@ -265,7 +269,6 @@
|
|||
D4B1B363C2414DA19C1AC521 /* OpenSans-Bold.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-Bold.ttf"; path = "../assets/fonts/OpenSans-Bold.ttf"; sourceTree = "<group>"; };
|
||||
EB4F0DF36537B0B21BE962FB /* Pods-Mattermost.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mattermost.debug.xcconfig"; path = "Target Support Files/Pods-Mattermost/Pods-Mattermost.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
FBBEC29EE2D3418D9AC33BD5 /* OpenSans-ExtraBoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-ExtraBoldItalic.ttf"; path = "../assets/fonts/OpenSans-ExtraBoldItalic.ttf"; sourceTree = "<group>"; };
|
||||
81061F4CBB31484A94D5A8EE /* libz.tbd */ = {isa = PBXFileReference; name = "libz.tbd"; path = "usr/lib/libz.tbd"; sourceTree = SDKROOT; fileEncoding = undefined; lastKnownFileType = sourcecode.text-based-dylib-definition; explicitFileType = undefined; includeInIndex = 0; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -370,6 +373,8 @@
|
|||
13B07FAE1A68108700A75B9A /* Mattermost */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
536CC6C223E79287002C478C /* RNNotificationEventHandler+HandleReplyAction.h */,
|
||||
536CC6C123E79287002C478C /* RNNotificationEventHandler+HandleReplyAction.m */,
|
||||
499F7A632354F51900E7AF6E /* OnPasteEventManager.h */,
|
||||
499F7A642354F51900E7AF6E /* OnPasteEventManager.m */,
|
||||
499F7A612354F4CC00E7AF6E /* NSData+MimeType.h */,
|
||||
|
|
@ -816,56 +821,56 @@
|
|||
showEnvVarsInLog = 0;
|
||||
};
|
||||
1D22DC6FC0A37F7F657B8274 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${SRCROOT}/Pods/Target Support Files/Pods-Mattermost/Pods-Mattermost-resources.sh",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Feather.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Brands.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Regular.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Foundation.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-youtube/assets/YTPlayerView-iframe-player.html",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Feather.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Brands.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Regular.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Solid.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Foundation.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Ionicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialCommunityIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/YTPlayerView-iframe-player.html",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Mattermost/Pods-Mattermost-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${SRCROOT}/Pods/Target Support Files/Pods-Mattermost/Pods-Mattermost-resources.sh",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Feather.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Brands.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Regular.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Foundation.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-youtube/assets/YTPlayerView-iframe-player.html",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Feather.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Brands.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Regular.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Solid.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Foundation.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Ionicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialCommunityIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/YTPlayerView-iframe-player.html",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Mattermost/Pods-Mattermost-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
AE4769B235D14E6C9C64EA78 /* Upload Debug Symbols to Sentry */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
|
|
@ -980,6 +985,7 @@
|
|||
499F7A652354F51900E7AF6E /* OnPasteEventManager.m in Sources */,
|
||||
7F240ACD220D460300637665 /* MattermostBucketModule.m in Sources */,
|
||||
7F5BA34722B99B7B005B05D3 /* Mattermost+RCTUITextView.m in Sources */,
|
||||
536CC6C323E79287002C478C /* RNNotificationEventHandler+HandleReplyAction.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
//
|
||||
// RNNotificationEventHandler+HandleReplyAction.h
|
||||
// Mattermost
|
||||
//
|
||||
// Created by Miguel Alatzar on 1/29/20.
|
||||
// Copyright © 2020 Mattermost. All rights reserved.
|
||||
//
|
||||
|
||||
#import <react-native-notifications/RNNotificationEventHandler.h>
|
||||
#import <react-native-notifications/RNNotificationCenter.h>
|
||||
|
||||
@interface RNNotificationEventHandler (HandleReplyAction)
|
||||
@property (nonatomic, strong) RNNotificationCenter *notificationCenter;
|
||||
@end
|
||||
|
||||
extern NSString *const ReplyActionID;
|
||||
136
ios/Mattermost/RNNotificationEventHandler+HandleReplyAction.m
Normal file
136
ios/Mattermost/RNNotificationEventHandler+HandleReplyAction.m
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
//
|
||||
// RNNotificationEventHandler+HandleReplyAction.m
|
||||
// Mattermost
|
||||
//
|
||||
// Created by Miguel Alatzar on 1/29/20.
|
||||
// Copyright © 2020 Mattermost. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "RNNotificationEventHandler+HandleReplyAction.h"
|
||||
#import <react-native-notifications/RNNotificationParser.h>
|
||||
#import <UploadAttachments-Bridging-Header.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#define notificationCenterKey @"notificationCenter"
|
||||
|
||||
NSString *const ReplyActionID = @"REPLY_ACTION";
|
||||
|
||||
@implementation RNNotificationEventHandler (HandleReplyAction)
|
||||
|
||||
- (RNNotificationCenter *)notificationCenter{
|
||||
return objc_getAssociatedObject(self, notificationCenterKey);
|
||||
}
|
||||
|
||||
- (void)setNotificationCenter:(RNNotificationCenter *)notificationCenter{
|
||||
objc_setAssociatedObject(self, notificationCenterKey, notificationCenter, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
+ (void)load {
|
||||
static dispatch_once_t once_token;
|
||||
dispatch_once(&once_token, ^{
|
||||
Class class = [self class];
|
||||
|
||||
SEL originalSelector = @selector(didReceiveNotificationResponse:completionHandler:);
|
||||
SEL swizzledSelector = @selector(handleReplyAction_didReceiveNotificationResponse:completionHandler:);
|
||||
|
||||
Method originalMethod = class_getInstanceMethod(class, originalSelector);
|
||||
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
|
||||
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)sendReply:(UNNotificationResponse *)response {
|
||||
StoreManager *store = [StoreManager shared];
|
||||
[store getEntities:true];
|
||||
NSString *serverUrl = [store getServerUrl];
|
||||
NSString *sessionToken = [store getToken];
|
||||
if (serverUrl == nil || sessionToken == nil) {
|
||||
[self handleReplyFailure:@""];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *completionKey = response.notification.request.identifier;
|
||||
NSDictionary *parsedResponse = [RNNotificationParser parseNotificationResponse:response];
|
||||
NSString *message = [parsedResponse valueForKeyPath:@"action.text"];
|
||||
NSString *channelId = [parsedResponse valueForKeyPath:@"payload.channel_id"];
|
||||
NSString *rootId = [parsedResponse valueForKeyPath:@"payload.root_id"];
|
||||
if (rootId == nil) {
|
||||
rootId = [parsedResponse valueForKeyPath:@"payload.post_id"];
|
||||
}
|
||||
|
||||
NSDictionary *post = @{
|
||||
@"message": message,
|
||||
@"channel_id": channelId,
|
||||
@"root_id": rootId
|
||||
};
|
||||
NSError *error;
|
||||
NSData *postData = [NSJSONSerialization dataWithJSONObject:post options:0 error:&error];
|
||||
if (!postData) {
|
||||
[self handleReplyFailure:channelId];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/api/v4/posts", serverUrl];
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
||||
[request setHTTPMethod:@"POST"];
|
||||
[request setValue:[NSString stringWithFormat:@"Bearer %@", sessionToken] forHTTPHeaderField:@"Authorization"];
|
||||
[request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
|
||||
[request setHTTPBody:postData];
|
||||
|
||||
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
|
||||
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
|
||||
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
|
||||
if (statusCode == 201) {
|
||||
[self handleReplySuccess:completionKey];
|
||||
} else {
|
||||
[self handleReplyFailure:channelId];
|
||||
}
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
- (void) handleReplySuccess:(NSString *)completionKey {
|
||||
[[RNNotificationsStore sharedInstance] completeAction:completionKey];
|
||||
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
||||
[center getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
|
||||
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:[notifications count]];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void) handleReplyFailure:(NSString *)channelId {
|
||||
RNNotificationCenter *notificationCenter = [self notificationCenter];
|
||||
if (!notificationCenter) {
|
||||
notificationCenter = [RNNotificationCenter new];
|
||||
[self setNotificationCenter:notificationCenter];
|
||||
}
|
||||
|
||||
NSString *id = [[NSUUID UUID] UUIDString];;
|
||||
NSDictionary *notification = @{
|
||||
@"body": @"Message failed to send.",
|
||||
@"alertAction": @"",
|
||||
@"userInfo": @{
|
||||
@"localNotification": @YES,
|
||||
@"localTest": @YES,
|
||||
@"channel_id": channelId
|
||||
}
|
||||
};
|
||||
[notificationCenter sendLocalNotification:notification withId:id];
|
||||
}
|
||||
|
||||
#pragma mark - Method Swizzling
|
||||
|
||||
- (void)handleReplyAction_didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(void))completionHandler {
|
||||
if ([response.actionIdentifier isEqualToString:ReplyActionID]) {
|
||||
[self sendReply:response];
|
||||
completionHandler();
|
||||
} else {
|
||||
[self handleReplyAction_didReceiveNotificationResponse:response completionHandler:completionHandler];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
Loading…
Reference in a new issue