fix: avatar style for incoming messages in groups

had to refactor a fair bit, but well...
pull/2940/head
Audric Ackermann 6 months ago
parent 8fa9b80fad
commit 4cbc452f26

@ -65,8 +65,7 @@ const StyledMessagesContainer = styled.div<{ isGroup: boolean }>`
padding-top: var(--margins-sm);
padding-right: var(--margins-lg);
padding-bottom: var(--margins-xl);
padding-left: ${props =>
props.isGroup ? 'calc(var(--margins-lg) + 11px)' : 'var(--margins-lg)'};
padding-left: ${props => (props.isGroup ? 'var(--margins-xs)' : 'var(--margins-lg)')};
.session-icon-button {
display: flex;
@ -127,7 +126,7 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
<StyledMessagesContainer
className="messages-container"
id={messageContainerDomID}
isGroup={!conversation.isMe && !conversation.isPrivate && !conversation.isPublic}
isGroup={!conversation.isPrivate}
onScroll={this.handleScroll}
ref={this.props.messageContainerRef}
data-testid="messages-container"

@ -5,6 +5,7 @@ import {
useAuthorName,
useAuthorProfileName,
useFirstMessageOfSeries,
useHideAvatarInMsgList,
useMessageAuthor,
useMessageDirection,
} from '../../../../state/selectors';
@ -19,9 +20,10 @@ type Props = {
messageId: string;
};
const StyledAuthorContainer = styled(Flex)`
const StyledAuthorContainer = styled(Flex)<{ hideAvatar: boolean }>`
color: var(--text-primary-color);
text-overflow: ellipsis;
margin-inline-start: ${props => (props.hideAvatar ? 0 : 'var(--width-avatar-group-msg-list)')};
`;
export const MessageAuthorText = (props: Props) => {
@ -32,6 +34,7 @@ export const MessageAuthorText = (props: Props) => {
const sender = useMessageAuthor(props.messageId);
const direction = useMessageDirection(props.messageId);
const firstMessageOfSeries = useFirstMessageOfSeries(props.messageId);
const hideAvatar = useHideAvatarInMsgList(props.messageId);
if (!props.messageId || !sender || !direction) {
return null;
@ -46,7 +49,7 @@ export const MessageAuthorText = (props: Props) => {
const displayedPubkey = authorProfileName ? PubKey.shorten(sender) : sender;
return (
<StyledAuthorContainer container={true}>
<StyledAuthorContainer container={true} hideAvatar={hideAvatar}>
<ContactName
pubkey={displayedPubkey}
name={authorName}

@ -26,9 +26,11 @@ import { Avatar, AvatarSize, CrownIcon } from '../../../avatar/Avatar';
const StyledAvatar = styled.div`
position: relative;
margin-inline-end: 20px;
padding-bottom: 6px;
padding-inline-end: 4px;
margin-inline-end: 10px;
max-width: var(
--width-avatar-group-msg-list
); // enforcing this so we change the variable when changing the content of the avatar
overflow-y: hidden;
`;
export type MessageAvatarSelectorProps = Pick<
@ -129,13 +131,13 @@ export const MessageAvatar = (props: Props) => {
}
if (!lastMessageOfSeries) {
return <div style={{ marginInlineEnd: '60px' }} key={`msg-avatar-${sender}`} />;
return <div style={{ marginInlineEnd: 'var(--width-avatar-group-msg-list)' }} />;
}
/* eslint-disable @typescript-eslint/no-misused-promises */
// The styledAvatar, when rendered needs to have a width with margins included of var(--width-avatar-group-msg-list).
// This is so that the other message is still aligned when the avatar is not rendered (we need to make up for the space used by the avatar, and we use a margin of width-avatar-group-msg-list)
return (
<StyledAvatar
key={`msg-avatar-${sender}`}
style={{
visibility: hideAvatar ? 'hidden' : undefined,
}}

@ -7,14 +7,19 @@ import { useSelector } from 'react-redux';
import styled, { css, keyframes } from 'styled-components';
import { MessageRenderingProps } from '../../../../models/messageType';
import { StateType } from '../../../../state/reducer';
import { useMessageIsDeleted } from '../../../../state/selectors';
import { useHideAvatarInMsgList, useMessageIsDeleted } from '../../../../state/selectors';
import {
getMessageContentSelectorProps,
getQuotedMessageToAnimate,
getShouldHighlightMessage,
} from '../../../../state/selectors/conversations';
import {
useSelectedIsGroup,
useSelectedIsPrivate,
} from '../../../../state/selectors/selectedConversation';
import { ScrollToLoadedMessageContext } from '../../SessionMessagesListContainer';
import { MessageAttachment } from './MessageAttachment';
import { MessageAvatar } from './MessageAvatar';
import { MessageLinkPreview } from './MessageLinkPreview';
import { MessageQuote } from './MessageQuote';
import { MessageText } from './MessageText';
@ -46,7 +51,9 @@ function onClickOnMessageInnerContainer(event: React.MouseEvent<HTMLDivElement>)
}
}
const StyledMessageContent = styled.div``;
const StyledMessageContent = styled.div`
display: flex;
`;
const opacityAnimation = keyframes`
0% {
@ -92,6 +99,12 @@ const StyledMessageOpaqueContent = styled(StyledMessageHighlighter)<{
export const IsMessageVisibleContext = createContext(false);
// NOTE aligns group member avatars with the ExpireTimer
const StyledAvatarContainer = styled.div<{ hideAvatar: boolean; isGroup: boolean }>`
/* margin-inline-start: ${props => (!props.hideAvatar && props.isGroup ? '-11px' : '')}; */
align-self: flex-end;
`;
export const MessageContent = (props: Props) => {
const [highlight, setHighlight] = useState(false);
const [didScroll, setDidScroll] = useState(false);
@ -102,6 +115,9 @@ export const MessageContent = (props: Props) => {
const [isMessageVisible, setMessageIsVisible] = useState(false);
const scrollToLoadedMessage = useContext(ScrollToLoadedMessageContext);
const selectedIsPrivate = useSelectedIsPrivate();
const isGroup = useSelectedIsGroup();
const hideAvatar = useHideAvatarInMsgList(props.messageId);
const [imageBroken, setImageBroken] = useState(false);
@ -169,6 +185,14 @@ export const MessageContent = (props: Props) => {
onClick={onClickOnMessageInnerContainer}
title={toolTipTitle}
>
<StyledAvatarContainer hideAvatar={hideAvatar} isGroup={isGroup}>
<MessageAvatar
messageId={props.messageId}
hideAvatar={hideAvatar}
isPrivate={selectedIsPrivate}
/>
</StyledAvatarContainer>
<InView
id={`inview-content-${props.messageId}`}
onChange={onVisible}

@ -7,6 +7,7 @@ import { MessageRenderingProps } from '../../../../models/messageType';
import { toggleSelectedMessageId } from '../../../../state/ducks/conversations';
import { updateReactListModal } from '../../../../state/ducks/modalDialog';
import { StateType } from '../../../../state/reducer';
import { useHideAvatarInMsgList } from '../../../../state/selectors';
import {
getMessageContentWithStatusesSelectorProps,
isMessageSelectionMode,
@ -15,7 +16,6 @@ import { Reactions } from '../../../../util/reactions';
import { Flex } from '../../../basic/Flex';
import { ExpirableReadableMessage } from '../message-item/ExpirableReadableMessage';
import { MessageAuthorText } from './MessageAuthorText';
import { MessageAvatar } from './MessageAvatar';
import { MessageContent } from './MessageContent';
import { MessageContextMenu } from './MessageContextMenu';
import { MessageReactions, StyledMessageReactions } from './MessageReactions';
@ -46,23 +46,19 @@ const StyledMessageContentContainer = styled.div<{ isIncoming: boolean }>`
}
`;
const StyledMessageWithAuthor = styled.div<{ isIncoming: boolean }>`
const StyledMessageWithAuthor = styled.div`
max-width: '100%';
display: flex;
flex-direction: column;
min-width: 0;
`;
// NOTE aligns group member avatars with the ExpireTimer
const StyledAvatarContainer = styled.div<{ hideAvatar: boolean; isGroup: boolean }>`
margin-inline-start: ${props => (!props.hideAvatar && props.isGroup ? '-11px' : '')};
`;
export const MessageContentWithStatuses = (props: Props) => {
const contentProps = useSelector((state: StateType) =>
getMessageContentWithStatusesSelectorProps(state, props.messageId)
);
const dispatch = useDispatch();
const hideAvatar = useHideAvatarInMsgList(props.messageId);
const multiSelectMode = useSelector(isMessageSelectionMode);
@ -103,12 +99,9 @@ export const MessageContentWithStatuses = (props: Props) => {
return null;
}
const { conversationType, direction, isDeleted, isGroup } = contentProps;
const { direction, isDeleted } = contentProps;
const isIncoming = direction === 'incoming';
const isPrivate = conversationType === 'private';
const hideAvatar = isPrivate || direction === 'outgoing';
const handleMessageReaction = async (emoji: string) => {
await Reactions.sendMessageReaction(messageId, emoji);
};
@ -132,12 +125,8 @@ export const MessageContentWithStatuses = (props: Props) => {
onDoubleClickCapture={onDoubleClickReplyToMessage}
dataTestId={dataTestId}
>
<StyledAvatarContainer hideAvatar={hideAvatar} isGroup={isGroup}>
<MessageAvatar messageId={messageId} hideAvatar={hideAvatar} isPrivate={isPrivate} />
</StyledAvatarContainer>
<Flex container={true} flexDirection="column" flexShrink={0}>
<StyledMessageWithAuthor isIncoming={isIncoming}>
<StyledMessageWithAuthor>
<MessageAuthorText messageId={messageId} />
<MessageContent messageId={messageId} isDetailView={isDetailView} />
</StyledMessageWithAuthor>

@ -8,6 +8,7 @@ import {
} from '../ducks/conversations';
import { StateType } from '../reducer';
import { getMessagePropsByMessageId } from './conversations';
import { useSelectedIsPrivate } from './selectedConversation';
function useMessagePropsByMessageId(messageId: string | undefined) {
return useSelector((state: StateType) => getMessagePropsByMessageId(state, messageId));
@ -125,3 +126,9 @@ export function useMessageTimestamp(messageId: string) {
export function useMessageBody(messageId: string) {
return useMessagePropsByMessageId(messageId)?.propsForMessage.text;
}
export function useHideAvatarInMsgList(messageId?: string) {
const msgProps = useMessagePropsByMessageId(messageId);
const selectedIsPrivate = useSelectedIsPrivate();
return msgProps?.propsForMessage.direction === 'outgoing' || selectedIsPrivate;
}

@ -27,6 +27,7 @@ export type ThemeGlobals = {
/* Padding */
'--padding-message-content': string;
'--padding-link-preview': string;
'--width-avatar-group-msg-list': string;
/* Border Radius */
'--border-radius': string;
@ -108,6 +109,7 @@ export const THEME_GLOBALS: ThemeGlobals = {
'--padding-message-content': '7px 13px',
'--padding-link-preview': '-7px -13px 7px -13px', // bottom has positive value because a link preview has always a body below
'--width-avatar-group-msg-list': '46px', // the width used by the avatar (and its margins when rendered as part of a group.)
'--border-radius': '5px',
'--border-radius-message-box': '16px',

Loading…
Cancel
Save