diff --git a/app/actions/views/root.js b/app/actions/views/root.js index e9c72eb64..65b715c9d 100644 --- a/app/actions/views/root.js +++ b/app/actions/views/root.js @@ -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]; diff --git a/app/components/network_indicator/network.tsx b/app/components/network_indicator/network.tsx index 23df1c485..765bde39c 100644 --- a/app/components/network_indicator/network.tsx +++ b/app/components/network_indicator/network.tsx @@ -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(() => { diff --git a/app/init/push_notifications.ts b/app/init/push_notifications.ts index 86a9c6e8b..020e3f625 100644 --- a/app/init/push_notifications.ts +++ b/app/init/push_notifications.ts @@ -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); diff --git a/app/screens/channel/channel_base.js b/app/screens/channel/channel_base.js index a56b573f6..7afb5c154 100644 --- a/app/screens/channel/channel_base.js +++ b/app/screens/channel/channel_base.js @@ -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 = () => {