forked from Ivasoft/mattermost-mobile
MM-37660 Fix keep mention for channel A when opening a push notification on channel B (#5597)
* Fix keep mention for channel A when opening a push notification on channel B * properly fix race condition * Load channels and channel members when opening the app from a push notification
This commit is contained in:
@@ -6,10 +6,10 @@ import {batchActions} from 'redux-batched-actions';
|
||||
import {Client4} from '@client/rest';
|
||||
import {NavigationTypes, ViewTypes} from '@constants';
|
||||
import {ChannelTypes, GeneralTypes, TeamTypes} from '@mm-redux/action_types';
|
||||
import {fetchMyChannelsAndMembers, getChannelAndMyMember} from '@mm-redux/actions/channels';
|
||||
import {getChannelAndMyMember} from '@mm-redux/actions/channels';
|
||||
import {getDataRetentionPolicy} from '@mm-redux/actions/general';
|
||||
import {receivedNewPost} from '@mm-redux/actions/posts';
|
||||
import {getMyTeams, getMyTeamMembers} from '@mm-redux/actions/teams';
|
||||
import {getMyTeams, getMyTeamMembers, getMyTeamUnreads} from '@mm-redux/actions/teams';
|
||||
import {General} from '@mm-redux/constants';
|
||||
import {isCollapsedThreadsEnabled} from '@mm-redux/selectors/entities/preferences';
|
||||
import EventEmitter from '@mm-redux/utils/event_emitter';
|
||||
@@ -17,7 +17,7 @@ import {getViewingGlobalThreads} from '@selectors/threads';
|
||||
import initialState from '@store/initial_state';
|
||||
import {getStateForReset} from '@store/utils';
|
||||
|
||||
import {markAsViewedAndReadBatch} from './channel';
|
||||
import {loadChannelsForTeam, markAsViewedAndReadBatch} from './channel';
|
||||
import {handleNotViewingGlobalThreadsScreen} from './threads';
|
||||
|
||||
export function startDataCleanup() {
|
||||
@@ -64,12 +64,11 @@ export function loadConfigAndLicense() {
|
||||
};
|
||||
}
|
||||
|
||||
export function loadFromPushNotification(notification) {
|
||||
export function loadFromPushNotification(notification, isInitialNotification) {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const {payload} = notification;
|
||||
const {currentTeamId, teams, myMembers: myTeamMembers} = state.entities.teams;
|
||||
const {channels} = state.entities.channels;
|
||||
|
||||
let channelId = '';
|
||||
let teamId = currentTeamId;
|
||||
@@ -88,8 +87,9 @@ export function loadFromPushNotification(notification) {
|
||||
loading.push(dispatch(getMyTeamMembers()));
|
||||
}
|
||||
|
||||
if (channelId && !channels[channelId]) {
|
||||
loading.push(dispatch(fetchMyChannelsAndMembers(teamId)));
|
||||
if (isInitialNotification) {
|
||||
loading.push(dispatch(getMyTeamUnreads()));
|
||||
loading.push(dispatch(loadChannelsForTeam(teamId)));
|
||||
}
|
||||
|
||||
if (loading.length > 0) {
|
||||
@@ -105,10 +105,18 @@ export function loadFromPushNotification(notification) {
|
||||
export function handleSelectTeamAndChannel(teamId, channelId) {
|
||||
return async (dispatch, getState) => {
|
||||
const dt = Date.now();
|
||||
await dispatch(getChannelAndMyMember(channelId));
|
||||
let state = getState();
|
||||
let {channels, myMembers} = state.entities.channels;
|
||||
|
||||
const state = getState();
|
||||
const {channels, currentChannelId, myMembers} = state.entities.channels;
|
||||
if (channelId && (!channels[channelId] || !myMembers[channelId])) {
|
||||
await dispatch(getChannelAndMyMember(channelId));
|
||||
state = getState();
|
||||
}
|
||||
|
||||
channels = state.entities.channels.channels;
|
||||
myMembers = state.entities.channels.myMembers;
|
||||
|
||||
const {currentChannelId} = state.entities.channels;
|
||||
const {currentTeamId} = state.entities.teams;
|
||||
const channel = channels[channelId];
|
||||
const member = myMembers[channelId];
|
||||
|
||||
@@ -174,10 +174,10 @@ const NetworkIndicator = ({
|
||||
handleWebSocket(active);
|
||||
|
||||
if (active) {
|
||||
// Clear the notifications for the current channel after one second
|
||||
// Clear the notifications for the current channel after two seconds
|
||||
// this is done so we can cancel it in case the app is brought to the
|
||||
// foreground by tapping a notification from another channel
|
||||
clearNotificationTimeout.current = setTimeout(clearNotifications, 1000);
|
||||
clearNotificationTimeout.current = setTimeout(clearNotifications, 2000);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -185,14 +185,22 @@ const NetworkIndicator = ({
|
||||
|
||||
return () => {
|
||||
AppState.removeEventListener('change', handleAppStateChange);
|
||||
if (clearNotificationTimeout.current && AppState.currentState !== 'active') {
|
||||
clearTimeout(clearNotificationTimeout.current);
|
||||
}
|
||||
};
|
||||
}, [netinfo.isInternetReachable]);
|
||||
}, [netinfo.isInternetReachable, channelId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (clearNotificationTimeout.current) {
|
||||
clearTimeout(clearNotificationTimeout.current);
|
||||
clearNotificationTimeout.current = undefined;
|
||||
if (channelId) {
|
||||
clearNotificationTimeout.current = setTimeout(clearNotifications, 1500);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (clearNotificationTimeout.current && channelId) {
|
||||
clearTimeout(clearNotificationTimeout.current);
|
||||
}
|
||||
};
|
||||
}, [channelId]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -100,19 +100,24 @@ class PushNotifications {
|
||||
Notifications.ios.removeDeliveredNotifications(ids);
|
||||
}
|
||||
|
||||
if (Store.redux) {
|
||||
const totalMentions = getBadgeCount(Store.redux.getState());
|
||||
if (totalMentions > -1) {
|
||||
// replaces the badge count based on the redux store.
|
||||
badgeCount = totalMentions;
|
||||
}
|
||||
}
|
||||
this.setBadgeCountByMentions(badgeCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
badgeCount = badgeCount <= 0 ? 0 : badgeCount;
|
||||
Notifications.ios.setBadgeCount(badgeCount);
|
||||
setBadgeCountByMentions = (initialBadge = 0) => {
|
||||
let badgeCount = initialBadge;
|
||||
if (Store.redux) {
|
||||
const totalMentions = getBadgeCount(Store.redux.getState());
|
||||
if (totalMentions > -1) {
|
||||
// replaces the badge count based on the redux store.
|
||||
badgeCount = totalMentions;
|
||||
}
|
||||
}
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
badgeCount = badgeCount <= 0 ? 0 : badgeCount;
|
||||
Notifications.ios.setBadgeCount(badgeCount);
|
||||
}
|
||||
}
|
||||
|
||||
createReplyCategory = () => {
|
||||
@@ -144,13 +149,13 @@ class PushNotifications {
|
||||
const interval = setInterval(() => {
|
||||
if (Store.redux) {
|
||||
clearInterval(interval);
|
||||
this.handleNotification(notification);
|
||||
this.handleNotification(notification, true);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
handleNotification = (notification: NotificationWithData) => {
|
||||
handleNotification = (notification: NotificationWithData, isInitialNotification = false) => {
|
||||
const {payload, foreground, userInteraction} = notification;
|
||||
|
||||
if (Store.redux && payload) {
|
||||
@@ -167,8 +172,9 @@ class PushNotifications {
|
||||
|
||||
if (foreground) {
|
||||
EventEmitter.emit(ViewTypes.NOTIFICATION_IN_APP, notification);
|
||||
this.setBadgeCountByMentions();
|
||||
} else if (userInteraction && !payload.userInfo?.local) {
|
||||
dispatch(loadFromPushNotification(notification));
|
||||
dispatch(loadFromPushNotification(notification, isInitialNotification));
|
||||
const componentId = EphemeralStore.getNavigationTopComponentId();
|
||||
if (componentId) {
|
||||
EventEmitter.emit(NavigationTypes.CLOSE_MAIN_SIDEBAR);
|
||||
|
||||
@@ -9,7 +9,6 @@ import {Alert, Animated, Keyboard, StyleSheet} from 'react-native';
|
||||
import {showModal, showModalOverCurrentContext} from '@actions/navigation';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import {TYPING_VISIBLE} from '@constants/post_draft';
|
||||
import PushNotifications from '@init/push_notifications';
|
||||
import {General} from '@mm-redux/constants';
|
||||
import EventEmitter from '@mm-redux/utils/event_emitter';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
@@ -87,7 +86,6 @@ export default class ChannelBase extends PureComponent {
|
||||
}
|
||||
|
||||
if (currentChannelId) {
|
||||
this.clearChannelNotifications();
|
||||
requestAnimationFrame(() => {
|
||||
actions.getChannelStats(currentChannelId);
|
||||
});
|
||||
@@ -125,8 +123,6 @@ export default class ChannelBase extends PureComponent {
|
||||
}
|
||||
|
||||
if (this.props.currentChannelId && this.props.currentChannelId !== prevProps.currentChannelId) {
|
||||
this.clearChannelNotifications();
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
this.props.actions.getChannelStats(this.props.currentChannelId);
|
||||
});
|
||||
@@ -139,13 +135,6 @@ 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 = () => {
|
||||
|
||||
Reference in New Issue
Block a user