Skip to content

Commit

Permalink
Participant list improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
josh-signal committed Nov 23, 2020
1 parent 7ca063a commit f8b4862
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 14 deletions.
26 changes: 26 additions & 0 deletions stylesheets/_modules.scss
Expand Up @@ -6110,8 +6110,30 @@ button.module-image__border-overlay:focus {
.module-calling-button {
&__participants {
@include color-svg('../images/icons/v2/group-solid-24.svg', $color-white);
display: inline-block;
height: 22px;
width: 22px;

&--container {
@include button-reset;
border: none;
color: $color-white;
}

&--shown {
background-color: $color-gray-75;
border-radius: 16px;
padding: 6px 8px;
padding-bottom: 2px;
margin-top: -6px;
margin-right: -8px;
}

&--count {
@include font-body-2-bold;
margin-left: 5px;
vertical-align: top;
}
}

&__settings {
Expand Down Expand Up @@ -6592,6 +6614,10 @@ button.module-image__border-overlay:focus {
@include font-body-2-bold;
}

&__contact-icon {
background-color: $color-gray-25;
}

&__list {
height: 100%;
margin-bottom: 0;
Expand Down
1 change: 1 addition & 0 deletions ts/components/CallManager.tsx
Expand Up @@ -178,6 +178,7 @@ const ActiveCallManager: React.FC<ActiveCallManagerPropsType> = ({
setLocalPreview={setLocalPreview}
setLocalAudio={setLocalAudio}
setLocalVideo={setLocalVideo}
showParticipantsList={showParticipantsList}
toggleParticipants={toggleParticipants}
toggleSettings={toggleSettings}
/>
Expand Down
7 changes: 6 additions & 1 deletion ts/components/CallScreen.tsx
Expand Up @@ -195,7 +195,11 @@ export const CallScreen: React.FC<PropsType> = ({
});

const remoteParticipants =
call.callMode === CallMode.Group ? call.remoteParticipants.length : 0;
call.callMode === CallMode.Group
? activeCall.groupCallParticipants.length
: 0;

const { showParticipantsList } = activeCall.activeCallState;

return (
<div
Expand Down Expand Up @@ -232,6 +236,7 @@ export const CallScreen: React.FC<PropsType> = ({
i18n={i18n}
isGroupCall={call.callMode === CallMode.Group}
remoteParticipants={remoteParticipants}
showParticipantsList={showParticipantsList}
toggleParticipants={toggleParticipants}
togglePip={togglePip}
toggleSettings={toggleSettings}
Expand Down
15 changes: 15 additions & 0 deletions ts/components/CallingHeader.stories.tsx
Expand Up @@ -21,6 +21,10 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
'remoteParticipants',
overrideProps.remoteParticipants || 0
),
showParticipantsList: boolean(
'showParticipantsList',
Boolean(overrideProps.showParticipantsList)
),
toggleParticipants: () => action('toggle-participants'),
togglePip: () => action('toggle-pip'),
toggleSettings: () => action('toggle-settings'),
Expand All @@ -44,6 +48,17 @@ story.add('With Participants', () => (
/>
));

story.add('With Participants (shown)', () => (
<CallingHeader
{...createProps({
canPip: true,
isGroupCall: true,
remoteParticipants: 10,
showParticipantsList: true,
})}
/>
));

story.add('Long Title', () => (
<CallingHeader
{...createProps({
Expand Down
17 changes: 15 additions & 2 deletions ts/components/CallingHeader.tsx
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only

import React from 'react';
import classNames from 'classnames';
import { LocalizerType } from '../types/Util';
import { Tooltip, TooltipTheme } from './Tooltip';

Expand All @@ -11,6 +12,7 @@ export type PropsType = {
i18n: LocalizerType;
isGroupCall?: boolean;
remoteParticipants?: number;
showParticipantsList: boolean;
toggleParticipants?: () => void;
togglePip?: () => void;
toggleSettings: () => void;
Expand All @@ -22,6 +24,7 @@ export const CallingHeader = ({
i18n,
isGroupCall = false,
remoteParticipants,
showParticipantsList,
toggleParticipants,
togglePip,
toggleSettings,
Expand All @@ -43,10 +46,20 @@ export const CallingHeader = ({
aria-label={i18n('calling__participants', [
String(remoteParticipants),
])}
className="module-calling-button__participants"
className={classNames(
'module-calling-button__participants--container',
{
'module-calling-button__participants--shown': showParticipantsList,
}
)}
onClick={toggleParticipants}
type="button"
/>
>
<i className="module-calling-button__participants" />
<span className="module-calling-button__participants--count">
{remoteParticipants}
</span>
</button>
</Tooltip>
</div>
) : null}
Expand Down
13 changes: 13 additions & 0 deletions ts/components/CallingLobby.stories.tsx
Expand Up @@ -39,6 +39,10 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
setLocalAudio: action('set-local-audio'),
setLocalPreview: action('set-local-preview'),
setLocalVideo: action('set-local-video'),
showParticipantsList: boolean(
'showParticipantsList',
Boolean(overrideProps.showParticipantsList)
),
toggleParticipants: action('toggle-participants'),
toggleSettings: action('toggle-settings'),
});
Expand Down Expand Up @@ -115,3 +119,12 @@ story.add('Group Call - 4', () => {
});
return <CallingLobby {...props} />;
});

story.add('Group Call - 4 (participants list)', () => {
const props = createProps({
isGroupCall: true,
participantNames: ['Sam', 'Cayce', 'April', 'Logan', 'Carl'],
showParticipantsList: true,
});
return <CallingLobby {...props} />;
});
3 changes: 3 additions & 0 deletions ts/components/CallingLobby.tsx
Expand Up @@ -34,6 +34,7 @@ export type PropsType = {
setLocalAudio: (_: SetLocalAudioType) => void;
setLocalVideo: (_: SetLocalVideoType) => void;
setLocalPreview: (_: SetLocalPreviewType) => void;
showParticipantsList: boolean;
toggleParticipants: () => void;
toggleSettings: () => void;
};
Expand All @@ -52,6 +53,7 @@ export const CallingLobby = ({
setLocalAudio,
setLocalPreview,
setLocalVideo,
showParticipantsList,
toggleParticipants,
toggleSettings,
}: PropsType): JSX.Element => {
Expand Down Expand Up @@ -117,6 +119,7 @@ export const CallingLobby = ({
i18n={i18n}
isGroupCall={isGroupCall}
remoteParticipants={participantNames.length}
showParticipantsList={showParticipantsList}
toggleParticipants={toggleParticipants}
toggleSettings={toggleSettings}
/>
Expand Down
3 changes: 3 additions & 0 deletions ts/components/CallingParticipantsList.stories.tsx
Expand Up @@ -24,6 +24,7 @@ function createParticipant(
hasRemoteAudio: Boolean(participantProps.hasRemoteAudio),
hasRemoteVideo: Boolean(participantProps.hasRemoteVideo),
isSelf: Boolean(participantProps.isSelf),
name: participantProps.name,
profileName: participantProps.title,
title: String(participantProps.title),
videoAspectRatio: 1.3,
Expand Down Expand Up @@ -64,6 +65,7 @@ story.add('Many Participants', () => {
createParticipant({
hasRemoteAudio: true,
hasRemoteVideo: true,
name: 'Rage Trunks',
title: 'Rage Trunks',
}),
createParticipant({
Expand All @@ -73,6 +75,7 @@ story.add('Many Participants', () => {
createParticipant({
hasRemoteAudio: true,
hasRemoteVideo: true,
name: 'Goku Black',
title: 'Goku Black',
}),
createParticipant({
Expand Down
34 changes: 28 additions & 6 deletions ts/components/CallingParticipantsList.tsx
Expand Up @@ -7,6 +7,7 @@ import React from 'react';
import { createPortal } from 'react-dom';
import { Avatar } from './Avatar';
import { ContactName } from './conversation/ContactName';
import { InContactsIcon } from './InContactsIcon';
import { LocalizerType } from '../types/Util';
import { GroupCallRemoteParticipantType } from '../types/Calling';

Expand All @@ -31,14 +32,24 @@ export const CallingParticipantsList = React.memo(
};
}, []);

const handleCancel = React.useCallback(
(e: React.MouseEvent) => {
if (e.target === e.currentTarget) {
onClose();
}
},
[onClose]
);

if (!root) {
return null;
}

return createPortal(
<div
role="presentation"
className="module-calling-participants-list__overlay"
onClick={handleCancel}
role="presentation"
>
<div className="module-calling-participants-list">
<div className="module-calling-participants-list__header">
Expand Down Expand Up @@ -80,11 +91,22 @@ export const CallingParticipantsList = React.memo(
{i18n('you')}
</span>
) : (
<ContactName
i18n={i18n}
module="module-calling-participants-list__name"
title={participant.title}
/>
<>
<ContactName
i18n={i18n}
module="module-calling-participants-list__name"
title={participant.title}
/>
{participant.name ? (
<span>
{' '}
<InContactsIcon
className="module-calling-participants-list__contact-icon"
i18n={i18n}
/>
</span>
) : null}
</>
)}
</div>
<div>
Expand Down
10 changes: 6 additions & 4 deletions ts/components/InContactsIcon.tsx
Expand Up @@ -2,26 +2,28 @@
// SPDX-License-Identifier: AGPL-3.0-only

import React from 'react';
import classNames from 'classnames';

import { Tooltip } from './Tooltip';
import { LocalizerType } from '../types/Util';

type PropsType = {
className?: string;
i18n: LocalizerType;
};

export const InContactsIcon = (props: PropsType): JSX.Element => {
const { i18n } = props;
const { className, i18n } = props;

/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
return (
<span className="module-in-contacts-icon__tooltip">
<Tooltip content={i18n('contactInAddressBook')}>
<span
tabIndex={0}
role="img"
aria-label={i18n('contactInAddressBook')}
className="module-in-contacts-icon__icon"
className={classNames('module-in-contacts-icon__icon', className)}
role="img"
tabIndex={0}
/>
</Tooltip>
</span>
Expand Down
1 change: 1 addition & 0 deletions ts/state/smart/CallManager.tsx
Expand Up @@ -70,6 +70,7 @@ const mapStateToActiveCallProp = (state: StateType) => {
hasRemoteAudio: remoteParticipant.hasRemoteAudio,
hasRemoteVideo: remoteParticipant.hasRemoteVideo,
isSelf: remoteParticipant.isSelf,
name: remoteConversation.name,
profileName: remoteConversation.profileName,
title: remoteConversation.title,
videoAspectRatio: remoteParticipant.videoAspectRatio,
Expand Down
1 change: 1 addition & 0 deletions ts/types/Calling.ts
Expand Up @@ -66,6 +66,7 @@ export interface GroupCallRemoteParticipantType {
hasRemoteAudio: boolean;
hasRemoteVideo: boolean;
isSelf: boolean;
name?: string;
profileName?: string;
title: string;
videoAspectRatio: number;
Expand Down
2 changes: 1 addition & 1 deletion ts/util/lint/exceptions.json
Expand Up @@ -14400,7 +14400,7 @@
"rule": "React-useRef",
"path": "ts/components/CallingLobby.tsx",
"line": " const localVideoRef = React.useRef(null);",
"lineNumber": 58,
"lineNumber": 60,
"reasonCategory": "usageTrusted",
"updated": "2020-10-26T19:12:24.410Z",
"reasonDetail": "Used to get the local video element for rendering."
Expand Down

0 comments on commit f8b4862

Please sign in to comment.