From b6fe67c62b77499ba62cedb6387fa6397dd7fa72 Mon Sep 17 00:00:00 2001 From: Przemyslaw Jozwik Date: Fri, 5 Jul 2024 10:43:02 +0200 Subject: [PATCH] fix: revert minimized calling cell --- src/i18n/en-US.json | 1 - .../components/Conversation/Conversation.tsx | 21 +- .../{CallingCell => }/CallingCell.test.tsx | 1 + src/script/components/calling/CallingCell.tsx | 654 ++++++++++++++++++ .../calling/CallingCell/CallingCell.styles.ts | 53 -- .../calling/CallingCell/CallingCell.tsx | 368 ---------- .../CallingControls/CallingControls.styles.ts | 35 - .../CallingControls/CallingControls.tsx | 226 ------ .../CallingCell/CallingControls/index.ts | 20 - .../CallingHeader/CallingHeader.styles.ts | 80 --- .../CallingHeader/CallingHeader.tsx | 163 ----- .../CallingCell/CallingHeader/index.ts | 20 - .../components/calling/CallingCell/index.ts | 20 - .../DetachedCallingCell.tsx | 2 +- .../panels/Conversations/Conversations.tsx | 63 +- .../panels/TemporaryGuestConversations.tsx | 30 +- src/style/components/group-video-grid.less | 2 +- .../list/conversation-list-calling-cell.less | 37 +- src/style/list/conversation-list-cell.less | 23 + 19 files changed, 762 insertions(+), 1057 deletions(-) rename src/script/components/calling/{CallingCell => }/CallingCell.test.tsx (99%) create mode 100644 src/script/components/calling/CallingCell.tsx delete mode 100644 src/script/components/calling/CallingCell/CallingCell.styles.ts delete mode 100644 src/script/components/calling/CallingCell/CallingCell.tsx delete mode 100644 src/script/components/calling/CallingCell/CallingControls/CallingControls.styles.ts delete mode 100644 src/script/components/calling/CallingCell/CallingControls/CallingControls.tsx delete mode 100644 src/script/components/calling/CallingCell/CallingControls/index.ts delete mode 100644 src/script/components/calling/CallingCell/CallingHeader/CallingHeader.styles.ts delete mode 100644 src/script/components/calling/CallingCell/CallingHeader/CallingHeader.tsx delete mode 100644 src/script/components/calling/CallingCell/CallingHeader/index.ts delete mode 100644 src/script/components/calling/CallingCell/index.ts diff --git a/src/i18n/en-US.json b/src/i18n/en-US.json index b95378eeb5a..7548cf364ad 100644 --- a/src/i18n/en-US.json +++ b/src/i18n/en-US.json @@ -1544,7 +1544,6 @@ "videoCallvideoInputCamera": "Camera", "videoSpeakersTabAll": "All ({{count}})", "videoSpeakersTabSpeakers": "Speakers", - "viewingInAnotherWindow": "Viewing in another window", "warningCallIssues": "This version of {{brandName}} can not participate in the call. Please use", "warningCallQualityPoor": "Poor connection", "warningCallUnsupportedIncoming": "{{user}} is calling. Your browser doesn’t support calls.", diff --git a/src/script/components/Conversation/Conversation.tsx b/src/script/components/Conversation/Conversation.tsx index ad87de960ef..4e2918b3a1b 100644 --- a/src/script/components/Conversation/Conversation.tsx +++ b/src/script/components/Conversation/Conversation.tsx @@ -490,16 +490,17 @@ export const Conversation = ({ } return ( - +
+ +
); })} diff --git a/src/script/components/calling/CallingCell/CallingCell.test.tsx b/src/script/components/calling/CallingCell.test.tsx similarity index 99% rename from src/script/components/calling/CallingCell/CallingCell.test.tsx rename to src/script/components/calling/CallingCell.test.tsx index 16ca62db913..ba35584f200 100644 --- a/src/script/components/calling/CallingCell/CallingCell.test.tsx +++ b/src/script/components/calling/CallingCell.test.tsx @@ -72,6 +72,7 @@ const createProps = async () => { pushToTalkKey: null, conversation, hasAccessToCamera: true, + isSelfVerified: true, teamState: mockTeamState, videoGrid: {grid: [], thumbnail: undefined}, } as CallingCellProps; diff --git a/src/script/components/calling/CallingCell.tsx b/src/script/components/calling/CallingCell.tsx new file mode 100644 index 00000000000..226532c9921 --- /dev/null +++ b/src/script/components/calling/CallingCell.tsx @@ -0,0 +1,654 @@ +/* + * Wire + * Copyright (C) 2022 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import React, {useCallback, useEffect, useState} from 'react'; + +import {DefaultConversationRoleName} from '@wireapp/api-client/lib/conversation/'; +import {TabIndex} from '@wireapp/react-ui-kit/lib/types/enums'; +import cx from 'classnames'; +import {container} from 'tsyringe'; + +import {CALL_TYPE, REASON as CALL_REASON, STATE as CALL_STATE} from '@wireapp/avs'; + +import {Avatar, AVATAR_SIZE, GroupAvatar} from 'Components/Avatar'; +import {Duration} from 'Components/calling/Duration'; +import {GroupVideoGrid} from 'Components/calling/GroupVideoGrid'; +import {useCallAlertState} from 'Components/calling/useCallAlertState'; +import {FadingScrollbar} from 'Components/FadingScrollbar'; +import * as Icon from 'Components/Icon'; +import {ConversationClassifiedBar} from 'Components/input/ClassifiedBar'; +import {usePushToTalk} from 'src/script/hooks/usePushToTalk/usePushToTalk'; +import {useAppMainState, ViewType} from 'src/script/page/state'; +import {useKoSubscribableChildren} from 'Util/ComponentUtil'; +import {isEnterKey, isSpaceOrEnterKey} from 'Util/KeyboardUtil'; +import {t} from 'Util/LocalizerUtil'; +import {sortUsersByPriority} from 'Util/StringUtil'; + +import {CallParticipantsListItem} from './CallParticipantsListItem'; +import {useDetachedCallingFeatureState} from './DetachedCallingCell/DetachedCallingFeature.state'; + +import type {Call} from '../../calling/Call'; +import type {CallingRepository} from '../../calling/CallingRepository'; +import {CallingViewMode, CallState, MuteState} from '../../calling/CallState'; +import type {Participant} from '../../calling/Participant'; +import {useVideoGrid} from '../../calling/videoGridHandler'; +import {generateConversationUrl} from '../../router/routeGenerator'; +import {createNavigate, createNavigateKeyboard} from '../../router/routerBindings'; +import {TeamState} from '../../team/TeamState'; +import {ContextMenuEntry, showContextMenu} from '../../ui/ContextMenu'; +import {CallActions, CallViewTab} from '../../view_model/CallingViewModel'; + +interface VideoCallProps { + hasAccessToCamera?: boolean; + isSelfVerified?: boolean; + teamState?: TeamState; +} + +interface AnsweringControlsProps { + call: Call; + callActions: CallActions; + callingRepository: Pick; + pushToTalkKey: string | null; + isFullUi?: boolean; + callState?: CallState; + classifiedDomains?: string[]; + isTemporaryUser?: boolean; + setMaximizedParticipant?: (participant: Participant | null) => void; +} + +export type CallingCellProps = VideoCallProps & AnsweringControlsProps; + +type labels = {dataUieName: string; text: string}; + +const CallingCell: React.FC = ({ + classifiedDomains, + isTemporaryUser, + call, + callActions, + isFullUi = false, + hasAccessToCamera, + isSelfVerified, + callingRepository, + pushToTalkKey, + setMaximizedParticipant, + teamState = container.resolve(TeamState), + callState = container.resolve(CallState), +}) => { + const {conversation} = call; + const {reason, state, isCbrEnabled, startedAt, participants, maximizedParticipant, muteState} = + useKoSubscribableChildren(call, [ + 'reason', + 'state', + 'isCbrEnabled', + 'startedAt', + 'participants', + 'maximizedParticipant', + 'pages', + 'currentPage', + 'muteState', + ]); + + const { + isGroup, + participating_user_ets: userEts, + selfUser, + display_name: conversationName, + roles, + } = useKoSubscribableChildren(conversation, [ + 'isGroup', + 'participating_user_ets', + 'selfUser', + 'display_name', + 'roles', + ]); + + const {viewMode} = useKoSubscribableChildren(callState, ['viewMode']); + const isFullScreenGrid = viewMode === CallingViewMode.FULL_SCREEN_GRID; + const isDetachedWindow = viewMode === CallingViewMode.DETACHED_WINDOW; + + const {isVideoCallingEnabled} = useKoSubscribableChildren(teamState, ['isVideoCallingEnabled']); + + const {activeCallViewTab} = useKoSubscribableChildren(callState, ['activeCallViewTab']); + const isMuted = muteState !== MuteState.NOT_MUTED; + + const isDeclined = !!reason && [CALL_REASON.STILL_ONGOING, CALL_REASON.ANSWERED_ELSEWHERE].includes(reason); + + const isOutgoing = state === CALL_STATE.OUTGOING; + const isIncoming = state === CALL_STATE.INCOMING; + const isConnecting = state === CALL_STATE.ANSWERED; + const isOngoing = state === CALL_STATE.MEDIA_ESTAB; + + const callStatus: Partial> = { + [CALL_STATE.OUTGOING]: { + dataUieName: 'call-label-outgoing', + text: t('callStateOutgoing'), + }, + [CALL_STATE.INCOMING]: { + dataUieName: 'call-label-incoming', + text: t('callStateIncoming'), + }, + [CALL_STATE.ANSWERED]: { + dataUieName: 'call-label-connecting', + text: t('callStateConnecting'), + }, + }; + + const currentCallStatus = callStatus[state]; + + const isVideoCall = call.initialType === CALL_TYPE.VIDEO; + + const showNoCameraPreview = !hasAccessToCamera && isVideoCall && !isOngoing; + const showVideoButton = isVideoCallingEnabled && (isVideoCall || isOngoing); + const showParticipantsButton = isOngoing && isGroup; + + const videoGrid = useVideoGrid(call); + + const conversationParticipants = conversation && (selfUser ? userEts.concat(selfUser) : userEts); + const conversationUrl = generateConversationUrl(conversation.qualifiedId); + const selfParticipant = call?.getSelfParticipant(); + + const { + sharesScreen: selfSharesScreen, + sharesCamera: selfSharesCamera, + hasActiveVideo: selfHasActiveVideo, + } = useKoSubscribableChildren(selfParticipant, ['sharesScreen', 'sharesCamera', 'hasActiveVideo']); + + const {activeSpeakers} = useKoSubscribableChildren(call, ['activeSpeakers']); + + const isOutgoingVideoCall = isOutgoing && selfSharesCamera; + const isVideoUnsupported = !selfSharesCamera && !conversation?.supportsVideoCall(call.isConference); + const disableVideoButton = isOutgoingVideoCall || isVideoUnsupported; + const disableScreenButton = !callingRepository.supportsScreenSharing; + + const [showParticipants, setShowParticipants] = useState(false); + const isModerator = selfUser && roles[selfUser.id] === DefaultConversationRoleName.WIRE_ADMIN; + + const toggleMute = useCallback( + (shouldMute: boolean) => callActions.toggleMute(call, shouldMute), + [call, callActions], + ); + + const isCurrentlyMuted = useCallback(() => { + const isMuted = call.muteState() === MuteState.SELF_MUTED; + return isMuted; + }, [call]); + + usePushToTalk({ + key: pushToTalkKey, + toggleMute, + isMuted: isCurrentlyMuted, + }); + + const getParticipantContext = (event: React.MouseEvent, participant: Participant) => { + event.preventDefault(); + + const muteParticipant: ContextMenuEntry = { + click: () => callingRepository.sendModeratorMute(conversation.qualifiedId, [participant]), + icon: Icon.MicOffIcon, + identifier: `moderator-mute-participant`, + isDisabled: participant.isMuted(), + label: t('moderatorMenuEntryMute'), + }; + + const muteOthers: ContextMenuEntry = { + click: () => { + callingRepository.sendModeratorMute( + conversation.qualifiedId, + participants.filter(p => p !== participant), + ); + }, + icon: Icon.MicOffIcon, + identifier: 'moderator-mute-others', + label: t('moderatorMenuEntryMuteAllOthers'), + }; + + const entries: ContextMenuEntry[] = [muteOthers].concat(!participant.user.isMe ? muteParticipant : []); + showContextMenu(event, entries, 'participant-moderator-menu'); + }; + + const handleMaximizeKeydown = useCallback( + (event: React.KeyboardEvent) => { + if (!isOngoing || isDetachedWindow) { + return; + } + if (isSpaceOrEnterKey(event.key)) { + callState.viewMode(CallingViewMode.FULL_SCREEN_GRID); + } + }, + [isOngoing, callState], + ); + + const handleMaximizeClick = useCallback(() => { + if (!isOngoing || isDetachedWindow) { + return; + } + callState.viewMode(CallingViewMode.FULL_SCREEN_GRID); + }, [isOngoing, callState]); + + const {setCurrentView} = useAppMainState(state => state.responsiveView); + const {showAlert, clearShowAlert} = useCallAlertState(); + + const answerCall = () => { + callActions.answer(call); + setCurrentView(ViewType.MOBILE_LEFT_SIDEBAR); + }; + + const answerOrRejectCall = useCallback( + (event: KeyboardEvent) => { + const answerCallShortcut = !event.shiftKey && event.ctrlKey && isEnterKey(event); + const hangUpCallShortcut = event.ctrlKey && event.shiftKey && isEnterKey(event); + + const removeEventListener = () => window.removeEventListener('keydown', answerOrRejectCall); + + if (answerCallShortcut || hangUpCallShortcut) { + event.preventDefault(); + event.stopPropagation(); + } + + if (answerCallShortcut) { + answerCall(); + removeEventListener(); + } + + if (hangUpCallShortcut) { + callActions.reject(call); + removeEventListener(); + } + }, + [call, callActions], + ); + + useEffect(() => { + if (isIncoming) { + // Capture will be dispatched to registered element before being dispatched to any EventTarget beneath it in the DOM Tree. + // It's needed because when someone is calling we need to change order of shortcuts to the top of keyboard usage. + // If we didn't pass this prop other Event Listeners will be dispatched in same time. + document.addEventListener('keydown', answerOrRejectCall, {capture: true}); + + return () => { + document.removeEventListener('keydown', answerOrRejectCall, {capture: true}); + }; + } + + return () => { + clearShowAlert(); + }; + }, [answerOrRejectCall, isIncoming]); + + const call1To1StartedAlert = t(isOutgoingVideoCall ? 'startedVideoCallingAlert' : 'startedAudioCallingAlert', { + conversationName, + cameraStatus: t(selfSharesCamera ? 'cameraStatusOn' : 'cameraStatusOff'), + }); + + const onGoingCallAlert = t(isOutgoingVideoCall ? 'ongoingVideoCall' : 'ongoingAudioCall', { + conversationName, + cameraStatus: t(selfSharesCamera ? 'cameraStatusOn' : 'cameraStatusOff'), + }); + + const callGroupStartedAlert = t(isOutgoingVideoCall ? 'startedVideoGroupCallingAlert' : 'startedGroupCallingAlert', { + conversationName, + cameraStatus: t(selfSharesCamera ? 'cameraStatusOn' : 'cameraStatusOff'), + }); + + const onGoingGroupCallAlert = t(isOutgoingVideoCall ? 'ongoingGroupVideoCall' : 'ongoingGroupAudioCall', { + conversationName, + cameraStatus: t(selfSharesCamera ? 'cameraStatusOn' : 'cameraStatusOff'), + }); + + const callStartedAlert = isGroup ? callGroupStartedAlert : call1To1StartedAlert; + const ongoingCallAlert = isGroup ? onGoingGroupCallAlert : onGoingCallAlert; + + const toggleDetachedWindow = () => { + if (isDetachedWindow) { + callState.viewMode(CallingViewMode.MINIMIZED); + } else { + callState.viewMode(CallingViewMode.DETACHED_WINDOW); + } + }; + + const isDetachedCallingFeatureEnabled = useDetachedCallingFeatureState(state => state.isSupported()); + + return ( +
+ {isIncoming && ( +

+ {t('callConversationAcceptOrDecline', conversationName)} +

+ )} + + {conversation && (!isDeclined || isTemporaryUser) && ( +
+ {muteState === MuteState.REMOTE_MUTED && isFullUi && ( +
{t('muteStateRemoteMute')}
+ )} + +
+
{ + if ((isGroup || isOngoing) && showAlert && !isVideoCall) { + element?.focus(); + } + }} + className="conversation-list-cell conversation-list-cell-button" + onClick={createNavigate(conversationUrl)} + onBlur={() => { + if (isGroup || isOngoing) { + clearShowAlert(); + } + }} + onKeyDown={createNavigateKeyboard(conversationUrl)} + tabIndex={TabIndex.FOCUSABLE} + role="button" + aria-label={ + showAlert + ? callStartedAlert + : `${isOngoing ? `${ongoingCallAlert} ` : ''}${t('accessibility.openConversation', conversationName)}` + } + > + {!isTemporaryUser && ( +
+ {isGroup && } + {!isGroup && !!conversationParticipants.length && ( + + )} +
+ )} + +

+ {conversationName} + + {currentCallStatus && ( + + {currentCallStatus.text} + + )} + + {isOngoing && startedAt && ( +
+ + + + + {isCbrEnabled && ( + + CBR + + )} +
+ )} +

+
+ +
+ {isOngoing && isDetachedCallingFeatureEnabled && ( + + )} + + {(isConnecting || isOngoing) && ( + + )} +
+
+ + {(isOngoing || selfHasActiveVideo) && !isFullScreenGrid && !!videoGrid?.grid?.length && isFullUi ? ( +
+ + + {isOngoing && !isDetachedWindow && ( +
+ +
+ )} +
+ ) : ( + showNoCameraPreview && + isFullUi && ( +
+ {t('callNoCameraAccess')} +
+ ) + )} + + {classifiedDomains && ( + + )} + +
+
    + {isFullUi && ( + <> +
  • + +
  • + + {showVideoButton && ( +
  • + +
  • + )} + + {isOngoing && ( +
  • + +
  • + )} + + )} +
+ +
    + {showParticipantsButton && isFullUi && ( +
  • + +
  • + )} + + {(isIncoming || isOutgoing) && !isDeclined && ( +
  • + +
  • + )} + + {isIncoming && ( +
  • + {isDeclined ? ( + + ) : ( + + )} +
  • + )} +
+
+ + {isFullUi && ( +
+ +
    + {participants + .slice() + .sort((participantA, participantB) => sortUsersByPriority(participantA.user, participantB.user)) + .map((participant, index, participantsArray) => ( +
  • + getParticipantContext(event, participant)} + isLast={participantsArray.length === index} + /> +
  • + ))} +
+
+
+ )} +
+ )} +
+ ); +}; + +export {CallingCell}; diff --git a/src/script/components/calling/CallingCell/CallingCell.styles.ts b/src/script/components/calling/CallingCell/CallingCell.styles.ts deleted file mode 100644 index 85ddecc6974..00000000000 --- a/src/script/components/calling/CallingCell/CallingCell.styles.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -import {CSSObject} from '@emotion/react'; - -export const callingCellWrapper: CSSObject = { - backgroundColor: 'var(--app-bg-secondary)', - border: '1px solid 1px solid var(--border-color)', - borderRadius: '8px', - display: 'flex', - flexDirection: 'column', - padding: '12px 12px 16px', -}; - -export const callingContainer = (isDetachedWindow: boolean): CSSObject => ({ - position: 'relative', - display: 'flex', - flexDirection: 'column', - flexShrink: '0', - padding: isDetachedWindow ? '12px' : '10px 12px 20px', - animation: 'show-call-ui @animation-timing-fast ease-in-out 0s 1', - - ...(isDetachedWindow && { - height: '100%', - }), -}); - -export const infoBar: CSSObject = { - backgroundColor: 'var(--accent-color)', - borderRadius: '8px', - color: 'var(--app-bg-secondary)', - fontSize: 'var(--line-height-xs)', - fontWeight: 'var(--font-weight-medium)', - margin: '8px 8px 0', - padding: '4px', - textAlign: 'center', -}; diff --git a/src/script/components/calling/CallingCell/CallingCell.tsx b/src/script/components/calling/CallingCell/CallingCell.tsx deleted file mode 100644 index fb581b2b36b..00000000000 --- a/src/script/components/calling/CallingCell/CallingCell.tsx +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Wire - * Copyright (C) 2022 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -import React, {useCallback, useEffect} from 'react'; - -import {TabIndex} from '@wireapp/react-ui-kit/lib/types/enums'; -import {container} from 'tsyringe'; - -import {CALL_TYPE, REASON as CALL_REASON, STATE as CALL_STATE} from '@wireapp/avs'; - -import {callingContainer} from 'Components/calling/CallingCell/CallingCell.styles'; -import {CallingControls} from 'Components/calling/CallingCell/CallingControls'; -import {CallingHeader} from 'Components/calling/CallingCell/CallingHeader'; -import {GroupVideoGrid} from 'Components/calling/GroupVideoGrid'; -import {useCallAlertState} from 'Components/calling/useCallAlertState'; -import * as Icon from 'Components/Icon'; -import {ConversationClassifiedBar} from 'Components/input/ClassifiedBar'; -import {usePushToTalk} from 'src/script/hooks/usePushToTalk/usePushToTalk'; -import {useAppMainState, ViewType} from 'src/script/page/state'; -import {useKoSubscribableChildren} from 'Util/ComponentUtil'; -import {isEnterKey, isSpaceOrEnterKey} from 'Util/KeyboardUtil'; -import {t} from 'Util/LocalizerUtil'; - -import type {Call} from '../../../calling/Call'; -import type {CallingRepository} from '../../../calling/CallingRepository'; -import {CallingViewMode, CallState, MuteState} from '../../../calling/CallState'; -import type {Participant} from '../../../calling/Participant'; -import {useVideoGrid} from '../../../calling/videoGridHandler'; -import {generateConversationUrl} from '../../../router/routeGenerator'; -import {TeamState} from '../../../team/TeamState'; -import {CallActions, CallViewTab} from '../../../view_model/CallingViewModel'; - -interface VideoCallProps { - hasAccessToCamera?: boolean; - teamState?: TeamState; -} - -interface AnsweringControlsProps { - call: Call; - callActions: CallActions; - callingRepository: Pick; - pushToTalkKey: string | null; - isFullUi?: boolean; - callState?: CallState; - classifiedDomains?: string[]; - isTemporaryUser?: boolean; - setMaximizedParticipant?: (participant: Participant | null) => void; - isDetached?: boolean; -} - -export type CallingCellProps = VideoCallProps & AnsweringControlsProps; - -export type CallLabel = {dataUieName: string; text: string}; - -export const CallingCell = ({ - classifiedDomains, - isTemporaryUser, - call, - callActions, - isFullUi = false, - hasAccessToCamera, - callingRepository, - pushToTalkKey, - setMaximizedParticipant, - teamState = container.resolve(TeamState), - callState = container.resolve(CallState), - isDetached = false, -}: CallingCellProps) => { - const {conversation} = call; - const {reason, state, isCbrEnabled, startedAt, maximizedParticipant, muteState} = useKoSubscribableChildren(call, [ - 'reason', - 'state', - 'isCbrEnabled', - 'startedAt', - 'maximizedParticipant', - 'pages', - 'currentPage', - 'muteState', - ]); - - const { - isGroup, - participating_user_ets: userEts, - selfUser, - display_name: conversationName, - } = useKoSubscribableChildren(conversation, ['isGroup', 'participating_user_ets', 'selfUser', 'display_name']); - const {activeCallViewTab, viewMode} = useKoSubscribableChildren(callState, ['activeCallViewTab', 'viewMode']); - - const selfParticipant = call.getSelfParticipant(); - - const {sharesCamera: selfSharesCamera, hasActiveVideo: selfHasActiveVideo} = useKoSubscribableChildren( - selfParticipant, - ['sharesCamera', 'hasActiveVideo'], - ); - - const {activeSpeakers} = useKoSubscribableChildren(call, ['activeSpeakers']); - - const isVideoCall = call.initialType === CALL_TYPE.VIDEO; - const isFullScreenGrid = viewMode === CallingViewMode.FULL_SCREEN_GRID; - const isDetachedWindow = viewMode === CallingViewMode.DETACHED_WINDOW; - - const isMuted = muteState !== MuteState.NOT_MUTED; - const isCurrentlyMuted = useCallback(() => muteState === MuteState.SELF_MUTED, [muteState]); - - const isDeclined = !!reason && [CALL_REASON.STILL_ONGOING, CALL_REASON.ANSWERED_ELSEWHERE].includes(reason); - - const isOutgoing = state === CALL_STATE.OUTGOING; - const isIncoming = state === CALL_STATE.INCOMING; - const isConnecting = state === CALL_STATE.ANSWERED; - const isOngoing = state === CALL_STATE.MEDIA_ESTAB; - - const callStatus: Partial> = { - [CALL_STATE.OUTGOING]: { - dataUieName: 'call-label-outgoing', - text: t('callStateOutgoing'), - }, - [CALL_STATE.INCOMING]: { - dataUieName: 'call-label-incoming', - text: t('callStateIncoming'), - }, - [CALL_STATE.ANSWERED]: { - dataUieName: 'call-label-connecting', - text: t('callStateConnecting'), - }, - }; - - const currentCallStatus = callStatus[state]; - - const showNoCameraPreview = !hasAccessToCamera && isVideoCall && !isOngoing; - - const videoGrid = useVideoGrid(call); - - const conversationParticipants = selfUser ? userEts.concat(selfUser) : userEts; - const conversationUrl = generateConversationUrl(conversation.qualifiedId); - - const isOutgoingVideoCall = isOutgoing && selfSharesCamera; - - const toggleMute = useCallback( - (shouldMute: boolean) => callActions.toggleMute(call, shouldMute), - [call, callActions], - ); - - usePushToTalk({ - key: pushToTalkKey, - toggleMute, - isMuted: isCurrentlyMuted, - }); - - const handleMaximizeKeydown = useCallback( - (event: React.KeyboardEvent) => { - if (!isOngoing || isDetachedWindow) { - return; - } - if (isSpaceOrEnterKey(event.key)) { - callState.viewMode(CallingViewMode.FULL_SCREEN_GRID); - } - }, - [isOngoing, callState], - ); - - const handleMaximizeClick = useCallback(() => { - if (!isOngoing || isDetachedWindow) { - return; - } - callState.viewMode(CallingViewMode.FULL_SCREEN_GRID); - }, [isOngoing, callState]); - - const {setCurrentView} = useAppMainState(state => state.responsiveView); - const {showAlert, clearShowAlert} = useCallAlertState(); - - const answerCall = () => { - callActions.answer(call); - setCurrentView(ViewType.MOBILE_LEFT_SIDEBAR); - }; - - const answerOrRejectCall = useCallback( - (event: KeyboardEvent) => { - const answerCallShortcut = !event.shiftKey && event.ctrlKey && isEnterKey(event); - const hangUpCallShortcut = event.ctrlKey && event.shiftKey && isEnterKey(event); - - const removeEventListener = () => window.removeEventListener('keydown', answerOrRejectCall); - - if (answerCallShortcut || hangUpCallShortcut) { - event.preventDefault(); - event.stopPropagation(); - } - - if (answerCallShortcut) { - answerCall(); - removeEventListener(); - } - - if (hangUpCallShortcut) { - callActions.reject(call); - removeEventListener(); - } - }, - [call, callActions], - ); - - useEffect(() => { - if (isIncoming) { - // Capture will be dispatched to registered element before being dispatched to any EventTarget beneath it in the DOM Tree. - // It's needed because when someone is calling we need to change order of shortcuts to the top of keyboard usage. - // If we didn't pass this prop other Event Listeners will be dispatched in same time. - document.addEventListener('keydown', answerOrRejectCall, {capture: true}); - - return () => { - document.removeEventListener('keydown', answerOrRejectCall, {capture: true}); - }; - } - - return () => { - clearShowAlert(); - }; - }, [answerOrRejectCall, isIncoming]); - - const call1To1StartedAlert = t(isOutgoingVideoCall ? 'startedVideoCallingAlert' : 'startedAudioCallingAlert', { - conversationName, - cameraStatus: t(selfSharesCamera ? 'cameraStatusOn' : 'cameraStatusOff'), - }); - - const onGoingCallAlert = t(isOutgoingVideoCall ? 'ongoingVideoCall' : 'ongoingAudioCall', { - conversationName, - cameraStatus: t(selfSharesCamera ? 'cameraStatusOn' : 'cameraStatusOff'), - }); - - const callGroupStartedAlert = t(isOutgoingVideoCall ? 'startedVideoGroupCallingAlert' : 'startedGroupCallingAlert', { - conversationName, - cameraStatus: t(selfSharesCamera ? 'cameraStatusOn' : 'cameraStatusOff'), - }); - - const onGoingGroupCallAlert = t(isOutgoingVideoCall ? 'ongoingGroupVideoCall' : 'ongoingGroupAudioCall', { - conversationName, - cameraStatus: t(selfSharesCamera ? 'cameraStatusOn' : 'cameraStatusOff'), - }); - - const toggleDetachedWindow = () => { - callState.viewMode(isDetachedWindow ? CallingViewMode.MINIMIZED : CallingViewMode.DETACHED_WINDOW); - }; - - return ( -
- {isIncoming && ( -

- {t('callConversationAcceptOrDecline', conversationName)} -

- )} - - {(!isDeclined || isTemporaryUser) && ( -
- {muteState === MuteState.REMOTE_MUTED && isFullUi && ( -
{t('muteStateRemoteMute')}
- )} - - - - {(isOngoing || selfHasActiveVideo) && !isFullScreenGrid && !!videoGrid?.grid?.length && isFullUi ? ( - <> - {isDetachedWindow && !isDetached ? ( - <> - ) : ( -
- - - {isOngoing && !isDetachedWindow && ( -
- -
- )} -
- )} - - ) : ( - showNoCameraPreview && - isFullUi && ( -
- {t('callNoCameraAccess')} -
- ) - )} - - {classifiedDomains && ( - - )} - - -
- )} -
- ); -}; diff --git a/src/script/components/calling/CallingCell/CallingControls/CallingControls.styles.ts b/src/script/components/calling/CallingCell/CallingControls/CallingControls.styles.ts deleted file mode 100644 index f4d85962667..00000000000 --- a/src/script/components/calling/CallingCell/CallingControls/CallingControls.styles.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -import {CSSObject} from '@emotion/react'; - -export const cellControlsWrapper: CSSObject = { - alignItems: 'center', - display: 'flex', - justifyContent: 'space-between', - width: '100%', -}; - -export const cellControlsList: CSSObject = { - display: 'flex', - gap: '8px', - listStyleType: 'none', - margin: 0, - padding: 0, -}; diff --git a/src/script/components/calling/CallingCell/CallingControls/CallingControls.tsx b/src/script/components/calling/CallingCell/CallingControls/CallingControls.tsx deleted file mode 100644 index 9ebf376d943..00000000000 --- a/src/script/components/calling/CallingCell/CallingControls/CallingControls.tsx +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -import cx from 'classnames'; -import {container} from 'tsyringe'; - -import { - cellControlsList, - cellControlsWrapper, -} from 'Components/calling/CallingCell/CallingControls/CallingControls.styles'; -import {useCallAlertState} from 'Components/calling/useCallAlertState'; -import * as Icon from 'Components/Icon'; -import {useKoSubscribableChildren} from 'Util/ComponentUtil'; -import {t} from 'Util/LocalizerUtil'; - -import {Call} from '../../../../calling/Call'; -import {Participant} from '../../../../calling/Participant'; -import {TeamState} from '../../../../team/TeamState'; -import {CallActions} from '../../../../view_model/CallingViewModel'; - -interface CallingControlsProps { - answerCall: () => void; - call: Call; - callActions: CallActions; - call1To1StartedAlert: string; - isDetachedWindow: boolean; - isFullUi?: boolean; - isMuted?: boolean; - isIncoming: boolean; - isOutgoing: boolean; - isOngoing: boolean; - isDeclined: boolean; - isGroup: boolean; - isVideoCall: boolean; - isConnecting?: boolean; - selfParticipant: Participant; - disableScreenButton: boolean; - teamState: TeamState; - supportsVideoCall: boolean; -} - -export const CallingControls = ({ - answerCall, - call, - callActions, - call1To1StartedAlert, - isFullUi, - isMuted, - isConnecting, - isDetachedWindow, - isIncoming, - isOutgoing, - isDeclined, - disableScreenButton, - isVideoCall, - isOngoing, - isGroup, - selfParticipant, - teamState = container.resolve(TeamState), - supportsVideoCall, -}: CallingControlsProps) => { - const {isVideoCallingEnabled} = useKoSubscribableChildren(teamState, ['isVideoCallingEnabled']); - const {sharesScreen: selfSharesScreen, sharesCamera: selfSharesCamera} = useKoSubscribableChildren(selfParticipant, [ - 'sharesScreen', - 'sharesCamera', - ]); - - const {showAlert, clearShowAlert} = useCallAlertState(); - - const isVideoUnsupported = !selfSharesCamera && !supportsVideoCall; - const showVideoButton = isVideoCallingEnabled && (isVideoCall || isOngoing); - const disableVideoButton = (isOutgoing && selfSharesCamera) || isVideoUnsupported; - - return ( -
-
    - {isFullUi && ( - <> -
  • - -
  • - - {showVideoButton && ( -
  • - -
  • - )} - - {isOngoing && ( -
  • - -
  • - )} - - )} -
- -
    - {(isIncoming || isOutgoing) && !isDeclined && ( -
  • - -
  • - )} - - {isIncoming && ( -
  • - {isDeclined ? ( - - ) : ( - - )} -
  • - )} - - {(isConnecting || isOngoing) && ( -
  • - -
  • - )} -
-
- ); -}; diff --git a/src/script/components/calling/CallingCell/CallingControls/index.ts b/src/script/components/calling/CallingCell/CallingControls/index.ts deleted file mode 100644 index 6fcd6a5624a..00000000000 --- a/src/script/components/calling/CallingCell/CallingControls/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -export * from './CallingControls'; diff --git a/src/script/components/calling/CallingCell/CallingHeader/CallingHeader.styles.ts b/src/script/components/calling/CallingCell/CallingHeader/CallingHeader.styles.ts deleted file mode 100644 index 270755160b6..00000000000 --- a/src/script/components/calling/CallingCell/CallingHeader/CallingHeader.styles.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -import {CSSObject} from '@emotion/react'; - -export const callingHeaderContainer: CSSObject = { - alignItems: 'center', - borderRadius: '8px 8px 0 0', - cursor: 'pointer', - display: 'flex', - fontWeight: 'var(--font-weight-regular)', - marginBottom: '8px', - position: 'relative', - width: '100%', -}; - -export const callingHeaderWrapper: CSSObject = { - alignItems: 'center', - display: 'flex', - gap: '12px', - width: '100%', - overflow: 'hidden', -}; - -export const callAvatar: CSSObject = { - alignItems: 'center', - display: 'flex', -}; - -export const conversationCallName: CSSObject = { - fontSize: 'var(--font-size-medium)', - fontWeight: 'var(--font-weight-medium)', - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', -}; - -export const callDescription: CSSObject = { - color: 'var(--background)', - fontSize: 'var(--font-size-small)', - fontWeight: 'var(--font-weight-regular)', -}; - -export const callDetails: CSSObject = { - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - paddingRight: '12px', - width: '100%', -}; - -export const cbrCallState: CSSObject = { - fontWeight: 'var(--font-weight-semibold)', - marginLeft: '6px', -}; - -export const detachedWindowButton: CSSObject = { - alignItems: 'center', - background: 'transparent', - border: 'none', - display: 'flex', - justifyContent: 'center', - padding: '8px 12px', -}; diff --git a/src/script/components/calling/CallingCell/CallingHeader/CallingHeader.tsx b/src/script/components/calling/CallingCell/CallingHeader/CallingHeader.tsx deleted file mode 100644 index fa4f3d5eb32..00000000000 --- a/src/script/components/calling/CallingCell/CallingHeader/CallingHeader.tsx +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -import {TabIndex} from '@wireapp/react-ui-kit/lib/types/enums'; - -import {Avatar, AVATAR_SIZE, GroupAvatar} from 'Components/Avatar'; -import {useDetachedCallingFeatureState} from 'Components/calling/DetachedCallingCell/DetachedCallingFeature.state'; -import {Duration} from 'Components/calling/Duration'; -import * as Icon from 'Components/Icon'; -import {t} from 'Util/LocalizerUtil'; - -import { - callAvatar, - callDescription, - callDetails, - callingHeaderContainer, - callingHeaderWrapper, - cbrCallState, - conversationCallName, - detachedWindowButton, -} from './CallingHeader.styles'; - -import {User} from '../../../../entity/User'; -import {createNavigate, createNavigateKeyboard} from '../../../../router/routerBindings'; - -interface CallingHeaderProps { - isOngoing: boolean; - isGroup: boolean; - - showAlert: boolean; - isVideoCall: boolean; - clearShowAlert: () => void; - conversationUrl: string; - callStartedAlert: string; - ongoingCallAlert: string; - isTemporaryUser: boolean; - conversationParticipants: User[]; - conversationName: string; - currentCallStatus: any; - startedAt?: number; - isCbrEnabled: boolean; - toggleDetachedWindow: () => void; - isDetached: boolean; - isDetachedWindow: boolean; -} - -export const CallingHeader = ({ - isGroup, - isOngoing, - showAlert, - isVideoCall, - clearShowAlert, - conversationUrl, - callStartedAlert, - ongoingCallAlert, - isTemporaryUser, - conversationParticipants, - conversationName, - currentCallStatus, - startedAt, - isCbrEnabled, - toggleDetachedWindow, - isDetached, - isDetachedWindow, -}: CallingHeaderProps) => { - const isDetachedCallingFeatureEnabled = useDetachedCallingFeatureState(state => state.isSupported()); - const isDetachedWindowActive = isDetachedWindow ? isDetached : true; - - return ( -
-
{ - if ((isGroup || isOngoing) && showAlert && !isVideoCall) { - element?.focus(); - } - }} - css={callingHeaderWrapper} - onClick={createNavigate(conversationUrl)} - onBlur={() => { - if (isGroup || isOngoing) { - clearShowAlert(); - } - }} - onKeyDown={createNavigateKeyboard(conversationUrl)} - tabIndex={TabIndex.FOCUSABLE} - role="button" - aria-label={ - showAlert - ? callStartedAlert - : `${isOngoing ? `${ongoingCallAlert} ` : ''}${t('accessibility.openConversation', conversationName)}` - } - > - {isDetachedWindowActive && !isTemporaryUser && ( -
- {isGroup && } - {!isGroup && !!conversationParticipants.length && ( - - )} -
- )} - -

-
{conversationName}
- - {currentCallStatus && ( -
- {currentCallStatus.text} -
- )} - - {isOngoing && startedAt && ( -
- {isDetachedWindow && !isDetached ? ( - - {t('viewingInAnotherWindow')} - - ) : ( - - - - )} - - {isCbrEnabled && isDetachedWindowActive && ( - - CBR - - )} -
- )} -

-
- - {isOngoing && isDetachedCallingFeatureEnabled && ( -
- -
- )} -
- ); -}; diff --git a/src/script/components/calling/CallingCell/CallingHeader/index.ts b/src/script/components/calling/CallingCell/CallingHeader/index.ts deleted file mode 100644 index 7d3a24f71a9..00000000000 --- a/src/script/components/calling/CallingCell/CallingHeader/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -export * from './CallingHeader'; diff --git a/src/script/components/calling/CallingCell/index.ts b/src/script/components/calling/CallingCell/index.ts deleted file mode 100644 index bdc2f2b8760..00000000000 --- a/src/script/components/calling/CallingCell/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -export * from './CallingCell'; diff --git a/src/script/components/calling/DetachedCallingCell/DetachedCallingCell.tsx b/src/script/components/calling/DetachedCallingCell/DetachedCallingCell.tsx index 002011e4a7e..5192ff97a21 100644 --- a/src/script/components/calling/DetachedCallingCell/DetachedCallingCell.tsx +++ b/src/script/components/calling/DetachedCallingCell/DetachedCallingCell.tsx @@ -72,8 +72,8 @@ export const DetachedCallingCell = ({ pushToTalkKey={pushToTalkKey} isFullUi hasAccessToCamera={hasAccessToCamera} + isSelfVerified={selfUser.is_verified()} setMaximizedParticipant={participant => activeCall.maximizedParticipant(participant)} - isDetached /> ); diff --git a/src/script/page/LeftSidebar/panels/Conversations/Conversations.tsx b/src/script/page/LeftSidebar/panels/Conversations/Conversations.tsx index 3a205c54bd8..f853fff3730 100644 --- a/src/script/page/LeftSidebar/panels/Conversations/Conversations.tsx +++ b/src/script/page/LeftSidebar/panels/Conversations/Conversations.tsx @@ -51,11 +51,10 @@ import {EmptyConversationList} from './EmptyConversationList'; import {getTabConversations} from './helpers'; import {SidebarStatus, SidebarTabs, useFolderState, useSidebarStore} from './state'; -import {CallState} from '../../../../calling/CallState'; +import {CallingViewMode, CallState} from '../../../../calling/CallState'; import {createLabel} from '../../../../conversation/ConversationLabelRepository'; import {ConversationRepository} from '../../../../conversation/ConversationRepository'; import {ConversationState} from '../../../../conversation/ConversationState'; -import type {Conversation} from '../../../../entity/Conversation'; import {User} from '../../../../entity/User'; import {useConversationFocus} from '../../../../hooks/useConversationFocus'; import {PreferenceNotificationRepository} from '../../../../notification/PreferenceNotificationRepository'; @@ -105,7 +104,6 @@ const Conversations: React.FC = ({ const [isConversationFilterFocused, setIsConversationFilterFocused] = useState(false); const {classifiedDomains, isTeam} = useKoSubscribableChildren(teamState, ['classifiedDomains', 'isTeam']); const {connectRequests} = useKoSubscribableChildren(userState, ['connectRequests']); - const {notifications} = useKoSubscribableChildren(preferenceNotificationRepository, ['notifications']); const { activeConversation, @@ -122,8 +120,9 @@ const Conversations: React.FC = ({ 'unreadConversations', 'visibleConversations', ]); + const {activeCalls, viewMode} = useKoSubscribableChildren(callState, ['activeCalls', 'viewMode']); - const {activeCalls} = useKoSubscribableChildren(callState, ['activeCalls']); + const isCallWindowDetached = viewMode === CallingViewMode.DETACHED_WINDOW; const {conversationLabelRepository} = conversationRepository; const favoriteConversations = conversationLabelRepository.getFavorites(conversations); @@ -143,11 +142,8 @@ const Conversations: React.FC = ({ const {openFolder, closeFolder, expandedFolder, isFoldersTabOpen, toggleFoldersTab} = useFolderState(); const {currentFocus, handleKeyDown, resetConversationFocus} = useConversationFocus(conversations); - // false when screen is larger than 1000px - // true when screen is smaller than 1000px - const isScreenLessThanMdBreakpoint = useMatchMedia('(max-width: 1000px)'); - const isSideBarOpen = - sidebarStatus === SidebarStatus.AUTO ? !isScreenLessThanMdBreakpoint : sidebarStatus === SidebarStatus.OPEN; + const mdBreakpoint = useMatchMedia('(max-width: 1000px)'); + const isSideBarOpen = sidebarStatus === SidebarStatus.AUTO ? mdBreakpoint : sidebarStatus === SidebarStatus.OPEN; const {conversations: currentTabConversations, searchInputPlaceholder} = getTabConversations({ currentTab, @@ -181,20 +177,6 @@ const Conversations: React.FC = ({ } }, [activeConversation, conversationState, listViewModel.contentViewModel, conversations.length]); - useEffect(() => { - amplify.subscribe(WebAppEvents.CONVERSATION.SHOW, (conversation?: Conversation) => { - if (!conversation) { - return; - } - - const includesConversation = currentTabConversations.includes(conversation); - - if (!includesConversation) { - setCurrentTab(SidebarTabs.RECENT); - } - }); - }, [currentTabConversations]); - useEffect(() => { if (!activeConversation) { return () => {}; @@ -256,7 +238,7 @@ const Conversations: React.FC = ({ } const sidebar = ( -