Fix call link delete to require inactive call

This commit is contained in:
ayumi-signal 2024-10-18 13:19:45 -07:00 committed by GitHub
parent 902c1f4634
commit 3f8b8bdb2d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 98 additions and 37 deletions

View file

@ -24,6 +24,7 @@ export default {
callHistoryGroup: getFakeCallLinkHistoryGroup(),
callLink: FAKE_CALL_LINK_WITH_ADMIN_KEY,
isAnybodyInCall: false,
isCallActiveOnServer: false,
isInCall: false,
isInAnotherCall: false,
onDeleteCallLink: action('onDeleteCallLink'),
@ -39,11 +40,19 @@ export function Admin(args: CallLinkDetailsProps): JSX.Element {
}
export function AdminAndCallActive(args: CallLinkDetailsProps): JSX.Element {
return <CallLinkDetails {...args} isAnybodyInCall />;
return <CallLinkDetails {...args} isAnybodyInCall isCallActiveOnServer />;
}
export function AdminAndInCall(args: CallLinkDetailsProps): JSX.Element {
return <CallLinkDetails {...args} isAnybodyInCall isInCall />;
return (
<CallLinkDetails {...args} isAnybodyInCall isCallActiveOnServer isInCall />
);
}
export function AdminRecentlyEndedCall(
args: CallLinkDetailsProps
): JSX.Element {
return <CallLinkDetails {...args} isCallActiveOnServer />;
}
export function NonAdmin(args: CallLinkDetailsProps): JSX.Element {
@ -52,13 +61,23 @@ export function NonAdmin(args: CallLinkDetailsProps): JSX.Element {
export function NonAdminAndCallActive(args: CallLinkDetailsProps): JSX.Element {
return (
<CallLinkDetails {...args} callLink={FAKE_CALL_LINK} isAnybodyInCall />
<CallLinkDetails
{...args}
callLink={FAKE_CALL_LINK}
isAnybodyInCall
isCallActiveOnServer
/>
);
}
export function InAnotherCall(args: CallLinkDetailsProps): JSX.Element {
return (
<CallLinkDetails {...args} callLink={FAKE_CALL_LINK} isInAnotherCall />
<CallLinkDetails
{...args}
callLink={FAKE_CALL_LINK}
isInAnotherCall
isCallActiveOnServer
/>
);
}
@ -70,6 +89,7 @@ export function InAnotherCallAndCallActive(
{...args}
callLink={FAKE_CALL_LINK}
isAnybodyInCall
isCallActiveOnServer
isInAnotherCall
/>
);

View file

@ -33,6 +33,7 @@ export type CallLinkDetailsProps = Readonly<{
callHistoryGroup: CallHistoryGroup;
callLink: CallLinkType | undefined;
isAnybodyInCall: boolean;
isCallActiveOnServer: boolean;
isInCall: boolean;
isInAnotherCall: boolean;
i18n: LocalizerType;
@ -48,6 +49,7 @@ export function CallLinkDetails({
callLink,
i18n,
isAnybodyInCall,
isCallActiveOnServer,
isInCall,
isInAnotherCall,
onDeleteCallLink,
@ -88,7 +90,7 @@ export function CallLinkDetails({
);
const callLinkRestrictionsSelect = (
<CallLinkRestrictionsSelect
disabled={isAnybodyInCall}
disabled={isCallActiveOnServer}
i18n={i18n}
value={callLink.restrictions}
onChange={onUpdateCallLinkRestrictions}
@ -159,7 +161,7 @@ export function CallLinkDetails({
}
label={i18n('icu:CallLinkDetails__ApproveAllMembersLabel')}
right={
isAnybodyInCall ? (
isCallActiveOnServer ? (
<Tooltip
className="CallLinkDetails__ApproveAllMembersDisabledTooltip"
content={i18n(
@ -207,9 +209,9 @@ export function CallLinkDetails({
className={classNames({
CallLinkDetails__DeleteLink: true,
'CallLinkDetails__DeleteLink--disabled-for-active-call':
isAnybodyInCall,
isCallActiveOnServer,
})}
disabled={isAnybodyInCall}
disabled={isCallActiveOnServer}
icon={
<ConversationDetailsIcon
ariaLabel={i18n('icu:CallLinkDetails__DeleteLink')}
@ -217,7 +219,7 @@ export function CallLinkDetails({
/>
}
label={
isAnybodyInCall ? (
isCallActiveOnServer ? (
<Tooltip
className="CallLinkDetails__DeleteLinkTooltip"
content={i18n(

View file

@ -311,32 +311,49 @@ export function CallsList({
const { mode, peerId } = callHistoryGroup;
const call = getCallByPeerId({ mode, peerId });
if (!call) {
if (!call || !isGroupOrAdhocCallState(call)) {
// We can't tell from CallHistory alone whether a 1:1 call is active
return false;
}
if (isGroupOrAdhocCallState(call)) {
if (!isAnybodyInGroupCall(call.peekInfo)) {
return false;
}
if (mode === CallMode.Group) {
const eraId = call.peekInfo?.eraId;
if (!eraId) {
return false;
}
const callId = getCallIdFromEra(eraId);
return callHistoryGroup.children.some(
groupItem => groupItem.callId === callId
);
}
return true;
// eraId indicates a group/call link call is active.
const eraId = call.peekInfo?.eraId;
if (!eraId) {
return false;
}
// We can't tell from CallHistory alone whether a 1:1 call is active
return false;
// Group calls have multiple entries sharing a peerId. To distinguish them we need
// to compare the active callId (derived from eraId) with this item's callId set.
if (mode === CallMode.Group) {
const callId = getCallIdFromEra(eraId);
return callHistoryGroup.children.some(
groupItem => groupItem.callId === callId
);
}
// Call links only show once in the calls list, so we can just return active.
return true;
},
[getCallByPeerId]
);
const getIsAnybodyInCall = useCallback(
({
callHistoryGroup,
}: {
callHistoryGroup: CallHistoryGroup | null;
}): boolean => {
if (!callHistoryGroup) {
return false;
}
const { mode, peerId } = callHistoryGroup;
const call = getCallByPeerId({ mode, peerId });
if (!call || !isGroupOrAdhocCallState(call)) {
return false;
}
return isAnybodyInGroupCall(call.peekInfo);
},
[getCallByPeerId]
);
@ -370,7 +387,7 @@ export function CallsList({
);
}
// For group and adhoc calls, a call has to have members in it (see getIsCallActive)
// For group and adhoc calls
return Boolean(
isActive &&
conversation &&
@ -433,8 +450,9 @@ export function CallsList({
for (const item of callItems) {
const { mode } = item;
if (isGroupOrAdhocCallMode(mode)) {
const isActive = getIsCallActive({ callHistoryGroup: item });
const isActive = getIsCallActive({
callHistoryGroup: item,
});
if (isActive) {
// Don't peek if you're already in the call.
const activeCallConversationId = activeCall?.conversationId;
@ -711,6 +729,13 @@ export function CallsList({
const isActive = getIsCallActive({
callHistoryGroup: item,
});
// After everyone leaves a call, it remains active on the server for a little bit.
// We don't need to show the active call join button in this case.
const isAnybodyInCall =
isActive &&
getIsAnybodyInCall({
callHistoryGroup: item,
});
const isInCall = getIsInCall({
activeCallConversationId,
callHistoryGroup: item,
@ -722,7 +747,9 @@ export function CallsList({
const isCallButtonVisible = Boolean(
!isAdhoc || (isAdhoc && getCallLink(item.peerId))
);
const isActiveVisible = Boolean(isCallButtonVisible && item && isActive);
const isActiveVisible = Boolean(
isCallButtonVisible && item && isAnybodyInCall
);
if (searchPending || item == null || conversation == null) {
return (
@ -887,6 +914,7 @@ export function CallsList({
searchPending,
getCallLink,
getConversationForItem,
getIsAnybodyInCall,
getIsCallActive,
getIsInCall,
selectedCallHistoryGroup,

View file

@ -54,3 +54,9 @@ export const isAnybodyInGroupCall = (
}
return peekInfo.acis.length > 0;
};
export const isGroupCallActiveOnServer = (
peekInfo: undefined | Readonly<Pick<GroupCallPeekInfoType, 'eraId'>>
): boolean => {
return Boolean(peekInfo?.eraId);
};

View file

@ -14,7 +14,10 @@ import { useGlobalModalActions } from '../ducks/globalModals';
import { useCallingActions } from '../ducks/calling';
import { strictAssert } from '../../util/assert';
import type { CallLinkRestrictions } from '../../types/CallLink';
import { isAnybodyInGroupCall } from '../ducks/callingHelpers';
import {
isAnybodyInGroupCall,
isGroupCallActiveOnServer,
} from '../ducks/callingHelpers';
export type SmartCallLinkDetailsProps = Readonly<{
roomId: string;
@ -66,7 +69,8 @@ export const SmartCallLinkDetails = memo(function SmartCallLinkDetails({
const adhocCallSelector = useSelector(getAdhocCallSelector);
const adhocCall = adhocCallSelector(roomId);
const hasActiveCall = isAnybodyInGroupCall(adhocCall?.peekInfo);
const isAnybodyInCall = isAnybodyInGroupCall(adhocCall?.peekInfo);
const isCallActiveOnServer = isGroupCallActiveOnServer(adhocCall?.peekInfo);
const activeCall = useSelector(getActiveCallState);
const isInAnotherCall = Boolean(
@ -80,7 +84,8 @@ export const SmartCallLinkDetails = memo(function SmartCallLinkDetails({
<CallLinkDetails
callHistoryGroup={callHistoryGroup}
callLink={callLink}
isAnybodyInCall={hasActiveCall}
isAnybodyInCall={isAnybodyInCall}
isCallActiveOnServer={isCallActiveOnServer}
isInCall={isInCall}
isInAnotherCall={isInAnotherCall}
i18n={i18n}