MM-36628 fix iOS app icon badge count (#5480) (#5483)

(cherry picked from commit bced848b8e)

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
This commit is contained in:
Mattermost Build 2021-06-24 18:56:33 +02:00 committed by GitHub
parent 3c034ae3c4
commit b028b2e146
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 27 additions and 102 deletions

View file

@ -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);
});
});

View file

@ -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') {

View file

@ -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 = () => {

View file

@ -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();
});

View file

@ -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(
<MainSidebarDrawerButton {...baseProps}/>,
@ -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(
<MainSidebarDrawerButton {...props}/>,
);
expect(setApplicationIconBadgeNumber).not.toBeCalled();
});
test('should set app icon badge on mount', () => {
const setApplicationIconBadgeNumber = jest.spyOn(PushNotification, 'setApplicationIconBadgeNumber');
const props = {
...baseProps,
badgeCount: 1,
};
shallowWithIntl(
<MainSidebarDrawerButton {...props}/>,
);
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(
<MainSidebarDrawerButton {...props}/>,
);
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(
<MainSidebarDrawerButton {...props}/>,
);
wrapper.setProps({badgeCount: 2});
expect(setApplicationIconBadgeNumber).toHaveBeenCalledWith(2);
wrapper.setProps({badgeCount: -1});
expect(setApplicationIconBadgeNumber).toHaveBeenCalledWith(-1);
});
test('Should be accessible', () => {
const wrapper = shallowWithIntl(
<MainSidebarDrawerButton {...baseProps}/>,