// Copyright 2020-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { useEffect, useRef, ReactChild } from 'react'; import { Avatar } from './Avatar'; import { Tooltip } from './Tooltip'; import { Intl } from './Intl'; import { Theme } from '../util/theme'; import { getParticipantName } from '../util/callingGetParticipantName'; import { ContactName } from './conversation/ContactName'; import { Emojify } from './conversation/Emojify'; import { LocalizerType } from '../types/Util'; import { AvatarColors } from '../types/Colors'; import { CallMode } from '../types/Calling'; import { ConversationType } from '../state/ducks/conversations'; import { AcceptCallType, DeclineCallType } from '../state/ducks/calling'; import { missingCaseError } from '../util/missingCaseError'; export type PropsType = { acceptCall: (_: AcceptCallType) => void; declineCall: (_: DeclineCallType) => void; i18n: LocalizerType; conversation: Pick< ConversationType, | 'acceptedMessageRequest' | 'avatarPath' | 'color' | 'id' | 'isMe' | 'name' | 'phoneNumber' | 'profileName' | 'sharedGroupNames' | 'title' | 'type' >; bounceAppIconStart(): unknown; bounceAppIconStop(): unknown; notifyForCall(conversationTitle: string, isVideoCall: boolean): unknown; } & ( | { callMode: CallMode.Direct; isVideoCall: boolean; } | { callMode: CallMode.Group; otherMembersRung: Array>; ringer: Pick; } ); type CallButtonProps = { classSuffix: string; tabIndex: number; tooltipContent: string; onClick: () => void; }; const CallButton = ({ classSuffix, onClick, tabIndex, tooltipContent, }: CallButtonProps): JSX.Element => { return ( ); }; const GroupCallMessage = ({ i18n, otherMembersRung, ringer, }: Readonly<{ i18n: LocalizerType; otherMembersRung: Array>; ringer: Pick; }>): JSX.Element => { // As an optimization, we only process the first two names. const [first, second] = otherMembersRung .slice(0, 2) .map(member => ); const ringerNode = ; switch (otherMembersRung.length) { case 0: return ( ); case 1: return ( ); case 2: return ( ); break; case 3: return ( ); break; default: return ( ); } }; export const IncomingCallBar = (props: PropsType): JSX.Element | null => { const { acceptCall, bounceAppIconStart, bounceAppIconStop, conversation, declineCall, i18n, notifyForCall, } = props; const { id: conversationId, acceptedMessageRequest, avatarPath, color, isMe, name, phoneNumber, profileName, sharedGroupNames, title, type: conversationType, } = conversation; let isVideoCall: boolean; let headerNode: ReactChild; let messageNode: ReactChild; switch (props.callMode) { case CallMode.Direct: ({ isVideoCall } = props); headerNode = ( ); messageNode = i18n( isVideoCall ? 'incomingVideoCall' : 'incomingAudioCall' ); break; case CallMode.Group: { const { otherMembersRung, ringer } = props; isVideoCall = true; headerNode = ; messageNode = ( ); break; } default: throw missingCaseError(props); } // We don't want to re-notify if the title changes. const initialTitleRef = useRef(title); useEffect(() => { const initialTitle = initialTitleRef.current; notifyForCall(initialTitle, isVideoCall); }, [isVideoCall, notifyForCall]); useEffect(() => { bounceAppIconStart(); return () => { bounceAppIconStop(); }; }, [bounceAppIconStart, bounceAppIconStop]); return (
{headerNode}
{messageNode}
{isVideoCall ? ( <> { declineCall({ conversationId }); }} tabIndex={0} tooltipContent={i18n('declineCall')} /> { acceptCall({ conversationId, asVideoCall: false }); }} tabIndex={0} tooltipContent={i18n('acceptCallWithoutVideo')} /> { acceptCall({ conversationId, asVideoCall: true }); }} tabIndex={0} tooltipContent={i18n('acceptCall')} /> ) : ( <> { declineCall({ conversationId }); }} tabIndex={0} tooltipContent={i18n('declineCall')} /> { acceptCall({ conversationId, asVideoCall: false }); }} tabIndex={0} tooltipContent={i18n('acceptCall')} /> )}
); };