Allow joining a call when already in a call, confirming first
This commit is contained in:
parent
f4a18414f1
commit
4ec3b98293
14 changed files with 290 additions and 137 deletions
|
@ -7242,12 +7242,12 @@
|
||||||
"description": "On the Calls Tab, when trying to join a different call when you're already in another one, this is the title of the confirmation dialog to leave the other call."
|
"description": "On the Calls Tab, when trying to join a different call when you're already in another one, this is the title of the confirmation dialog to leave the other call."
|
||||||
},
|
},
|
||||||
"icu:CallsList__LeaveCallDialogBody": {
|
"icu:CallsList__LeaveCallDialogBody": {
|
||||||
"messageformat": "You must leave the current call before joining a new call.",
|
"messageformat": "You must leave the current call before starting or joining a new call.",
|
||||||
"description": "On the Calls Tab, when trying to join a different call when you're already in another one, this is the body of the confirmation dialog to leave the other call."
|
"description": "When trying to join a different call when you're already in another one, this is the body of the confirmation dialog to leave the other call."
|
||||||
},
|
},
|
||||||
"icu:CallsList__LeaveCallDialogButton--leave": {
|
"icu:CallsList__LeaveCallDialogButton--leave": {
|
||||||
"messageformat": "Leave call",
|
"messageformat": "Leave call",
|
||||||
"description": "On the Calls Tab, when trying to join a different call when you're already in another one, this is the button to confirm leaving the other call."
|
"description": "When trying to join a different call when you're already in another one, this is the button to confirm leaving the other call."
|
||||||
},
|
},
|
||||||
"icu:CallsNewCall__EmptyState--noQuery": {
|
"icu:CallsNewCall__EmptyState--noQuery": {
|
||||||
"messageformat": "No recent conversations.",
|
"messageformat": "No recent conversations.",
|
||||||
|
|
|
@ -376,7 +376,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.CallsNewCall__ItemActionButton--join-call-disabled {
|
.CallsNewCall__ItemActionButton--join-call-disabled {
|
||||||
cursor: default;
|
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ import type {
|
||||||
PeekNotConnectedGroupCallType,
|
PeekNotConnectedGroupCallType,
|
||||||
} from '../state/ducks/calling';
|
} from '../state/ducks/calling';
|
||||||
import { DAY, MINUTE, SECOND } from '../util/durations';
|
import { DAY, MINUTE, SECOND } from '../util/durations';
|
||||||
import { ConfirmationDialog } from './ConfirmationDialog';
|
import type { StartCallData } from './ConfirmLeaveCallModal';
|
||||||
|
|
||||||
function Timestamp({
|
function Timestamp({
|
||||||
i18n,
|
i18n,
|
||||||
|
@ -148,7 +148,8 @@ type CallsListProps = Readonly<{
|
||||||
onOutgoingVideoCallInConversation: (conversationId: string) => void;
|
onOutgoingVideoCallInConversation: (conversationId: string) => void;
|
||||||
onChangeCallsTabSelectedView: (selectedView: CallsTabSelectedView) => void;
|
onChangeCallsTabSelectedView: (selectedView: CallsTabSelectedView) => void;
|
||||||
peekNotConnectedGroupCall: (options: PeekNotConnectedGroupCallType) => void;
|
peekNotConnectedGroupCall: (options: PeekNotConnectedGroupCallType) => void;
|
||||||
startCallLinkLobbyByRoomId: (roomId: string) => void;
|
startCallLinkLobbyByRoomId: (options: { roomId: string }) => void;
|
||||||
|
toggleConfirmLeaveCallModal: (options: StartCallData | null) => void;
|
||||||
togglePip: () => void;
|
togglePip: () => void;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
@ -179,7 +180,6 @@ export function CallsList({
|
||||||
getCall,
|
getCall,
|
||||||
getCallLink,
|
getCallLink,
|
||||||
getConversation,
|
getConversation,
|
||||||
hangUpActiveCall,
|
|
||||||
i18n,
|
i18n,
|
||||||
selectedCallHistoryGroup,
|
selectedCallHistoryGroup,
|
||||||
onCreateCallLink,
|
onCreateCallLink,
|
||||||
|
@ -188,6 +188,7 @@ export function CallsList({
|
||||||
onChangeCallsTabSelectedView,
|
onChangeCallsTabSelectedView,
|
||||||
peekNotConnectedGroupCall,
|
peekNotConnectedGroupCall,
|
||||||
startCallLinkLobbyByRoomId,
|
startCallLinkLobbyByRoomId,
|
||||||
|
toggleConfirmLeaveCallModal,
|
||||||
togglePip,
|
togglePip,
|
||||||
}: CallsListProps): JSX.Element {
|
}: CallsListProps): JSX.Element {
|
||||||
const infiniteLoaderRef = useRef<InfiniteLoader>(null);
|
const infiniteLoaderRef = useRef<InfiniteLoader>(null);
|
||||||
|
@ -195,8 +196,6 @@ export function CallsList({
|
||||||
const [queryInput, setQueryInput] = useState('');
|
const [queryInput, setQueryInput] = useState('');
|
||||||
const [statusInput, setStatusInput] = useState(CallHistoryFilterStatus.All);
|
const [statusInput, setStatusInput] = useState(CallHistoryFilterStatus.All);
|
||||||
const [searchState, setSearchState] = useState(defaultInitState);
|
const [searchState, setSearchState] = useState(defaultInitState);
|
||||||
const [isLeaveCallDialogVisible, setIsLeaveCallDialogVisible] =
|
|
||||||
useState(false);
|
|
||||||
|
|
||||||
const prevOptionsRef = useRef<CallHistoryFilterOptions | null>(null);
|
const prevOptionsRef = useRef<CallHistoryFilterOptions | null>(null);
|
||||||
|
|
||||||
|
@ -330,7 +329,7 @@ export function CallsList({
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Direct is not supported currently
|
// We can't tell from CallHistory alone whether a 1:1 call is active
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
[getCallByPeerId]
|
[getCallByPeerId]
|
||||||
|
@ -358,12 +357,14 @@ export function CallsList({
|
||||||
return peerId === activeCallConversationId;
|
return peerId === activeCallConversationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not supported currently
|
// For direct conversations, we know the call is active if it's the active call!
|
||||||
if (mode === CallMode.Direct) {
|
if (mode === CallMode.Direct) {
|
||||||
return false;
|
return Boolean(
|
||||||
|
conversation && conversation?.id === activeCallConversationId
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group
|
// For group and adhoc calls, a call has to have members in it (see getIsCallActive)
|
||||||
return Boolean(
|
return Boolean(
|
||||||
isActive &&
|
isActive &&
|
||||||
conversation &&
|
conversation &&
|
||||||
|
@ -773,6 +774,43 @@ export function CallsList({
|
||||||
strictAssert(false, 'Cannot format call');
|
strictAssert(false, 'Cannot format call');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const inCallAndNotThisOne = !isInCall && activeCall;
|
||||||
|
const callButton = (
|
||||||
|
<CallsNewCallButton
|
||||||
|
callType={item.type}
|
||||||
|
isActive={isActiveVisible}
|
||||||
|
isInCall={isInCall}
|
||||||
|
isEnabled={!inCallAndNotThisOne}
|
||||||
|
onClick={() => {
|
||||||
|
if (isInCall) {
|
||||||
|
togglePip();
|
||||||
|
} else if (activeCall) {
|
||||||
|
if (isAdhoc) {
|
||||||
|
toggleConfirmLeaveCallModal({
|
||||||
|
type: 'adhoc-roomId',
|
||||||
|
roomId: item.peerId,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toggleConfirmLeaveCallModal({
|
||||||
|
type: 'conversation',
|
||||||
|
conversationId: conversation.id,
|
||||||
|
isVideoCall: item.type !== CallType.Audio,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (isAdhoc) {
|
||||||
|
startCallLinkLobbyByRoomId({ roomId: item.peerId });
|
||||||
|
} else if (conversation) {
|
||||||
|
if (item.type === CallType.Audio) {
|
||||||
|
onOutgoingAudioCallInConversation(conversation.id);
|
||||||
|
} else {
|
||||||
|
onOutgoingVideoCallInConversation(conversation.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
i18n={i18n}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={key}
|
key={key}
|
||||||
|
@ -801,34 +839,7 @@ export function CallsList({
|
||||||
className="CallsList__ItemAvatar"
|
className="CallsList__ItemAvatar"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
trailing={
|
trailing={isCallButtonVisible ? callButton : undefined}
|
||||||
isCallButtonVisible ? (
|
|
||||||
<CallsNewCallButton
|
|
||||||
callType={item.type}
|
|
||||||
isActive={isActiveVisible}
|
|
||||||
isInCall={isInCall}
|
|
||||||
isEnabled={isInCall || !activeCall}
|
|
||||||
onClick={() => {
|
|
||||||
if (isInCall) {
|
|
||||||
togglePip();
|
|
||||||
} else if (activeCall) {
|
|
||||||
if (isActiveVisible) {
|
|
||||||
setIsLeaveCallDialogVisible(true);
|
|
||||||
}
|
|
||||||
} else if (isAdhoc) {
|
|
||||||
startCallLinkLobbyByRoomId(item.peerId);
|
|
||||||
} else if (conversation) {
|
|
||||||
if (item.type === CallType.Audio) {
|
|
||||||
onOutgoingAudioCallInConversation(conversation.id);
|
|
||||||
} else {
|
|
||||||
onOutgoingVideoCallInConversation(conversation.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
i18n={i18n}
|
|
||||||
/>
|
|
||||||
) : undefined
|
|
||||||
}
|
|
||||||
title={
|
title={
|
||||||
<span
|
<span
|
||||||
className="CallsList__ItemTitle"
|
className="CallsList__ItemTitle"
|
||||||
|
@ -887,6 +898,7 @@ export function CallsList({
|
||||||
onOutgoingAudioCallInConversation,
|
onOutgoingAudioCallInConversation,
|
||||||
onOutgoingVideoCallInConversation,
|
onOutgoingVideoCallInConversation,
|
||||||
startCallLinkLobbyByRoomId,
|
startCallLinkLobbyByRoomId,
|
||||||
|
toggleConfirmLeaveCallModal,
|
||||||
togglePip,
|
togglePip,
|
||||||
i18n,
|
i18n,
|
||||||
]
|
]
|
||||||
|
@ -913,31 +925,6 @@ export function CallsList({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isLeaveCallDialogVisible && (
|
|
||||||
<ConfirmationDialog
|
|
||||||
dialogName="GroupCallRemoteParticipant.blockInfo"
|
|
||||||
cancelText={i18n('icu:cancel')}
|
|
||||||
i18n={i18n}
|
|
||||||
onClose={() => {
|
|
||||||
setIsLeaveCallDialogVisible(false);
|
|
||||||
}}
|
|
||||||
title={i18n('icu:CallsList__LeaveCallDialogTitle')}
|
|
||||||
actions={[
|
|
||||||
{
|
|
||||||
text: i18n('icu:CallsList__LeaveCallDialogButton--leave'),
|
|
||||||
style: 'affirmative',
|
|
||||||
action: () => {
|
|
||||||
hangUpActiveCall(
|
|
||||||
'Calls Tab leave active call to join different call'
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{i18n('icu:CallsList__LeaveCallDialogBody')}
|
|
||||||
</ConfirmationDialog>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<NavSidebarSearchHeader>
|
<NavSidebarSearchHeader>
|
||||||
<SearchInput
|
<SearchInput
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { SizeObserver } from '../hooks/useSizeObserver';
|
||||||
import { CallType } from '../types/CallDisposition';
|
import { CallType } from '../types/CallDisposition';
|
||||||
import type { CallsTabSelectedView } from './CallsTab';
|
import type { CallsTabSelectedView } from './CallsTab';
|
||||||
import { Tooltip, TooltipPlacement } from './Tooltip';
|
import { Tooltip, TooltipPlacement } from './Tooltip';
|
||||||
|
import { offsetDistanceModifier } from '../util/popperUtil';
|
||||||
|
|
||||||
type CallsNewCallProps = Readonly<{
|
type CallsNewCallProps = Readonly<{
|
||||||
hasActiveCall: boolean;
|
hasActiveCall: boolean;
|
||||||
|
@ -53,17 +54,18 @@ export function CallsNewCallButton({
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
let innerContent: React.ReactNode | string;
|
let innerContent: React.ReactNode | string;
|
||||||
let tooltipContent = '';
|
let tooltipContent = '';
|
||||||
if (callType === CallType.Audio) {
|
if (!isEnabled) {
|
||||||
innerContent = (
|
tooltipContent = i18n('icu:ContactModal--already-in-call');
|
||||||
<span className="CallsNewCall__ItemIcon CallsNewCall__ItemIcon--Phone" />
|
}
|
||||||
);
|
// Note: isActive is only set for groups and adhoc calls
|
||||||
} else if (isActive) {
|
if (isActive) {
|
||||||
innerContent = isInCall
|
innerContent = isInCall
|
||||||
? i18n('icu:CallsNewCallButton--return')
|
? i18n('icu:CallsNewCallButton--return')
|
||||||
: i18n('icu:joinOngoingCall');
|
: i18n('icu:joinOngoingCall');
|
||||||
if (!isEnabled) {
|
} else if (callType === CallType.Audio) {
|
||||||
tooltipContent = i18n('icu:CallsNewCallButtonTooltip--in-another-call');
|
innerContent = (
|
||||||
}
|
<span className="CallsNewCall__ItemIcon CallsNewCall__ItemIcon--Phone" />
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
innerContent = (
|
innerContent = (
|
||||||
<span className="CallsNewCall__ItemIcon CallsNewCall__ItemIcon--Video" />
|
<span className="CallsNewCall__ItemIcon CallsNewCall__ItemIcon--Video" />
|
||||||
|
@ -97,6 +99,7 @@ export function CallsNewCallButton({
|
||||||
className="CallsNewCall__ItemActionButtonTooltip"
|
className="CallsNewCall__ItemActionButtonTooltip"
|
||||||
content={tooltipContent}
|
content={tooltipContent}
|
||||||
direction={TooltipPlacement.Top}
|
direction={TooltipPlacement.Top}
|
||||||
|
popperModifiers={[offsetDistanceModifier(15)]}
|
||||||
>
|
>
|
||||||
{buttonContent}
|
{buttonContent}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
|
@ -23,6 +23,7 @@ import type { UnreadStats } from '../util/countUnreadStats';
|
||||||
import type { WidthBreakpoint } from './_util';
|
import type { WidthBreakpoint } from './_util';
|
||||||
import type { CallLinkType } from '../types/CallLink';
|
import type { CallLinkType } from '../types/CallLink';
|
||||||
import type { CallStateType } from '../state/selectors/calling';
|
import type { CallStateType } from '../state/selectors/calling';
|
||||||
|
import type { StartCallData } from './ConfirmLeaveCallModal';
|
||||||
|
|
||||||
enum CallsTabSidebarView {
|
enum CallsTabSidebarView {
|
||||||
CallsListView,
|
CallsListView,
|
||||||
|
@ -72,7 +73,8 @@ type CallsTabProps = Readonly<{
|
||||||
}) => JSX.Element;
|
}) => JSX.Element;
|
||||||
regionCode: string | undefined;
|
regionCode: string | undefined;
|
||||||
savePreferredLeftPaneWidth: (preferredLeftPaneWidth: number) => void;
|
savePreferredLeftPaneWidth: (preferredLeftPaneWidth: number) => void;
|
||||||
startCallLinkLobbyByRoomId: (roomId: string) => void;
|
startCallLinkLobbyByRoomId: (options: { roomId: string }) => void;
|
||||||
|
toggleConfirmLeaveCallModal: (options: StartCallData | null) => void;
|
||||||
togglePip: () => void;
|
togglePip: () => void;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
@ -119,6 +121,7 @@ export function CallsTab({
|
||||||
regionCode,
|
regionCode,
|
||||||
savePreferredLeftPaneWidth,
|
savePreferredLeftPaneWidth,
|
||||||
startCallLinkLobbyByRoomId,
|
startCallLinkLobbyByRoomId,
|
||||||
|
toggleConfirmLeaveCallModal,
|
||||||
togglePip,
|
togglePip,
|
||||||
}: CallsTabProps): JSX.Element {
|
}: CallsTabProps): JSX.Element {
|
||||||
const [sidebarView, setSidebarView] = useState(
|
const [sidebarView, setSidebarView] = useState(
|
||||||
|
@ -282,6 +285,7 @@ export function CallsTab({
|
||||||
}
|
}
|
||||||
peekNotConnectedGroupCall={peekNotConnectedGroupCall}
|
peekNotConnectedGroupCall={peekNotConnectedGroupCall}
|
||||||
startCallLinkLobbyByRoomId={startCallLinkLobbyByRoomId}
|
startCallLinkLobbyByRoomId={startCallLinkLobbyByRoomId}
|
||||||
|
toggleConfirmLeaveCallModal={toggleConfirmLeaveCallModal}
|
||||||
togglePip={togglePip}
|
togglePip={togglePip}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
59
ts/components/ConfirmLeaveCallModal.tsx
Normal file
59
ts/components/ConfirmLeaveCallModal.tsx
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2024 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { ConfirmationDialog } from './ConfirmationDialog';
|
||||||
|
|
||||||
|
import type { LocalizerType } from '../types/Util';
|
||||||
|
import type {
|
||||||
|
StartCallingLobbyType,
|
||||||
|
StartCallLinkLobbyByRoomIdType,
|
||||||
|
StartCallLinkLobbyType,
|
||||||
|
} from '../state/ducks/calling';
|
||||||
|
|
||||||
|
export type StartCallData =
|
||||||
|
| ({
|
||||||
|
type: 'conversation';
|
||||||
|
} & StartCallingLobbyType)
|
||||||
|
| ({ type: 'adhoc-roomId' } & StartCallLinkLobbyByRoomIdType)
|
||||||
|
| ({ type: 'adhoc-rootKey' } & StartCallLinkLobbyType);
|
||||||
|
type HousekeepingProps = {
|
||||||
|
i18n: LocalizerType;
|
||||||
|
};
|
||||||
|
type DispatchProps = {
|
||||||
|
toggleConfirmLeaveCallModal: (options: StartCallData | null) => void;
|
||||||
|
leaveCurrentCallAndStartCallingLobby: (options: StartCallData) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Props = { data: StartCallData } & HousekeepingProps & DispatchProps;
|
||||||
|
|
||||||
|
export function ConfirmLeaveCallModal({
|
||||||
|
i18n,
|
||||||
|
data,
|
||||||
|
leaveCurrentCallAndStartCallingLobby,
|
||||||
|
toggleConfirmLeaveCallModal,
|
||||||
|
}: Props): JSX.Element | null {
|
||||||
|
return (
|
||||||
|
<ConfirmationDialog
|
||||||
|
dialogName="GroupCallRemoteParticipant.blockInfo"
|
||||||
|
cancelText={i18n('icu:cancel')}
|
||||||
|
i18n={i18n}
|
||||||
|
onClose={() => {
|
||||||
|
toggleConfirmLeaveCallModal(null);
|
||||||
|
}}
|
||||||
|
title={i18n('icu:CallsList__LeaveCallDialogTitle')}
|
||||||
|
actions={[
|
||||||
|
{
|
||||||
|
text: i18n('icu:CallsList__LeaveCallDialogButton--leave'),
|
||||||
|
style: 'affirmative',
|
||||||
|
action: () => {
|
||||||
|
leaveCurrentCallAndStartCallingLobby(data);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{i18n('icu:CallsList__LeaveCallDialogBody')}
|
||||||
|
</ConfirmationDialog>
|
||||||
|
);
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ import { ButtonVariant } from './Button';
|
||||||
import { ConfirmationDialog } from './ConfirmationDialog';
|
import { ConfirmationDialog } from './ConfirmationDialog';
|
||||||
import { SignalConnectionsModal } from './SignalConnectionsModal';
|
import { SignalConnectionsModal } from './SignalConnectionsModal';
|
||||||
import { WhatsNewModal } from './WhatsNewModal';
|
import { WhatsNewModal } from './WhatsNewModal';
|
||||||
|
import type { StartCallData } from './ConfirmLeaveCallModal';
|
||||||
|
|
||||||
// NOTE: All types should be required for this component so that the smart
|
// NOTE: All types should be required for this component so that the smart
|
||||||
// component gives you type errors when adding/removing props.
|
// component gives you type errors when adding/removing props.
|
||||||
|
@ -35,6 +36,9 @@ export type PropsType = {
|
||||||
// CallLinkEditModal
|
// CallLinkEditModal
|
||||||
callLinkEditModalRoomId: string | null;
|
callLinkEditModalRoomId: string | null;
|
||||||
renderCallLinkEditModal: () => JSX.Element;
|
renderCallLinkEditModal: () => JSX.Element;
|
||||||
|
// ConfirmLeaveCallModal
|
||||||
|
confirmLeaveCallModalState: StartCallData | null;
|
||||||
|
renderConfirmLeaveCallModal: () => JSX.Element;
|
||||||
// ContactModal
|
// ContactModal
|
||||||
contactModalState: ContactModalStateType | undefined;
|
contactModalState: ContactModalStateType | undefined;
|
||||||
renderContactModal: () => JSX.Element;
|
renderContactModal: () => JSX.Element;
|
||||||
|
@ -114,6 +118,9 @@ export function GlobalModalContainer({
|
||||||
// CallLinkEditModal
|
// CallLinkEditModal
|
||||||
callLinkEditModalRoomId,
|
callLinkEditModalRoomId,
|
||||||
renderCallLinkEditModal,
|
renderCallLinkEditModal,
|
||||||
|
// ConfirmLeaveCallModal
|
||||||
|
confirmLeaveCallModalState,
|
||||||
|
renderConfirmLeaveCallModal,
|
||||||
// ContactModal
|
// ContactModal
|
||||||
contactModalState,
|
contactModalState,
|
||||||
renderContactModal,
|
renderContactModal,
|
||||||
|
@ -196,6 +203,10 @@ export function GlobalModalContainer({
|
||||||
|
|
||||||
// The Rest
|
// The Rest
|
||||||
|
|
||||||
|
if (confirmLeaveCallModalState) {
|
||||||
|
return renderConfirmLeaveCallModal();
|
||||||
|
}
|
||||||
|
|
||||||
if (addUserToAnotherGroupModalContactId) {
|
if (addUserToAnotherGroupModalContactId) {
|
||||||
return renderAddUserToAnotherGroup();
|
return renderAddUserToAnotherGroup();
|
||||||
}
|
}
|
||||||
|
|
|
@ -424,14 +424,14 @@ export function ConversationDetails({
|
||||||
{!conversation.isMe && (
|
{!conversation.isMe && (
|
||||||
<>
|
<>
|
||||||
<ConversationDetailsCallButton
|
<ConversationDetailsCallButton
|
||||||
disabled={hasActiveCall}
|
hasActiveCall={hasActiveCall}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClick={() => onOutgoingVideoCallInConversation(conversation.id)}
|
onClick={() => onOutgoingVideoCallInConversation(conversation.id)}
|
||||||
type="video"
|
type="video"
|
||||||
/>
|
/>
|
||||||
{!isGroup && (
|
{!isGroup && (
|
||||||
<ConversationDetailsCallButton
|
<ConversationDetailsCallButton
|
||||||
disabled={hasActiveCall}
|
hasActiveCall={hasActiveCall}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
onOutgoingAudioCallInConversation(conversation.id)
|
onOutgoingAudioCallInConversation(conversation.id)
|
||||||
|
@ -733,19 +733,18 @@ export function ConversationDetails({
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConversationDetailsCallButton({
|
function ConversationDetailsCallButton({
|
||||||
disabled,
|
hasActiveCall,
|
||||||
i18n,
|
i18n,
|
||||||
onClick,
|
onClick,
|
||||||
type,
|
type,
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
disabled: boolean;
|
hasActiveCall: boolean;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
onClick: () => unknown;
|
onClick: () => unknown;
|
||||||
type: 'audio' | 'video';
|
type: 'audio' | 'video';
|
||||||
}>) {
|
}>) {
|
||||||
const button = (
|
const button = (
|
||||||
<Button
|
<Button
|
||||||
disabled={disabled}
|
|
||||||
icon={ButtonIconType[type]}
|
icon={ButtonIconType[type]}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
variant={ButtonVariant.Details}
|
variant={ButtonVariant.Details}
|
||||||
|
@ -754,7 +753,7 @@ function ConversationDetailsCallButton({
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (disabled) {
|
if (hasActiveCall) {
|
||||||
return (
|
return (
|
||||||
<Tooltip content={i18n('icu:calling__in-another-call-tooltip')}>
|
<Tooltip content={i18n('icu:calling__in-another-call-tooltip')}>
|
||||||
{button}
|
{button}
|
||||||
|
|
|
@ -82,8 +82,11 @@ import {
|
||||||
isGroupOrAdhocCallMode,
|
isGroupOrAdhocCallMode,
|
||||||
isGroupOrAdhocCallState,
|
isGroupOrAdhocCallState,
|
||||||
} from '../../util/isGroupOrAdhocCall';
|
} from '../../util/isGroupOrAdhocCall';
|
||||||
import type { ShowErrorModalActionType } from './globalModals';
|
import type {
|
||||||
import { SHOW_ERROR_MODAL } from './globalModals';
|
ShowErrorModalActionType,
|
||||||
|
ToggleConfirmLeaveCallModalActionType,
|
||||||
|
} from './globalModals';
|
||||||
|
import { SHOW_ERROR_MODAL, toggleConfirmLeaveCallModal } from './globalModals';
|
||||||
import { ButtonVariant } from '../../components/Button';
|
import { ButtonVariant } from '../../components/Button';
|
||||||
import { getConversationIdForLogging } from '../../util/idForLogging';
|
import { getConversationIdForLogging } from '../../util/idForLogging';
|
||||||
import { DataReader, DataWriter } from '../../sql/Client';
|
import { DataReader, DataWriter } from '../../sql/Client';
|
||||||
|
@ -92,6 +95,7 @@ import type { CallHistoryAdd } from './callHistory';
|
||||||
import { addCallHistory } from './callHistory';
|
import { addCallHistory } from './callHistory';
|
||||||
import { saveDraftRecordingIfNeeded } from './composer';
|
import { saveDraftRecordingIfNeeded } from './composer';
|
||||||
import type { CallHistoryDetails } from '../../types/CallDisposition';
|
import type { CallHistoryDetails } from '../../types/CallDisposition';
|
||||||
|
import type { StartCallData } from '../../components/ConfirmLeaveCallModal';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
|
@ -1464,48 +1468,6 @@ function handleCallLinkUpdate(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* When starting a lobby and there's an active call, if we're already in call then
|
|
||||||
* focus it (toggle pip), otherwise show an error.
|
|
||||||
* @returns {boolean} `true` if there was an active call and we handled it.
|
|
||||||
*/
|
|
||||||
function handleActiveCallOnStartLobby({
|
|
||||||
conversationId,
|
|
||||||
state,
|
|
||||||
dispatch,
|
|
||||||
}: {
|
|
||||||
conversationId: string;
|
|
||||||
state: RootStateType;
|
|
||||||
dispatch: ThunkDispatch<
|
|
||||||
RootStateType,
|
|
||||||
unknown,
|
|
||||||
ShowErrorModalActionType | TogglePipActionType
|
|
||||||
>;
|
|
||||||
}): boolean {
|
|
||||||
const { activeCallState } = state.calling;
|
|
||||||
if (!activeCallState) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activeCallState.conversationId === conversationId) {
|
|
||||||
dispatch({
|
|
||||||
type: TOGGLE_PIP,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const i18n = getIntl(state);
|
|
||||||
dispatch({
|
|
||||||
type: SHOW_ERROR_MODAL,
|
|
||||||
payload: {
|
|
||||||
title: i18n('icu:calling__cant-join'),
|
|
||||||
description: i18n('icu:calling__dialog-already-in-call'),
|
|
||||||
buttonVariant: ButtonVariant.Primary,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hangUpActiveCall(
|
function hangUpActiveCall(
|
||||||
reason: string
|
reason: string
|
||||||
): ThunkAction<void, RootStateType, unknown, HangUpActionType> {
|
): ThunkAction<void, RootStateType, unknown, HangUpActionType> {
|
||||||
|
@ -2046,9 +2008,9 @@ function updateCallLinkRestrictions(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function startCallLinkLobbyByRoomId(
|
function startCallLinkLobbyByRoomId({
|
||||||
roomId: string
|
roomId,
|
||||||
): StartCallLinkLobbyThunkActionType {
|
}: StartCallLinkLobbyByRoomIdType): StartCallLinkLobbyThunkActionType {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const callLink = getOwn(state.calling.callLinks, roomId);
|
const callLink = getOwn(state.calling.callLinks, roomId);
|
||||||
|
@ -2082,6 +2044,7 @@ const _startCallLinkLobby = async ({
|
||||||
unknown,
|
unknown,
|
||||||
| StartCallLinkLobbyActionType
|
| StartCallLinkLobbyActionType
|
||||||
| ShowErrorModalActionType
|
| ShowErrorModalActionType
|
||||||
|
| ToggleConfirmLeaveCallModalActionType
|
||||||
| TogglePipActionType
|
| TogglePipActionType
|
||||||
>;
|
>;
|
||||||
getState: () => RootStateType;
|
getState: () => RootStateType;
|
||||||
|
@ -2090,9 +2053,20 @@ const _startCallLinkLobby = async ({
|
||||||
const roomId = getRoomIdFromRootKey(callLinkRootKey);
|
const roomId = getRoomIdFromRootKey(callLinkRootKey);
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
if (
|
const { activeCallState } = state.calling;
|
||||||
handleActiveCallOnStartLobby({ conversationId: roomId, state, dispatch })
|
if (activeCallState && activeCallState.conversationId === roomId) {
|
||||||
) {
|
dispatch({
|
||||||
|
type: TOGGLE_PIP,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (activeCallState) {
|
||||||
|
dispatch(
|
||||||
|
toggleConfirmLeaveCallModal({
|
||||||
|
type: 'adhoc-rootKey',
|
||||||
|
rootKey,
|
||||||
|
})
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2181,6 +2155,34 @@ const _startCallLinkLobby = async ({
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function leaveCurrentCallAndStartCallingLobby(
|
||||||
|
data: StartCallData
|
||||||
|
): ThunkAction<void, RootStateType, unknown, HangUpActionType> {
|
||||||
|
return async (dispatch, getState) => {
|
||||||
|
hangUpActiveCall(
|
||||||
|
'Leave call button pressed in ConfirmLeaveCurrentCallModal'
|
||||||
|
)(dispatch, getState, undefined);
|
||||||
|
|
||||||
|
const { type } = data;
|
||||||
|
if (type === 'conversation') {
|
||||||
|
const { conversationId, isVideoCall } = data;
|
||||||
|
startCallingLobby({ conversationId, isVideoCall })(
|
||||||
|
dispatch,
|
||||||
|
getState,
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
} else if (type === 'adhoc-roomId') {
|
||||||
|
const { roomId } = data;
|
||||||
|
startCallLinkLobbyByRoomId({ roomId })(dispatch, getState, undefined);
|
||||||
|
} else if (type === 'adhoc-rootKey') {
|
||||||
|
const { rootKey } = data;
|
||||||
|
startCallLinkLobby({ rootKey })(dispatch, getState, undefined);
|
||||||
|
} else {
|
||||||
|
throw missingCaseError(type);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function startCallingLobby({
|
function startCallingLobby({
|
||||||
conversationId,
|
conversationId,
|
||||||
isVideoCall,
|
isVideoCall,
|
||||||
|
@ -2188,7 +2190,9 @@ function startCallingLobby({
|
||||||
void,
|
void,
|
||||||
RootStateType,
|
RootStateType,
|
||||||
unknown,
|
unknown,
|
||||||
StartCallingLobbyActionType | TogglePipActionType
|
| StartCallingLobbyActionType
|
||||||
|
| ToggleConfirmLeaveCallModalActionType
|
||||||
|
| TogglePipActionType
|
||||||
> {
|
> {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
@ -2201,10 +2205,16 @@ function startCallingLobby({
|
||||||
"startCallingLobby: can't start lobby without a conversation"
|
"startCallingLobby: can't start lobby without a conversation"
|
||||||
);
|
);
|
||||||
|
|
||||||
strictAssert(
|
if (state.calling.activeCallState) {
|
||||||
!state.calling.activeCallState,
|
dispatch(
|
||||||
"startCallingLobby: can't start lobby if a call is active"
|
toggleConfirmLeaveCallModal({
|
||||||
);
|
type: 'conversation',
|
||||||
|
conversationId,
|
||||||
|
isVideoCall,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// The group call device count is considered 0 for a direct call.
|
// The group call device count is considered 0 for a direct call.
|
||||||
const groupCall = getGroupCall(
|
const groupCall = getGroupCall(
|
||||||
|
@ -2374,6 +2384,7 @@ export const actions = {
|
||||||
hangUpActiveCall,
|
hangUpActiveCall,
|
||||||
handleCallLinkUpdate,
|
handleCallLinkUpdate,
|
||||||
joinedAdhocCall,
|
joinedAdhocCall,
|
||||||
|
leaveCurrentCallAndStartCallingLobby,
|
||||||
onOutgoingVideoCallInConversation,
|
onOutgoingVideoCallInConversation,
|
||||||
onOutgoingAudioCallInConversation,
|
onOutgoingAudioCallInConversation,
|
||||||
openSystemPreferencesAction,
|
openSystemPreferencesAction,
|
||||||
|
|
|
@ -48,6 +48,7 @@ import { ForwardMessagesModalType } from '../../components/ForwardMessagesModal'
|
||||||
import type { CallLinkType } from '../../types/CallLink';
|
import type { CallLinkType } from '../../types/CallLink';
|
||||||
import type { LocalizerType } from '../../types/I18N';
|
import type { LocalizerType } from '../../types/I18N';
|
||||||
import { linkCallRoute } from '../../util/signalRoutes';
|
import { linkCallRoute } from '../../util/signalRoutes';
|
||||||
|
import type { StartCallData } from '../../components/ConfirmLeaveCallModal';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
|
@ -93,6 +94,7 @@ export type GlobalModalsStateType = ReadonlyDeep<{
|
||||||
aboutContactModalContactId?: string;
|
aboutContactModalContactId?: string;
|
||||||
callLinkAddNameModalRoomId: string | null;
|
callLinkAddNameModalRoomId: string | null;
|
||||||
callLinkEditModalRoomId: string | null;
|
callLinkEditModalRoomId: string | null;
|
||||||
|
confirmLeaveCallModalState: StartCallData | null;
|
||||||
contactModalState?: ContactModalStateType;
|
contactModalState?: ContactModalStateType;
|
||||||
deleteMessagesProps?: DeleteMessagesPropsType;
|
deleteMessagesProps?: DeleteMessagesPropsType;
|
||||||
editHistoryMessages?: EditHistoryMessagesType;
|
editHistoryMessages?: EditHistoryMessagesType;
|
||||||
|
@ -168,6 +170,8 @@ const TOGGLE_CONFIRMATION_MODAL = 'globalModals/TOGGLE_CONFIRMATION_MODAL';
|
||||||
const SHOW_EDIT_HISTORY_MODAL = 'globalModals/SHOW_EDIT_HISTORY_MODAL';
|
const SHOW_EDIT_HISTORY_MODAL = 'globalModals/SHOW_EDIT_HISTORY_MODAL';
|
||||||
const CLOSE_EDIT_HISTORY_MODAL = 'globalModals/CLOSE_EDIT_HISTORY_MODAL';
|
const CLOSE_EDIT_HISTORY_MODAL = 'globalModals/CLOSE_EDIT_HISTORY_MODAL';
|
||||||
const TOGGLE_USERNAME_ONBOARDING = 'globalModals/TOGGLE_USERNAME_ONBOARDING';
|
const TOGGLE_USERNAME_ONBOARDING = 'globalModals/TOGGLE_USERNAME_ONBOARDING';
|
||||||
|
const TOGGLE_CONFIRM_LEAVE_CALL_MODAL =
|
||||||
|
'globalModals/TOGGLE_CONFIRM_LEAVE_CALL_MODAL';
|
||||||
|
|
||||||
export type ContactModalStateType = ReadonlyDeep<{
|
export type ContactModalStateType = ReadonlyDeep<{
|
||||||
contactId: string;
|
contactId: string;
|
||||||
|
@ -221,6 +225,11 @@ type ToggleForwardMessagesModalActionType = ReadonlyDeep<{
|
||||||
payload: ForwardMessagesPropsType | undefined;
|
payload: ForwardMessagesPropsType | undefined;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
export type ToggleConfirmLeaveCallModalActionType = ReadonlyDeep<{
|
||||||
|
type: typeof TOGGLE_CONFIRM_LEAVE_CALL_MODAL;
|
||||||
|
payload: StartCallData | null;
|
||||||
|
}>;
|
||||||
|
|
||||||
type ToggleNotePreviewModalActionType = ReadonlyDeep<{
|
type ToggleNotePreviewModalActionType = ReadonlyDeep<{
|
||||||
type: typeof TOGGLE_NOTE_PREVIEW_MODAL;
|
type: typeof TOGGLE_NOTE_PREVIEW_MODAL;
|
||||||
payload: NotePreviewModalPropsType | null;
|
payload: NotePreviewModalPropsType | null;
|
||||||
|
@ -385,6 +394,7 @@ export type GlobalModalsActionType = ReadonlyDeep<
|
||||||
| ToggleCallLinkAddNameModalActionType
|
| ToggleCallLinkAddNameModalActionType
|
||||||
| ToggleCallLinkEditModalActionType
|
| ToggleCallLinkEditModalActionType
|
||||||
| ToggleConfirmationModalActionType
|
| ToggleConfirmationModalActionType
|
||||||
|
| ToggleConfirmLeaveCallModalActionType
|
||||||
| ToggleDeleteMessagesModalActionType
|
| ToggleDeleteMessagesModalActionType
|
||||||
| ToggleForwardMessagesModalActionType
|
| ToggleForwardMessagesModalActionType
|
||||||
| ToggleNotePreviewModalActionType
|
| ToggleNotePreviewModalActionType
|
||||||
|
@ -426,6 +436,7 @@ export const actions = {
|
||||||
toggleCallLinkAddNameModal,
|
toggleCallLinkAddNameModal,
|
||||||
toggleCallLinkEditModal,
|
toggleCallLinkEditModal,
|
||||||
toggleConfirmationModal,
|
toggleConfirmationModal,
|
||||||
|
toggleConfirmLeaveCallModal,
|
||||||
toggleDeleteMessagesModal,
|
toggleDeleteMessagesModal,
|
||||||
toggleForwardMessagesModal,
|
toggleForwardMessagesModal,
|
||||||
toggleNotePreviewModal,
|
toggleNotePreviewModal,
|
||||||
|
@ -682,6 +693,15 @@ function showShareCallLinkViaSignal(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toggleConfirmLeaveCallModal(
|
||||||
|
payload: StartCallData | null
|
||||||
|
): ToggleConfirmLeaveCallModalActionType {
|
||||||
|
return {
|
||||||
|
type: TOGGLE_CONFIRM_LEAVE_CALL_MODAL,
|
||||||
|
payload,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function toggleNotePreviewModal(
|
function toggleNotePreviewModal(
|
||||||
payload: NotePreviewModalPropsType | null
|
payload: NotePreviewModalPropsType | null
|
||||||
): ToggleNotePreviewModalActionType {
|
): ToggleNotePreviewModalActionType {
|
||||||
|
@ -954,6 +974,7 @@ export function getEmptyState(): GlobalModalsStateType {
|
||||||
hasConfirmationModal: false,
|
hasConfirmationModal: false,
|
||||||
callLinkAddNameModalRoomId: null,
|
callLinkAddNameModalRoomId: null,
|
||||||
callLinkEditModalRoomId: null,
|
callLinkEditModalRoomId: null,
|
||||||
|
confirmLeaveCallModalState: null,
|
||||||
editNicknameAndNoteModalProps: null,
|
editNicknameAndNoteModalProps: null,
|
||||||
isProfileEditorVisible: false,
|
isProfileEditorVisible: false,
|
||||||
isShortcutGuideModalVisible: false,
|
isShortcutGuideModalVisible: false,
|
||||||
|
@ -979,6 +1000,13 @@ export function reducer(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action.type === TOGGLE_CONFIRM_LEAVE_CALL_MODAL) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
confirmLeaveCallModalState: action.payload,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (action.type === TOGGLE_NOTE_PREVIEW_MODAL) {
|
if (action.type === TOGGLE_NOTE_PREVIEW_MODAL) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|
|
@ -32,6 +32,11 @@ export const getCallLinkAddNameModalRoomId = createSelector(
|
||||||
({ callLinkAddNameModalRoomId }) => callLinkAddNameModalRoomId
|
({ callLinkAddNameModalRoomId }) => callLinkAddNameModalRoomId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getConfirmLeaveCallModalState = createSelector(
|
||||||
|
getGlobalModalsState,
|
||||||
|
({ confirmLeaveCallModalState }) => confirmLeaveCallModalState
|
||||||
|
);
|
||||||
|
|
||||||
export const getContactModalState = createSelector(
|
export const getContactModalState = createSelector(
|
||||||
getGlobalModalsState,
|
getGlobalModalsState,
|
||||||
({ contactModalState }) => contactModalState
|
({ contactModalState }) => contactModalState
|
||||||
|
|
|
@ -172,7 +172,8 @@ export const SmartCallsTab = memo(function SmartCallsTab() {
|
||||||
markCallHistoryRead,
|
markCallHistoryRead,
|
||||||
markCallsTabViewed,
|
markCallsTabViewed,
|
||||||
} = useCallHistoryActions();
|
} = useCallHistoryActions();
|
||||||
const { toggleCallLinkEditModal } = useGlobalModalActions();
|
const { toggleCallLinkEditModal, toggleConfirmLeaveCallModal } =
|
||||||
|
useGlobalModalActions();
|
||||||
|
|
||||||
const getCallHistoryGroupsCount = useCallback(
|
const getCallHistoryGroupsCount = useCallback(
|
||||||
async (options: CallHistoryFilterOptions) => {
|
async (options: CallHistoryFilterOptions) => {
|
||||||
|
@ -257,6 +258,7 @@ export const SmartCallsTab = memo(function SmartCallsTab() {
|
||||||
regionCode={regionCode}
|
regionCode={regionCode}
|
||||||
savePreferredLeftPaneWidth={savePreferredLeftPaneWidth}
|
savePreferredLeftPaneWidth={savePreferredLeftPaneWidth}
|
||||||
startCallLinkLobbyByRoomId={startCallLinkLobbyByRoomId}
|
startCallLinkLobbyByRoomId={startCallLinkLobbyByRoomId}
|
||||||
|
toggleConfirmLeaveCallModal={toggleConfirmLeaveCallModal}
|
||||||
togglePip={togglePip}
|
togglePip={togglePip}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
37
ts/state/smart/ConfirmLeaveCallModal.tsx
Normal file
37
ts/state/smart/ConfirmLeaveCallModal.tsx
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright 2024 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import React, { memo } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { useCallingActions } from '../ducks/calling';
|
||||||
|
import { getIntl } from '../selectors/user';
|
||||||
|
import { useGlobalModalActions } from '../ducks/globalModals';
|
||||||
|
import { getConfirmLeaveCallModalState } from '../selectors/globalModals';
|
||||||
|
import { ConfirmLeaveCallModal } from '../../components/ConfirmLeaveCallModal';
|
||||||
|
|
||||||
|
export const SmartConfirmLeaveCallModal = memo(
|
||||||
|
function SmartConfirmLeaveCallModal(): JSX.Element | null {
|
||||||
|
const i18n = useSelector(getIntl);
|
||||||
|
const confirmLeaveCallModalState = useSelector(
|
||||||
|
getConfirmLeaveCallModalState
|
||||||
|
);
|
||||||
|
|
||||||
|
const { leaveCurrentCallAndStartCallingLobby } = useCallingActions();
|
||||||
|
const { toggleConfirmLeaveCallModal } = useGlobalModalActions();
|
||||||
|
|
||||||
|
if (!confirmLeaveCallModalState) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmLeaveCallModal
|
||||||
|
i18n={i18n}
|
||||||
|
data={confirmLeaveCallModalState}
|
||||||
|
leaveCurrentCallAndStartCallingLobby={
|
||||||
|
leaveCurrentCallAndStartCallingLobby
|
||||||
|
}
|
||||||
|
toggleConfirmLeaveCallModal={toggleConfirmLeaveCallModal}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
|
@ -28,6 +28,7 @@ import { SmartEditNicknameAndNoteModal } from './EditNicknameAndNoteModal';
|
||||||
import { SmartNotePreviewModal } from './NotePreviewModal';
|
import { SmartNotePreviewModal } from './NotePreviewModal';
|
||||||
import { SmartCallLinkEditModal } from './CallLinkEditModal';
|
import { SmartCallLinkEditModal } from './CallLinkEditModal';
|
||||||
import { SmartCallLinkAddNameModal } from './CallLinkAddNameModal';
|
import { SmartCallLinkAddNameModal } from './CallLinkAddNameModal';
|
||||||
|
import { SmartConfirmLeaveCallModal } from './ConfirmLeaveCallModal';
|
||||||
|
|
||||||
function renderCallLinkAddNameModal(): JSX.Element {
|
function renderCallLinkAddNameModal(): JSX.Element {
|
||||||
return <SmartCallLinkAddNameModal />;
|
return <SmartCallLinkAddNameModal />;
|
||||||
|
@ -37,6 +38,10 @@ function renderCallLinkEditModal(): JSX.Element {
|
||||||
return <SmartCallLinkEditModal />;
|
return <SmartCallLinkEditModal />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderConfirmLeaveCallModal(): JSX.Element {
|
||||||
|
return <SmartConfirmLeaveCallModal />;
|
||||||
|
}
|
||||||
|
|
||||||
function renderEditHistoryMessagesModal(): JSX.Element {
|
function renderEditHistoryMessagesModal(): JSX.Element {
|
||||||
return <SmartEditHistoryMessagesModal />;
|
return <SmartEditHistoryMessagesModal />;
|
||||||
}
|
}
|
||||||
|
@ -102,6 +107,7 @@ export const SmartGlobalModalContainer = memo(
|
||||||
addUserToAnotherGroupModalContactId,
|
addUserToAnotherGroupModalContactId,
|
||||||
callLinkAddNameModalRoomId,
|
callLinkAddNameModalRoomId,
|
||||||
callLinkEditModalRoomId,
|
callLinkEditModalRoomId,
|
||||||
|
confirmLeaveCallModalState,
|
||||||
contactModalState,
|
contactModalState,
|
||||||
deleteMessagesProps,
|
deleteMessagesProps,
|
||||||
editHistoryMessages,
|
editHistoryMessages,
|
||||||
|
@ -182,6 +188,7 @@ export const SmartGlobalModalContainer = memo(
|
||||||
}
|
}
|
||||||
callLinkAddNameModalRoomId={callLinkAddNameModalRoomId}
|
callLinkAddNameModalRoomId={callLinkAddNameModalRoomId}
|
||||||
callLinkEditModalRoomId={callLinkEditModalRoomId}
|
callLinkEditModalRoomId={callLinkEditModalRoomId}
|
||||||
|
confirmLeaveCallModalState={confirmLeaveCallModalState}
|
||||||
contactModalState={contactModalState}
|
contactModalState={contactModalState}
|
||||||
editHistoryMessages={editHistoryMessages}
|
editHistoryMessages={editHistoryMessages}
|
||||||
editNicknameAndNoteModalProps={editNicknameAndNoteModalProps}
|
editNicknameAndNoteModalProps={editNicknameAndNoteModalProps}
|
||||||
|
@ -206,6 +213,7 @@ export const SmartGlobalModalContainer = memo(
|
||||||
renderAddUserToAnotherGroup={renderAddUserToAnotherGroup}
|
renderAddUserToAnotherGroup={renderAddUserToAnotherGroup}
|
||||||
renderCallLinkAddNameModal={renderCallLinkAddNameModal}
|
renderCallLinkAddNameModal={renderCallLinkAddNameModal}
|
||||||
renderCallLinkEditModal={renderCallLinkEditModal}
|
renderCallLinkEditModal={renderCallLinkEditModal}
|
||||||
|
renderConfirmLeaveCallModal={renderConfirmLeaveCallModal}
|
||||||
renderContactModal={renderContactModal}
|
renderContactModal={renderContactModal}
|
||||||
renderEditHistoryMessagesModal={renderEditHistoryMessagesModal}
|
renderEditHistoryMessagesModal={renderEditHistoryMessagesModal}
|
||||||
renderEditNicknameAndNoteModal={renderEditNicknameAndNoteModal}
|
renderEditNicknameAndNoteModal={renderEditNicknameAndNoteModal}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue