View contact modal from call participants list

This commit is contained in:
ayumi-signal 2024-06-18 09:15:56 -07:00 committed by GitHub
parent 49a6fa6007
commit 378bd7487f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 233 additions and 62 deletions

View file

@ -3686,6 +3686,10 @@
"messageformat": "A window", "messageformat": "A window",
"description": "Title for the select your screen sharing sources modal" "description": "Title for the select your screen sharing sources modal"
}, },
"icu:calling__ParticipantInfoButton": {
"messageformat": "More info about this contact",
"description": "Aria label for clickable contact info button in the in-call participant info popup. When clicked a popup appears with the contact's details and options to message them."
},
"icu:CallingAdhocCallInfo__CopyLink": { "icu:CallingAdhocCallInfo__CopyLink": {
"messageformat": "Copy call link", "messageformat": "Copy call link",
"description": "Menu item in the in-call info popup for call link calls. The action is to add the call link to the clipboard." "description": "Menu item in the in-call info popup for call link calls. The action is to add the call link to the clipboard."
@ -4666,6 +4670,10 @@
"messageformat": "Remove from group", "messageformat": "Remove from group",
"description": "Button text for remove from group button in Group Contact Details modal" "description": "Button text for remove from group button in Group Contact Details modal"
}, },
"icu:ContactModal--already-in-call": {
"messageformat": "You are already in a call",
"description": "Tooltip text for video or audio call button in Contact Details modal"
},
"icu:showChatColorEditor": { "icu:showChatColorEditor": {
"messageformat": "Chat color", "messageformat": "Chat color",
"description": "This is a button in the conversation context menu to show the chat color editor" "description": "This is a button in the conversation context menu to show the chat color editor"

View file

@ -4450,17 +4450,23 @@ button.module-image__border-overlay:focus {
&__contact { &__contact {
@include font-body-1; @include font-body-1;
@include button-reset;
display: flex; display: flex;
align-items: center; align-items: center;
width: 100%;
margin-block: 2px; margin-block: 2px;
padding-block: 8px; padding-block: 8px;
padding-inline-start: 10px; padding-inline-start: 10px;
padding-inline-end: 2px; padding-inline-end: 2px;
list-style-type: none; list-style-type: none;
border-radius: 6px; border-radius: 6px;
cursor: auto;
&:hover { &:hover {
background-color: $color-gray-62; background-color: $color-gray-62;
} }
&[disabled] {
cursor: auto;
}
} }
&__avatar-and-name { &__avatar-and-name {
@ -4551,6 +4557,10 @@ button.module-image__border-overlay:focus {
} }
} }
button.module-calling-participants-list__contact {
cursor: pointer;
}
.module-call-need-permission-screen { .module-call-need-permission-screen {
align-items: center; align-items: center;
background-color: $color-gray-95; background-color: $color-gray-95;

View file

@ -309,4 +309,8 @@
margin-block: 8px 5px; margin-block: 8px 5px;
} }
&__tooltip {
@include tooltip;
}
} }

View file

@ -113,6 +113,7 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
setPresenting: action('toggle-presenting'), setPresenting: action('toggle-presenting'),
setRendererCanvas: action('set-renderer-canvas'), setRendererCanvas: action('set-renderer-canvas'),
setOutgoingRing: action('set-outgoing-ring'), setOutgoingRing: action('set-outgoing-ring'),
showContactModal: action('show-contact-modal'),
showShareCallLinkViaSignal: action('show-share-call-link-via-signal'), showShareCallLinkViaSignal: action('show-share-call-link-via-signal'),
startCall: action('start-call'), startCall: action('start-call'),
stopRingtone: action('stop-ringtone'), stopRingtone: action('stop-ringtone'),

View file

@ -96,6 +96,7 @@ export type PropsType = {
renderReactionPicker: ( renderReactionPicker: (
props: React.ComponentProps<typeof SmartReactionPicker> props: React.ComponentProps<typeof SmartReactionPicker>
) => JSX.Element; ) => JSX.Element;
showContactModal: (contactId: string, conversationId?: string) => void;
startCall: (payload: StartCallType) => void; startCall: (payload: StartCallType) => void;
toggleParticipants: () => void; toggleParticipants: () => void;
acceptCall: (_: AcceptCallType) => void; acceptCall: (_: AcceptCallType) => void;
@ -188,6 +189,7 @@ function ActiveCallManager({
setPresenting, setPresenting,
setRendererCanvas, setRendererCanvas,
setOutgoingRing, setOutgoingRing,
showContactModal,
showShareCallLinkViaSignal, showShareCallLinkViaSignal,
startCall, startCall,
switchToPresentationView, switchToPresentationView,
@ -395,13 +397,16 @@ function ActiveCallManager({
onCopyCallLink={onCopyCallLink} onCopyCallLink={onCopyCallLink}
onShareCallLinkViaSignal={handleShareCallLinkViaSignal} onShareCallLinkViaSignal={handleShareCallLinkViaSignal}
removeClient={removeClient} removeClient={removeClient}
showContactModal={showContactModal}
/> />
) : ( ) : (
<CallingParticipantsList <CallingParticipantsList
conversationId={conversation.id}
i18n={i18n} i18n={i18n}
onClose={toggleParticipants} onClose={toggleParticipants}
ourServiceId={me.serviceId} ourServiceId={me.serviceId}
participants={peekedParticipants} participants={peekedParticipants}
showContactModal={showContactModal}
/> />
))} ))}
</> </>
@ -489,13 +494,16 @@ function ActiveCallManager({
onCopyCallLink={onCopyCallLink} onCopyCallLink={onCopyCallLink}
onShareCallLinkViaSignal={handleShareCallLinkViaSignal} onShareCallLinkViaSignal={handleShareCallLinkViaSignal}
removeClient={removeClient} removeClient={removeClient}
showContactModal={showContactModal}
/> />
) : ( ) : (
<CallingParticipantsList <CallingParticipantsList
conversationId={conversation.id}
i18n={i18n} i18n={i18n}
onClose={toggleParticipants} onClose={toggleParticipants}
ourServiceId={me.serviceId} ourServiceId={me.serviceId}
participants={groupCallParticipantsForParticipantsList} participants={groupCallParticipantsForParticipantsList}
showContactModal={showContactModal}
/> />
))} ))}
</> </>
@ -543,6 +551,7 @@ export function CallManager({
setOutgoingRing, setOutgoingRing,
setPresenting, setPresenting,
setRendererCanvas, setRendererCanvas,
showContactModal,
showShareCallLinkViaSignal, showShareCallLinkViaSignal,
startCall, startCall,
stopRingtone, stopRingtone,
@ -633,6 +642,7 @@ export function CallManager({
setOutgoingRing={setOutgoingRing} setOutgoingRing={setOutgoingRing}
setPresenting={setPresenting} setPresenting={setPresenting}
setRendererCanvas={setRendererCanvas} setRendererCanvas={setRendererCanvas}
showContactModal={showContactModal}
showShareCallLinkViaSignal={showShareCallLinkViaSignal} showShareCallLinkViaSignal={showShareCallLinkViaSignal}
startCall={startCall} startCall={startCall}
switchFromPresentationView={switchFromPresentationView} switchFromPresentationView={switchFromPresentationView}

View file

@ -68,6 +68,7 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
onCopyCallLink: action('on-copy-call-link'), onCopyCallLink: action('on-copy-call-link'),
onShareCallLinkViaSignal: action('on-share-call-link-via-signal'), onShareCallLinkViaSignal: action('on-share-call-link-via-signal'),
removeClient: overrideProps.removeClient || action('remove-client'), removeClient: overrideProps.removeClient || action('remove-client'),
showContactModal: action('show-contact-modal'),
}); });
export default { export default {

View file

@ -41,6 +41,10 @@ export type PropsType = {
readonly onCopyCallLink: () => void; readonly onCopyCallLink: () => void;
readonly onShareCallLinkViaSignal: () => void; readonly onShareCallLinkViaSignal: () => void;
readonly removeClient: ((payload: RemoveClientType) => void) | null; readonly removeClient: ((payload: RemoveClientType) => void) | null;
readonly showContactModal: (
contactId: string,
conversationId?: string
) => void;
}; };
type UnknownContactsPropsType = { type UnknownContactsPropsType = {
@ -145,6 +149,7 @@ export function CallingAdhocCallInfo({
onCopyCallLink, onCopyCallLink,
onShareCallLinkViaSignal, onShareCallLinkViaSignal,
removeClient, removeClient,
showContactModal,
}: PropsType): JSX.Element | null { }: PropsType): JSX.Element | null {
const [isUnknownContactDialogVisible, setIsUnknownContactDialogVisible] = const [isUnknownContactDialogVisible, setIsUnknownContactDialogVisible] =
React.useState(false); React.useState(false);
@ -173,12 +178,23 @@ export function CallingAdhocCallInfo({
const renderParticipant = React.useCallback( const renderParticipant = React.useCallback(
(participant: ParticipantType, key: React.Key) => ( (participant: ParticipantType, key: React.Key) => (
<li <button
aria-label={i18n('icu:calling__ParticipantInfoButton')}
className="module-calling-participants-list__contact" className="module-calling-participants-list__contact"
disabled={participant.isMe}
// It's tempting to use `participant.serviceId` as the `key` // It's tempting to use `participant.serviceId` as the `key`
// here, but that can result in duplicate keys for // here, but that can result in duplicate keys for
// participants who have joined on multiple devices. // participants who have joined on multiple devices.
key={key} key={key}
onClick={() => {
if (participant.isMe) {
return;
}
onClose();
showContactModal(participant.id);
}}
type="button"
> >
<div className="module-calling-participants-list__avatar-and-name"> <div className="module-calling-participants-list__avatar-and-name">
<Avatar <Avatar
@ -250,18 +266,28 @@ export function CallingAdhocCallInfo({
'module-calling-participants-list__status-icon', 'module-calling-participants-list__status-icon',
'module-calling-participants-list__remove' 'module-calling-participants-list__remove'
)} )}
onClick={() => { onClick={event => {
if (!participant.demuxId) { if (!participant.demuxId) {
return; return;
} }
event.stopPropagation();
event.preventDefault();
removeClient({ demuxId: participant.demuxId }); removeClient({ demuxId: participant.demuxId });
}} }}
type="button" type="button"
/> />
) : null} ) : null}
</li> </button>
), ),
[i18n, isCallLinkAdmin, ourServiceId, removeClient] [
i18n,
isCallLinkAdmin,
onClose,
ourServiceId,
removeClient,
showContactModal,
]
); );
return ( return (

View file

@ -43,9 +43,11 @@ function createParticipant(
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
i18n, i18n,
conversationId: 'fake-conversation-id',
onClose: action('on-close'), onClose: action('on-close'),
ourServiceId: generateAci(), ourServiceId: generateAci(),
participants: overrideProps.participants || [], participants: overrideProps.participants || [],
showContactModal: action('show-contact-modal'),
}); });
export default { export default {

View file

@ -26,18 +26,25 @@ type ParticipantType = ConversationType & {
}; };
export type PropsType = { export type PropsType = {
readonly conversationId: string;
readonly i18n: LocalizerType; readonly i18n: LocalizerType;
readonly onClose: () => void; readonly onClose: () => void;
readonly ourServiceId: ServiceIdString | undefined; readonly ourServiceId: ServiceIdString | undefined;
readonly participants: Array<ParticipantType>; readonly participants: Array<ParticipantType>;
readonly showContactModal: (
contactId: string,
conversationId?: string
) => void;
}; };
export const CallingParticipantsList = React.memo( export const CallingParticipantsList = React.memo(
function CallingParticipantsListInner({ function CallingParticipantsListInner({
conversationId,
i18n, i18n,
onClose, onClose,
ourServiceId, ourServiceId,
participants, participants,
showContactModal,
}: PropsType) { }: PropsType) {
const [root, setRoot] = React.useState<HTMLElement | null>(null); const [root, setRoot] = React.useState<HTMLElement | null>(null);
@ -96,15 +103,26 @@ export const CallingParticipantsList = React.memo(
aria-label={i18n('icu:close')} aria-label={i18n('icu:close')}
/> />
</div> </div>
<ul className="module-calling-participants-list__list"> <div className="module-calling-participants-list__list">
{sortedParticipants.map( {sortedParticipants.map(
(participant: ParticipantType, index: number) => ( (participant: ParticipantType, index: number) => (
<li <button
aria-label={i18n('icu:calling__ParticipantInfoButton')}
className="module-calling-participants-list__contact" className="module-calling-participants-list__contact"
disabled={participant.isMe}
// It's tempting to use `participant.serviceId` as the `key` // It's tempting to use `participant.serviceId` as the `key`
// here, but that can result in duplicate keys for // here, but that can result in duplicate keys for
// participants who have joined on multiple devices. // participants who have joined on multiple devices.
key={index} key={index}
onClick={() => {
if (participant.isMe) {
return;
}
onClose();
showContactModal(participant.id, conversationId);
}}
type="button"
> >
<div className="module-calling-participants-list__avatar-and-name"> <div className="module-calling-participants-list__avatar-and-name">
<Avatar <Avatar
@ -165,10 +183,10 @@ export const CallingParticipantsList = React.memo(
'module-calling-participants-list__muted--audio' 'module-calling-participants-list__muted--audio'
)} )}
/> />
</li> </button>
) )
)} )}
</ul> </div>
</div> </div>
</div> </div>
</FocusTrap>, </FocusTrap>,

View file

@ -26,6 +26,9 @@ import { Button, ButtonIconType, ButtonVariant } from '../Button';
import { isInSystemContacts } from '../../util/isInSystemContacts'; import { isInSystemContacts } from '../../util/isInSystemContacts';
import { InContactsIcon } from '../InContactsIcon'; import { InContactsIcon } from '../InContactsIcon';
import { canHaveNicknameAndNote } from '../../util/nicknames'; import { canHaveNicknameAndNote } from '../../util/nicknames';
import { Tooltip, TooltipPlacement } from '../Tooltip';
import { offsetDistanceModifier } from '../../util/popperUtil';
import { getThemeByThemeType } from '../../util/theme';
export type PropsDataType = { export type PropsDataType = {
areWeASubscriber: boolean; areWeASubscriber: boolean;
@ -39,6 +42,7 @@ export type PropsDataType = {
isMember: boolean; isMember: boolean;
theme: ThemeType; theme: ThemeType;
hasActiveCall: boolean; hasActiveCall: boolean;
isInFullScreenCall: boolean;
}; };
type PropsActionType = { type PropsActionType = {
@ -51,6 +55,7 @@ type PropsActionType = {
showConversation: ShowConversationType; showConversation: ShowConversationType;
toggleAdmin: (conversationId: string, contactId: string) => void; toggleAdmin: (conversationId: string, contactId: string) => void;
toggleAboutContactModal: (conversationId: string) => unknown; toggleAboutContactModal: (conversationId: string) => unknown;
togglePip: () => void;
toggleSafetyNumberModal: (conversationId: string) => unknown; toggleSafetyNumberModal: (conversationId: string) => unknown;
toggleAddUserToAnotherGroupModal: (conversationId: string) => void; toggleAddUserToAnotherGroupModal: (conversationId: string) => void;
updateConversationModelSharedGroups: (conversationId: string) => void; updateConversationModelSharedGroups: (conversationId: string) => void;
@ -82,6 +87,7 @@ export function ContactModal({
hasActiveCall, hasActiveCall,
hasStories, hasStories,
hideContactModal, hideContactModal,
isInFullScreenCall,
i18n, i18n,
isAdmin, isAdmin,
isMember, isMember,
@ -94,6 +100,7 @@ export function ContactModal({
toggleAboutContactModal, toggleAboutContactModal,
toggleAddUserToAnotherGroupModal, toggleAddUserToAnotherGroupModal,
toggleAdmin, toggleAdmin,
togglePip,
toggleSafetyNumberModal, toggleSafetyNumberModal,
updateConversationModelSharedGroups, updateConversationModelSharedGroups,
viewUserStories, viewUserStories,
@ -106,6 +113,7 @@ export function ContactModal({
const [subModalState, setSubModalState] = useState<SubModalState>( const [subModalState, setSubModalState] = useState<SubModalState>(
SubModalState.None SubModalState.None
); );
const modalTheme = getThemeByThemeType(theme);
useEffect(() => { useEffect(() => {
if (contact?.id) { if (contact?.id) {
@ -114,6 +122,94 @@ export function ContactModal({
} }
}, [contact?.id, updateConversationModelSharedGroups]); }, [contact?.id, updateConversationModelSharedGroups]);
const renderQuickActions = React.useCallback(
(conversationId: string) => {
const videoCallButton = (
<Button
icon={ButtonIconType.video}
variant={ButtonVariant.Details}
disabled={hasActiveCall}
onClick={() => {
hideContactModal();
onOutgoingVideoCallInConversation(conversationId);
}}
>
{i18n('icu:video')}
</Button>
);
const audioCallButton = (
<Button
icon={ButtonIconType.audio}
variant={ButtonVariant.Details}
disabled={hasActiveCall}
onClick={() => {
hideContactModal();
onOutgoingAudioCallInConversation(conversationId);
}}
>
{i18n('icu:audio')}
</Button>
);
return (
<div className="ContactModal__quick-actions">
<Button
icon={ButtonIconType.message}
variant={ButtonVariant.Details}
onClick={() => {
hideContactModal();
showConversation({
conversationId,
switchToAssociatedView: true,
});
if (isInFullScreenCall) {
togglePip();
}
}}
>
{i18n('icu:ConversationDetails__HeaderButton--Message')}
</Button>
{hasActiveCall ? (
<Tooltip
className="ContactModal__tooltip"
wrapperClassName="ContactModal__tooltip-wrapper"
content={i18n('icu:ContactModal--already-in-call')}
direction={TooltipPlacement.Top}
popperModifiers={[offsetDistanceModifier(5)]}
>
{videoCallButton}
</Tooltip>
) : (
videoCallButton
)}
{hasActiveCall ? (
<Tooltip
className="ContactModal__tooltip"
wrapperClassName="ContactModal__tooltip-wrapper"
content={i18n('icu:ContactModal--already-in-call')}
direction={TooltipPlacement.Top}
popperModifiers={[offsetDistanceModifier(5)]}
>
{audioCallButton}
</Tooltip>
) : (
audioCallButton
)}
</div>
);
},
[
hasActiveCall,
hideContactModal,
i18n,
isInFullScreenCall,
onOutgoingAudioCallInConversation,
onOutgoingVideoCallInConversation,
showConversation,
togglePip,
]
);
let modalNode: ReactNode; let modalNode: ReactNode;
switch (subModalState) { switch (subModalState) {
case SubModalState.None: case SubModalState.None:
@ -213,6 +309,7 @@ export function ContactModal({
i18n={i18n} i18n={i18n}
onClose={hideContactModal} onClose={hideContactModal}
padded={false} padded={false}
theme={modalTheme}
> >
<div className="ContactModal"> <div className="ContactModal">
<Avatar <Avatar
@ -265,45 +362,7 @@ export function ContactModal({
</div> </div>
<i className="ContactModal__name__chevron" /> <i className="ContactModal__name__chevron" />
</button> </button>
{!contact.isMe && ( {!contact.isMe && renderQuickActions(contact.id)}
<div className="ContactModal__quick-actions">
<Button
icon={ButtonIconType.message}
variant={ButtonVariant.Details}
onClick={() => {
hideContactModal();
showConversation({
conversationId: contact?.id,
switchToAssociatedView: true,
});
}}
>
{i18n('icu:ConversationDetails__HeaderButton--Message')}
</Button>
<Button
icon={ButtonIconType.video}
variant={ButtonVariant.Details}
disabled={hasActiveCall}
onClick={() => {
hideContactModal();
onOutgoingVideoCallInConversation(contact.id);
}}
>
{i18n('icu:video')}
</Button>
<Button
icon={ButtonIconType.audio}
variant={ButtonVariant.Details}
disabled={hasActiveCall}
onClick={() => {
hideContactModal();
onOutgoingAudioCallInConversation(contact.id);
}}
>
{i18n('icu:audio')}
</Button>
</div>
)}
<div className="ContactModal__divider" /> <div className="ContactModal__divider" />
<div className="ContactModal__button-container"> <div className="ContactModal__button-container">
{canHaveNicknameAndNote(contact) && ( {canHaveNicknameAndNote(contact) && (
@ -319,20 +378,32 @@ export function ContactModal({
</button> </button>
)} )}
{!contact.isMe && ( {!contact.isMe &&
<button (contact.isBlocked ? (
type="button" <div className="ContactModal__button ContactModal__block">
className="ContactModal__button ContactModal__block" <div className="ContactModal__bubble-icon">
onClick={() => <div className="ContactModal__block__bubble-icon" />
setSubModalState(SubModalState.ConfirmingBlock) </div>
} <span>
> {i18n('icu:AboutContactModal__blocked', {
<div className="ContactModal__bubble-icon"> name: contact.title,
<div className="ContactModal__block__bubble-icon" /> })}
</span>
</div> </div>
<span>{i18n('icu:MessageRequests--block')}</span> ) : (
</button> <button
)} type="button"
className="ContactModal__button ContactModal__block"
onClick={() =>
setSubModalState(SubModalState.ConfirmingBlock)
}
>
<div className="ContactModal__bubble-icon">
<div className="ContactModal__block__bubble-icon" />
</div>
<span>{i18n('icu:MessageRequests--block')}</span>
</button>
))}
{!contact.isMe && ( {!contact.isMe && (
<button <button
type="button" type="button"

View file

@ -455,7 +455,8 @@ export const SmartCallManager = memo(function SmartCallManager() {
toggleSettings, toggleSettings,
} = useCallingActions(); } = useCallingActions();
const { pauseVoiceNotePlayer } = useAudioPlayerActions(); const { pauseVoiceNotePlayer } = useAudioPlayerActions();
const { showShareCallLinkViaSignal } = useGlobalModalActions(); const { showContactModal, showShareCallLinkViaSignal } =
useGlobalModalActions();
return ( return (
<CallManager <CallManager
@ -501,6 +502,7 @@ export const SmartCallManager = memo(function SmartCallManager() {
setOutgoingRing={setOutgoingRing} setOutgoingRing={setOutgoingRing}
setPresenting={setPresenting} setPresenting={setPresenting}
setRendererCanvas={setRendererCanvas} setRendererCanvas={setRendererCanvas}
showContactModal={showContactModal}
showShareCallLinkViaSignal={showShareCallLinkViaSignal} showShareCallLinkViaSignal={showShareCallLinkViaSignal}
startCall={startCall} startCall={startCall}
stopRingtone={stopRingtone} stopRingtone={stopRingtone}

View file

@ -9,7 +9,10 @@ import { getIntl, getTheme } from '../selectors/user';
import { getBadgesSelector } from '../selectors/badges'; import { getBadgesSelector } from '../selectors/badges';
import { getConversationSelector } from '../selectors/conversations'; import { getConversationSelector } from '../selectors/conversations';
import { getHasStoriesSelector } from '../selectors/stories2'; import { getHasStoriesSelector } from '../selectors/stories2';
import { getActiveCallState } from '../selectors/calling'; import {
getActiveCallState,
isInFullScreenCall as getIsInFullScreenCall,
} from '../selectors/calling';
import { useStoriesActions } from '../ducks/stories'; import { useStoriesActions } from '../ducks/stories';
import { useConversationsActions } from '../ducks/conversations'; import { useConversationsActions } from '../ducks/conversations';
import { useGlobalModalActions } from '../ducks/globalModals'; import { useGlobalModalActions } from '../ducks/globalModals';
@ -24,6 +27,7 @@ export const SmartContactModal = memo(function SmartContactModal() {
const conversationSelector = useSelector(getConversationSelector); const conversationSelector = useSelector(getConversationSelector);
const hasStoriesSelector = useSelector(getHasStoriesSelector); const hasStoriesSelector = useSelector(getHasStoriesSelector);
const activeCallState = useSelector(getActiveCallState); const activeCallState = useSelector(getActiveCallState);
const isInFullScreenCall = useSelector(getIsInFullScreenCall);
const badgesSelector = useSelector(getBadgesSelector); const badgesSelector = useSelector(getBadgesSelector);
const areWeASubscriber = useSelector(getAreWeASubscriber); const areWeASubscriber = useSelector(getAreWeASubscriber);
@ -62,6 +66,7 @@ export const SmartContactModal = memo(function SmartContactModal() {
const { const {
onOutgoingVideoCallInConversation, onOutgoingVideoCallInConversation,
onOutgoingAudioCallInConversation, onOutgoingAudioCallInConversation,
togglePip,
} = useCallingActions(); } = useCallingActions();
const handleOpenEditNicknameAndNoteModal = useCallback(() => { const handleOpenEditNicknameAndNoteModal = useCallback(() => {
@ -82,6 +87,7 @@ export const SmartContactModal = memo(function SmartContactModal() {
hideContactModal={hideContactModal} hideContactModal={hideContactModal}
i18n={i18n} i18n={i18n}
isAdmin={isAdmin} isAdmin={isAdmin}
isInFullScreenCall={isInFullScreenCall}
isMember={isMember} isMember={isMember}
onOpenEditNicknameAndNoteModal={handleOpenEditNicknameAndNoteModal} onOpenEditNicknameAndNoteModal={handleOpenEditNicknameAndNoteModal}
onOutgoingAudioCallInConversation={onOutgoingAudioCallInConversation} onOutgoingAudioCallInConversation={onOutgoingAudioCallInConversation}
@ -92,6 +98,7 @@ export const SmartContactModal = memo(function SmartContactModal() {
toggleAboutContactModal={toggleAboutContactModal} toggleAboutContactModal={toggleAboutContactModal}
toggleAddUserToAnotherGroupModal={toggleAddUserToAnotherGroupModal} toggleAddUserToAnotherGroupModal={toggleAddUserToAnotherGroupModal}
toggleAdmin={toggleAdmin} toggleAdmin={toggleAdmin}
togglePip={togglePip}
toggleSafetyNumberModal={toggleSafetyNumberModal} toggleSafetyNumberModal={toggleSafetyNumberModal}
updateConversationModelSharedGroups={updateConversationModelSharedGroups} updateConversationModelSharedGroups={updateConversationModelSharedGroups}
viewUserStories={viewUserStories} viewUserStories={viewUserStories}

View file

@ -30,3 +30,14 @@ export function themeClassName2(theme: ThemeType): string {
throw missingCaseError(theme); throw missingCaseError(theme);
} }
} }
export function getThemeByThemeType(theme: ThemeType): Theme {
switch (theme) {
case ThemeType.light:
return Theme.Light;
case ThemeType.dark:
return Theme.Dark;
default:
throw missingCaseError(theme);
}
}