diff --git a/app/products/calls/components/current_call_bar/current_call_bar.tsx b/app/products/calls/components/current_call_bar/current_call_bar.tsx index 7376567c0f..5c296f03ff 100644 --- a/app/products/calls/components/current_call_bar/current_call_bar.tsx +++ b/app/products/calls/components/current_call_bar/current_call_bar.tsx @@ -13,7 +13,7 @@ import CompassIcon from '@components/compass_icon'; import {Events, Screens, WebsocketEvents} from '@constants'; import {CURRENT_CALL_BAR_HEIGHT} from '@constants/view'; import {useTheme} from '@context/theme'; -import {goToScreen} from '@screens/navigation'; +import {dismissAllModalsAndPopToScreen} from '@screens/navigation'; import {makeStyleSheetFromTheme} from '@utils/theme'; import {displayUsername} from '@utils/user'; @@ -24,6 +24,7 @@ type Props = { currentCall: CurrentCall | null; userModelsDict: Dictionary; teammateNameDisplay: string; + threadScreen?: boolean; } const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { @@ -85,6 +86,7 @@ const CurrentCallBar = ({ currentCall, userModelsDict, teammateNameDisplay, + threadScreen, }: Props) => { const theme = useTheme(); const {formatMessage} = useIntl(); @@ -128,7 +130,7 @@ const CurrentCallBar = ({ } }, [speaker, setTalkingMessage]); - const goToCallScreen = useCallback(() => { + const goToCallScreen = useCallback(async () => { const options: Options = { layout: { backgroundColor: '#000', @@ -143,8 +145,8 @@ const CurrentCallBar = ({ }, }; const title = formatMessage({id: 'mobile.calls_call_screen', defaultMessage: 'Call'}); - goToScreen(Screens.CALL, title, {}, options); - }, []); + await dismissAllModalsAndPopToScreen(Screens.CALL, title, {fromThreadScreen: threadScreen}, options); + }, [formatMessage, threadScreen]); const myParticipant = currentCall?.participants[currentCall.myUserId]; diff --git a/app/products/calls/components/floating_call_container.tsx b/app/products/calls/components/floating_call_container.tsx index 8a2d52205b..e51864e834 100644 --- a/app/products/calls/components/floating_call_container.tsx +++ b/app/products/calls/components/floating_call_container.tsx @@ -29,12 +29,13 @@ const style = StyleSheet.create({ type Props = { children: React.ReactNode; + threadScreen?: boolean; } -const FloatingCallContainer = (props: Props) => { +const FloatingCallContainer = ({threadScreen, ...props}: Props) => { const insets = useSafeAreaInsets(); const wrapperTop = { - top: topBarHeight + insets.top, + top: insets.top + (threadScreen ? 0 : topBarHeight), }; return ( diff --git a/app/products/calls/screens/call_screen/call_screen.tsx b/app/products/calls/screens/call_screen/call_screen.tsx index 823bfd16b0..3f983b1890 100644 --- a/app/products/calls/screens/call_screen/call_screen.tsx +++ b/app/products/calls/screens/call_screen/call_screen.tsx @@ -38,7 +38,13 @@ import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item'; import {WebsocketEvents, Screens} from '@constants'; import {useTheme} from '@context/theme'; import DatabaseManager from '@database/manager'; -import {bottomSheet, dismissBottomSheet, goToScreen, popTopScreen} from '@screens/navigation'; +import { + bottomSheet, + dismissAllModalsAndPopToScreen, + dismissBottomSheet, + goToScreen, + popTopScreen, +} from '@screens/navigation'; import NavigationStore from '@store/navigation_store'; import {bottomSheetSnapPoint} from '@utils/helpers'; import {mergeNavigationOptions} from '@utils/navigation'; @@ -50,6 +56,7 @@ export type Props = { currentCall: CurrentCall | null; participantsDict: Dictionary; teammateNameDisplay: string; + fromThreadScreen?: boolean; } const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ @@ -247,18 +254,20 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ }, })); -const CallScreen = ({componentId, currentCall, participantsDict, teammateNameDisplay}: Props) => { +const CallScreen = ({componentId, currentCall, participantsDict, teammateNameDisplay, fromThreadScreen}: Props) => { const intl = useIntl(); const theme = useTheme(); const insets = useSafeAreaInsets(); const {width, height} = useWindowDimensions(); - const isLandscape = width > height; const [showControlsInLandscape, setShowControlsInLandscape] = useState(false); - const myParticipant = currentCall?.participants[currentCall.myUserId]; - const style = getStyleSheet(theme); - const showControls = !isLandscape || showControlsInLandscape; const [speakers, setSpeakers] = useState>({}); + const style = getStyleSheet(theme); + const isLandscape = width > height; + const showControls = !isLandscape || showControlsInLandscape; + const myParticipant = currentCall?.participants[currentCall.myUserId]; + const chatThreadTitle = intl.formatMessage({id: 'mobile.calls_chat_thread', defaultMessage: 'Chat thread'}); + useEffect(() => { mergeNavigationOptions('Call', { layout: { @@ -329,17 +338,20 @@ const CallScreen = ({componentId, currentCall, participantsDict, teammateNameDis const activeUrl = await DatabaseManager.getActiveServerUrl(); if (activeUrl === currentCall.serverUrl) { - goToScreen(Screens.THREAD, '', {rootId: currentCall.threadId}); + await dismissAllModalsAndPopToScreen(Screens.THREAD, chatThreadTitle, {rootId: currentCall.threadId}); return; } // TODO: this is a temporary solution until we have a proper cross-team thread view. // https://mattermost.atlassian.net/browse/MM-45752 - popTopScreen(componentId); + await popTopScreen(componentId); + if (fromThreadScreen) { + await popTopScreen(Screens.THREAD); + } await DatabaseManager.setActiveServerDatabase(currentCall.serverUrl); await appEntry(currentCall.serverUrl, Date.now()); - goToScreen(Screens.THREAD, '', {rootId: currentCall.threadId}); - }, [currentCall?.serverUrl, currentCall?.threadId]); + await goToScreen(Screens.THREAD, chatThreadTitle, {rootId: currentCall.threadId}); + }, [currentCall?.serverUrl, currentCall?.threadId, fromThreadScreen, componentId, chatThreadTitle]); const showOtherActions = useCallback(() => { const renderContent = () => { @@ -348,7 +360,7 @@ const CallScreen = ({componentId, currentCall, participantsDict, teammateNameDis ); diff --git a/app/screens/channel/channel.tsx b/app/screens/channel/channel.tsx index 2029a6d1bb..f29e6921eb 100644 --- a/app/screens/channel/channel.tsx +++ b/app/screens/channel/channel.tsx @@ -28,7 +28,6 @@ type ChannelProps = { serverUrl: string; channelId: string; componentId?: string; - isCallsPluginEnabled: boolean; isCallInCurrentChannel: boolean; isInACall: boolean; isInCurrentChannelCall: boolean; @@ -47,7 +46,6 @@ const Channel = ({ serverUrl, channelId, componentId, - isCallsPluginEnabled, isCallInCurrentChannel, isInACall, isInCurrentChannelCall, @@ -120,7 +118,7 @@ const Channel = ({ let callsComponents: JSX.Element | null = null; const showJoinCallBanner = isCallInCurrentChannel && !isInCurrentChannelCall; - if (isCallsPluginEnabled && (showJoinCallBanner || isInACall)) { + if (showJoinCallBanner || isInACall) { callsComponents = ( {showJoinCallBanner && diff --git a/app/screens/channel/index.tsx b/app/screens/channel/index.tsx index 6bc215a87a..7ed6ba6e9e 100644 --- a/app/screens/channel/index.tsx +++ b/app/screens/channel/index.tsx @@ -20,10 +20,6 @@ type EnhanceProps = WithDatabaseArgs & { const enhanced = withObservables([], ({database, serverUrl}: EnhanceProps) => { const channelId = observeCurrentChannelId(database); - const isCallsPluginEnabled = observeCallsConfig(serverUrl).pipe( - switchMap((config) => of$(config.pluginEnabled)), - distinctUntilChanged(), - ); const isCallInCurrentChannel = combineLatest([channelId, observeChannelsWithCalls(serverUrl)]).pipe( switchMap(([id, calls]) => of$(Boolean(calls[id]))), distinctUntilChanged(), @@ -60,7 +56,6 @@ const enhanced = withObservables([], ({database, serverUrl}: EnhanceProps) => { return { channelId, - isCallsPluginEnabled, isCallInCurrentChannel, isInACall, isInCurrentChannelCall, diff --git a/app/screens/navigation.ts b/app/screens/navigation.ts index dfe018412f..42f95a8708 100644 --- a/app/screens/navigation.ts +++ b/app/screens/navigation.ts @@ -403,7 +403,7 @@ export async function dismissAllModalsAndPopToRoot() { * (if the screen is not in the stack, it will push a new one) * @param screenId Screen to pop or display * @param title Title to be shown in the top bar - * @param passProps Props to pass to the screen (Only if the screen does not exist in the stack) + * @param passProps Props to pass to the screen * @param options Navigation options */ export async function dismissAllModalsAndPopToScreen(screenId: string, title: string, passProps = {}, options = {}) { @@ -421,6 +421,9 @@ export async function dismissAllModalsAndPopToScreen(screenId: string, title: st } try { await Navigation.popTo(screenId, mergeOptions); + if (Object.keys(passProps).length > 0) { + await Navigation.updateProps(screenId, passProps); + } } catch { // catch in case there is nothing to pop } diff --git a/app/screens/thread/index.tsx b/app/screens/thread/index.tsx index cbc5016de1..5d635cfbb2 100644 --- a/app/screens/thread/index.tsx +++ b/app/screens/thread/index.tsx @@ -3,7 +3,10 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; +import {of as of$} from 'rxjs'; +import {distinctUntilChanged, switchMap} from 'rxjs/operators'; +import {observeCurrentCall} from '@calls/state'; import {observePost} from '@queries/servers/post'; import Thread from './thread'; @@ -11,8 +14,14 @@ import Thread from './thread'; import type {WithDatabaseArgs} from '@typings/database/database'; const enhanced = withObservables(['rootId'], ({database, rootId}: WithDatabaseArgs & {rootId: string}) => { + const isInACall = observeCurrentCall().pipe( + switchMap((call) => of$(Boolean(call))), + distinctUntilChanged(), + ); + return { rootPost: observePost(database, rootId), + isInACall, }; }); diff --git a/app/screens/thread/thread.tsx b/app/screens/thread/thread.tsx index 86ce5d1837..99a51fa2d6 100644 --- a/app/screens/thread/thread.tsx +++ b/app/screens/thread/thread.tsx @@ -6,6 +6,8 @@ import {DeviceEventEmitter, LayoutChangeEvent, StyleSheet, View} from 'react-nat import {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view'; import {Edge, SafeAreaView} from 'react-native-safe-area-context'; +import CurrentCallBar from '@calls/components/current_call_bar'; +import FloatingCallContainer from '@calls/components/floating_call_container'; import FreezeScreen from '@components/freeze_screen'; import PostDraft from '@components/post_draft'; import RoundedHeaderContext from '@components/rounded_header_context'; @@ -23,6 +25,7 @@ import type PostModel from '@typings/database/models/servers/post'; type ThreadProps = { componentId: string; rootPost?: PostModel; + isInACall: boolean; }; const edges: Edge[] = ['left', 'right']; @@ -31,7 +34,7 @@ const styles = StyleSheet.create({ flex: {flex: 1}, }); -const Thread = ({componentId, rootPost}: ThreadProps) => { +const Thread = ({componentId, rootPost, isInACall}: ThreadProps) => { const appState = useAppState(); const postDraftRef = useRef(null); const [containerHeight, setContainerHeight] = useState(0); @@ -96,6 +99,11 @@ const Thread = ({componentId, rootPost}: ThreadProps) => { /> } + {isInACall && + + + + } );