cleanup props passing of avatar and name with a custom hook

pull/2045/head
Audric Ackermann 4 years ago
parent 5ba7f20162
commit 894349e710
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -5,6 +5,7 @@ import { AvatarPlaceHolder, ClosedGroupAvatar } from './AvatarPlaceHolder';
import { useEncryptedFileFetch } from '../hooks/useEncryptedFileFetch'; import { useEncryptedFileFetch } from '../hooks/useEncryptedFileFetch';
import _ from 'underscore'; import _ from 'underscore';
import { useMembersAvatars } from '../hooks/useMembersAvatars'; import { useMembersAvatars } from '../hooks/useMembersAvatars';
import { useAvatarPath, useConversationUsername } from '../hooks/useParamSelector';
export enum AvatarSize { export enum AvatarSize {
XS = 28, XS = 28,
@ -16,8 +17,8 @@ export enum AvatarSize {
} }
type Props = { type Props = {
avatarPath?: string | null; forcedAvatarPath?: string | null;
name?: string; // display name, profileName or pubkey, whatever is set first forcedName?: string;
pubkey?: string; pubkey?: string;
size: AvatarSize; size: AvatarSize;
base64Data?: string; // if this is not empty, it will be used to render the avatar with base64 encoded data base64Data?: string; // if this is not empty, it will be used to render the avatar with base64 encoded data
@ -26,8 +27,8 @@ type Props = {
}; };
const Identicon = (props: Props) => { const Identicon = (props: Props) => {
const { size, name, pubkey } = props; const { size, forcedName, pubkey } = props;
const userName = name || '0'; const userName = forcedName || '0';
return ( return (
<AvatarPlaceHolder <AvatarPlaceHolder
@ -40,14 +41,12 @@ const Identicon = (props: Props) => {
); );
}; };
const NoImage = (props: { const NoImage = (
name?: string; props: Pick<Props, 'forcedName' | 'size' | 'pubkey' | 'onAvatarClick'> & {
pubkey?: string; isClosedGroup: boolean;
size: AvatarSize; }
isClosedGroup: boolean; ) => {
onAvatarClick?: () => void; const { forcedName, size, pubkey, isClosedGroup } = props;
}) => {
const { name, size, pubkey, isClosedGroup } = props;
// if no image but we have conversations set for the group, renders group members avatars // if no image but we have conversations set for the group, renders group members avatars
if (pubkey && isClosedGroup) { if (pubkey && isClosedGroup) {
return ( return (
@ -55,7 +54,7 @@ const NoImage = (props: {
); );
} }
return <Identicon size={size} name={name} pubkey={pubkey} />; return <Identicon size={size} forcedName={forcedName} pubkey={pubkey} />;
}; };
const AvatarImage = (props: { const AvatarImage = (props: {
@ -88,17 +87,21 @@ const AvatarImage = (props: {
}; };
const AvatarInner = (props: Props) => { const AvatarInner = (props: Props) => {
const { avatarPath, base64Data, size, pubkey, name, dataTestId } = props; const { base64Data, size, pubkey, forcedAvatarPath, forcedName, dataTestId } = props;
const [imageBroken, setImageBroken] = useState(false); const [imageBroken, setImageBroken] = useState(false);
const closedGroupMembers = useMembersAvatars(pubkey); const closedGroupMembers = useMembersAvatars(pubkey);
const avatarPath = useAvatarPath(pubkey);
const name = useConversationUsername(pubkey);
// contentType is not important // contentType is not important
const { urlToLoad } = useEncryptedFileFetch(avatarPath || '', ''); const { urlToLoad } = useEncryptedFileFetch(forcedAvatarPath || avatarPath || '', '');
const handleImageError = () => { const handleImageError = () => {
window.log.warn( window.log.warn(
'Avatar: Image failed to load; failing over to placeholder', 'Avatar: Image failed to load; failing over to placeholder',
urlToLoad, urlToLoad,
avatarPath forcedAvatarPath || avatarPath
); );
setImageBroken(true); setImageBroken(true);
}; };
@ -127,7 +130,7 @@ const AvatarInner = (props: Props) => {
avatarPath={urlToLoad} avatarPath={urlToLoad}
base64Data={base64Data} base64Data={base64Data}
imageBroken={imageBroken} imageBroken={imageBroken}
name={name} name={forcedName || name}
handleImageError={handleImageError} handleImageError={handleImageError}
/> />
) : ( ) : (

@ -11,8 +11,6 @@ type Props = {
function getClosedGroupAvatarsSize(size: AvatarSize): AvatarSize { function getClosedGroupAvatarsSize(size: AvatarSize): AvatarSize {
// Always use the size directly under the one requested // Always use the size directly under the one requested
switch (size) { switch (size) {
case AvatarSize.XS:
return AvatarSize.XS;
case AvatarSize.S: case AvatarSize.S:
return AvatarSize.XS; return AvatarSize.XS;
case AvatarSize.M: case AvatarSize.M:
@ -33,25 +31,13 @@ export const ClosedGroupAvatar = (props: Props) => {
const memberAvatars = useMembersAvatars(closedGroupId); const memberAvatars = useMembersAvatars(closedGroupId);
const avatarsDiameter = getClosedGroupAvatarsSize(size); const avatarsDiameter = getClosedGroupAvatarsSize(size);
const firstMember = memberAvatars?.[0]; const firstMemberId = memberAvatars?.[0];
const secondMember = memberAvatars?.[1]; const secondMemberID = memberAvatars?.[1];
return ( return (
<div className="module-avatar__icon-closed"> <div className="module-avatar__icon-closed">
<Avatar <Avatar size={avatarsDiameter} pubkey={firstMemberId} onAvatarClick={onAvatarClick} />
avatarPath={firstMember?.avatarPath} <Avatar size={avatarsDiameter} pubkey={secondMemberID} onAvatarClick={onAvatarClick} />
name={firstMember?.name}
size={avatarsDiameter}
pubkey={firstMember?.id}
onAvatarClick={onAvatarClick}
/>
<Avatar
avatarPath={secondMember?.avatarPath}
name={secondMember?.name}
size={avatarsDiameter}
pubkey={secondMember?.id}
onAvatarClick={onAvatarClick}
/>
</div> </div>
); );
}; };

@ -3,55 +3,43 @@ import classNames from 'classnames';
import { Avatar, AvatarSize } from './Avatar'; import { Avatar, AvatarSize } from './Avatar';
import { Emojify } from './conversation/Emojify'; import { Emojify } from './conversation/Emojify';
import { useConversationUsername, useIsMe } from '../hooks/useParamSelector';
interface Props { type Props = {
pubkey: string; pubkey: string;
isMe?: boolean;
name?: string;
profileName?: string;
avatarPath?: string;
onClick?: () => void; onClick?: () => void;
} };
export class ContactListItem extends React.Component<Props> { const AvatarItem = (props: { pubkey: string }) => {
public renderAvatar() { const { pubkey } = props;
const { avatarPath, name, pubkey, profileName } = this.props;
return <Avatar size={AvatarSize.S} pubkey={pubkey} />;
const userName = name || profileName || pubkey; };
return <Avatar avatarPath={avatarPath} name={userName} size={AvatarSize.S} pubkey={pubkey} />; export const ContactListItem = (props: Props) => {
} const { onClick, pubkey } = props;
public render() { const name = useConversationUsername(pubkey);
const { name, onClick, isMe, pubkey, profileName } = this.props; const isMe = useIsMe(pubkey);
const title = name ? name : pubkey; const title = name ? name : pubkey;
const displayName = isMe ? window.i18n('me') : title; const displayName = isMe ? window.i18n('me') : title;
const profileElement = return (
!isMe && profileName && !name ? ( <div
<span className="module-contact-list-item__text__profile-name"> role="button"
~ onClick={onClick}
<Emojify text={profileName} key={`emojify-list-item-${pubkey}`} /> className={classNames(
</span> 'module-contact-list-item',
) : null; onClick ? 'module-contact-list-item--with-click-handler' : null
)}
return ( >
<div <AvatarItem pubkey={pubkey} />
role="button" <div className="module-contact-list-item__text">
onClick={onClick} <div className="module-contact-list-item__text__name">
className={classNames( <Emojify text={displayName} />
'module-contact-list-item',
onClick ? 'module-contact-list-item--with-click-handler' : null
)}
>
{this.renderAvatar()}
<div className="module-contact-list-item__text">
<div className="module-contact-list-item__text__name">
<Emojify text={displayName} /> {profileElement}
</div>
</div> </div>
</div> </div>
); </div>
} );
} };

@ -26,6 +26,7 @@ import { SectionType } from '../state/ducks/section';
import { getFocusedSection } from '../state/selectors/section'; import { getFocusedSection } from '../state/selectors/section';
import { ConversationNotificationSettingType } from '../models/conversation'; import { ConversationNotificationSettingType } from '../models/conversation';
import { updateUserDetailsModal } from '../state/ducks/modalDialog'; import { updateUserDetailsModal } from '../state/ducks/modalDialog';
import { useAvatarPath, useConversationUsername, useIsMe } from '../hooks/useParamSelector';
// tslint:disable-next-line: no-empty-interface // tslint:disable-next-line: no-empty-interface
export interface ConversationListItemProps extends ReduxConversationType {} export interface ConversationListItemProps extends ReduxConversationType {}
@ -52,11 +53,8 @@ const Portal = ({ children }: { children: any }) => {
const HeaderItem = (props: { const HeaderItem = (props: {
unreadCount: number; unreadCount: number;
isMe: boolean;
mentionedUs: boolean; mentionedUs: boolean;
activeAt?: number; activeAt?: number;
name?: string;
profileName?: string;
conversationId: string; conversationId: string;
isPinned: boolean; isPinned: boolean;
currentNotificationSetting: ConversationNotificationSettingType; currentNotificationSetting: ConversationNotificationSettingType;
@ -65,11 +63,8 @@ const HeaderItem = (props: {
unreadCount, unreadCount,
mentionedUs, mentionedUs,
activeAt, activeAt,
isMe,
isPinned, isPinned,
conversationId, conversationId,
profileName,
name,
currentNotificationSetting, currentNotificationSetting,
} = props; } = props;
@ -116,12 +111,7 @@ const HeaderItem = (props: {
unreadCount > 0 ? 'module-conversation-list-item__header__name--with-unread' : null unreadCount > 0 ? 'module-conversation-list-item__header__name--with-unread' : null
)} )}
> >
<UserItem <UserItem conversationId={conversationId} />
isMe={isMe}
conversationId={conversationId}
name={name}
profileName={profileName}
/>
</div> </div>
<StyledConversationListItemIconWrapper> <StyledConversationListItemIconWrapper>
@ -143,21 +133,18 @@ const HeaderItem = (props: {
); );
}; };
const UserItem = (props: { const UserItem = (props: { conversationId: string }) => {
name?: string; const { conversationId } = props;
profileName?: string;
isMe: boolean;
conversationId: string;
}) => {
const { name, conversationId, profileName, isMe } = props;
const shortenedPubkey = PubKey.shorten(conversationId); const shortenedPubkey = PubKey.shorten(conversationId);
const isMe = useIsMe(conversationId);
const username = useConversationUsername(conversationId);
const displayedPubkey = profileName ? shortenedPubkey : conversationId; const displayedPubkey = username ? shortenedPubkey : conversationId;
const displayName = isMe ? window.i18n('noteToSelf') : profileName; const displayName = isMe ? window.i18n('noteToSelf') : username;
let shouldShowPubkey = false; let shouldShowPubkey = false;
if ((!name || name.length === 0) && (!displayName || displayName.length === 0)) { if ((!username || username.length === 0) && (!displayName || displayName.length === 0)) {
shouldShowPubkey = true; shouldShowPubkey = true;
} }
@ -165,7 +152,7 @@ const UserItem = (props: {
<div className="module-conversation__user"> <div className="module-conversation__user">
<ContactName <ContactName
pubkey={displayedPubkey} pubkey={displayedPubkey}
name={name} name={username}
profileName={displayName} profileName={displayName}
module="module-conversation__user" module="module-conversation__user"
boldProfileName={true} boldProfileName={true}
@ -212,22 +199,15 @@ const MessageItem = (props: {
); );
}; };
const AvatarItem = (props: { const AvatarItem = (props: { conversationId: string; isPrivate: boolean }) => {
avatarPath: string | null; const { isPrivate, conversationId } = props;
conversationId: string; const userName = useConversationUsername(conversationId);
name?: string; const avatarPath = useAvatarPath(conversationId);
profileName?: string;
isPrivate: boolean;
}) => {
const { avatarPath, name, isPrivate, conversationId, profileName } = props;
const userName = name || profileName || conversationId;
const dispatch = useDispatch(); const dispatch = useDispatch();
return ( return (
<div className="module-conversation-list-item__avatar-container"> <div className="module-conversation-list-item__avatar-container">
<Avatar <Avatar
avatarPath={avatarPath}
name={userName}
size={AvatarSize.S} size={AvatarSize.S}
pubkey={conversationId} pubkey={conversationId}
onAvatarClick={() => { onAvatarClick={() => {
@ -235,7 +215,7 @@ const AvatarItem = (props: {
dispatch( dispatch(
updateUserDetailsModal({ updateUserDetailsModal({
conversationId: conversationId, conversationId: conversationId,
userName, userName: userName || '',
authorAvatarPath: avatarPath, authorAvatarPath: avatarPath,
}) })
); );
@ -256,9 +236,7 @@ const ConversationListItem = (props: Props) => {
style, style,
mentionedUs, mentionedUs,
isMe, isMe,
name,
isPinned, isPinned,
profileName,
isTyping, isTyping,
lastMessage, lastMessage,
hasNickname, hasNickname,
@ -309,23 +287,14 @@ const ConversationListItem = (props: Props) => {
isBlocked ? 'module-conversation-list-item--is-blocked' : null isBlocked ? 'module-conversation-list-item--is-blocked' : null
)} )}
> >
<AvatarItem <AvatarItem conversationId={conversationId} isPrivate={isPrivate || false} />
conversationId={conversationId}
avatarPath={avatarPath || null}
profileName={profileName}
name={name}
isPrivate={isPrivate || false}
/>
<div className="module-conversation-list-item__content"> <div className="module-conversation-list-item__content">
<HeaderItem <HeaderItem
mentionedUs={!!mentionedUs} mentionedUs={!!mentionedUs}
unreadCount={unreadCount || 0} unreadCount={unreadCount || 0}
activeAt={activeAt} activeAt={activeAt}
isMe={!!isMe}
isPinned={!!isPinned} isPinned={!!isPinned}
conversationId={conversationId} conversationId={conversationId}
name={name}
profileName={profileName}
currentNotificationSetting={currentNotificationSetting || 'all'} currentNotificationSetting={currentNotificationSetting || 'all'}
/> />
<MessageItem <MessageItem
@ -349,8 +318,6 @@ const ConversationListItem = (props: Props) => {
type={type} type={type}
currentNotificationSetting={currentNotificationSetting || 'all'} currentNotificationSetting={currentNotificationSetting || 'all'}
avatarPath={avatarPath || null} avatarPath={avatarPath || null}
name={name}
profileName={profileName}
/> />
</Portal> </Portal>
</div> </div>

@ -162,26 +162,20 @@ const ExpirationLength = (props: { expirationSettingName?: string }) => {
}; };
const AvatarHeader = (props: { const AvatarHeader = (props: {
avatarPath: string | null;
name?: string;
pubkey: string; pubkey: string;
profileName?: string;
showBackButton: boolean; showBackButton: boolean;
onAvatarClick?: (pubkey: string) => void; onAvatarClick?: (pubkey: string) => void;
}) => { }) => {
const { avatarPath, name, pubkey, profileName } = props; const { pubkey, onAvatarClick, showBackButton } = props;
const userName = name || profileName || pubkey;
return ( return (
<span className="module-conversation-header__avatar"> <span className="module-conversation-header__avatar">
<Avatar <Avatar
avatarPath={avatarPath}
name={userName}
size={AvatarSize.S} size={AvatarSize.S}
onAvatarClick={() => { onAvatarClick={() => {
// do not allow right panel to appear if another button is shown on the SessionConversation // do not allow right panel to appear if another button is shown on the SessionConversation
if (props.onAvatarClick && !props.showBackButton) { if (onAvatarClick && !showBackButton) {
props.onAvatarClick(pubkey); onAvatarClick(pubkey);
} }
}} }}
pubkey={pubkey} pubkey={pubkey}
@ -393,9 +387,6 @@ export const ConversationHeaderWithDetails = () => {
}} }}
pubkey={conversationKey} pubkey={conversationKey}
showBackButton={isMessageDetailOpened} showBackButton={isMessageDetailOpened}
avatarPath={avatarPath}
name={name}
profileName={profileName}
/> />
</> </>
)} )}

@ -13,11 +13,10 @@ import {
} from '../../state/selectors/conversations'; } from '../../state/selectors/conversations';
import { deleteMessagesById } from '../../interactions/conversations/unsendingInteractions'; import { deleteMessagesById } from '../../interactions/conversations/unsendingInteractions';
const AvatarItem = (props: { contact: ContactPropsMessageDetail }) => { const AvatarItem = (props: { pubkey: string | undefined }) => {
const { avatarPath, pubkey, name, profileName } = props.contact; const { pubkey } = props;
const userName = name || profileName || pubkey;
return <Avatar avatarPath={avatarPath} name={userName} size={AvatarSize.S} pubkey={pubkey} />; return <Avatar size={AvatarSize.S} pubkey={pubkey} />;
}; };
const DeleteButtonItem = (props: { messageId: string; convoId: string; isDeletable: boolean }) => { const DeleteButtonItem = (props: { messageId: string; convoId: string; isDeletable: boolean }) => {
@ -68,7 +67,7 @@ const ContactItem = (props: { contact: ContactPropsMessageDetail }) => {
return ( return (
<div key={contact.pubkey} className="module-message-detail__contact"> <div key={contact.pubkey} className="module-message-detail__contact">
<AvatarItem contact={contact} /> <AvatarItem pubkey={contact.pubkey} />
<div className="module-message-detail__contact__text"> <div className="module-message-detail__contact__text">
<div className="module-message-detail__contact__name"> <div className="module-message-detail__contact__name">
<ContactName <ContactName

@ -62,13 +62,7 @@ export const MessageAvatar = (props: Props) => {
return ( return (
<div className="module-message__author-avatar" key={`msg-avatar-${authorPhoneNumber}`}> <div className="module-message__author-avatar" key={`msg-avatar-${authorPhoneNumber}`}>
<Avatar <Avatar size={AvatarSize.S} onAvatarClick={onMessageAvatarClick} pubkey={authorPhoneNumber} />
avatarPath={authorAvatarPath}
name={userName}
size={AvatarSize.S}
onAvatarClick={onMessageAvatarClick}
pubkey={authorPhoneNumber}
/>
{isPublic && isSenderAdmin && ( {isPublic && isSenderAdmin && (
<div className="module-avatar__icon--crown-wrapper"> <div className="module-avatar__icon--crown-wrapper">
<div className="module-avatar__icon--crown" /> <div className="module-avatar__icon--crown" />

@ -246,7 +246,12 @@ export class EditProfileDialog extends React.Component<{}, State> {
const userName = profileName || this.convo.id; const userName = profileName || this.convo.id;
return ( return (
<Avatar avatarPath={avatar} name={userName} size={AvatarSize.XL} pubkey={this.convo.id} /> <Avatar
forcedAvatarPath={avatar}
forcedName={userName}
size={AvatarSize.XL}
pubkey={this.convo.id}
/>
); );
} }

@ -191,7 +191,7 @@ export class UpdateGroupNameDialog extends React.Component<Props, State> {
return ( return (
<div className="avatar-center"> <div className="avatar-center">
<div className="avatar-center-inner"> <div className="avatar-center-inner">
<Avatar avatarPath={this.state.avatar || ''} size={AvatarSize.XL} pubkey={pubkey} /> <Avatar forcedAvatarPath={this.state.avatar || ''} size={AvatarSize.XL} pubkey={pubkey} />
<div <div
className="image-upload-section" className="image-upload-section"
role="button" role="button"

@ -25,7 +25,6 @@ export const UserDetailsDialog = (props: Props) => {
const convo = getConversationController().get(props.conversationId); const convo = getConversationController().get(props.conversationId);
const size = isEnlargedImageShown ? AvatarSize.HUGE : AvatarSize.XL; const size = isEnlargedImageShown ? AvatarSize.HUGE : AvatarSize.XL;
const userName = props.userName || props.conversationId;
const [_, copyToClipboard] = useCopyToClipboard(); const [_, copyToClipboard] = useCopyToClipboard();
@ -57,8 +56,6 @@ export const UserDetailsDialog = (props: Props) => {
<div className="avatar-center"> <div className="avatar-center">
<div className="avatar-center-inner"> <div className="avatar-center-inner">
<Avatar <Avatar
avatarPath={props.authorAvatarPath}
name={userName}
size={size} size={size}
onAvatarClick={() => { onAvatarClick={() => {
setIsEnlargedImageShown(!isEnlargedImageShown); setIsEnlargedImageShown(!isEnlargedImageShown);

@ -50,11 +50,11 @@ import { DraggableCallContainer } from './calling/DraggableCallContainer';
import { IncomingCallDialog } from './calling/IncomingCallDialog'; import { IncomingCallDialog } from './calling/IncomingCallDialog';
import { CallInFullScreenContainer } from './calling/CallInFullScreenContainer'; import { CallInFullScreenContainer } from './calling/CallInFullScreenContainer';
const Section = (props: { type: SectionType; avatarPath?: string | null }) => { const Section = (props: { type: SectionType }) => {
const ourNumber = useSelector(getOurNumber); const ourNumber = useSelector(getOurNumber);
const unreadMessageCount = useSelector(getUnreadMessageCount); const unreadMessageCount = useSelector(getUnreadMessageCount);
const dispatch = useDispatch(); const dispatch = useDispatch();
const { type, avatarPath } = props; const { type } = props;
const focusedSection = useSelector(getFocusedSection); const focusedSection = useSelector(getFocusedSection);
const isSelected = focusedSection === props.type; const isSelected = focusedSection === props.type;
@ -85,16 +85,10 @@ const Section = (props: { type: SectionType; avatarPath?: string | null }) => {
}; };
if (type === SectionType.Profile) { if (type === SectionType.Profile) {
const conversation = getConversationController().get(ourNumber);
const profile = conversation?.getLokiProfile();
const userName = (profile && profile.displayName) || ourNumber;
return ( return (
<Avatar <Avatar
avatarPath={avatarPath}
size={AvatarSize.XS} size={AvatarSize.XS}
onAvatarClick={handleClick} onAvatarClick={handleClick}
name={userName}
pubkey={ourNumber} pubkey={ourNumber}
dataTestId="leftpane-primary-avatar" dataTestId="leftpane-primary-avatar"
/> />
@ -287,12 +281,7 @@ export const ActionsPanel = () => {
return () => clearTimeout(timeout); return () => clearTimeout(timeout);
}, []); }, []);
useInterval( useInterval(cleanUpOldDecryptedMedias, startCleanUpMedia ? cleanUpMediasInterval : null);
() => {
cleanUpOldDecryptedMedias();
},
startCleanUpMedia ? cleanUpMediasInterval : null
);
if (!ourPrimaryConversation) { if (!ourPrimaryConversation) {
window?.log?.warn('ActionsPanel: ourPrimaryConversation is not set'); window?.log?.warn('ActionsPanel: ourPrimaryConversation is not set');
@ -328,7 +317,7 @@ export const ActionsPanel = () => {
className="module-left-pane__sections-container" className="module-left-pane__sections-container"
data-testid="leftpane-section-container" data-testid="leftpane-section-container"
> >
<Section type={SectionType.Profile} avatarPath={ourPrimaryConversation.avatarPath} /> <Section type={SectionType.Profile} />
<Section type={SectionType.Message} /> <Section type={SectionType.Message} />
<Section type={SectionType.Contact} /> <Section type={SectionType.Contact} />
<Section type={SectionType.Settings} /> <Section type={SectionType.Settings} />

@ -23,37 +23,17 @@ type Props = {
isSelected: boolean; isSelected: boolean;
// this bool is used to make a zombie appear with less opacity than a normal member // this bool is used to make a zombie appear with less opacity than a normal member
isZombie?: boolean; isZombie?: boolean;
onSelect?: any; onSelect?: (selectedMember: ContactType) => void;
onUnselect?: any; onUnselect?: (selectedMember: ContactType) => void;
};
const AvatarItem = (props: { memberPubkey?: string }) => {
return <Avatar size={AvatarSize.XS} pubkey={props.memberPubkey} />;
}; };
export const SessionMemberListItem = (props: Props) => { export const SessionMemberListItem = (props: Props) => {
const { isSelected, member, isZombie, onSelect, onUnselect } = props; const { isSelected, member, isZombie, onSelect, onUnselect } = props;
const renderAvatar = () => {
const { authorAvatarPath, authorName, authorPhoneNumber, authorProfileName } = member;
const userName = authorName || authorProfileName || authorPhoneNumber;
return (
<Avatar
avatarPath={authorAvatarPath}
name={userName}
size={AvatarSize.XS}
pubkey={authorPhoneNumber}
/>
);
};
const selectMember = () => {
onSelect?.(member);
};
const unselectMember = () => {
onUnselect?.(member);
};
const handleSelectionAction = () => {
isSelected ? unselectMember() : selectMember();
};
const name = member.authorProfileName || PubKey.shorten(member.authorPhoneNumber); const name = member.authorProfileName || PubKey.shorten(member.authorPhoneNumber);
return ( return (
@ -64,11 +44,15 @@ export const SessionMemberListItem = (props: Props) => {
isSelected && 'selected', isSelected && 'selected',
isZombie && 'zombie' isZombie && 'zombie'
)} )}
onClick={handleSelectionAction} onClick={() => {
isSelected ? onUnselect?.(member) : onSelect?.(member);
}}
role="button" role="button"
> >
<div className="session-member-item__info"> <div className="session-member-item__info">
<span className="session-member-item__avatar">{renderAvatar()}</span> <span className="session-member-item__avatar">
<AvatarItem memberPubkey={member.id} />
</span>
<span className="session-member-item__name">{name}</span> <span className="session-member-item__name">{name}</span>
</div> </div>
<span className={classNames('session-member-item__checkmark', isSelected && 'selected')}> <span className={classNames('session-member-item__checkmark', isSelected && 'selected')}>

@ -9,7 +9,6 @@ import { getHasOngoingCall, getHasOngoingCallWith } from '../../../state/selecto
import { openConversationWithMessages } from '../../../state/ducks/conversations'; import { openConversationWithMessages } from '../../../state/ducks/conversations';
import { Avatar, AvatarSize } from '../../Avatar'; import { Avatar, AvatarSize } from '../../Avatar';
import { useVideoCallEventsListener } from '../../../hooks/useVideoEventListener'; import { useVideoCallEventsListener } from '../../../hooks/useVideoEventListener';
import { useAvatarPath, useConversationUsername } from '../../../hooks/useParamSelector';
import { VideoLoadingSpinner } from './InConversationCallContainer'; import { VideoLoadingSpinner } from './InConversationCallContainer';
export const DraggableCallWindow = styled.div` export const DraggableCallWindow = styled.div`
@ -77,8 +76,6 @@ export const DraggableCallContainer = () => {
'DraggableCallContainer', 'DraggableCallContainer',
false false
); );
const ongoingCallUsername = useConversationUsername(ongoingCallPubkey);
const avatarPath = useAvatarPath(ongoingCallPubkey);
const videoRefRemote = useRef<HTMLVideoElement>(null); const videoRefRemote = useRef<HTMLVideoElement>(null);
function onWindowResize() { function onWindowResize() {
@ -140,12 +137,7 @@ export const DraggableCallContainer = () => {
/> />
{remoteStreamVideoIsMuted && ( {remoteStreamVideoIsMuted && (
<CenteredAvatarInDraggable> <CenteredAvatarInDraggable>
<Avatar <Avatar size={AvatarSize.XL} pubkey={ongoingCallPubkey} />
size={AvatarSize.XL}
avatarPath={avatarPath}
name={ongoingCallUsername}
pubkey={ongoingCallPubkey}
/>
</CenteredAvatarInDraggable> </CenteredAvatarInDraggable>
)} )}
</DraggableCallWindowInner> </DraggableCallWindowInner>

@ -6,7 +6,6 @@ import _ from 'underscore';
import { UserUtils } from '../../../session/utils'; import { UserUtils } from '../../../session/utils';
import { import {
getCallIsInFullScreen, getCallIsInFullScreen,
getHasOngoingCallWith,
getHasOngoingCallWithFocusedConvo, getHasOngoingCallWithFocusedConvo,
getHasOngoingCallWithFocusedConvoIsOffering, getHasOngoingCallWithFocusedConvoIsOffering,
getHasOngoingCallWithFocusedConvosIsConnecting, getHasOngoingCallWithFocusedConvosIsConnecting,
@ -16,11 +15,6 @@ import { StyledVideoElement } from './DraggableCallContainer';
import { Avatar, AvatarSize } from '../../Avatar'; import { Avatar, AvatarSize } from '../../Avatar';
import { useVideoCallEventsListener } from '../../../hooks/useVideoEventListener'; import { useVideoCallEventsListener } from '../../../hooks/useVideoEventListener';
import {
useAvatarPath,
useOurAvatarPath,
useOurConversationUsername,
} from '../../../hooks/useParamSelector';
import { useModuloWithTripleDots } from '../../../hooks/useModuloWithTripleDots'; import { useModuloWithTripleDots } from '../../../hooks/useModuloWithTripleDots';
import { CallWindowControls } from './CallButtons'; import { CallWindowControls } from './CallButtons';
import { SessionSpinner } from '../SessionSpinner'; import { SessionSpinner } from '../SessionSpinner';
@ -118,23 +112,15 @@ export const VideoLoadingSpinner = (props: { fullWidth: boolean }) => {
// tslint:disable-next-line: max-func-body-length // tslint:disable-next-line: max-func-body-length
export const InConversationCallContainer = () => { export const InConversationCallContainer = () => {
const ongoingCallProps = useSelector(getHasOngoingCallWith);
const isInFullScreen = useSelector(getCallIsInFullScreen); const isInFullScreen = useSelector(getCallIsInFullScreen);
const ongoingCallPubkey = useSelector(getHasOngoingCallWithPubkey); const ongoingCallPubkey = useSelector(getHasOngoingCallWithPubkey);
const ongoingCallWithFocused = useSelector(getHasOngoingCallWithFocusedConvo); const ongoingCallWithFocused = useSelector(getHasOngoingCallWithFocusedConvo);
const ongoingCallUsername = ongoingCallProps?.profileName || ongoingCallProps?.name;
const videoRefRemote = useRef<HTMLVideoElement>(null); const videoRefRemote = useRef<HTMLVideoElement>(null);
const videoRefLocal = useRef<HTMLVideoElement>(null); const videoRefLocal = useRef<HTMLVideoElement>(null);
const ourPubkey = UserUtils.getOurPubKeyStrFromCache(); const ourPubkey = UserUtils.getOurPubKeyStrFromCache();
const remoteAvatarPath = useAvatarPath(ongoingCallPubkey);
const ourAvatarPath = useOurAvatarPath();
const ourUsername = useOurConversationUsername();
const { const {
currentConnectedAudioInputs, currentConnectedAudioInputs,
currentConnectedCameras, currentConnectedCameras,
@ -190,12 +176,7 @@ export const InConversationCallContainer = () => {
/> />
{remoteStreamVideoIsMuted && ( {remoteStreamVideoIsMuted && (
<CenteredAvatarInConversation> <CenteredAvatarInConversation>
<Avatar <Avatar size={AvatarSize.XL} pubkey={ongoingCallPubkey} />
size={AvatarSize.XL}
avatarPath={remoteAvatarPath}
name={ongoingCallUsername}
pubkey={ongoingCallPubkey}
/>
</CenteredAvatarInConversation> </CenteredAvatarInConversation>
)} )}
</VideoContainer> </VideoContainer>
@ -208,12 +189,7 @@ export const InConversationCallContainer = () => {
/> />
{localStreamVideoIsMuted && ( {localStreamVideoIsMuted && (
<CenteredAvatarInConversation> <CenteredAvatarInConversation>
<Avatar <Avatar size={AvatarSize.XL} pubkey={ourPubkey} />
size={AvatarSize.XL}
avatarPath={ourAvatarPath}
name={ourUsername}
pubkey={ourPubkey}
/>
</CenteredAvatarInConversation> </CenteredAvatarInConversation>
)} )}
</VideoContainer> </VideoContainer>

@ -3,7 +3,7 @@ import { useSelector } from 'react-redux';
import styled from 'styled-components'; import styled from 'styled-components';
import _ from 'underscore'; import _ from 'underscore';
import { useAvatarPath, useConversationUsername } from '../../../hooks/useParamSelector'; import { useConversationUsername } from '../../../hooks/useParamSelector';
import { ed25519Str } from '../../../session/onions/onionPath'; import { ed25519Str } from '../../../session/onions/onionPath';
import { CallManager } from '../../../session/utils'; import { CallManager } from '../../../session/utils';
import { getHasIncomingCall, getHasIncomingCallFrom } from '../../../state/selectors/call'; import { getHasIncomingCall, getHasIncomingCallFrom } from '../../../state/selectors/call';
@ -70,7 +70,6 @@ export const IncomingCallDialog = () => {
} }
}; };
const from = useConversationUsername(incomingCallFromPubkey); const from = useConversationUsername(incomingCallFromPubkey);
const incomingAvatar = useAvatarPath(incomingCallFromPubkey);
if (!hasIncomingCall) { if (!hasIncomingCall) {
return null; return null;
} }
@ -79,12 +78,7 @@ export const IncomingCallDialog = () => {
return ( return (
<SessionWrapperModal title={window.i18n('incomingCallFrom', from)}> <SessionWrapperModal title={window.i18n('incomingCallFrom', from)}>
<IncomingCallAvatatContainer> <IncomingCallAvatatContainer>
<Avatar <Avatar size={AvatarSize.XL} pubkey={incomingCallFromPubkey} />
size={AvatarSize.XL}
avatarPath={incomingAvatar}
name={from}
pubkey={incomingCallFromPubkey}
/>
</IncomingCallAvatatContainer> </IncomingCallAvatatContainer>
<div className="session-modal__button-group"> <div className="session-modal__button-group">
<SessionButton <SessionButton

@ -113,19 +113,9 @@ const HeaderItem = () => {
if (!selectedConversation) { if (!selectedConversation) {
return null; return null;
} }
const { const { id, isGroup, isKickedFromGroup, isBlocked, left } = selectedConversation;
avatarPath,
id,
isGroup,
isKickedFromGroup,
profileName,
isBlocked,
left,
name,
} = selectedConversation;
const showInviteContacts = isGroup && !isKickedFromGroup && !isBlocked && !left; const showInviteContacts = isGroup && !isKickedFromGroup && !isBlocked && !left;
const userName = name || profileName || id;
return ( return (
<div className="group-settings-header"> <div className="group-settings-header">
@ -137,7 +127,7 @@ const HeaderItem = () => {
dispatch(closeRightPanel()); dispatch(closeRightPanel());
}} }}
/> />
<Avatar avatarPath={avatarPath || ''} name={userName} size={AvatarSize.XL} pubkey={id} /> <Avatar size={AvatarSize.XL} pubkey={id} />
<div className="invite-friends-container"> <div className="invite-friends-container">
{showInviteContacts && ( {showInviteContacts && (
<SessionIconButton <SessionIconButton

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { animation, Menu } from 'react-contexify'; import { animation, Menu } from 'react-contexify';
import _ from 'underscore'; import _ from 'underscore';
import { useAvatarPath, useConversationUsername } from '../../../hooks/useParamSelector';
import { import {
ConversationNotificationSettingType, ConversationNotificationSettingType,
ConversationTypeEnum, ConversationTypeEnum,
@ -34,8 +35,6 @@ export type PropsContextConversationItem = {
left: boolean; left: boolean;
theme?: any; theme?: any;
currentNotificationSetting: ConversationNotificationSettingType; currentNotificationSetting: ConversationNotificationSettingType;
name: string | undefined;
profileName: string | undefined;
avatarPath: string | null; avatarPath: string | null;
}; };
@ -52,13 +51,12 @@ const ConversationListItemContextMenu = (props: PropsContextConversationItem) =>
isKickedFromGroup, isKickedFromGroup,
currentNotificationSetting, currentNotificationSetting,
isPrivate, isPrivate,
name,
profileName,
avatarPath,
} = props; } = props;
const isGroup = type === 'group'; const isGroup = type === 'group';
const userName = name || profileName || conversationId;
const userName = useConversationUsername(conversationId);
const avatarPath = useAvatarPath(conversationId);
return ( return (
<Menu id={triggerId} animation={animation.fade}> <Menu id={triggerId} animation={animation.fade}>
@ -80,7 +78,7 @@ const ConversationListItemContextMenu = (props: PropsContextConversationItem) =>
{getInviteContactMenuItem(isGroup, isPublic, conversationId)} {getInviteContactMenuItem(isGroup, isPublic, conversationId)}
{getDeleteContactMenuItem(isGroup, isPublic, left, isKickedFromGroup, conversationId)} {getDeleteContactMenuItem(isGroup, isPublic, left, isKickedFromGroup, conversationId)}
{getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, conversationId)} {getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, conversationId)}
{getShowUserDetailsMenuItem(isPrivate, conversationId, avatarPath, userName)} {getShowUserDetailsMenuItem(isPrivate, conversationId, avatarPath, userName || '')}
</Menu> </Menu>
); );
}; };

@ -3,16 +3,10 @@ import * as _ from 'lodash';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { StateType } from '../state/reducer'; import { StateType } from '../state/reducer';
export type ConversationAvatar = {
avatarPath?: string;
id: string; // member's pubkey
name: string;
};
export function useMembersAvatars(closedGroupPubkey: string | undefined) { export function useMembersAvatars(closedGroupPubkey: string | undefined) {
const ourPrimary = UserUtils.getOurPubKeyStrFromCache(); const ourPrimary = UserUtils.getOurPubKeyStrFromCache();
return useSelector((state: StateType): Array<ConversationAvatar> | undefined => { return useSelector((state: StateType): Array<string> | undefined => {
if (!closedGroupPubkey) { if (!closedGroupPubkey) {
return undefined; return undefined;
} }
@ -37,16 +31,7 @@ export function useMembersAvatars(closedGroupPubkey: string | undefined) {
usAtTheEndMaxTwo usAtTheEndMaxTwo
.map(m => state.conversations.conversationLookup[m]) .map(m => state.conversations.conversationLookup[m])
.map(m => { .map(m => {
if (!m) { return m?.id || undefined;
return undefined;
}
const userName = m.name || m.profileName || m.id;
return {
avatarPath: m.avatarPath || undefined,
id: m.id,
name: userName,
};
}) })
); );

@ -5,9 +5,9 @@ import { StateType } from '../state/reducer';
export function useAvatarPath(pubkey: string | undefined) { export function useAvatarPath(pubkey: string | undefined) {
return useSelector((state: StateType) => { return useSelector((state: StateType) => {
if (!pubkey) { if (!pubkey) {
return undefined; return null;
} }
return state.conversations.conversationLookup[pubkey]?.avatarPath; return state.conversations.conversationLookup[pubkey]?.avatarPath || null;
}); });
} }
@ -15,12 +15,19 @@ export function useOurAvatarPath() {
return useAvatarPath(UserUtils.getOurPubKeyStrFromCache()); return useAvatarPath(UserUtils.getOurPubKeyStrFromCache());
} }
export function useConversationUsername(pubkey: string | undefined) { /**
*
* @returns convo.profileName || convo.name || convo.id or undefined if the convo is not found
*/
export function useConversationUsername(pubkey?: string) {
return useSelector((state: StateType) => { return useSelector((state: StateType) => {
if (!pubkey) { if (!pubkey) {
return undefined; return undefined;
} }
const convo = state.conversations.conversationLookup[pubkey]; const convo = state.conversations.conversationLookup[pubkey];
if (!convo) {
return pubkey;
}
return convo?.profileName || convo?.name || convo.id; return convo?.profileName || convo?.name || convo.id;
}); });
} }
@ -28,3 +35,7 @@ export function useConversationUsername(pubkey: string | undefined) {
export function useOurConversationUsername() { export function useOurConversationUsername() {
return useConversationUsername(UserUtils.getOurPubKeyStrFromCache()); return useConversationUsername(UserUtils.getOurPubKeyStrFromCache());
} }
export function useIsMe(pubkey?: string) {
return pubkey && pubkey === UserUtils.getOurPubKeyStrFromCache();
}

Loading…
Cancel
Save