<commit_before>// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {AppState, DeviceEventEmitter, Platform} from 'react-native';
import DeviceInfo from 'react-native-device-info';
import {
    Notification,
    NotificationAction,
    NotificationBackgroundFetchResult,
    NotificationCategory,
    NotificationCompletion,
    Notifications,
    NotificationTextInput,
    Registered,
} from 'react-native-notifications';

import {storeDeviceToken} from '@actions/app/global';
import {markChannelAsViewed} from '@actions/local/channel';
import {backgroundNotification, openNotification} from '@actions/remote/notifications';
import {Device, Events, Navigation, Screens} from '@constants';
import DatabaseManager from '@database/manager';
import {getTotalMentionsForServer} from '@database/subscription/unreads';
import {DEFAULT_LOCALE, getLocalizedMessage, t} from '@i18n';
import NativeNotifications from '@notifications';
import {queryServerName} from '@queries/app/servers';
import {getCurrentChannelId} from '@queries/servers/system';
import {showOverlay} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
import {isTablet} from '@utils/helpers';
import {convertToNotificationData} from '@utils/notification';

const CATEGORY = 'CAN_REPLY';
const REPLY_ACTION = 'REPLY_ACTION';
const NOTIFICATION_TYPE = {
    CLEAR: 'clear',
    MESSAGE: 'message',
    SESSION: 'session',
};

class PushNotifications {
    configured = false;

    init() {
        Notifications.registerRemoteNotifications();
        Notifications.events().registerNotificationOpened(this.onNotificationOpened);
        Notifications.events().registerRemoteNotificationsRegistered(this.onRemoteNotificationsRegistered);
        Notifications.events().registerNotificationReceivedBackground(this.onNotificationReceivedBackground);
        Notifications.events().registerNotificationReceivedForeground(this.onNotificationReceivedForeground);
    }

    cancelAllLocalNotifications = () => {
        Notifications.cancelAllLocalNotifications();
    };

    cancelChannelNotifications = async (channelId: string) => {
        const notifications = await NativeNotifications.getDeliveredNotifications();
        this.cancelNotificationsForChannel(notifications, channelId);
    };

    cancelChannelsNotifications = async (channelIds: string[]) => {
        const notifications = await NativeNotifications.getDeliveredNotifications();
        for (const channelId of channelIds) {
            this.cancelNotificationsForChannel(notifications, channelId);
        }
    };

    cancelNotificationsForChannel = (notifications: NotificationWithChannel[], channelId: string) => {
        if (Platform.OS === 'android') {
            NativeNotifications.removeDeliveredNotifications(channelId);
        } else {
            const ids: string[] = [];

            for (const notification of notifications) {
                if (notification.channel_id === channelId) {
                    ids.push(notification.identifier);
                }
            }

            if (ids.length) {
                NativeNotifications.removeDeliveredNotifications(ids);
            }

            const serversUrl = Object.keys(DatabaseManager.serverDatabases);
            const mentionPromises = serversUrl.map((url) => getTotalMentionsForServer(url));
            Promise.all(mentionPromises).then((result) => {
                let badgeCount = result.reduce((acc, count) => (acc + count), 0);
                badgeCount = badgeCount <= 0 ? 0 : badgeCount;
                Notifications.ios.setBadgeCount(badgeCount);
            });
        }
    };

    createReplyCategory = () => {
        const replyTitle = getLocalizedMessage(DEFAULT_LOCALE, t('mobile.push_notification_reply.title'));
        const replyButton = getLocalizedMessage(DEFAULT_LOCALE, t('mobile.push_notification_reply.button'));
        const replyPlaceholder = getLocalizedMessage(DEFAULT_LOCALE, t('mobile.push_notification_reply.placeholder'));
        const replyTextInput: NotificationTextInput = {buttonTitle: replyButton, placeholder: replyPlaceholder};
        const replyAction = new NotificationAction(REPLY_ACTION, 'background', replyTitle, true, replyTextInput);<commit_msg>Preserve notifications when tapping or clearing notifications from a channel (#6209)<commit_after>// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {AppState, DeviceEventEmitter, Platform} from 'react-native';
import DeviceInfo from 'react-native-device-info';
import {
    Notification,
    NotificationAction,
    NotificationBackgroundFetchResult,
    NotificationCategory,
    NotificationCompletion,
    Notifications,
    NotificationTextInput,
    Registered,
} from 'react-native-notifications';

import {storeDeviceToken} from '@actions/app/global';
import {markChannelAsViewed} from '@actions/local/channel';
import {backgroundNotification, openNotification} from '@actions/remote/notifications';
import {Device, Events, Navigation, Screens} from '@constants';
import DatabaseManager from '@database/manager';
import {getTotalMentionsForServer} from '@database/subscription/unreads';
import {DEFAULT_LOCALE, getLocalizedMessage, t} from '@i18n';
import NativeNotifications from '@notifications';
import {queryServerName} from '@queries/app/servers';
import {getCurrentChannelId} from '@queries/servers/system';
import {showOverlay} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
import {isTablet} from '@utils/helpers';
import {convertToNotificationData} from '@utils/notification';

const CATEGORY = 'CAN_REPLY';
const REPLY_ACTION = 'REPLY_ACTION';
const NOTIFICATION_TYPE = {
    CLEAR: 'clear',
    MESSAGE: 'message',
    SESSION: 'session',
};

class PushNotifications {
    configured = false;

    init() {
        Notifications.registerRemoteNotifications();
        Notifications.events().registerNotificationOpened(this.onNotificationOpened);
        Notifications.events().registerRemoteNotificationsRegistered(this.onRemoteNotificationsRegistered);
        Notifications.events().registerNotificationReceivedBackground(this.onNotificationReceivedBackground);
        Notifications.events().registerNotificationReceivedForeground(this.onNotificationReceivedForeground);
    }

    cancelAllLocalNotifications = () => {
        Notifications.cancelAllLocalNotifications();
    };

    cancelChannelNotifications = async (channelId: string) => {
        const notifications = await NativeNotifications.getDeliveredNotifications();
        this.cancelNotificationsForChannel(notifications, channelId);
    };

    cancelChannelsNotifications = async (channelIds: string[]) => {
        const notifications = await NativeNotifications.getDeliveredNotifications();
        for (const channelId of channelIds) {
            this.cancelNotificationsForChannel(notifications, channelId);
        }
    };

    cancelNotificationsForChannel = (notifications: NotificationWithChannel[], channelId: string) => {
        if (Platform.OS === 'android') {
            NativeNotifications.removeDeliveredNotifications(channelId);
        } else {
            const ids: string[] = [];

            for (const notification of notifications) {
                if (notification.channel_id === channelId) {
                    ids.push(notification.identifier);
                }
            }

            if (ids.length) {
                NativeNotifications.removeDeliveredNotifications(ids);
            }

            let badgeCount = notifications.length - ids.length;

            const serversUrl = Object.keys(DatabaseManager.serverDatabases);
            const mentionPromises = serversUrl.map((url) => getTotalMentionsForServer(url));
            Promise.all(mentionPromises).then((result) => {
                badgeCount += result.reduce((acc, count) => (acc + count), 0);
                badgeCount = badgeCount <= 0 ? 0 : badgeCount;
                Notifications.ios.setBadgeCount(badgeCount);
            });
        }
    };

    createReplyCategory = () => {
        const replyTitle = getLocalizedMessage(DEFAULT_LOCALE, t('mobile.push_notification_reply.title'));
        const replyButton = getLocalizedMessage(DEFAULT_LOCALE, t('mobile.push_notification_reply.button'));
        const replyPlaceholder = getLocalizedMessage(DEFAULT_LOCALE, t('mobile.push_notification_reply.placeholder'));
        const replyTextInput: NotificationTextInput = {buttonTitle: replyButton, placeholder: replyPlaceholder};
        const replyAction = new NotificationAction(REPLY_ACTION, 'background', replyTitle, true, replyTextInput);
{'fraction_non_alphanumeric': 0.10197556240721709, 'fraction_numerical': 0.0025122758935708575, 'mean_word_length': 3.9648526077097506, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6413175', 'n_tokens_mistral': 2249, 'n_tokens_neox': 2161, 'n_words': 456}