Group Calling: show participant name on hover

This commit is contained in:
Josh Perez 2020-11-19 18:31:04 -05:00 committed by Josh Perez
parent 5cc7c9a66a
commit 6a6f8e28ce
5 changed files with 145 additions and 45 deletions

View file

@ -6281,17 +6281,33 @@ button.module-image__border-overlay:focus {
background-color: $color-gray-75;
}
&--audio-muted::before {
&--title {
@include font-caption;
background: linear-gradient($color-black-alpha-40, transparent);
bottom: 0;
display: flex;
padding: 6px;
position: absolute;
width: 100%;
}
&--contact-name {
margin-right: 20px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&--audio-muted::after {
@include color-svg(
'../images/icons/v2/mic-off-solid-28.svg',
$color-white
);
bottom: 12px;
content: '';
height: 28px;
height: 14px;
position: absolute;
right: 12px;
width: 28px;
right: 6px;
width: 14px;
z-index: 1;
}
}
@ -6461,7 +6477,7 @@ button.module-image__border-overlay:focus {
position: relative;
width: 100%;
.module-ongoing-call__group-call-remote-participant--audio-muted::before {
.module-ongoing-call__group-call-remote-participant--audio-muted::after {
display: none;
}
}

View file

@ -10,6 +10,44 @@ import { LocalizerType } from '../types/Util';
import { CallMode, VideoFrameSource } from '../types/Calling';
import { ActiveCallType, SetRendererCanvasType } from '../state/ducks/calling';
const NoVideo = ({
activeCall,
i18n,
}: {
activeCall: ActiveCallType;
i18n: LocalizerType;
}): JSX.Element => {
const {
avatarPath,
color,
name,
phoneNumber,
profileName,
title,
} = activeCall.conversation;
return (
<div className="module-calling-pip__video--remote">
<CallBackgroundBlur avatarPath={avatarPath} color={color}>
<div className="module-calling-pip__video--avatar">
<Avatar
avatarPath={avatarPath}
color={color || 'ultramarine'}
noteToSelf={false}
conversationType="direct"
i18n={i18n}
name={name}
phoneNumber={phoneNumber}
profileName={profileName}
title={title}
size={52}
/>
</div>
</CallBackgroundBlur>
</div>
);
};
export interface PropsType {
activeCall: ActiveCallType;
getGroupCallVideoFrameSource: (demuxId: number) => VideoFrameSource;
@ -27,35 +65,7 @@ export const CallingPipRemoteVideo = ({
if (call.callMode === CallMode.Direct) {
if (!call.hasRemoteVideo) {
const {
avatarPath,
color,
name,
phoneNumber,
profileName,
title,
} = conversation;
return (
<div className="module-calling-pip__video--remote">
<CallBackgroundBlur avatarPath={avatarPath} color={color}>
<div className="module-calling-pip__video--avatar">
<Avatar
avatarPath={avatarPath}
color={color || 'ultramarine'}
noteToSelf={false}
conversationType="direct"
i18n={i18n}
name={name}
phoneNumber={phoneNumber}
profileName={profileName}
title={title}
size={52}
/>
</div>
</CallBackgroundBlur>
</div>
);
return <NoVideo activeCall={activeCall} i18n={i18n} />;
}
return (
@ -74,6 +84,10 @@ export const CallingPipRemoteVideo = ({
const { groupCallParticipants } = activeCall;
const speaker = groupCallParticipants[0];
if (!speaker) {
return <NoVideo activeCall={activeCall} i18n={i18n} />;
}
return (
<div className="module-calling-pip__video--remote">
<GroupCallRemoteParticipant

View file

@ -0,0 +1,54 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import * as React from 'react';
import { noop } from 'lodash';
import { storiesOf } from '@storybook/react';
import {
GroupCallRemoteParticipant,
PropsType,
} from './GroupCallRemoteParticipant';
import { setup as setupI18n } from '../../js/modules/i18n';
import enMessages from '../../_locales/en/messages.json';
const i18n = setupI18n('en', enMessages);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const createProps = (overrideProps: Partial<PropsType> = {}): any => ({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getGroupCallVideoFrameSource: noop as any,
i18n,
remoteParticipant: {
demuxId: 123,
hasRemoteAudio: false,
hasRemoteVideo: true,
isSelf: false,
title:
'Pablo Diego José Francisco de Paula Juan Nepomuceno María de los Remedios Cipriano de la Santísima Trinidad Ruiz y Picasso',
videoAspectRatio: 1.3,
},
...overrideProps,
});
const story = storiesOf('Components/GroupCallRemoteParticipant', module);
story.add('Default', () => (
<GroupCallRemoteParticipant
{...createProps({
isInPip: false,
height: 120,
left: 0,
top: 0,
width: 120,
})}
/>
));
story.add('isInPip', () => (
<GroupCallRemoteParticipant
{...createProps({
isInPip: true,
})}
/>
));

View file

@ -18,6 +18,7 @@ import {
import { LocalizerType } from '../types/Util';
import { CallBackgroundBlur } from './CallBackgroundBlur';
import { Avatar, AvatarSize } from './Avatar';
import { ContactName } from './conversation/ContactName';
// The max size video frame we'll support (in RGBA)
const FRAME_BUFFER_SIZE = 1920 * 1080 * 4;
@ -40,7 +41,7 @@ interface NotInPipPropsType {
width: number;
}
type PropsType = BasePropsType & (InPipPropsType | NotInPipPropsType);
export type PropsType = BasePropsType & (InPipPropsType | NotInPipPropsType);
export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
props => {
@ -57,6 +58,7 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
} = props.remoteParticipant;
const [isWide, setIsWide] = useState(true);
const [hasHover, setHover] = useState(false);
const remoteVideoRef = useRef<HTMLCanvasElement | null>(null);
const canvasContextRef = useRef<CanvasRenderingContext2D | null>(null);
@ -172,14 +174,28 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
return (
<div
className={classNames(
'module-ongoing-call__group-call-remote-participant',
{
'module-ongoing-call__group-call-remote-participant--audio-muted': !hasRemoteAudio,
}
)}
className="module-ongoing-call__group-call-remote-participant"
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
style={containerStyles}
>
{hasHover && (
<div
className={classNames(
'module-ongoing-call__group-call-remote-participant--title',
{
'module-ongoing-call__group-call-remote-participant--audio-muted': !hasRemoteAudio,
}
)}
>
<ContactName
module="module-ongoing-call__group-call-remote-participant--contact-name"
profileName={profileName}
title={title}
i18n={props.i18n}
/>
</div>
)}
{hasRemoteVideo ? (
<canvas
className="module-ongoing-call__group-call-remote-participant__remote-video"

View file

@ -14571,7 +14571,7 @@
"rule": "React-useRef",
"path": "ts/components/GroupCallRemoteParticipant.js",
"line": " const remoteVideoRef = react_1.useRef(null);",
"lineNumber": 26,
"lineNumber": 28,
"reasonCategory": "usageTrusted",
"updated": "2020-11-11T21:56:04.179Z",
"reasonDetail": "Needed to render the remote video element."
@ -14580,7 +14580,7 @@
"rule": "React-useRef",
"path": "ts/components/GroupCallRemoteParticipant.js",
"line": " const canvasContextRef = react_1.useRef(null);",
"lineNumber": 27,
"lineNumber": 29,
"reasonCategory": "usageTrusted",
"updated": "2020-11-17T23:29:38.698Z",
"reasonDetail": "Doesn't touch the DOM."
@ -14589,7 +14589,7 @@
"rule": "React-useRef",
"path": "ts/components/GroupCallRemoteParticipant.js",
"line": " const frameBufferRef = react_1.useRef(new ArrayBuffer(FRAME_BUFFER_SIZE));",
"lineNumber": 28,
"lineNumber": 30,
"reasonCategory": "usageTrusted",
"updated": "2020-11-17T16:24:25.480Z",
"reasonDetail": "Doesn't touch the DOM."