From f0334d8c0e6b1ef62ca1f59d2ba1e7ec9c9074f1 Mon Sep 17 00:00:00 2001 From: Christopher Poile Date: Tue, 14 Nov 2023 17:03:55 -0500 Subject: [PATCH] MM-54323 - Calls: Incoming call from different server (#7646) * refactor; tried to clarify more_messages; new design * adjust more_messages text spacing * small fix for height with incoming call on current channel * move calls-specific code in the calls product behind a hook * show servername for notifications from other servers * if >1 active servers, always show server name, otherwise don't * add height of notification bar in measurements --------- Co-authored-by: Mattermost Build --- .../call_notification/call_notification.tsx | 44 ++++++++++++++++--- .../components/call_notification/index.ts | 2 + app/products/calls/hooks.ts | 34 +++++++++++--- 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/app/products/calls/components/call_notification/call_notification.tsx b/app/products/calls/components/call_notification/call_notification.tsx index 40fa401ac..046461bd4 100644 --- a/app/products/calls/components/call_notification/call_notification.tsx +++ b/app/products/calls/components/call_notification/call_notification.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useCallback, useEffect} from 'react'; +import React, {useCallback, useEffect, useState} from 'react'; import {useIntl} from 'react-intl'; import {Pressable, Text, View} from 'react-native'; @@ -18,11 +18,14 @@ import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import DatabaseManager from '@database/manager'; import WebsocketManager from '@managers/websocket_manager'; +import {getServerDisplayName} from '@queries/app/servers'; import ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; import {displayUsername} from '@utils/user'; +import type ServersModel from '@typings/database/models/app/servers'; + const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ outerContainer: { borderRadius: 8, @@ -39,6 +42,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ shadowRadius: 4, elevation: 4, }, + outerContainerServerName: { + height: CALL_NOTIFICATION_BAR_HEIGHT + 8, + }, innerContainer: { flexDirection: 'row', width: '100%', @@ -71,6 +77,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ }, textContainer: { flex: 1, + flexDirection: 'column', marginLeft: 8, }, text: { @@ -81,6 +88,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ ...typography('Body', 100, 'SemiBold'), lineHeight: 20, }, + textServerName: { + ...typography('Heading', 25), + color: changeOpacity(theme.buttonColor, 0.72), + textTransform: 'uppercase', + }, dismissContainer: { alignItems: 'center', width: 32, @@ -93,6 +105,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ })); type Props = { + servers: ServersModel[]; incomingCall: IncomingCallNotification; currentUserId: string; teammateNameDisplay: string; @@ -101,6 +114,7 @@ type Props = { } export const CallNotification = ({ + servers, incomingCall, currentUserId, teammateNameDisplay, @@ -111,6 +125,8 @@ export const CallNotification = ({ const serverUrl = useServerUrl(); const theme = useTheme(); const style = getStyleSheet(theme); + const [serverName, setServerName] = useState(''); + const moreThanOneServer = servers.length > 1; useEffect(() => { const channelMembers = members?.filter((m) => m.userId !== currentUserId); @@ -119,13 +135,24 @@ export const CallNotification = ({ } }, []); + // We only need to getServerDisplayName once + useEffect(() => { + async function getName() { + setServerName(await getServerDisplayName(incomingCall.serverUrl)); + } + + if (moreThanOneServer) { + getName(); + } + }, [moreThanOneServer, incomingCall.serverUrl]); + const onContainerPress = useCallback(async () => { - if (serverUrl !== incomingCall.serverUrl) { + if (incomingCall.serverUrl !== serverUrl) { await DatabaseManager.setActiveServerDatabase(incomingCall.serverUrl); await WebsocketManager.initializeClient(incomingCall.serverUrl); } switchToChannelById(incomingCall.serverUrl, incomingCall.channelID); - }, [serverUrl, incomingCall]); + }, [incomingCall, serverUrl]); const onDismissPress = useCallback(() => { removeIncomingCall(serverUrl, incomingCall.callID, incomingCall.channelID); @@ -143,7 +170,7 @@ export const CallNotification = ({ name: displayUsername(incomingCall.callerModel, intl.locale, teammateNameDisplay), }} style={style.text} - numberOfLines={2} + numberOfLines={1} ellipsizeMode={'tail'} /> ); @@ -158,14 +185,14 @@ export const CallNotification = ({ num: (members?.length || 2) - 1, }} style={style.text} - numberOfLines={2} + numberOfLines={1} ellipsizeMode={'tail'} /> ); } return ( - + {message} + {moreThanOneServer && + + {serverName} + + } diff --git a/app/products/calls/components/call_notification/index.ts b/app/products/calls/components/call_notification/index.ts index 7e7c807f8..ff0dfc6f2 100644 --- a/app/products/calls/components/call_notification/index.ts +++ b/app/products/calls/components/call_notification/index.ts @@ -5,6 +5,7 @@ import withObservables from '@nozbe/with-observables'; import {of as of$} from 'rxjs'; import {distinctUntilChanged, switchMap} from 'rxjs/operators'; +import {observeAllActiveServers} from '@app/queries/app/servers'; import {CallNotification} from '@calls/components/call_notification/call_notification'; import DatabaseManager from '@database/manager'; import {observeChannelMembers} from '@queries/servers/channel'; @@ -33,6 +34,7 @@ const enhanced = withObservables(['incomingCall'], ({incomingCall}: OwnProps) => ); return { + servers: observeAllActiveServers(), currentUserId, teammateNameDisplay, members, diff --git a/app/products/calls/hooks.ts b/app/products/calls/hooks.ts index 28d0fe35a..28a4aaf4f 100644 --- a/app/products/calls/hooks.ts +++ b/app/products/calls/hooks.ts @@ -8,13 +8,26 @@ import {useIntl} from 'react-intl'; import {Alert, Platform} from 'react-native'; import Permissions from 'react-native-permissions'; -import {CALL_ERROR_BAR_HEIGHT, CALL_NOTIFICATION_BAR_HEIGHT, CURRENT_CALL_BAR_HEIGHT, JOIN_CALL_BAR_HEIGHT} from '@app/constants/view'; +import { + CALL_ERROR_BAR_HEIGHT, + CALL_NOTIFICATION_BAR_HEIGHT, + CURRENT_CALL_BAR_HEIGHT, + JOIN_CALL_BAR_HEIGHT, +} from '@app/constants/view'; import {initializeVoiceTrack} from '@calls/actions/calls'; -import {setMicPermissionsGranted, useCallsState, useChannelsWithCalls, useCurrentCall, useGlobalCallsState, useIncomingCalls} from '@calls/state'; +import { + setMicPermissionsGranted, + useCallsState, + useChannelsWithCalls, + useCurrentCall, + useGlobalCallsState, + useIncomingCalls, +} from '@calls/state'; import {errorAlert} from '@calls/utils'; import {useServerUrl} from '@context/server'; import {useAppState} from '@hooks/device'; import NetworkManager from '@managers/network_manager'; +import {queryAllActiveServers} from '@queries/app/servers'; import {getFullErrorMessage} from '@utils/errors'; import type {Client} from '@client/rest'; @@ -110,26 +123,35 @@ export const usePermissionsChecker = (micPermissionsGranted: boolean) => { }, [appState]); }; -export const useCallsAdjustment = (serverUrl: string, channelId: string) => { +export const useCallsAdjustment = (serverUrl: string, channelId: string): number => { const incomingCalls = useIncomingCalls().incomingCalls; const channelsWithCalls = useChannelsWithCalls(serverUrl); const callsState = useCallsState(serverUrl); const globalCallsState = useGlobalCallsState(); const currentCall = useCurrentCall(); + const [numServers, setNumServers] = useState(1); const dismissed = Boolean(callsState.calls[channelId]?.dismissed[callsState.myUserId]); const inCurrentCall = currentCall?.id === channelId; const joinCallBannerVisible = Boolean(channelsWithCalls[channelId]) && !dismissed && !inCurrentCall; + useEffect(() => { + const getNumServers = async () => { + const query = await queryAllActiveServers()?.fetch(); + setNumServers(query?.length || 0); + }; + getNumServers(); + }, []); + // Do we have calls banners? const currentCallBarVisible = Boolean(currentCall); const micPermissionsError = !globalCallsState.micPermissionsGranted && (currentCall && !currentCall.micPermissionsErrorDismissed); const callQualityAlert = Boolean(currentCall?.callQualityAlert); const incomingCallsShowing = incomingCalls.filter((ic) => ic.channelID !== channelId); - const callsIncomingAdjustment = (incomingCallsShowing.length * CALL_NOTIFICATION_BAR_HEIGHT) + (incomingCallsShowing.length * 8); - const callsAdjustment = (currentCallBarVisible ? CURRENT_CALL_BAR_HEIGHT + 8 : 0) + + const notificationBarHeight = CALL_NOTIFICATION_BAR_HEIGHT + (numServers > 1 ? 8 : 0); + const callsIncomingAdjustment = (incomingCallsShowing.length * notificationBarHeight) + (incomingCallsShowing.length * 8); + return (currentCallBarVisible ? CURRENT_CALL_BAR_HEIGHT + 8 : 0) + (micPermissionsError ? CALL_ERROR_BAR_HEIGHT + 8 : 0) + (callQualityAlert ? CALL_ERROR_BAR_HEIGHT + 8 : 0) + (joinCallBannerVisible ? JOIN_CALL_BAR_HEIGHT + 8 : 0) + callsIncomingAdjustment; - return callsAdjustment; };