CallScreen interactivity fixes

This commit is contained in:
Fedor Indutny 2021-09-17 17:20:29 -07:00 committed by GitHub
parent 427055ea47
commit 4dcbb7352f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 37 deletions

View file

@ -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<PropsType> = ({
activeCall,
getGroupCallVideoFrameSource,
@ -145,7 +180,6 @@ export const CallScreen: React.FC<PropsType> = ({
setControlsHover(false);
}, [setControlsHover]);
const [acceptedDuration, setAcceptedDuration] = useState<number | null>(null);
const [showControls, setShowControls] = useState(true);
const localVideoRef = useRef<HTMLVideoElement | null>(null);
@ -157,17 +191,6 @@ export const CallScreen: React.FC<PropsType> = ({
};
}, [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<PropsType> = ({
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<PropsType> = ({
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<PropsType> = ({
activeCall.callState === CallState.Prering ||
activeCall.callState === CallState.Ringing;
hasCallStarted = !isRinging;
headerMessage = renderDirectCallHeaderMessage(
i18n,
activeCall.callState || CallState.Prering,
acceptedDuration
headerMessage = (
<DirectCallHeaderMessage
i18n={i18n}
callState={activeCall.callState || CallState.Prering}
joinedAt={joinedAt}
/>
);
headerTitle = isRinging ? undefined : conversation.title;
isConnected = activeCall.callState === CallState.Accepted;
@ -252,7 +277,6 @@ export const CallScreen: React.FC<PropsType> = ({
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<PropsType> = ({
hasCallStarted ? 'call-started' : 'call-not-started'
}`
)}
onFocus={() => {
setShowControls(true);
}}
onMouseMove={() => {
setShowControls(true);
}}
@ -451,27 +478,33 @@ export const CallScreen: React.FC<PropsType> = ({
'module-ongoing-call__footer__actions',
controlsFadeClass
)}
onMouseEnter={onControlsMouseEnter}
onMouseLeave={onControlsMouseLeave}
>
<CallingButton
buttonType={presentingButtonType}
i18n={i18n}
onMouseEnter={onControlsMouseEnter}
onMouseLeave={onControlsMouseLeave}
onClick={togglePresenting}
/>
<CallingButton
buttonType={videoButtonType}
i18n={i18n}
onMouseEnter={onControlsMouseEnter}
onMouseLeave={onControlsMouseLeave}
onClick={toggleVideo}
/>
<CallingButton
buttonType={audioButtonType}
i18n={i18n}
onMouseEnter={onControlsMouseEnter}
onMouseLeave={onControlsMouseLeave}
onClick={toggleAudio}
/>
<CallingButton
buttonType={CallingButtonType.HANG_UP}
i18n={i18n}
onMouseEnter={onControlsMouseEnter}
onMouseLeave={onControlsMouseLeave}
onClick={() => {
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()

View file

@ -19,6 +19,8 @@ const createProps = (overrideProps: Partial<PropsType> = {}): 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,

View file

@ -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"
>
<div />

View file

@ -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;