Skip to content

Commit

Permalink
Call link admin key fix and in-call approve, deny, remove
Browse files Browse the repository at this point in the history
Co-authored-by: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com>
  • Loading branch information
automated-signal and ayumi-signal committed Apr 30, 2024
1 parent 72afab4 commit 7d6aec8
Show file tree
Hide file tree
Showing 20 changed files with 599 additions and 43 deletions.
16 changes: 16 additions & 0 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,18 @@
"messageformat": "More options",
"description": "Tooltip label for button in the calling screen that opens a menu with other call actions such as React or Raise Hand."
},
"icu:CallingPendingParticipants__ApproveUser": {
"messageformat": "Approve join request",
"description": "Tooltip label for check mark button to approve a user's request to join a call."
},
"icu:CallingPendingParticipants__DenyUser": {
"messageformat": "Deny join request",
"description": "Tooltip label for check mark button to deny a user's request to join a call."
},
"icu:CallingPendingParticipants__RequestsToJoin": {
"messageformat": "{count, plural, one {# request} other {# requests}} to join the call",
"description": "Shown in the call pending join request list to describe how many people are requesting to join"
},
"icu:CallingRaisedHandsList__Title": {
"messageformat": "Raised hands · {count, plural, one {# person} other {# people}}",
"description": "Shown in the call raised hands list to describe how many people have active raised hands"
Expand Down Expand Up @@ -3654,6 +3666,10 @@
"messageformat": "Copy link",
"description": "Menu item in the in-call info popup for call link calls. The action is to add the call link to the clipboard."
},
"icu:CallingAdhocCallInfo__RemoveClient": {
"messageformat": "Remove this person from the call",
"description": "Button in the in-call info popup for call link calls showing all participants. The action is to remove the participant from the call."
},
"icu:callingDeviceSelection__label--video": {
"messageformat": "Video",
"description": "Label for video input selector"
Expand Down
7 changes: 7 additions & 0 deletions stylesheets/_modules.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4511,6 +4511,13 @@ button.module-image__border-overlay:focus {
$color-white
);
}

&__remove {
@include color-svg(
'../images/icons/v3/minus/minus-circle-compact.svg',
$color-white
);
}
}

.module-call-need-permission-screen {
Expand Down
8 changes: 8 additions & 0 deletions stylesheets/components/CallingAdhocCallInfo.scss
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,11 @@
margin-inline: 10px;
border: 1px solid $color-gray-65;
}

.CallingAdhocCallInfo__RemoveClient {
@include button-reset;
width: 16px;
height: 16px;
margin-inline: 8px;
background: $color-white;
}
34 changes: 34 additions & 0 deletions stylesheets/components/CallingPendingParticipants.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

.CallingPendingParticipants {
width: 420px;
height: auto;
padding-block-end: 2px;
margin-block-start: auto;
margin-block-end: 36px;
margin-inline-start: auto;
margin-inline-end: auto;
}

.CallingPendingParticipants__PendingActionButton {
padding-inline: 0;
margin-inline-end: 16px;
}

.CallingPendingParticipants__PendingActionButton:last-child {
margin-inline-end: 8px;
}

.CallingPendingParticipants__PendingActionButtonIcon {
width: 20px;
height: 20px;
}

.CallingPendingParticipants__PendingActionButtonIcon--Approve {
@include color-svg('../images/icons/v3/check/check.svg', $color-white);
}

.CallingPendingParticipants__PendingActionButtonIcon--Deny {
@include color-svg('../images/icons/v3/x/x.svg', $color-white);
}
1 change: 1 addition & 0 deletions stylesheets/manifest.scss
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
@import './components/CallControls.scss';
@import './components/CallSettingsButton.scss';
@import './components/CallingLobby.scss';
@import './components/CallingPendingParticipants.scss';
@import './components/CallingPreCallInfo.scss';
@import './components/CallingScreenSharingController.scss';
@import './components/CallingSelectPresentingSourcesModal.scss';
Expand Down
4 changes: 4 additions & 0 deletions ts/components/CallManager.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,14 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
...storyProps,
availableCameras: [],
acceptCall: action('accept-call'),
approveUser: action('approve-user'),
bounceAppIconStart: action('bounce-app-icon-start'),
bounceAppIconStop: action('bounce-app-icon-stop'),
cancelCall: action('cancel-call'),
changeCallView: action('change-call-view'),
closeNeedPermissionScreen: action('close-need-permission-screen'),
declineCall: action('decline-call'),
denyUser: action('deny-user'),
getGroupCallVideoFrameSource: (_: string, demuxId: number) =>
fakeGetGroupCallVideoFrameSource(demuxId),
getPresentingSources: action('get-presenting-sources'),
Expand All @@ -84,6 +86,7 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
notifyForCall: action('notify-for-call'),
openSystemPreferencesAction: action('open-system-preferences-action'),
playRingtone: action('play-ringtone'),
removeClient: action('remove-client'),
renderDeviceSelection: () => <div />,
renderEmojiPicker: () => <>EmojiPicker</>,
renderReactionPicker: () => <div />,
Expand Down Expand Up @@ -156,6 +159,7 @@ export function OngoingGroupCall(): JSX.Element {
groupMembers: [],
isConversationTooBigToRing: false,
peekedParticipants: [],
pendingParticipants: [],
raisedHands: new Set<number>(),
remoteParticipants: [],
remoteAudioLevels: new Map<number, number>(),
Expand Down
24 changes: 24 additions & 0 deletions ts/components/CallManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import type {
CancelCallType,
DeclineCallType,
GroupCallParticipantInfoType,
PendingUserActionPayloadType,
RemoveClientType,
SendGroupCallRaiseHandType,
SendGroupCallReactionType,
SetGroupCallVideoRequestType,
Expand Down Expand Up @@ -95,9 +97,11 @@ export type PropsType = {
startCall: (payload: StartCallType) => void;
toggleParticipants: () => void;
acceptCall: (_: AcceptCallType) => void;
approveUser: (payload: PendingUserActionPayloadType) => void;
bounceAppIconStart: () => unknown;
bounceAppIconStop: () => unknown;
declineCall: (_: DeclineCallType) => void;
denyUser: (payload: PendingUserActionPayloadType) => void;
hasInitialLoadCompleted: boolean;
i18n: LocalizerType;
isGroupCallRaiseHandEnabled: boolean;
Expand All @@ -109,6 +113,7 @@ export type PropsType = {
) => unknown;
openSystemPreferencesAction: () => unknown;
playRingtone: () => unknown;
removeClient: (payload: RemoveClientType) => void;
sendGroupCallRaiseHand: (payload: SendGroupCallRaiseHandType) => void;
sendGroupCallReaction: (payload: SendGroupCallReactionType) => void;
setGroupCallVideoRequest: (_: SetGroupCallVideoRequestType) => void;
Expand Down Expand Up @@ -151,11 +156,13 @@ type ActiveCallManagerPropsType = {

function ActiveCallManager({
activeCall,
approveUser,
availableCameras,
callLink,
cancelCall,
changeCallView,
closeNeedPermissionScreen,
denyUser,
hangUpActiveCall,
i18n,
isGroupCallRaiseHandEnabled,
Expand All @@ -166,6 +173,7 @@ function ActiveCallManager({
renderDeviceSelection,
renderEmojiPicker,
renderReactionPicker,
removeClient,
sendGroupCallRaiseHand,
sendGroupCallReaction,
setGroupCallVideoRequest,
Expand Down Expand Up @@ -258,6 +266,7 @@ function ActiveCallManager({
let isConvoTooBigToRing = false;
let isAdhocAdminApprovalRequired = false;
let isAdhocJoinRequestPending = false;
let isCallLinkAdmin = false;

switch (activeCall.callMode) {
case CallMode.Direct: {
Expand Down Expand Up @@ -292,6 +301,7 @@ function ActiveCallManager({
isAdhocJoinRequestPending =
isAdhocAdminApprovalRequired &&
activeCall.joinState === GroupCallJoinState.Pending;
isCallLinkAdmin = Boolean(callLink?.adminKey);
break;
}
default:
Expand Down Expand Up @@ -352,10 +362,12 @@ function ActiveCallManager({
<CallingAdhocCallInfo
callLink={callLink}
i18n={i18n}
isCallLinkAdmin={isCallLinkAdmin}
ourServiceId={me.serviceId}
participants={peekedParticipants}
onClose={toggleParticipants}
onCopyCallLink={onCopyCallLink}
removeClient={removeClient}
/>
) : (
<CallingParticipantsList
Expand Down Expand Up @@ -388,6 +400,7 @@ function ActiveCallManager({
hasRemoteVideo: hasLocalVideo,
isHandRaised,
presenting: Boolean(activeCall.presentingSource),
demuxId: activeCall.localDemuxId,
},
]
: [];
Expand All @@ -396,12 +409,15 @@ function ActiveCallManager({
<>
<CallScreen
activeCall={activeCall}
approveUser={approveUser}
changeCallView={changeCallView}
denyUser={denyUser}
getPresentingSources={getPresentingSources}
getGroupCallVideoFrameSource={getGroupCallVideoFrameSourceForActiveCall}
groupMembers={groupMembers}
hangUpActiveCall={hangUpActiveCall}
i18n={i18n}
isCallLinkAdmin={isCallLinkAdmin}
isGroupCallRaiseHandEnabled={isGroupCallRaiseHandEnabled}
me={me}
openSystemPreferencesAction={openSystemPreferencesAction}
Expand Down Expand Up @@ -438,10 +454,12 @@ function ActiveCallManager({
<CallingAdhocCallInfo
callLink={callLink}
i18n={i18n}
isCallLinkAdmin={isCallLinkAdmin}
ourServiceId={me.serviceId}
participants={groupCallParticipantsForParticipantsList}
onClose={toggleParticipants}
onCopyCallLink={onCopyCallLink}
removeClient={removeClient}
/>
) : (
<CallingParticipantsList
Expand All @@ -458,6 +476,7 @@ function ActiveCallManager({
export function CallManager({
acceptCall,
activeCall,
approveUser,
availableCameras,
bounceAppIconStart,
bounceAppIconStop,
Expand All @@ -466,6 +485,7 @@ export function CallManager({
changeCallView,
closeNeedPermissionScreen,
declineCall,
denyUser,
getGroupCallVideoFrameSource,
getPresentingSources,
hangUpActiveCall,
Expand All @@ -479,6 +499,7 @@ export function CallManager({
openSystemPreferencesAction,
pauseVoiceNotePlayer,
playRingtone,
removeClient,
renderDeviceSelection,
renderEmojiPicker,
renderReactionPicker,
Expand Down Expand Up @@ -552,10 +573,12 @@ export function CallManager({
<ActiveCallManager
activeCall={activeCall}
availableCameras={availableCameras}
approveUser={approveUser}
callLink={callLink}
cancelCall={cancelCall}
changeCallView={changeCallView}
closeNeedPermissionScreen={closeNeedPermissionScreen}
denyUser={denyUser}
getGroupCallVideoFrameSource={getGroupCallVideoFrameSource}
getPresentingSources={getPresentingSources}
hangUpActiveCall={hangUpActiveCall}
Expand All @@ -564,6 +587,7 @@ export function CallManager({
me={me}
openSystemPreferencesAction={openSystemPreferencesAction}
pauseVoiceNotePlayer={pauseVoiceNotePlayer}
removeClient={removeClient}
renderDeviceSelection={renderDeviceSelection}
renderEmojiPicker={renderEmojiPicker}
renderReactionPicker={renderReactionPicker}
Expand Down
5 changes: 5 additions & 0 deletions ts/components/CallScreen.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type GroupCallOverrideProps = OverridePropsBase & {
callMode: CallMode.Group;
connectionState?: GroupCallConnectionState;
peekedParticipants?: Array<ConversationType>;
pendingParticipants?: Array<ConversationType>;
raisedHands?: Set<number>;
remoteParticipants?: Array<GroupCallRemoteParticipantType>;
remoteAudioLevel?: number;
Expand Down Expand Up @@ -135,6 +136,7 @@ const createActiveGroupCallProp = (overrideProps: GroupCallOverrideProps) => ({
isConversationTooBigToRing: false,
peekedParticipants:
overrideProps.peekedParticipants || overrideProps.remoteParticipants || [],
pendingParticipants: overrideProps.pendingParticipants || [],
raisedHands:
overrideProps.raisedHands ||
getRaisedHands(overrideProps) ||
Expand Down Expand Up @@ -181,11 +183,14 @@ const createProps = (
}
): PropsType => ({
activeCall: createActiveCallProp(overrideProps),
approveUser: action('approve-user'),
changeCallView: action('change-call-view'),
denyUser: action('deny-user'),
getGroupCallVideoFrameSource: fakeGetGroupCallVideoFrameSource,
getPresentingSources: action('get-presenting-sources'),
hangUpActiveCall: action('hang-up'),
i18n,
isCallLinkAdmin: true,
isGroupCallRaiseHandEnabled: true,
me: getDefaultConversation({
color: AvatarColors[1],
Expand Down
22 changes: 22 additions & 0 deletions ts/components/CallScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import classNames from 'classnames';
import type { VideoFrameSource } from '@signalapp/ringrtc';
import type {
ActiveCallStateType,
PendingUserActionPayloadType,
SendGroupCallRaiseHandType,
SendGroupCallReactionType,
SetLocalAudioType,
Expand Down Expand Up @@ -88,14 +89,18 @@ import {
import { isGroupOrAdhocActiveCall } from '../util/isGroupOrAdhocCall';
import { assertDev } from '../util/assert';
import { emojiToData } from './emoji/lib';
import { CallingPendingParticipants } from './CallingPendingParticipants';

export type PropsType = {
activeCall: ActiveCallType;
approveUser: (payload: PendingUserActionPayloadType) => void;
denyUser: (payload: PendingUserActionPayloadType) => void;
getGroupCallVideoFrameSource: (demuxId: number) => VideoFrameSource;
getPresentingSources: () => void;
groupMembers?: Array<Pick<ConversationType, 'id' | 'firstName' | 'title'>>;
hangUpActiveCall: (reason: string) => void;
i18n: LocalizerType;
isCallLinkAdmin: boolean;
isGroupCallRaiseHandEnabled: boolean;
me: ConversationType;
openSystemPreferencesAction: () => unknown;
Expand Down Expand Up @@ -178,12 +183,15 @@ function CallDuration({

export function CallScreen({
activeCall,
approveUser,
changeCallView,
denyUser,
getGroupCallVideoFrameSource,
getPresentingSources,
groupMembers,
hangUpActiveCall,
i18n,
isCallLinkAdmin,
isGroupCallRaiseHandEnabled,
me,
openSystemPreferencesAction,
Expand Down Expand Up @@ -396,6 +404,11 @@ export function CallScreen({
throw missingCaseError(activeCall);
}

const pendingParticipants =
activeCall.callMode === CallMode.Adhoc && isCallLinkAdmin
? activeCall.pendingParticipants
: [];

let lonelyInCallNode: ReactNode;
let localPreviewNode: ReactNode;

Expand Down Expand Up @@ -811,6 +824,15 @@ export function CallScreen({
renderRaisedHandsToast={renderRaisedHandsToast}
i18n={i18n}
/>
{pendingParticipants.length ? (
<CallingPendingParticipants
i18n={i18n}
ourServiceId={me.serviceId}
participants={pendingParticipants}
approveUser={approveUser}
denyUser={denyUser}
/>
) : null}
{/* We render the local preview first and set the footer flex direction to row-reverse
to ensure the preview is visible at low viewport widths. */}
<div className="module-ongoing-call__footer">
Expand Down

0 comments on commit 7d6aec8

Please sign in to comment.