diff --git a/ts/components/CallScreen.tsx b/ts/components/CallScreen.tsx index 252f719734..4e4d9e6190 100644 --- a/ts/components/CallScreen.tsx +++ b/ts/components/CallScreen.tsx @@ -75,6 +75,41 @@ export type PropsType = { toggleSpeakerView: () => void; }; +type DirectCallHeaderMessagePropsType = { + i18n: LocalizerType; + callState: CallState; + joinedAt?: number; +}; + +function DirectCallHeaderMessage({ + callState, + i18n, + joinedAt, +}: DirectCallHeaderMessagePropsType): JSX.Element | null { + const [acceptedDuration, setAcceptedDuration] = useState< + number | undefined + >(); + + useEffect(() => { + if (!joinedAt) { + return noop; + } + // It's really jumpy with a value of 500ms. + const interval = setInterval(() => { + setAcceptedDuration(Date.now() - joinedAt); + }, 100); + return clearInterval.bind(null, interval); + }, [joinedAt]); + + if (callState === CallState.Reconnecting) { + return <>{i18n('callReconnecting')}; + } + if (callState === CallState.Accepted && acceptedDuration) { + return <>{i18n('callDuration', [renderDuration(acceptedDuration)])}; + } + return null; +} + export const CallScreen: React.FC = ({ activeCall, getGroupCallVideoFrameSource, @@ -145,7 +180,6 @@ export const CallScreen: React.FC = ({ setControlsHover(false); }, [setControlsHover]); - const [acceptedDuration, setAcceptedDuration] = useState(null); const [showControls, setShowControls] = useState(true); const localVideoRef = useRef(null); @@ -157,17 +191,6 @@ export const CallScreen: React.FC = ({ }; }, [setLocalPreview, setRendererCanvas]); - useEffect(() => { - if (!joinedAt) { - return noop; - } - // It's really jumpy with a value of 500ms. - const interval = setInterval(() => { - setAcceptedDuration(Date.now() - joinedAt); - }, 100); - return clearInterval.bind(null, interval); - }, [joinedAt]); - useEffect(() => { if (!showControls || stickyControls || controlsHover) { return noop; @@ -175,7 +198,7 @@ export const CallScreen: React.FC = ({ const timer = setTimeout(() => { setShowControls(false); }, 5000); - return clearInterval.bind(null, timer); + return clearTimeout.bind(null, timer); }, [showControls, stickyControls, controlsHover]); useEffect(() => { @@ -215,7 +238,7 @@ export const CallScreen: React.FC = ({ let isRinging: boolean; let hasCallStarted: boolean; - let headerMessage: string | undefined; + let headerMessage: ReactNode | undefined; let headerTitle: string | undefined; let isConnected: boolean; let participantCount: number; @@ -227,10 +250,12 @@ export const CallScreen: React.FC = ({ activeCall.callState === CallState.Prering || activeCall.callState === CallState.Ringing; hasCallStarted = !isRinging; - headerMessage = renderDirectCallHeaderMessage( - i18n, - activeCall.callState || CallState.Prering, - acceptedDuration + headerMessage = ( + ); headerTitle = isRinging ? undefined : conversation.title; isConnected = activeCall.callState === CallState.Accepted; @@ -252,7 +277,6 @@ export const CallScreen: React.FC = ({ activeCall.outgoingRing && !activeCall.remoteParticipants.length; hasCallStarted = activeCall.joinState !== GroupCallJoinState.NotJoined; participantCount = activeCall.remoteParticipants.length + 1; - headerMessage = undefined; if (isRinging) { headerTitle = undefined; @@ -399,6 +423,9 @@ export const CallScreen: React.FC = ({ hasCallStarted ? 'call-started' : 'call-not-started' }` )} + onFocus={() => { + setShowControls(true); + }} onMouseMove={() => { setShowControls(true); }} @@ -451,27 +478,33 @@ export const CallScreen: React.FC = ({ 'module-ongoing-call__footer__actions', controlsFadeClass )} - onMouseEnter={onControlsMouseEnter} - onMouseLeave={onControlsMouseLeave} > { hangUp({ conversationId: conversation.id }); }} @@ -502,20 +535,6 @@ function getCallModeClassSuffix( } } -function renderDirectCallHeaderMessage( - i18n: LocalizerType, - callState: CallState, - acceptedDuration: null | number -): string | undefined { - if (callState === CallState.Reconnecting) { - return i18n('callReconnecting'); - } - if (callState === CallState.Accepted && acceptedDuration) { - return i18n('callDuration', [renderDuration(acceptedDuration)]); - } - return undefined; -} - function renderDuration(ms: number): string { const secs = Math.floor((ms / 1000) % 60) .toString() diff --git a/ts/components/CallingButton.stories.tsx b/ts/components/CallingButton.stories.tsx index dfd1399a70..d2f381e57a 100644 --- a/ts/components/CallingButton.stories.tsx +++ b/ts/components/CallingButton.stories.tsx @@ -19,6 +19,8 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ select('buttonType', CallingButtonType, CallingButtonType.HANG_UP), i18n, onClick: action('on-click'), + onMouseEnter: action('on-mouse-enter'), + onMouseLeave: action('on-mouse-leave'), tooltipDirection: select( 'tooltipDirection', TooltipPlacement, diff --git a/ts/components/CallingButton.tsx b/ts/components/CallingButton.tsx index 3516b6e3d1..33e4871cca 100644 --- a/ts/components/CallingButton.tsx +++ b/ts/components/CallingButton.tsx @@ -29,6 +29,8 @@ export type PropsType = { i18n: LocalizerType; isVisible?: boolean; onClick: () => void; + onMouseEnter?: () => void; + onMouseLeave?: () => void; tooltipDirection?: TooltipPlacement; }; @@ -37,6 +39,8 @@ export const CallingButton = ({ i18n, isVisible = true, onClick, + onMouseEnter, + onMouseLeave, tooltipDirection, }: PropsType): JSX.Element => { const uniqueButtonId = useMemo(() => uuid(), []); @@ -128,6 +132,8 @@ export const CallingButton = ({ disabled={disabled} id={uniqueButtonId} onClick={onClick} + onMouseEnter={onMouseEnter} + onMouseLeave={onMouseLeave} type="button" >
diff --git a/ts/components/CallingHeader.tsx b/ts/components/CallingHeader.tsx index 5e69cc5255..c7c12664be 100644 --- a/ts/components/CallingHeader.tsx +++ b/ts/components/CallingHeader.tsx @@ -1,7 +1,7 @@ // Copyright 2020-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import React from 'react'; +import React, { ReactNode } from 'react'; import classNames from 'classnames'; import { LocalizerType } from '../types/Util'; import { Tooltip } from './Tooltip'; @@ -11,7 +11,7 @@ export type PropsType = { i18n: LocalizerType; isInSpeakerView?: boolean; isGroupCall?: boolean; - message?: string; + message?: ReactNode; onCancel?: () => void; participantCount: number; showParticipantsList: boolean;