Fix pre call info for call links with admin approval

This commit is contained in:
ayumi-signal 2024-11-14 12:43:02 -08:00 committed by GitHub
parent b7d67b453a
commit ec3c46d356
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 143 additions and 45 deletions

View file

@ -1881,6 +1881,10 @@
"messageformat": "{first}, {second}, and {others, plural, one {#} other {#}} others are in this call", "messageformat": "{first}, {second}, and {others, plural, one {#} other {#}} others are in this call",
"description": "Shown in the calling lobby to describe who is in the call" "description": "Shown in the calling lobby to describe who is in the call"
}, },
"icu:calling__pre-call-info--only-unknown-contacts-in-call": {
"messageformat": "{count, plural, one {# person is in this call} other {# people are in this call}}",
"description": "Shown in the calling lobby to describe people in the call when all are unknown contacts"
},
"icu:calling__pre-call-info--will-ring-1": { "icu:calling__pre-call-info--will-ring-1": {
"messageformat": "Signal will ring {person}", "messageformat": "Signal will ring {person}",
"description": "Shown in the calling lobby to describe who will be rung" "description": "Shown in the calling lobby to describe who will be rung"

View file

@ -9,6 +9,11 @@ import enMessages from '../../_locales/en/messages.json';
import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation'; import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation';
import type { PropsType } from './CallingPreCallInfo'; import type { PropsType } from './CallingPreCallInfo';
import { CallingPreCallInfo, RingMode } from './CallingPreCallInfo'; import { CallingPreCallInfo, RingMode } from './CallingPreCallInfo';
import type { ConversationType } from '../state/ducks/conversations';
import { getPlaceholderContact } from '../state/selectors/conversations';
import { generateAci } from '../types/ServiceId';
import { FAKE_CALL_LINK } from '../test-both/helpers/fakeCallLink';
import { callLinkToConversation } from '../util/callLinks';
const i18n = setupI18n('en', enMessages); const i18n = setupI18n('en', enMessages);
const getDefaultGroupConversation = () => const getDefaultGroupConversation = () =>
@ -21,6 +26,11 @@ const getDefaultGroupConversation = () =>
}); });
const otherMembers = times(6, () => getDefaultConversation()); const otherMembers = times(6, () => getDefaultConversation());
const getUnknownContact = (): ConversationType => ({
...getPlaceholderContact(),
serviceId: generateAci(),
});
export default { export default {
title: 'Components/CallingPreCallInfo', title: 'Components/CallingPreCallInfo',
} satisfies Meta<PropsType>; } satisfies Meta<PropsType>;
@ -245,3 +255,63 @@ export function GroupConversationCallIsFull(): JSX.Element {
/> />
); );
} }
export function CallLinkUnknownContact(): JSX.Element {
return (
<CallingPreCallInfo
conversation={callLinkToConversation(FAKE_CALL_LINK, i18n)}
groupMembers={otherMembers}
i18n={i18n}
me={getDefaultConversation()}
peekedParticipants={[getUnknownContact()]}
ringMode={RingMode.WillNotRing}
/>
);
}
export function CallLink3UnknownContacts(): JSX.Element {
return (
<CallingPreCallInfo
conversation={callLinkToConversation(FAKE_CALL_LINK, i18n)}
groupMembers={otherMembers}
i18n={i18n}
me={getDefaultConversation()}
peekedParticipants={[
getUnknownContact(),
getUnknownContact(),
getUnknownContact(),
]}
ringMode={RingMode.WillNotRing}
/>
);
}
export function CallLink1Known1UnknownContact(): JSX.Element {
return (
<CallingPreCallInfo
conversation={callLinkToConversation(FAKE_CALL_LINK, i18n)}
groupMembers={otherMembers}
i18n={i18n}
me={getDefaultConversation()}
peekedParticipants={[otherMembers[0], getUnknownContact()]}
ringMode={RingMode.WillNotRing}
/>
);
}
export function CallLink1Known2UnknownContacts(): JSX.Element {
return (
<CallingPreCallInfo
conversation={callLinkToConversation(FAKE_CALL_LINK, i18n)}
groupMembers={otherMembers}
i18n={i18n}
me={getDefaultConversation()}
peekedParticipants={[
otherMembers[0],
getUnknownContact(),
getUnknownContact(),
]}
ringMode={RingMode.WillNotRing}
/>
);
}

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import React from 'react'; import React from 'react';
import { partition } from 'lodash';
import type { ConversationType } from '../state/ducks/conversations'; import type { ConversationType } from '../state/ducks/conversations';
import type { CallingConversationType } from '../types/Calling'; import type { CallingConversationType } from '../types/Calling';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
@ -16,6 +17,16 @@ export enum RingMode {
IsRinging, IsRinging,
} }
type PeekedParticipantType = Pick<
ConversationType,
| 'firstName'
| 'systemGivenName'
| 'systemNickname'
| 'title'
| 'serviceId'
| 'titleNoDefault'
>;
export type PropsType = { export type PropsType = {
conversation: Pick< conversation: Pick<
CallingConversationType, CallingConversationType,
@ -44,12 +55,7 @@ export type PropsType = {
> >
>; >;
isCallFull?: boolean; isCallFull?: boolean;
peekedParticipants?: Array< peekedParticipants?: Array<PeekedParticipantType>;
Pick<
ConversationType,
'firstName' | 'systemGivenName' | 'systemNickname' | 'title' | 'serviceId'
>
>;
}; };
export function CallingPreCallInfo({ export function CallingPreCallInfo({
@ -61,52 +67,70 @@ export function CallingPreCallInfo({
peekedParticipants = [], peekedParticipants = [],
ringMode, ringMode,
}: PropsType): JSX.Element { }: PropsType): JSX.Element {
const [visibleParticipants, unknownParticipants] = React.useMemo<
[Array<PeekedParticipantType>, Array<PeekedParticipantType>]
>(
() =>
partition(peekedParticipants, (participant: PeekedParticipantType) =>
Boolean(participant.titleNoDefault)
),
[peekedParticipants]
);
let subtitle: string; let subtitle: string;
if (ringMode === RingMode.IsRinging) { if (ringMode === RingMode.IsRinging) {
subtitle = i18n('icu:outgoingCallRinging'); subtitle = i18n('icu:outgoingCallRinging');
} else if (isCallFull) { } else if (isCallFull) {
subtitle = i18n('icu:calling__call-is-full'); subtitle = i18n('icu:calling__call-is-full');
} else if (peekedParticipants.length) { } else if (peekedParticipants.length) {
// It should be rare to see yourself in this list, but it's possible if (1) you rejoin if (unknownParticipants.length > 0) {
// quickly, causing the server to return stale state (2) you have joined on another subtitle = i18n(
// device. 'icu:calling__pre-call-info--only-unknown-contacts-in-call',
let hasYou = false; {
const participantNames = peekedParticipants.map(participant => { count: peekedParticipants.length,
if (participant.serviceId === me.serviceId) { }
hasYou = true; );
return i18n('icu:you'); } else {
// It should be rare to see yourself in this list, but it's possible if (1) you
// rejoin quickly, causing the server to return stale state (2) you have joined on
// another device.
let hasYou = false;
const participantNames = visibleParticipants.map(participant => {
if (participant.serviceId === me.serviceId) {
hasYou = true;
return i18n('icu:you');
}
return getParticipantName(participant);
});
switch (participantNames.length) {
case 1:
subtitle = hasYou
? i18n('icu:calling__pre-call-info--another-device-in-call')
: i18n('icu:calling__pre-call-info--1-person-in-call', {
first: participantNames[0],
});
break;
case 2:
subtitle = i18n('icu:calling__pre-call-info--2-people-in-call', {
first: participantNames[0],
second: participantNames[1],
});
break;
case 3:
subtitle = i18n('icu:calling__pre-call-info--3-people-in-call', {
first: participantNames[0],
second: participantNames[1],
third: participantNames[2],
});
break;
default:
subtitle = i18n('icu:calling__pre-call-info--many-people-in-call', {
first: participantNames[0],
second: participantNames[1],
others: participantNames.length - 2,
});
break;
} }
return getParticipantName(participant);
});
switch (participantNames.length) {
case 1:
subtitle = hasYou
? i18n('icu:calling__pre-call-info--another-device-in-call')
: i18n('icu:calling__pre-call-info--1-person-in-call', {
first: participantNames[0],
});
break;
case 2:
subtitle = i18n('icu:calling__pre-call-info--2-people-in-call', {
first: participantNames[0],
second: participantNames[1],
});
break;
case 3:
subtitle = i18n('icu:calling__pre-call-info--3-people-in-call', {
first: participantNames[0],
second: participantNames[1],
third: participantNames[2],
});
break;
default:
subtitle = i18n('icu:calling__pre-call-info--many-people-in-call', {
first: participantNames[0],
second: participantNames[1],
others: participantNames.length - 2,
});
break;
} }
} else { } else {
let memberNames: Array<string>; let memberNames: Array<string>;