Show 'join anyway' in verify dialog when joining call

This commit is contained in:
Scott Nonnenberg 2023-09-05 17:34:51 -07:00 committed by GitHub
parent b6ed789197
commit 507986db92
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 85 additions and 46 deletions

View file

@ -611,6 +611,10 @@
"messageformat": "Call anyway", "messageformat": "Call anyway",
"description": "Used on a warning dialog to make it clear that it might be risky to call the conversation." "description": "Used on a warning dialog to make it clear that it might be risky to call the conversation."
}, },
"icu:joinAnyway": {
"messageformat": "Join anyway",
"description": "Used on a warning dialog to make it clear that it might be risky to join the call."
},
"icu:continueCall": { "icu:continueCall": {
"messageformat": "Continue Call", "messageformat": "Continue Call",
"description": "Used on a warning dialog to make it clear that it might be risky to continue the group call." "description": "Used on a warning dialog to make it clear that it might be risky to continue the group call."

View file

@ -26,7 +26,8 @@ import type { StoryDistributionIdString } from '../types/StoryDistributionId';
import { UserText } from './UserText'; import { UserText } from './UserText';
export enum SafetyNumberChangeSource { export enum SafetyNumberChangeSource {
Calling = 'Calling', InitiateCall = 'InitiateCall',
JoinCall = 'JoinCall',
MessageSend = 'MessageSend', MessageSend = 'MessageSend',
Story = 'Story', Story = 'Story',
} }

View file

@ -61,8 +61,13 @@ const getCommonProps = (options: {
conversationId: conversation.id, conversationId: conversation.id,
i18n, i18n,
isNextItemCallingNotification: false, isNextItemCallingNotification: false,
onOutgoingAudioCallInConversation: action(
'onOutgoingAudioCallInConversation'
),
onOutgoingVideoCallInConversation: action(
'onOutgoingVideoCallInConversation'
),
returnToActiveCall: action('returnToActiveCall'), returnToActiveCall: action('returnToActiveCall'),
startCallingLobby: action('startCallingLobby'),
callHistory: { callHistory: {
callId: '123', callId: '123',
peerId: conversation.id, peerId: conversation.id,

View file

@ -26,11 +26,9 @@ import {
} from '../../types/CallDisposition'; } from '../../types/CallDisposition';
export type PropsActionsType = { export type PropsActionsType = {
onOutgoingAudioCallInConversation: (conversationId: string) => void;
onOutgoingVideoCallInConversation: (conversationId: string) => void;
returnToActiveCall: () => void; returnToActiveCall: () => void;
startCallingLobby: (_: {
conversationId: string;
isVideoCall: boolean;
}) => void;
}; };
type PropsHousekeeping = { type PropsHousekeeping = {
@ -86,8 +84,9 @@ function renderCallingNotificationButton(
conversationId, conversationId,
i18n, i18n,
isNextItemCallingNotification, isNextItemCallingNotification,
onOutgoingAudioCallInConversation,
onOutgoingVideoCallInConversation,
returnToActiveCall, returnToActiveCall,
startCallingLobby,
} = props; } = props;
if (isNextItemCallingNotification) { if (isNextItemCallingNotification) {
@ -114,10 +113,11 @@ function renderCallingNotificationButton(
onClick = noop; onClick = noop;
} else { } else {
onClick = () => { onClick = () => {
startCallingLobby({ if (type === CallType.Video) {
conversationId, onOutgoingVideoCallInConversation(conversationId);
isVideoCall: type === CallType.Video, } else {
}); onOutgoingAudioCallInConversation(conversationId);
}
}; };
} }
break; break;
@ -147,7 +147,7 @@ function renderCallingNotificationButton(
} else { } else {
buttonText = i18n('icu:calling__join'); buttonText = i18n('icu:calling__join');
onClick = () => { onClick = () => {
startCallingLobby({ conversationId, isVideoCall: true }); onOutgoingVideoCallInConversation(conversationId);
}; };
} }
break; break;

View file

@ -313,7 +313,12 @@ const actions = () => ({
toggleSafetyNumberModal: action('toggleSafetyNumberModal'), toggleSafetyNumberModal: action('toggleSafetyNumberModal'),
startCallingLobby: action('startCallingLobby'), onOutgoingAudioCallInConversation: action(
'onOutgoingAudioCallInConversation'
),
onOutgoingVideoCallInConversation: action(
'onOutgoingVideoCallInConversation'
),
startConversation: action('startConversation'), startConversation: action('startConversation'),
returnToActiveCall: action('returnToActiveCall'), returnToActiveCall: action('returnToActiveCall'),

View file

@ -79,6 +79,12 @@ const getDefaultProps = () => ({
showConversation: action('showConversation'), showConversation: action('showConversation'),
openGiftBadge: action('openGiftBadge'), openGiftBadge: action('openGiftBadge'),
saveAttachment: action('saveAttachment'), saveAttachment: action('saveAttachment'),
onOutgoingAudioCallInConversation: action(
'onOutgoingAudioCallInConversation'
),
onOutgoingVideoCallInConversation: action(
'onOutgoingVideoCallInConversation'
),
pushPanelForConversation: action('pushPanelForConversation'), pushPanelForConversation: action('pushPanelForConversation'),
showContactModal: action('showContactModal'), showContactModal: action('showContactModal'),
showLightbox: action('showLightbox'), showLightbox: action('showLightbox'),
@ -94,7 +100,6 @@ const getDefaultProps = () => ({
), ),
scrollToQuotedMessage: action('scrollToQuotedMessage'), scrollToQuotedMessage: action('scrollToQuotedMessage'),
showSpoiler: action('showSpoiler'), showSpoiler: action('showSpoiler'),
startCallingLobby: action('startCallingLobby'),
startConversation: action('startConversation'), startConversation: action('startConversation'),
returnToActiveCall: action('returnToActiveCall'), returnToActiveCall: action('returnToActiveCall'),
shouldCollapseAbove: false, shouldCollapseAbove: false,

View file

@ -193,6 +193,8 @@ export const TimelineItem = memo(function TimelineItem({
isNextItemCallingNotification, isNextItemCallingNotification,
isTargeted, isTargeted,
item, item,
onOutgoingAudioCallInConversation,
onOutgoingVideoCallInConversation,
platform, platform,
renderUniversalTimerNotification, renderUniversalTimerNotification,
returnToActiveCall, returnToActiveCall,
@ -202,7 +204,6 @@ export const TimelineItem = memo(function TimelineItem({
shouldCollapseBelow, shouldCollapseBelow,
shouldHideMetadata, shouldHideMetadata,
shouldRenderDateHeader, shouldRenderDateHeader,
startCallingLobby,
theme, theme,
...reducedProps ...reducedProps
}: PropsType): JSX.Element | null { }: PropsType): JSX.Element | null {
@ -248,8 +249,9 @@ export const TimelineItem = memo(function TimelineItem({
conversationId={conversationId} conversationId={conversationId}
i18n={i18n} i18n={i18n}
isNextItemCallingNotification={isNextItemCallingNotification} isNextItemCallingNotification={isNextItemCallingNotification}
onOutgoingAudioCallInConversation={onOutgoingAudioCallInConversation}
onOutgoingVideoCallInConversation={onOutgoingVideoCallInConversation}
returnToActiveCall={returnToActiveCall} returnToActiveCall={returnToActiveCall}
startCallingLobby={startCallingLobby}
{...item.data} {...item.data}
/> />
); );

View file

@ -56,6 +56,7 @@ import type { ShowToastActionType } from './toast';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions'; import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
import { useBoundActions } from '../../hooks/useBoundActions'; import { useBoundActions } from '../../hooks/useBoundActions';
import { isAnybodyElseInGroupCall } from './callingHelpers'; import { isAnybodyElseInGroupCall } from './callingHelpers';
import { SafetyNumberChangeSource } from '../../components/SafetyNumberChangeDialog';
// State // State
@ -1259,17 +1260,10 @@ function onOutgoingVideoCallInConversation(
log.info('onOutgoingVideoCallInConversation: about to start a video call'); log.info('onOutgoingVideoCallInConversation: about to start a video call');
// if it's a group call on an announcementsOnly group const call = getOwn(getState().calling.callsByConversation, conversationId);
// only allow join if the call has already been started (presumably by the admin)
if (conversation.get('announcementsOnly') && !conversation.areWeAdmin()) {
const call = getOwn(
getState().calling.callsByConversation,
conversationId
);
// technically not necessary, but isAnybodyElseInGroupCall requires it // Technically not necessary, but isAnybodyElseInGroupCall requires it
const ourAci = window.storage.user.getCheckedAci(); const ourAci = window.storage.user.getCheckedAci();
const isOngoingGroupCall = const isOngoingGroupCall =
call && call &&
ourAci && ourAci &&
@ -1277,6 +1271,9 @@ function onOutgoingVideoCallInConversation(
call.peekInfo && call.peekInfo &&
isAnybodyElseInGroupCall(call.peekInfo, ourAci); isAnybodyElseInGroupCall(call.peekInfo, ourAci);
// If it's a group call on an announcementsOnly group, only allow join if the call
// has already been started (presumably by the admin)
if (conversation.get('announcementsOnly') && !conversation.areWeAdmin()) {
if (!isOngoingGroupCall) { if (!isOngoingGroupCall) {
dispatch({ dispatch({
type: SHOW_TOAST, type: SHOW_TOAST,
@ -1288,7 +1285,11 @@ function onOutgoingVideoCallInConversation(
} }
} }
if (await isCallSafe(conversation.attributes)) { const source = isOngoingGroupCall
? SafetyNumberChangeSource.JoinCall
: SafetyNumberChangeSource.InitiateCall;
if (await isCallSafe(conversation.attributes, source)) {
log.info( log.info(
'onOutgoingVideoCallInConversation: call is deemed "safe". Making call' 'onOutgoingVideoCallInConversation: call is deemed "safe". Making call'
); );
@ -1323,10 +1324,13 @@ function onOutgoingAudioCallInConversation(
`onOutgoingAudioCallInConversation: Conversation ${conversation.idForLogging()} is not 1:1` `onOutgoingAudioCallInConversation: Conversation ${conversation.idForLogging()} is not 1:1`
); );
} }
// Because audio calls are currently restricted to 1:1 conversations, this will always
// be a new call we are initiating.
const source = SafetyNumberChangeSource.InitiateCall;
log.info('onOutgoingAudioCallInConversation: about to start an audio call'); log.info('onOutgoingAudioCallInConversation: about to start an audio call');
if (await isCallSafe(conversation.attributes)) { if (await isCallSafe(conversation.attributes, source)) {
log.info( log.info(
'onOutgoingAudioCallInConversation: call is deemed "safe". Making call' 'onOutgoingAudioCallInConversation: call is deemed "safe". Making call'
); );

View file

@ -45,12 +45,18 @@ export function SmartSendAnywayDialog(): JSX.Element {
let confirmText: string | undefined = i18n( let confirmText: string | undefined = i18n(
'icu:safetyNumberChangeDialog__pending-messages' 'icu:safetyNumberChangeDialog__pending-messages'
); );
if (safetyNumberChangedBlockingData?.source) { if (
confirmText =
safetyNumberChangedBlockingData?.source === safetyNumberChangedBlockingData?.source ===
SafetyNumberChangeSource.Calling SafetyNumberChangeSource.InitiateCall
? i18n('icu:callAnyway') ) {
: undefined; confirmText = i18n('icu:callAnyway');
} else if (
safetyNumberChangedBlockingData?.source ===
SafetyNumberChangeSource.JoinCall
) {
confirmText = i18n('icu:joinAnyway');
} else {
confirmText = undefined;
} }
return ( return (

View file

@ -149,7 +149,11 @@ export function SmartTimelineItem(props: ExternalProps): JSX.Element {
const { viewStory } = useStoriesActions(); const { viewStory } = useStoriesActions();
const { returnToActiveCall, startCallingLobby } = useCallingActions(); const {
onOutgoingAudioCallInConversation,
onOutgoingVideoCallInConversation,
returnToActiveCall,
} = useCallingActions();
return ( return (
<TimelineItem <TimelineItem
@ -186,6 +190,8 @@ export function SmartTimelineItem(props: ExternalProps): JSX.Element {
pushPanelForConversation={pushPanelForConversation} pushPanelForConversation={pushPanelForConversation}
reactToMessage={reactToMessage} reactToMessage={reactToMessage}
copyMessageText={copyMessageText} copyMessageText={copyMessageText}
onOutgoingAudioCallInConversation={onOutgoingAudioCallInConversation}
onOutgoingVideoCallInConversation={onOutgoingVideoCallInConversation}
retryDeleteForEveryone={retryDeleteForEveryone} retryDeleteForEveryone={retryDeleteForEveryone}
retryMessageSend={retryMessageSend} retryMessageSend={retryMessageSend}
returnToActiveCall={returnToActiveCall} returnToActiveCall={returnToActiveCall}
@ -201,7 +207,6 @@ export function SmartTimelineItem(props: ExternalProps): JSX.Element {
showLightbox={showLightbox} showLightbox={showLightbox}
showLightboxForViewOnceMedia={showLightboxForViewOnceMedia} showLightboxForViewOnceMedia={showLightboxForViewOnceMedia}
showSpoiler={showSpoiler} showSpoiler={showSpoiler}
startCallingLobby={startCallingLobby}
startConversation={startConversation} startConversation={startConversation}
toggleDeleteMessagesModal={toggleDeleteMessagesModal} toggleDeleteMessagesModal={toggleDeleteMessagesModal}
toggleForwardMessagesModal={toggleForwardMessagesModal} toggleForwardMessagesModal={toggleForwardMessagesModal}

View file

@ -4,18 +4,20 @@
import type { ConversationAttributesType } from '../model-types'; import type { ConversationAttributesType } from '../model-types';
import * as log from '../logging/log'; import * as log from '../logging/log';
import { SafetyNumberChangeSource } from '../components/SafetyNumberChangeDialog';
import { blockSendUntilConversationsAreVerified } from './blockSendUntilConversationsAreVerified'; import { blockSendUntilConversationsAreVerified } from './blockSendUntilConversationsAreVerified';
import { getRecipientsByConversation } from './getRecipientsByConversation'; import { getRecipientsByConversation } from './getRecipientsByConversation';
import type { SafetyNumberChangeSource } from '../components/SafetyNumberChangeDialog';
export async function isCallSafe( export async function isCallSafe(
attributes: ConversationAttributesType attributes: ConversationAttributesType,
source: SafetyNumberChangeSource
): Promise<boolean> { ): Promise<boolean> {
const recipientsByConversation = getRecipientsByConversation([attributes]); const recipientsByConversation = getRecipientsByConversation([attributes]);
const callAnyway = await blockSendUntilConversationsAreVerified( const callAnyway = await blockSendUntilConversationsAreVerified(
recipientsByConversation, recipientsByConversation,
SafetyNumberChangeSource.Calling source
); );
if (!callAnyway) { if (!callAnyway) {