forked from Ivasoft/mattermost-mobile
* MM-26749 Fix race condition when open from PN * setStartFromNotification earlier * Fix Android race condition when closing the app with the back button
238 lines
7.4 KiB
JavaScript
238 lines
7.4 KiB
JavaScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import {AppState} from 'react-native';
|
|
import NotificationsIOS, {
|
|
NotificationAction,
|
|
NotificationCategory,
|
|
DEVICE_REMOTE_NOTIFICATIONS_REGISTERED_EVENT,
|
|
DEVICE_NOTIFICATION_RECEIVED_FOREGROUND_EVENT,
|
|
DEVICE_NOTIFICATION_OPENED_EVENT,
|
|
} from 'react-native-notifications';
|
|
|
|
import {getLocalizedMessage} from '@i18n';
|
|
import {getCurrentLocale} from '@selectors/i18n';
|
|
import {getBadgeCount} from '@selectors/views';
|
|
import EphemeralStore from '@store/ephemeral_store';
|
|
import Store from '@store/store';
|
|
import {t} from '@utils/i18n';
|
|
|
|
const CATEGORY = 'CAN_REPLY';
|
|
const REPLY_ACTION = 'REPLY_ACTION';
|
|
|
|
class PushNotification {
|
|
constructor() {
|
|
this.deviceNotification = null;
|
|
this.onRegister = null;
|
|
this.onNotification = null;
|
|
|
|
NotificationsIOS.addEventListener(DEVICE_REMOTE_NOTIFICATIONS_REGISTERED_EVENT, this.onRemoteNotificationsRegistered);
|
|
NotificationsIOS.addEventListener(DEVICE_NOTIFICATION_RECEIVED_FOREGROUND_EVENT, this.onNotificationReceivedForeground);
|
|
NotificationsIOS.addEventListener(DEVICE_NOTIFICATION_OPENED_EVENT, this.onNotificationOpened);
|
|
}
|
|
|
|
handleNotification = (data, foreground, userInteraction) => {
|
|
this.deviceNotification = {
|
|
data,
|
|
foreground,
|
|
message: data.body || data.message,
|
|
userInfo: data.userInfo,
|
|
userInteraction,
|
|
};
|
|
|
|
if (this.onNotification) {
|
|
this.onNotification(this.deviceNotification);
|
|
}
|
|
};
|
|
|
|
configure(options) {
|
|
this.onRegister = options.onRegister;
|
|
this.onNotification = options.onNotification;
|
|
|
|
this.requestNotificationReplyPermissions();
|
|
|
|
return new Promise((resolve) => {
|
|
if (!options.popInitialNotification) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
NotificationsIOS.getInitialNotification().
|
|
then((notification) => {
|
|
if (notification) {
|
|
const data = notification.getData();
|
|
if (data) {
|
|
EphemeralStore.setStartFromNotification(true);
|
|
this.handleNotification(data, false, true);
|
|
}
|
|
}
|
|
}).
|
|
catch((err) => {
|
|
console.log('iOS getInitialNotifiation() failed', err); //eslint-disable-line no-console
|
|
}).
|
|
finally(() => {
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
requestNotificationReplyPermissions = () => {
|
|
const replyCategory = this.createReplyCategory();
|
|
this.requestPermissions([replyCategory]);
|
|
}
|
|
|
|
createReplyCategory = () => {
|
|
const {getState} = Store.redux;
|
|
const state = getState();
|
|
const locale = getCurrentLocale(state);
|
|
|
|
const replyTitle = getLocalizedMessage(locale, t('mobile.push_notification_reply.title'));
|
|
const replyButton = getLocalizedMessage(locale, t('mobile.push_notification_reply.button'));
|
|
const replyPlaceholder = getLocalizedMessage(locale, t('mobile.push_notification_reply.placeholder'));
|
|
|
|
const replyAction = new NotificationAction({
|
|
activationMode: 'background',
|
|
title: replyTitle,
|
|
textInput: {
|
|
buttonTitle: replyButton,
|
|
placeholder: replyPlaceholder,
|
|
},
|
|
authenticationRequired: true,
|
|
identifier: REPLY_ACTION,
|
|
});
|
|
|
|
return new NotificationCategory({
|
|
identifier: CATEGORY,
|
|
actions: [replyAction],
|
|
context: 'default',
|
|
});
|
|
}
|
|
|
|
requestPermissions = (permissions) => {
|
|
NotificationsIOS.requestPermissions(permissions);
|
|
};
|
|
|
|
localNotificationSchedule(notification) {
|
|
if (notification.date) {
|
|
const deviceNotification = {
|
|
fireDate: notification.date.toISOString(),
|
|
body: notification.message,
|
|
alertAction: '',
|
|
userInfo: notification.userInfo,
|
|
};
|
|
|
|
NotificationsIOS.localNotification(deviceNotification);
|
|
}
|
|
}
|
|
|
|
localNotification(notification) {
|
|
this.deviceNotification = {
|
|
body: notification.message,
|
|
alertAction: '',
|
|
userInfo: notification.userInfo,
|
|
};
|
|
|
|
NotificationsIOS.localNotification(this.deviceNotification);
|
|
}
|
|
|
|
cancelAllLocalNotifications() {
|
|
NotificationsIOS.cancelAllLocalNotifications();
|
|
}
|
|
|
|
onNotificationReceivedBackground = (notification) => {
|
|
const userInteraction = AppState.currentState === 'active';
|
|
|
|
// mark the app as started as soon as possible
|
|
if (userInteraction) {
|
|
EphemeralStore.setStartFromNotification(true);
|
|
}
|
|
|
|
const data = notification.getData();
|
|
const info = {
|
|
...data,
|
|
message: data.body || notification.getMessage(),
|
|
};
|
|
|
|
if (!userInteraction) {
|
|
this.handleNotification(info, false, userInteraction);
|
|
}
|
|
};
|
|
|
|
onNotificationReceivedForeground = (notification) => {
|
|
const data = notification.getData();
|
|
const info = {
|
|
...data,
|
|
message: data.body || notification.getMessage(),
|
|
};
|
|
this.handleNotification(info, true, false);
|
|
};
|
|
|
|
onNotificationOpened = (notification, completion) => {
|
|
const data = notification.getData();
|
|
const info = {
|
|
...data,
|
|
message: data.body || notification.getMessage(),
|
|
};
|
|
this.handleNotification(info, false, true);
|
|
completion();
|
|
};
|
|
|
|
onRemoteNotificationsRegistered = (deviceToken) => {
|
|
if (this.onRegister) {
|
|
this.onRegister({token: deviceToken});
|
|
}
|
|
};
|
|
|
|
setApplicationIconBadgeNumber(number) {
|
|
const count = number < 0 ? 0 : number;
|
|
NotificationsIOS.setBadgesCount(count);
|
|
}
|
|
|
|
getNotification() {
|
|
return this.deviceNotification;
|
|
}
|
|
|
|
resetNotification() {
|
|
this.deviceNotification = null;
|
|
}
|
|
|
|
getDeliveredNotifications(callback) {
|
|
NotificationsIOS.getDeliveredNotifications(callback);
|
|
}
|
|
|
|
clearChannelNotifications(channelId) {
|
|
NotificationsIOS.getDeliveredNotifications((notifications) => {
|
|
const ids = [];
|
|
let badgeCount = notifications.length;
|
|
|
|
if (Store.redux) {
|
|
const totalMentions = getBadgeCount(Store.redux.getState());
|
|
if (totalMentions > -1) {
|
|
badgeCount = totalMentions;
|
|
}
|
|
}
|
|
|
|
for (let i = 0; i < notifications.length; i++) {
|
|
const notification = notifications[i];
|
|
|
|
if (notification.channel_id === channelId) {
|
|
ids.push(notification.identifier);
|
|
}
|
|
}
|
|
|
|
if (ids.length) {
|
|
NotificationsIOS.removeDeliveredNotifications(ids);
|
|
}
|
|
|
|
this.setApplicationIconBadgeNumber(badgeCount);
|
|
});
|
|
}
|
|
|
|
clearNotifications = () => {
|
|
this.setApplicationIconBadgeNumber(0);
|
|
this.cancelAllLocalNotifications(); // TODO: Only cancel the local notifications that belong to this server
|
|
}
|
|
}
|
|
|
|
export default new PushNotification();
|