mattermost-mobile/app/push_notifications/push_notifications.ios.js

230 lines
7.5 KiB
JavaScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {AppState} from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import NotificationsIOS, {NotificationAction, NotificationCategory} from 'react-native-notifications';
import ephemeralStore from 'app/store/ephemeral_store';
const CATEGORY = 'CAN_REPLY';
const REPLY_ACTION = 'REPLY_ACTION';
export const FOREGROUND_NOTIFICATIONS_KEY = '@FOREGROUND_NOTIFICATIONS';
let replyCategory;
const replies = new Set();
class PushNotification {
constructor() {
this.deviceNotification = null;
this.onRegister = null;
this.onNotification = null;
this.onReply = null;
NotificationsIOS.addEventListener('remoteNotificationsRegistered', this.onRemoteNotificationsRegistered);
NotificationsIOS.addEventListener('notificationReceivedForeground', this.onNotificationReceivedForeground);
NotificationsIOS.addEventListener('notificationReceivedBackground', this.onNotificationReceivedBackground);
NotificationsIOS.addEventListener('notificationOpened', this.onNotificationOpened);
const replyAction = new NotificationAction({
activationMode: 'background',
title: 'Reply',
behavior: 'textInput',
authenticationRequired: true,
identifier: REPLY_ACTION,
}, this.handleReply);
replyCategory = new NotificationCategory({
identifier: CATEGORY,
actions: [replyAction],
context: 'default',
});
}
handleNotification = (data, foreground, userInteraction) => {
this.deviceNotification = {
data,
foreground,
message: data.message,
userInfo: data.userInfo,
userInteraction,
};
if (this.onNotification) {
this.onNotification(this.deviceNotification);
}
if (foreground) {
this.trackForegroundNotification(data.channel_id);
}
};
handleReply = (action, completed) => {
if (action.identifier === REPLY_ACTION) {
const data = action.notification.getData();
const text = action.text;
const badge = parseInt(action.notification._badge, 10) - 1; //eslint-disable-line no-underscore-dangle
if (this.onReply && !replies.has(action.completionKey)) {
replies.add(action.completionKey);
this.onReply(data, text, badge, completed);
}
} else {
completed();
}
};
configure(options) {
this.onRegister = options.onRegister;
this.onNotification = options.onNotification;
this.onReply = options.onReply;
this.requestPermissions([replyCategory]);
NotificationsIOS.consumeBackgroundQueue();
}
requestPermissions = (permissions) => {
NotificationsIOS.requestPermissions(permissions);
};
localNotificationSchedule(notification) {
if (notification.date) {
const deviceNotification = {
fireDate: notification.date.toISOString(),
alertBody: notification.message,
alertAction: '',
userInfo: notification.userInfo,
};
NotificationsIOS.localNotification(deviceNotification);
}
}
localNotification(notification) {
this.deviceNotification = {
alertBody: 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.appStartedFromPushNotification = true;
}
const info = {
...notification.getData(),
message: notification.getMessage(),
};
if (!userInteraction) {
this.handleNotification(info, false, userInteraction);
}
};
onNotificationReceivedForeground = (notification) => {
const info = {
...notification.getData(),
message: notification.getMessage(),
};
this.handleNotification(info, true, false);
NotificationsIOS.getBadgesCount((count) => {
this.setApplicationIconBadgeNumber(count + 1);
});
};
onNotificationOpened = (notification) => {
const info = {
...notification.getData(),
message: notification.getMessage(),
};
this.handleNotification(info, false, true);
};
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;
}
clearChannelNotifications(channelId) {
NotificationsIOS.getDeliveredNotifications(async (notifications) => {
let foregroundNotifications;
try {
const value = await AsyncStorage.getItem(FOREGROUND_NOTIFICATIONS_KEY);
foregroundNotifications = JSON.parse(value) || {};
} catch (e) {
foregroundNotifications = {};
}
Reflect.deleteProperty(foregroundNotifications, channelId);
AsyncStorage.setItem(FOREGROUND_NOTIFICATIONS_KEY, JSON.stringify(foregroundNotifications));
const foregroundCount = Object.values(foregroundNotifications).reduce((a, b) => a + b, 0);
let badgeCount = notifications.length + foregroundCount;
const ids = [];
for (let i = 0; i < notifications.length; i++) {
const notification = notifications[i];
if (notification.userInfo.channel_id === channelId) {
ids.push(notification.identifier);
}
}
if (ids.length) {
badgeCount -= ids.length;
NotificationsIOS.removeDeliveredNotifications(ids);
}
this.setApplicationIconBadgeNumber(badgeCount);
});
}
trackForegroundNotification = async (channelId) => {
const value = await AsyncStorage.getItem(FOREGROUND_NOTIFICATIONS_KEY);
const foregroundNotifications = value ? JSON.parse(value) : {};
if (!foregroundNotifications.hasOwnProperty(channelId)) {
foregroundNotifications[channelId] = 0;
}
foregroundNotifications[channelId] += 1;
await AsyncStorage.setItem(FOREGROUND_NOTIFICATIONS_KEY, JSON.stringify(foregroundNotifications));
}
clearForegroundNotifications = () => {
AsyncStorage.removeItem(FOREGROUND_NOTIFICATIONS_KEY);
};
clearNotifications = () => {
this.setApplicationIconBadgeNumber(0);
this.cancelAllLocalNotifications(); // TODO: Only cancel the local notifications that belong to this server
this.clearForegroundNotifications(); // TODO: Only clear the foreground notifications that belong to this server
}
}
export default new PushNotification();