Improve in call display of missing media keys

This commit is contained in:
ayumi-signal 2024-09-25 06:50:21 -07:00 committed by GitHub
parent 5c6a289bb4
commit 01b087f056
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 128 additions and 37 deletions

View file

@ -1881,6 +1881,10 @@
"messageformat": "Can't receive audio and video from {name}", "messageformat": "Can't receive audio and video from {name}",
"description": "When you can't view someone's audio and video in a call because their media keys are unavailable" "description": "When you can't view someone's audio and video in a call because their media keys are unavailable"
}, },
"icu:calling__missing-media-keys--unknown-contact": {
"messageformat": "Can't receive audio and video",
"description": "When you can't view someone's audio and video in a call because their media keys are unavailable, and their profile information is not available"
},
"icu:calling__missing-media-keys-info": { "icu:calling__missing-media-keys-info": {
"messageformat": "This may be because they have not verified your safety number change, there's a problem with their device, or they have blocked you.", "messageformat": "This may be because they have not verified your safety number change, there's a problem with their device, or they have blocked you.",
"description": "Detailed explanation why you can't view someone's audio and video in a call because their media keys are unavailable." "description": "Detailed explanation why you can't view someone's audio and video in a call because their media keys are unavailable."

View file

@ -3873,10 +3873,6 @@ button.module-image__border-overlay:focus {
padding-inline: 16px; padding-inline: 16px;
} }
.module-ongoing-call__group-call-remote-participant__error-icon {
margin-block-end: 16px;
}
.module-ongoing-call__group-call-remote-participant__error { .module-ongoing-call__group-call-remote-participant__error {
display: block; display: block;
} }
@ -4099,7 +4095,7 @@ button.module-image__border-overlay:focus {
// when @container size is big enough // when @container size is big enough
display: none; display: none;
margin-block-end: 12px; margin-block-end: 16px;
margin-inline: 8px; margin-inline: 8px;
font-size: 12px; font-size: 12px;
line-height: 16px; line-height: 16px;
@ -4113,7 +4109,7 @@ button.module-image__border-overlay:focus {
padding-block: 3px; padding-block: 3px;
padding-inline: 10px; padding-inline: 10px;
border-radius: 16px; border-radius: 16px;
background-color: $color-gray-75; background-color: $color-black-alpha-30;
color: $color-white; color: $color-white;
font-size: 12px; font-size: 12px;
line-height: 16px; line-height: 16px;
@ -4128,12 +4124,29 @@ button.module-image__border-overlay:focus {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
// Shown in the mini version / overflow sidebar
&--icon {
width: 20px;
height: 20px;
}
&--icon-blocked {
@include color-svg('../images/icons/v3/block/block.svg', $color-white);
}
&--icon-missing-media-keys {
@include color-svg(
'../images/icons/v3/error/error-circle.svg',
$color-white
);
}
} }
&__error-icon { &__error-icon {
width: 24px; width: 20px;
height: 24px; height: 20px;
margin-block-end: 8px; margin-block-end: 12px;
&--blocked { &--blocked {
@include color-svg('../images/icons/v3/block/block.svg', $color-white); @include color-svg('../images/icons/v3/block/block.svg', $color-white);
@ -4141,7 +4154,7 @@ button.module-image__border-overlay:focus {
&--missing-media-keys { &--missing-media-keys {
@include color-svg( @include color-svg(
'../images/icons/v3/error/error-circle-solid.svg', '../images/icons/v3/error/error-circle.svg',
$color-white $color-white
); );
} }

View file

@ -65,8 +65,9 @@ type DirectCallOverrideProps = OverridePropsBase & {
}; };
type GroupCallOverrideProps = OverridePropsBase & { type GroupCallOverrideProps = OverridePropsBase & {
callMode: CallMode.Group; callMode: CallMode.Group | CallMode.Adhoc;
connectionState?: GroupCallConnectionState; connectionState?: GroupCallConnectionState;
groupMembers?: Array<ConversationType>;
peekedParticipants?: Array<ConversationType>; peekedParticipants?: Array<ConversationType>;
pendingParticipants?: Array<ConversationType>; pendingParticipants?: Array<ConversationType>;
raisedHands?: Set<number>; raisedHands?: Set<number>;
@ -131,7 +132,8 @@ const createActiveGroupCallProp = (overrideProps: GroupCallOverrideProps) => ({
localDemuxId: LOCAL_DEMUX_ID, localDemuxId: LOCAL_DEMUX_ID,
maxDevices: 5, maxDevices: 5,
deviceCount: (overrideProps.remoteParticipants || []).length, deviceCount: (overrideProps.remoteParticipants || []).length,
groupMembers: overrideProps.remoteParticipants || [], groupMembers:
overrideProps.groupMembers || overrideProps.remoteParticipants || [],
// Because remote participants are a superset, we can use them in place of peeked // Because remote participants are a superset, we can use them in place of peeked
// participants. // participants.
isConversationTooBigToRing: false, isConversationTooBigToRing: false,
@ -173,6 +175,12 @@ const createActiveCallProp = (
return { ...baseResult, ...createActiveDirectCallProp(overrideProps) }; return { ...baseResult, ...createActiveDirectCallProp(overrideProps) };
case CallMode.Group: case CallMode.Group:
return { ...baseResult, ...createActiveGroupCallProp(overrideProps) }; return { ...baseResult, ...createActiveGroupCallProp(overrideProps) };
case CallMode.Adhoc:
return {
...baseResult,
...createActiveGroupCallProp(overrideProps),
callMode: CallMode.Adhoc as CallMode.Adhoc,
};
default: default:
throw missingCaseError(overrideProps); throw missingCaseError(overrideProps);
} }
@ -872,3 +880,26 @@ export function GroupCallSomeoneBlocked(): JSX.Element {
/> />
); );
} }
export function CallLinkUnknownContactMissingMediaKeys(): JSX.Element {
return (
<CallScreen
{...createProps({
callMode: CallMode.Adhoc,
groupMembers: [],
remoteParticipants: allRemoteParticipants
.slice(0, 5)
.map((participant, index) => ({
...participant,
title: index === 1 ? 'Unknown Contact' : participant.title,
titleNoDefault:
index === 1 ? undefined : participant.titleNoDefault,
addedTime: index === 1 ? Date.now() - 60000 : undefined,
hasRemoteAudio: false,
hasRemoteVideo: false,
mediaKeysReceived: index !== 1,
})),
})}
/>
);
}

View file

@ -137,6 +137,7 @@ export function GroupCallOverflowArea({
remoteParticipantsCount={remoteParticipantsCount} remoteParticipantsCount={remoteParticipantsCount}
isActiveSpeakerInSpeakerView={false} isActiveSpeakerInSpeakerView={false}
isCallReconnecting={isCallReconnecting} isCallReconnecting={isCallReconnecting}
isInOverflow
/> />
))} ))}
</div> </div>

View file

@ -43,6 +43,7 @@ type BasePropsType = {
imageDataCache: React.RefObject<CallingImageDataCache>; imageDataCache: React.RefObject<CallingImageDataCache>;
isActiveSpeakerInSpeakerView: boolean; isActiveSpeakerInSpeakerView: boolean;
isCallReconnecting: boolean; isCallReconnecting: boolean;
isInOverflow?: boolean;
onClickRaisedHand?: () => void; onClickRaisedHand?: () => void;
onVisibilityChanged?: (demuxId: number, isVisible: boolean) => unknown; onVisibilityChanged?: (demuxId: number, isVisible: boolean) => unknown;
remoteParticipant: GroupCallRemoteParticipantType; remoteParticipant: GroupCallRemoteParticipantType;
@ -80,6 +81,7 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
remoteParticipantsCount, remoteParticipantsCount,
isActiveSpeakerInSpeakerView, isActiveSpeakerInSpeakerView,
isCallReconnecting, isCallReconnecting,
isInOverflow,
} = props; } = props;
const { const {
@ -98,6 +100,7 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
sharedGroupNames, sharedGroupNames,
sharingScreen, sharingScreen,
title, title,
titleNoDefault,
videoAspectRatio, videoAspectRatio,
} = props.remoteParticipant; } = props.remoteParticipant;
@ -357,26 +360,60 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
{i18n('icu:moreInfo')} {i18n('icu:moreInfo')}
</button> </button>
); );
if (isBlocked) { if (isBlocked) {
noVideoNode = ( if (isInOverflow) {
<> noVideoNode = (
<i className="module-ongoing-call__group-call-remote-participant__error-icon module-ongoing-call__group-call-remote-participant__error-icon--blocked" /> <button
<div className="module-ongoing-call__group-call-remote-participant__error"> type="button"
{i18n('icu:calling__blocked-participant', { name: title })} className="module-ongoing-call__group-call-remote-participant__more-info module-ongoing-call__group-call-remote-participant__more-info--icon module-ongoing-call__group-call-remote-participant__more-info--icon-blocked"
</div> onClick={() => {
{showDialogButton} setShowErrorDialog(true);
</> }}
); aria-label={i18n('icu:calling__blocked-participant', {
name: title,
})}
/>
);
} else {
noVideoNode = (
<>
<i className="module-ongoing-call__group-call-remote-participant__error-icon module-ongoing-call__group-call-remote-participant__error-icon--blocked" />
<div className="module-ongoing-call__group-call-remote-participant__error">
{i18n('icu:calling__blocked-participant', { name: title })}
</div>
{showDialogButton}
</>
);
}
} else if (showMissingMediaKeys) { } else if (showMissingMediaKeys) {
noVideoNode = ( const errorMessage = titleNoDefault
<> ? i18n('icu:calling__missing-media-keys', {
<i className="module-ongoing-call__group-call-remote-participant__error-icon module-ongoing-call__group-call-remote-participant__error-icon--missing-media-keys" /> name: titleNoDefault,
<div className="module-ongoing-call__group-call-remote-participant__error"> })
{i18n('icu:calling__missing-media-keys', { name: title })} : i18n('icu:calling__missing-media-keys--unknown-contact');
</div> if (isInOverflow) {
{showDialogButton} noVideoNode = (
</> <button
); type="button"
className="module-ongoing-call__group-call-remote-participant__more-info module-ongoing-call__group-call-remote-participant__more-info--icon module-ongoing-call__group-call-remote-participant__more-info--icon-missing-media-keys"
onClick={() => {
setShowErrorDialog(true);
}}
aria-label={errorMessage}
/>
);
} else {
noVideoNode = (
<>
<i className="module-ongoing-call__group-call-remote-participant__error-icon module-ongoing-call__group-call-remote-participant__error-icon--missing-media-keys" />
<div className="module-ongoing-call__group-call-remote-participant__error">
{errorMessage}
</div>
{showDialogButton}
</>
);
}
} else { } else {
noVideoNode = ( noVideoNode = (
<Avatar <Avatar
@ -424,13 +461,17 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
} else if (showMissingMediaKeys) { } else if (showMissingMediaKeys) {
setErrorDialogTitle( setErrorDialogTitle(
<div className="module-ongoing-call__group-call-remote-participant__more-info-modal-title"> <div className="module-ongoing-call__group-call-remote-participant__more-info-modal-title">
<I18n {titleNoDefault ? (
i18n={i18n} <I18n
id="icu:calling__missing-media-keys" i18n={i18n}
components={{ id="icu:calling__missing-media-keys"
name: <ContactName key="name" title={title} />, components={{
}} name: <ContactName key="name" title={titleNoDefault} />,
/> }}
/>
) : (
i18n('icu:calling__missing-media-keys--unknown-contact')
)}
</div> </div>
); );
setErrorDialogBody(i18n('icu:calling__missing-media-keys-info')); setErrorDialogBody(i18n('icu:calling__missing-media-keys-info'));
@ -445,6 +486,7 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
showErrorDialog, showErrorDialog,
showMissingMediaKeys, showMissingMediaKeys,
title, title,
titleNoDefault,
]); ]);
return ( return (