From dbd943ab8d3ae6ca07b0054d106103c5f55bf750 Mon Sep 17 00:00:00 2001 From: Christopher Poile Date: Mon, 12 Jun 2023 08:55:48 -0400 Subject: [PATCH] MM-52949 - Calls: Blank screen after ending a call and exiting its thread (#7380) * remove thread and call screen * simplify how we remove the call screen --------- Co-authored-by: Mattermost Build --- app/products/calls/actions/calls.test.ts | 7 +++++++ app/products/calls/actions/calls.ts | 17 ++------------- app/products/calls/alerts.ts | 5 ++--- .../calls/screens/call_screen/call_screen.tsx | 21 +------------------ app/products/calls/state/actions.test.ts | 8 +++++++ app/products/calls/state/actions.ts | 7 ++++++- 6 files changed, 26 insertions(+), 39 deletions(-) diff --git a/app/products/calls/actions/calls.test.ts b/app/products/calls/actions/calls.test.ts index 6d975e50e..9b3b018a3 100644 --- a/app/products/calls/actions/calls.test.ts +++ b/app/products/calls/actions/calls.test.ts @@ -89,6 +89,13 @@ jest.mock('@queries/servers/thread', () => ({ })); jest.mock('@calls/alerts'); +jest.mock('react-native-navigation', () => ({ + Navigation: { + pop: jest.fn(() => Promise.resolve({ + catch: jest.fn(), + })), + }, +})); const addFakeCall = (serverUrl: string, channelId: string) => { const call = { diff --git a/app/products/calls/actions/calls.ts b/app/products/calls/actions/calls.ts index cb0c227b1..4d372dcbf 100644 --- a/app/products/calls/actions/calls.ts +++ b/app/products/calls/actions/calls.ts @@ -3,7 +3,6 @@ import {Alert} from 'react-native'; import InCallManager from 'react-native-incall-manager'; -import {Navigation} from 'react-native-navigation'; import {forceLogoutIfNecessary} from '@actions/remote/session'; import {updateThreadFollowing} from '@actions/remote/thread'; @@ -24,7 +23,7 @@ import { getCurrentCall, getChannelsWithCalls, } from '@calls/state'; -import {General, Preferences, Screens} from '@constants'; +import {General, Preferences} from '@constants'; import Calls from '@constants/calls'; import DatabaseManager from '@database/manager'; import {getTeammateNameDisplaySetting} from '@helpers/api/preference'; @@ -34,8 +33,6 @@ import {queryDisplayNamePreferences} from '@queries/servers/preference'; import {getConfig, getLicense} from '@queries/servers/system'; import {getThreadById} from '@queries/servers/thread'; import {getCurrentUser, getUserById} from '@queries/servers/user'; -import {dismissAllModalsAndPopToScreen} from '@screens/navigation'; -import NavigationStore from '@store/navigation_store'; import {getFullErrorMessage} from '@utils/errors'; import {logDebug} from '@utils/log'; import {displayUsername, getUserIdFromChannelName, isSystemAdmin} from '@utils/user'; @@ -271,16 +268,6 @@ export const leaveCall = () => { } }; -export const leaveCallPopCallScreen = async () => { - leaveCall(); - - // Need to pop the call screen, if it's somewhere in the stack. - if (NavigationStore.getScreensInStack().includes(Screens.CALL)) { - await dismissAllModalsAndPopToScreen(Screens.CALL, 'Call'); - Navigation.pop(Screens.CALL).catch(() => null); - } -}; - export const muteMyself = () => { if (connection) { connection.mute(); @@ -459,7 +446,7 @@ export const handleCallsSlashCommand = async (value: string, serverUrl: string, return {handled: true}; case 'leave': if (getCurrentCall()?.channelId === channelId) { - await leaveCallPopCallScreen(); + await leaveCall(); return {handled: true}; } return { diff --git a/app/products/calls/alerts.ts b/app/products/calls/alerts.ts index f3e89d595..0759cb6d8 100644 --- a/app/products/calls/alerts.ts +++ b/app/products/calls/alerts.ts @@ -3,8 +3,7 @@ import {Alert} from 'react-native'; -import {hasMicrophonePermission, joinCall, unmuteMyself} from '@calls/actions'; -import {leaveCallPopCallScreen} from '@calls/actions/calls'; +import {hasMicrophonePermission, joinCall, leaveCall, unmuteMyself} from '@calls/actions'; import {hasBluetoothPermission} from '@calls/actions/permissions'; import { getCallsConfig, @@ -265,7 +264,7 @@ export const recordingAlert = (isHost: boolean, intl: IntlShape) => { defaultMessage: 'Leave', }), onPress: async () => { - await leaveCallPopCallScreen(); + await leaveCall(); }, style: 'destructive', }, diff --git a/app/products/calls/screens/call_screen/call_screen.tsx b/app/products/calls/screens/call_screen/call_screen.tsx index 53b7f4577..9161aab3e 100644 --- a/app/products/calls/screens/call_screen/call_screen.tsx +++ b/app/products/calls/screens/call_screen/call_screen.tsx @@ -4,7 +4,6 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {useIntl} from 'react-intl'; import { - DeviceEventEmitter, Keyboard, type LayoutChangeEvent, type LayoutRectangle, @@ -40,7 +39,7 @@ import {getHandsRaised, makeCallsTheme, sortParticipants} from '@calls/utils'; import CompassIcon from '@components/compass_icon'; import FormattedText from '@components/formatted_text'; import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item'; -import {Calls, Preferences, Screens, WebsocketEvents} from '@constants'; +import {Calls, Preferences, Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import DatabaseManager from '@database/manager'; @@ -56,7 +55,6 @@ import { popTopScreen, setScreensOrientation, } from '@screens/navigation'; -import NavigationStore from '@store/navigation_store'; import {freezeOtherScreens} from '@utils/gallery'; import {bottomSheetSnapPoint} from '@utils/helpers'; import {mergeNavigationOptions} from '@utils/navigation'; @@ -504,16 +502,6 @@ const CallScreen = ({ popTopScreen(componentId); }); - useEffect(() => { - const listener = DeviceEventEmitter.addListener(WebsocketEvents.CALLS_CALL_END, ({channelId}) => { - if (channelId === currentCall?.channelId && NavigationStore.getVisibleScreen() === componentId) { - Navigation.pop(componentId); - } - }); - - return () => listener.remove(); - }, []); - useEffect(() => { const didDismissListener = Navigation.events().registerComponentDidDisappearListener(async ({componentId: screen}) => { if (componentId === screen) { @@ -550,13 +538,6 @@ const CallScreen = ({ }, []); if (!currentCall || !myParticipant) { - // Note: this happens because the screen is "rendered", even after the screen has been popped, and the - // currentCall will have already been set to null when those extra renders run. We probably don't ever need - // to pop, but just in case. - if (NavigationStore.getVisibleScreen() === componentId) { - // ignore the error because the call screen has likely already been popped async - Navigation.pop(componentId).catch(() => null); - } return null; } diff --git a/app/products/calls/state/actions.test.ts b/app/products/calls/state/actions.test.ts index ad3adb4da..a53457658 100644 --- a/app/products/calls/state/actions.test.ts +++ b/app/products/calls/state/actions.test.ts @@ -75,6 +75,14 @@ jest.mock('@queries/servers/thread', () => ({ })), })); +jest.mock('react-native-navigation', () => ({ + Navigation: { + pop: jest.fn(() => Promise.resolve({ + catch: jest.fn(), + })), + }, +})); + const call1: Call = { participants: { 'user-1': {id: 'user-1', muted: false, raisedHand: 0}, diff --git a/app/products/calls/state/actions.ts b/app/products/calls/state/actions.ts index 8e7b711c3..2872f32e7 100644 --- a/app/products/calls/state/actions.ts +++ b/app/products/calls/state/actions.ts @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import {mosThreshold} from '@mattermost/calls/lib/rtc_monitor'; +import {Navigation} from 'react-native-navigation'; import {updateThreadFollowing} from '@actions/remote/thread'; import {needsRecordingAlert} from '@calls/alerts'; @@ -27,7 +28,7 @@ import { DefaultCurrentCall, type ReactionStreamEmoji, } from '@calls/types/calls'; -import {Calls} from '@constants'; +import {Calls, Screens} from '@constants'; import DatabaseManager from '@database/manager'; import {getChannelById} from '@queries/servers/channel'; import {getThreadById} from '@queries/servers/thread'; @@ -217,6 +218,10 @@ export const newCurrentCall = (serverUrl: string, channelId: string, myUserId: s export const myselfLeftCall = () => { setCurrentCall(null); + + // Remove the call screen, and in some situations it needs to be removed twice before actually being removed. + Navigation.pop(Screens.CALL).catch(() => null); + Navigation.pop(Screens.CALL).catch(() => null); }; export const callStarted = async (serverUrl: string, call: Call) => {