From b028b2e146fe50772d0b85ff1fe6622d669db5bd Mon Sep 17 00:00:00 2001 From: Mattermost Build Date: Thu, 24 Jun 2021 18:56:33 +0200 Subject: [PATCH] MM-36628 fix iOS app icon badge count (#5480) (#5483) (cherry picked from commit bced848b8eed520245621fd5b71be7d449e11c1b) Co-authored-by: Elias Nahum --- app/init/push_notifications.test.js | 13 ++-- app/init/push_notifications.ts | 25 ++++---- app/screens/channel/channel_base.js | 11 +++- .../main_sidebar_drawer_button.js | 18 ------ .../main_sidebar_drawer_button.test.js | 62 ------------------- 5 files changed, 27 insertions(+), 102 deletions(-) diff --git a/app/init/push_notifications.test.js b/app/init/push_notifications.test.js index 7ef3245ae..a59a0a3db 100644 --- a/app/init/push_notifications.test.js +++ b/app/init/push_notifications.test.js @@ -59,11 +59,11 @@ describe('PushNotification', () => { }); it('should clear all notifications', async () => { - const setApplicationIconBadgeNumber = jest.spyOn(PushNotification, 'setApplicationIconBadgeNumber'); + const setApplicationIconBadgeNumber = jest.spyOn(Notifications.ios, 'setBadgeCount'); const cancelAllLocalNotifications = jest.spyOn(PushNotification, 'cancelAllLocalNotifications'); PushNotification.clearNotifications(); - await expect(setApplicationIconBadgeNumber).toHaveBeenCalledWith(0, true); + await expect(setApplicationIconBadgeNumber).toHaveBeenCalledWith(0); expect(Notifications.ios.setBadgeCount).toHaveBeenCalledWith(0); expect(cancelAllLocalNotifications).toHaveBeenCalled(); expect(Notifications.cancelAllLocalNotifications).toHaveBeenCalled(); @@ -71,7 +71,7 @@ describe('PushNotification', () => { it('clearChannelNotifications should set app badge number from to delivered notification count when redux store is not set', async () => { Store.redux = null; - const setApplicationIconBadgeNumber = jest.spyOn(PushNotification, 'setApplicationIconBadgeNumber'); + const setApplicationIconBadgeNumber = jest.spyOn(Notifications.ios, 'setBadgeCount'); const deliveredNotifications = [{identifier: 1}, {identifier: 2}]; Notifications.setDeliveredNotifications(deliveredNotifications); @@ -83,7 +83,7 @@ describe('PushNotification', () => { Store.redux = { getState: jest.fn(), }; - const setApplicationIconBadgeNumber = jest.spyOn(PushNotification, 'setApplicationIconBadgeNumber'); + const setApplicationIconBadgeNumber = jest.spyOn(Notifications.ios, 'setBadgeCount'); const deliveredNotifications = [{identifier: 1}, {identifier: 2}]; Notifications.setDeliveredNotifications(deliveredNotifications); @@ -99,12 +99,11 @@ describe('PushNotification', () => { let deliveredNotifications = [{identifier: 1}]; Notifications.setDeliveredNotifications(deliveredNotifications); - await PushNotification.setApplicationIconBadgeNumber(0); - expect(setBadgeCount).not.toHaveBeenCalled(); + await Notifications.ios.setBadgeCount(0); deliveredNotifications = []; Notifications.setDeliveredNotifications(deliveredNotifications); - await PushNotification.setApplicationIconBadgeNumber(0); + await PushNotification.clearChannelNotifications(); expect(setBadgeCount).toHaveBeenCalledWith(0); }); }); diff --git a/app/init/push_notifications.ts b/app/init/push_notifications.ts index 11a5ff568..206bcf0ae 100644 --- a/app/init/push_notifications.ts +++ b/app/init/push_notifications.ts @@ -65,10 +65,13 @@ class PushNotifications { } clearNotifications = () => { - this.setApplicationIconBadgeNumber(0, true); - // TODO: Only cancel the local notifications that belong to this server this.cancelAllLocalNotifications(); + + if (Platform.OS === 'ios') { + // TODO: Set the badge number to the total amount of mentions on other servers + Notifications.ios.setBadgeCount(0); + } }; clearChannelNotifications = async (channelId: string) => { @@ -81,11 +84,14 @@ class PushNotifications { } else { const ids: string[] = []; const notifications = await Notifications.ios.getDeliveredNotifications(); + + //set the badge count to the total amount of notifications present in the not-center let badgeCount = notifications.length; if (Store.redux) { const totalMentions = getBadgeCount(Store.redux.getState()); if (totalMentions > -1) { + // replaces the badge count based on the redux store. badgeCount = totalMentions; } } @@ -101,7 +107,10 @@ class PushNotifications { Notifications.ios.removeDeliveredNotifications(ids); } - this.setApplicationIconBadgeNumber(badgeCount); + if (Platform.OS === 'ios') { + badgeCount = badgeCount <= 0 ? 0 : badgeCount; + Notifications.ios.setBadgeCount(badgeCount); + } } } @@ -243,16 +252,6 @@ class PushNotifications { } }; - setApplicationIconBadgeNumber = async (value: number, force = false) => { - if (Platform.OS === 'ios') { - const count = value < 0 ? 0 : value; - const notifications = await Notifications.ios.getDeliveredNotifications(); - if (count === 0 && (force || notifications.length === 0)) { - Notifications.ios.setBadgeCount(count); - } - } - }; - scheduleNotification = (notification: Notification) => { if (notification.fireDate) { if (Platform.OS === 'ios') { diff --git a/app/screens/channel/channel_base.js b/app/screens/channel/channel_base.js index 35862bd86..c7cad4dc6 100644 --- a/app/screens/channel/channel_base.js +++ b/app/screens/channel/channel_base.js @@ -85,7 +85,7 @@ export default class ChannelBase extends PureComponent { } if (currentChannelId) { - PushNotifications.clearChannelNotifications(currentChannelId); + this.clearChannelNotifications(); requestAnimationFrame(() => { actions.getChannelStats(currentChannelId); }); @@ -123,7 +123,7 @@ export default class ChannelBase extends PureComponent { } if (this.props.currentChannelId && this.props.currentChannelId !== prevProps.currentChannelId) { - PushNotifications.clearChannelNotifications(this.props.currentChannelId); + this.clearChannelNotifications(); requestAnimationFrame(() => { this.props.actions.getChannelStats(this.props.currentChannelId); @@ -137,6 +137,13 @@ export default class ChannelBase extends PureComponent { EventEmitter.off(General.REMOVED_FROM_CHANNEL, this.handleRemovedFromChannel); } + clearChannelNotifications = () => { + const clearNotificationsTimeout = setTimeout(() => { + clearTimeout(clearNotificationsTimeout); + PushNotifications.clearChannelNotifications(this.props.currentChannelId); + }, 1000); + } + registerTypingAnimation = (animation) => { const length = this.typingAnimations.push(animation); const removeAnimation = () => { diff --git a/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.js b/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.js index 7e5fe960f..53e98e0c4 100644 --- a/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.js +++ b/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.js @@ -11,7 +11,6 @@ import {intlShape} from 'react-intl'; import Badge from '@components/badge'; import CompassIcon from '@components/compass_icon'; -import PushNotifications from '@init/push_notifications'; import {preventDoubleTap} from '@utils/tap'; import {makeStyleSheetFromTheme} from '@utils/theme'; import {t} from '@utils/i18n'; @@ -37,23 +36,6 @@ export default class MainSidebarDrawerButton extends PureComponent { visible: true, }; - componentDidMount() { - if (this.props.badgeCount > 0) { - // Only set the icon badge number if once the component mounts we have at least one mention - // reason is to prevent the notification in the notification center to get cleared - // while the app is retrieving unread mentions from the server - PushNotifications.setApplicationIconBadgeNumber(this.props.badgeCount); - } - } - - componentDidUpdate(prevProps) { - // Once the component updates we know for sure if there are or not mentions when it mounted - // a) the app had mentions - if (prevProps.badgeCount !== this.props.badgeCount) { - PushNotifications.setApplicationIconBadgeNumber(this.props.badgeCount); - } - } - handlePress = preventDoubleTap(() => { this.props.openSidebar(); }); diff --git a/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.test.js b/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.test.js index d4d150b98..67bb38ee6 100644 --- a/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.test.js +++ b/app/screens/channel/channel_nav_bar/main_sidebar_drawer_button/main_sidebar_drawer_button.test.js @@ -5,7 +5,6 @@ import React from 'react'; import Badge from '@components/badge'; import Preferences from '@mm-redux/constants/preferences'; -import PushNotification from '@init/push_notifications'; import {shallowWithIntl} from 'test/intl-test-helper'; import MainSidebarDrawerButton from './main_sidebar_drawer_button'; @@ -18,8 +17,6 @@ describe('MainSidebarDrawerButton', () => { visible: false, }; - afterEach(() => PushNotification.setApplicationIconBadgeNumber(0)); - test('should match, full snapshot', () => { const wrapper = shallowWithIntl( , @@ -35,65 +32,6 @@ describe('MainSidebarDrawerButton', () => { expect(wrapper.find(Badge).length).toEqual(1); }); - test('should not set app icon badge on mount', () => { - const setApplicationIconBadgeNumber = jest.spyOn(PushNotification, 'setApplicationIconBadgeNumber'); - const props = { - ...baseProps, - badgeCount: 0, - }; - - shallowWithIntl( - , - ); - expect(setApplicationIconBadgeNumber).not.toBeCalled(); - }); - - test('should set app icon badge on mount', () => { - const setApplicationIconBadgeNumber = jest.spyOn(PushNotification, 'setApplicationIconBadgeNumber'); - const props = { - ...baseProps, - badgeCount: 1, - }; - - shallowWithIntl( - , - ); - expect(setApplicationIconBadgeNumber).toHaveBeenCalledTimes(1); - }); - - test('should set app icon badge update', () => { - const setApplicationIconBadgeNumber = jest.spyOn(PushNotification, 'setApplicationIconBadgeNumber'); - const props = { - ...baseProps, - badgeCount: 0, - }; - - const wrapper = shallowWithIntl( - , - ); - - wrapper.setProps({badgeCount: 2}); - expect(setApplicationIconBadgeNumber).toHaveBeenCalledTimes(1); - expect(setApplicationIconBadgeNumber).toHaveBeenCalledWith(2); - }); - - test('should set remove icon badge on update', () => { - const setApplicationIconBadgeNumber = jest.spyOn(PushNotification, 'setApplicationIconBadgeNumber'); - const props = { - ...baseProps, - badgeCount: 0, - }; - - const wrapper = shallowWithIntl( - , - ); - wrapper.setProps({badgeCount: 2}); - expect(setApplicationIconBadgeNumber).toHaveBeenCalledWith(2); - - wrapper.setProps({badgeCount: -1}); - expect(setApplicationIconBadgeNumber).toHaveBeenCalledWith(-1); - }); - test('Should be accessible', () => { const wrapper = shallowWithIntl( ,