fix: ellipsis on name rather than pubkey

also cleaned up our contexts a little bit
pull/3055/head
Audric Ackermann 2 months ago
parent 4774c8a669
commit cef59be005

@ -609,6 +609,9 @@
flex-direction: column;
align-items: stretch;
overflow: hidden;
max-height: 100%;
display: flex;
gap: 5px;
.session-icon-button:first-child {
margin-right: var(--margins-sm);

@ -1,12 +1,11 @@
import React from 'react';
import classNames from 'classnames';
import { CSSProperties } from 'styled-components';
import React from 'react';
import { Emojify } from './Emojify';
import {
useNicknameOrProfileNameOrShortenedPubkey,
useIsPrivate,
useNicknameOrProfileNameOrShortenedPubkey,
} from '../../hooks/useParamSelector';
import { Emojify } from './Emojify';
type Props = {
pubkey: string;
@ -25,12 +24,20 @@ export const ContactName = (props: Props) => {
const convoName = useNicknameOrProfileNameOrShortenedPubkey(pubkey);
const isPrivate = useIsPrivate(pubkey);
const shouldShowProfile = Boolean(convoName || profileName || name);
const commonStyles = {
'min-width': 0,
'text-overflow': 'ellipsis',
overflow: 'hidden',
} as React.CSSProperties;
const styles = (
boldProfileName
? {
fontWeight: 'bold',
...commonStyles,
}
: {}
: commonStyles
) as React.CSSProperties;
const textProfile = profileName || name || convoName || window.i18n('anonymous');
@ -39,15 +46,19 @@ export const ContactName = (props: Props) => {
className={classNames(prefix, compact && 'compact')}
dir="auto"
data-testid={`${prefix}__profile-name`}
style={{ textOverflow: 'inherit' }}
style={{
textOverflow: 'inherit',
display: 'flex',
flexDirection: 'row',
gap: 'var(--margins-xs)',
}}
>
{shouldShowProfile ? (
<span style={styles as CSSProperties} className={`${prefix}__profile-name`}>
<div style={styles} className={`${prefix}__profile-name`}>
<Emojify text={textProfile} sizeClass="small" isGroup={!isPrivate} />
</span>
</div>
) : null}
{shouldShowProfile ? ' ' : null}
{shouldShowPubkey ? <span className={`${prefix}__profile-number`}>{pubkey}</span> : null}
{shouldShowPubkey ? <div className={`${prefix}__profile-number`}>{pubkey}</div> : null}
</span>
);
};

@ -1,4 +1,4 @@
import React, { useContext } from 'react';
import React from 'react';
import styled from 'styled-components';
import {
@ -10,10 +10,10 @@ import {
isVideoAttachment,
} from '../../types/Attachment';
import { useIsMessageVisible } from '../../contexts/isMessageVisibleContext';
import { useMessageSelected } from '../../state/selectors';
import { THUMBNAIL_SIDE } from '../../types/attachments/VisualAttachment';
import { Image } from './Image';
import { IsMessageVisibleContext } from './message/message-content/MessageContent';
type Props = {
attachments: Array<AttachmentTypeWithPath>;
@ -46,7 +46,7 @@ const Row = (
totalAttachmentsCount,
selected,
} = props;
const isMessageVisible = useContext(IsMessageVisibleContext);
const isMessageVisible = useIsMessageVisible();
const moreMessagesOverlay = totalAttachmentsCount > 3;
const moreMessagesOverlayText = moreMessagesOverlay ? `+${totalAttachmentsCount - 3}` : undefined;

@ -1,9 +1,9 @@
import React, { useContext, useLayoutEffect } from 'react';
import React, { useLayoutEffect } from 'react';
import { useSelector } from 'react-redux';
import styled from 'styled-components';
import { useScrollToLoadedMessage } from '../../contexts/ScrollToLoadedMessage';
import { getQuotedMessageToAnimate } from '../../state/selectors/conversations';
import { isDarkTheme } from '../../state/selectors/theme';
import { ScrollToLoadedMessageContext } from './SessionMessagesListContainer';
const LastSeenBar = styled.div`
height: 2px;
@ -52,7 +52,7 @@ export const SessionLastSeenIndicator = (props: {
const darkMode = useSelector(isDarkTheme);
// if this unread-indicator is not unique it's going to cause issues
const quotedMessageToAnimate = useSelector(getQuotedMessageToAnimate);
const scrollToLoadedMessage = useContext(ScrollToLoadedMessageContext);
const scrollToLoadedMessage = useScrollToLoadedMessage();
const { messageId, didScroll, setDidScroll } = props;

@ -26,9 +26,10 @@ import { Message } from './message/message-item/Message';
import { MessageRequestResponse } from './message/message-item/MessageRequestResponse';
import { CallNotification } from './message/message-item/notification-bubble/CallNotification';
import { DataExtractionNotification } from './message/message-item/DataExtractionNotification';
import { IsDetailMessageViewContext } from '../../contexts/isDetailViewContext';
import { SessionLastSeenIndicator } from './SessionLastSeenIndicator';
import { TimerNotification } from './TimerNotification';
import { DataExtractionNotification } from './message/message-item/DataExtractionNotification';
import { InteractionNotification } from './message/message-item/InteractionNotification';
function isNotTextboxEvent(e: KeyboardEvent) {
@ -98,7 +99,7 @@ export const SessionMessagesList = (props: {
}
return (
<>
<IsDetailMessageViewContext.Provider value={false}>
{messagesProps.map(messageProps => {
const messageId = messageProps.message.props.messageId;
const unreadIndicator = messageProps.showUnreadIndicator ? (
@ -170,6 +171,6 @@ export const SessionMessagesList = (props: {
return [<Message messageId={messageId} key={messageId} />, ...componentToMerge];
})}
</>
</IsDetailMessageViewContext.Provider>
);
};

@ -15,6 +15,10 @@ import {
} from '../../state/ducks/conversations';
import { SessionScrollButton } from '../SessionScrollButton';
import {
ScrollToLoadedMessageContext,
ScrollToLoadedReasons,
} from '../../contexts/ScrollToLoadedMessage';
import { StateType } from '../../state/reducer';
import {
getQuotedMessageToAnimate,
@ -31,17 +35,6 @@ export type SessionMessageListProps = {
};
export const messageContainerDomID = 'messages-container';
export type ScrollToLoadedReasons =
| 'quote-or-search-result'
| 'go-to-bottom'
| 'unread-indicator'
| 'load-more-top'
| 'load-more-bottom';
export const ScrollToLoadedMessageContext = React.createContext(
(_loadedMessageIdToScrollTo: string, _reason: ScrollToLoadedReasons) => {}
);
type Props = SessionMessageListProps & {
conversationKey?: string;
messagesProps: Array<SortedMessageModelProps>;

@ -1,10 +1,13 @@
import classNames from 'classnames';
import { isEmpty } from 'lodash';
import moment from 'moment';
import React, { createContext, useCallback, useContext, useLayoutEffect, useState } from 'react';
import React, { useCallback, useLayoutEffect, useState } from 'react';
import { InView } from 'react-intersection-observer';
import { useSelector } from 'react-redux';
import styled from 'styled-components';
import { useScrollToLoadedMessage } from '../../../../contexts/ScrollToLoadedMessage';
import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext';
import { IsMessageVisibleContext } from '../../../../contexts/isMessageVisibleContext';
import { MessageModelType, MessageRenderingProps } from '../../../../models/messageType';
import { StateType } from '../../../../state/reducer';
import {
@ -19,8 +22,6 @@ import {
} from '../../../../state/selectors/conversations';
import { useSelectedIsPrivate } from '../../../../state/selectors/selectedConversation';
import { canDisplayImage } from '../../../../types/Attachment';
import { ScrollToLoadedMessageContext } from '../../SessionMessagesListContainer';
import { hasDetailView } from '../message-item/Message';
import { MessageAttachment } from './MessageAttachment';
import { MessageAvatar } from './MessageAvatar';
import { MessageHighlighter } from './MessageHighlighter';
@ -33,7 +34,7 @@ export type MessageContentSelectorProps = Pick<
'text' | 'direction' | 'timestamp' | 'serverTimestamp' | 'previews' | 'quote' | 'attachments'
>;
type Props = hasDetailView & {
type Props = {
messageId: string;
};
@ -76,13 +77,13 @@ const StyledMessageOpaqueContent = styled(MessageHighlighter)<{
${props => props.selected && `box-shadow: var(--drop-shadow);`}
`;
export const IsMessageVisibleContext = createContext(false);
const StyledAvatarContainer = styled.div`
align-self: flex-end;
`;
export const MessageContent = (props: Props) => {
const isDetailView = useIsDetailMessageView();
const [highlight, setHighlight] = useState(false);
const [didScroll, setDidScroll] = useState(false);
const contentProps = useSelector((state: StateType) =>
@ -91,9 +92,9 @@ export const MessageContent = (props: Props) => {
const isDeleted = useMessageIsDeleted(props.messageId);
const [isMessageVisible, setMessageIsVisible] = useState(false);
const scrollToLoadedMessage = useContext(ScrollToLoadedMessageContext);
const scrollToLoadedMessage = useScrollToLoadedMessage();
const selectedIsPrivate = useSelectedIsPrivate();
const hideAvatar = useHideAvatarInMsgList(props.messageId, props.isDetailView);
const hideAvatar = useHideAvatarInMsgList(props.messageId, isDetailView);
const [imageBroken, setImageBroken] = useState(false);
@ -153,8 +154,7 @@ export const MessageContent = (props: Props) => {
const toolTipTitle = moment(serverTimestamp || timestamp).format('llll');
const isDetailViewAndSupportsAttachmentCarousel =
props.isDetailView && canDisplayImage(attachments);
const isDetailViewAndSupportsAttachmentCarousel = isDetailView && canDisplayImage(attachments);
return (
<StyledMessageContent
@ -181,6 +181,7 @@ export const MessageContent = (props: Props) => {
display: 'flex',
flexDirection: 'column',
gap: 'var(--margins-xs)',
maxWidth: '100%',
}}
>
<IsMessageVisibleContext.Provider value={isMessageVisible}>
@ -192,7 +193,7 @@ export const MessageContent = (props: Props) => {
>
{!isDeleted && (
<>
<MessageQuote messageId={props.messageId} isDetailView={props.isDetailView} />
<MessageQuote messageId={props.messageId} />
<MessageLinkPreview
messageId={props.messageId}
handleImageError={handleImageError}

@ -2,6 +2,7 @@ import classNames from 'classnames';
import React, { useCallback, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import styled from 'styled-components';
import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext';
import { replyToMessage } from '../../../../interactions/conversationInteractions';
import { MessageRenderingProps } from '../../../../models/messageType';
import { toggleSelectedMessageId } from '../../../../state/ducks/conversations';
@ -15,7 +16,6 @@ import {
import { Reactions } from '../../../../util/reactions';
import { Flex } from '../../../basic/Flex';
import { ExpirableReadableMessage } from '../message-item/ExpirableReadableMessage';
import { hasDetailView } from '../message-item/Message';
import { MessageAuthorText } from './MessageAuthorText';
import { MessageContent } from './MessageContent';
import { MessageContextMenu } from './MessageContextMenu';
@ -27,14 +27,14 @@ export type MessageContentWithStatusSelectorProps = { isGroup: boolean } & Pick<
'conversationType' | 'direction' | 'isDeleted'
>;
type Props = hasDetailView & {
type Props = {
messageId: string;
ctxMenuID: string;
dataTestId: string;
enableReactions: boolean;
};
const StyledMessageContentContainer = styled.div<hasDetailView & { isIncoming: boolean }>`
const StyledMessageContentContainer = styled.div<{ isIncoming: boolean; isDetailView: boolean }>`
display: flex;
flex-direction: column;
justify-content: flex-start;
@ -42,17 +42,20 @@ const StyledMessageContentContainer = styled.div<hasDetailView & { isIncoming: b
padding-left: ${props => (props.isDetailView || props.isIncoming ? 0 : '25%')};
padding-right: ${props => (props.isDetailView || !props.isIncoming ? 0 : '25%')};
width: 100%;
max-width: '100%';
margin-right: var(--margins-md);
`;
const StyledMessageWithAuthor = styled.div`
max-width: '100%';
max-width: 100%;
display: flex;
flex-direction: column;
min-width: 0;
`;
export const MessageContentWithStatuses = (props: Props) => {
const isDetailView = useIsDetailMessageView();
const contentProps = useSelector((state: StateType) =>
getMessageContentWithStatusesSelectorProps(state, props.messageId)
);
@ -91,7 +94,7 @@ export const MessageContentWithStatuses = (props: Props) => {
}
};
const { messageId, ctxMenuID, isDetailView = false, dataTestId, enableReactions } = props;
const { messageId, ctxMenuID, dataTestId, enableReactions } = props;
const [popupReaction, setPopupReaction] = useState('');
if (!contentProps) {
@ -128,21 +131,22 @@ export const MessageContentWithStatuses = (props: Props) => {
messageId={messageId}
className={classNames('module-message', `module-message--${direction}`)}
role={'button'}
isDetailView={isDetailView}
onClick={onClickOnMessageOuterContainer}
onDoubleClickCapture={onDoubleClickReplyToMessage}
dataTestId={dataTestId}
>
<Flex container={true} flexDirection="column" flexShrink={0} alignItems="flex-end">
<Flex
container={true}
flexDirection="column"
flexShrink={0}
alignItems="flex-end"
maxWidth="100%"
>
<StyledMessageWithAuthor>
{!isDetailView && <MessageAuthorText messageId={messageId} />}
<MessageContent messageId={messageId} isDetailView={isDetailView} />
<MessageContent messageId={messageId} />
</StyledMessageWithAuthor>
<MessageStatus
dataTestId="msg-status"
messageId={messageId}
isDetailView={isDetailView}
/>
<MessageStatus dataTestId="msg-status" messageId={messageId} />
</Flex>
{!isDeleted && (
<MessageContextMenu
@ -161,7 +165,6 @@ export const MessageContentWithStatuses = (props: Props) => {
setPopupReaction={setPopupReaction}
onPopupClick={handlePopupClick}
noAvatar={hideAvatar}
isDetailView={isDetailView}
/>
) : null}
</StyledMessageContentContainer>

@ -1,6 +1,7 @@
import { isEmpty, toNumber } from 'lodash';
import React from 'react';
import { useSelector } from 'react-redux';
import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext';
import { Data } from '../../../../data/data';
import { MessageRenderingProps } from '../../../../models/messageType';
import { ToastUtils } from '../../../../session/utils';
@ -8,10 +9,9 @@ import { openConversationToSpecificMessage } from '../../../../state/ducks/conve
import { StateType } from '../../../../state/reducer';
import { useMessageDirection } from '../../../../state/selectors';
import { getMessageQuoteProps } from '../../../../state/selectors/conversations';
import { hasDetailView } from '../message-item/Message';
import { Quote } from './quote/Quote';
type Props = hasDetailView & {
type Props = {
messageId: string;
};
@ -20,6 +20,7 @@ export type MessageQuoteSelectorProps = Pick<MessageRenderingProps, 'quote' | 'd
export const MessageQuote = (props: Props) => {
const selected = useSelector((state: StateType) => getMessageQuoteProps(state, props.messageId));
const direction = useMessageDirection(props.messageId);
const isMessageDetailView = useIsDetailMessageView();
if (!selected || isEmpty(selected)) {
return null;
@ -39,6 +40,10 @@ export const MessageQuote = (props: Props) => {
event.preventDefault();
event.stopPropagation();
if (isMessageDetailView) {
return;
}
if (!quote) {
ToastUtils.pushOriginalNotFound();
window.log.warn('onQuoteClick: quote not valid');
@ -98,7 +103,6 @@ export const MessageQuote = (props: Props) => {
author={quote.author}
referencedMessageNotFound={quoteNotFound}
isFromMe={Boolean(quote.isFromMe)}
isDetailView={props.isDetailView}
/>
);
};

@ -1,6 +1,7 @@
import { isEmpty, isEqual } from 'lodash';
import React, { ReactElement, useEffect, useState } from 'react';
import styled from 'styled-components';
import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext';
import { useMessageReactsPropsById } from '../../../../hooks/useParamSelector';
import { MessageRenderingProps } from '../../../../models/messageType';
import { REACT_LIMIT } from '../../../../session/constants';
@ -9,7 +10,6 @@ import { SortedReactionList } from '../../../../types/Reaction';
import { nativeEmojiData } from '../../../../util/emoji';
import { Flex } from '../../../basic/Flex';
import { SessionIcon } from '../../../icon';
import { hasDetailView } from '../message-item/Message';
import { Reaction, ReactionProps } from '../reactions/Reaction';
import { StyledPopupContainer } from '../reactions/ReactionPopup';
@ -138,7 +138,7 @@ export type MessageReactsSelectorProps = Pick<
'convoId' | 'serverId' | 'reacts' | 'sortedReacts'
>;
type Props = hasDetailView & {
type Props = {
messageId: string;
hasReactLimit?: boolean;
onClick: (emoji: string) => void;
@ -151,6 +151,8 @@ type Props = hasDetailView & {
};
export const MessageReactions = (props: Props) => {
const isDetailView = useIsDetailMessageView();
const {
messageId,
hasReactLimit = true,
@ -161,7 +163,6 @@ export const MessageReactions = (props: Props) => {
inModal = false,
onSelected,
noAvatar,
isDetailView,
} = props;
const [reactions, setReactions] = useState<SortedReactionList>([]);

@ -5,14 +5,14 @@ import styled from 'styled-components';
import { useMessageExpirationPropsById } from '../../../../hooks/useParamSelector';
import { useMessageStatus } from '../../../../state/selectors';
import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext';
import { getMostRecentMessageId } from '../../../../state/selectors/conversations';
import { useSelectedIsGroupOrCommunity } from '../../../../state/selectors/selectedConversation';
import { SpacerXS } from '../../../basic/Text';
import { SessionIcon, SessionIconType } from '../../../icon';
import { ExpireTimer } from '../../ExpireTimer';
import { hasDetailView } from '../message-item/Message';
type Props = hasDetailView & {
type Props = {
messageId: string;
dataTestId?: string | undefined;
};
@ -30,7 +30,9 @@ type Props = hasDetailView & {
* - if the message is incoming: do not show anything (3)
* - if the message is outgoing: show the text for the last message, or a message sending, or in the error state. (4)
*/
export const MessageStatus = ({ isDetailView, messageId, dataTestId }: Props) => {
export const MessageStatus = ({ messageId, dataTestId }: Props) => {
const isDetailView = useIsDetailMessageView();
const status = useMessageStatus(messageId);
const selected = useMessageExpirationPropsById(messageId);

@ -4,7 +4,6 @@ import { isEmpty } from 'lodash';
import styled from 'styled-components';
import { useIsMessageSelectionMode } from '../../../../../state/selectors/selectedConversation';
import * as MIME from '../../../../../types/MIME';
import { hasDetailView } from '../../message-item/Message';
import { QuoteAuthor } from './QuoteAuthor';
import { QuoteIconContainer } from './QuoteIconContainer';
import { QuoteText } from './QuoteText';
@ -44,7 +43,7 @@ const StyledQuoteTextContent = styled.div`
justify-content: center;
`;
export type QuoteProps = hasDetailView & {
export type QuoteProps = {
author: string;
isFromMe: boolean;
isIncoming: boolean;
@ -71,7 +70,7 @@ export interface QuotedAttachmentType {
export const Quote = (props: QuoteProps) => {
const isSelectionMode = useIsMessageSelectionMode();
const { isIncoming, attachment, text, isDetailView, referencedMessageNotFound, onClick } = props;
const { isIncoming, attachment, text, referencedMessageNotFound, onClick } = props;
const [imageBroken, setImageBroken] = useState(false);
const handleImageErrorBound = () => {
@ -96,7 +95,7 @@ export const Quote = (props: QuoteProps) => {
referencedMessageNotFound={referencedMessageNotFound}
/>
<StyledQuoteTextContent>
<QuoteAuthor author={props.author} isIncoming={isIncoming} isDetailView={isDetailView} />
<QuoteAuthor author={props.author} isIncoming={isIncoming} />
<QuoteText
isIncoming={isIncoming}
text={text}

@ -4,10 +4,9 @@ import { useQuoteAuthorName } from '../../../../../hooks/useParamSelector';
import { PubKey } from '../../../../../session/types';
import { useSelectedIsPublic } from '../../../../../state/selectors/selectedConversation';
import { ContactName } from '../../../ContactName';
import { hasDetailView } from '../../message-item/Message';
import { QuoteProps } from './Quote';
const StyledQuoteAuthor = styled.div<hasDetailView & { isIncoming: boolean }>`
const StyledQuoteAuthor = styled.div<{ isIncoming: boolean }>`
color: ${props =>
props.isIncoming
? 'var(--message-bubbles-received-text-color)'
@ -17,17 +16,18 @@ const StyledQuoteAuthor = styled.div<hasDetailView & { isIncoming: boolean }>`
line-height: 18px;
margin-bottom: 2px;
overflow-x: hidden;
white-space: ${props => (props.isDetailView ? undefined : 'nowrap')};
white-space: nowrap;
text-overflow: ellipsis;
.module-contact-name {
font-weight: bold;
}
`;
type QuoteAuthorProps = Pick<QuoteProps, 'author' | 'isIncoming'> & hasDetailView;
type QuoteAuthorProps = Pick<QuoteProps, 'author' | 'isIncoming'>;
export const QuoteAuthor = (props: QuoteAuthorProps) => {
const { author, isIncoming, isDetailView } = props;
const { author, isIncoming } = props;
const isPublic = useSelectedIsPublic();
const { authorName, isMe } = useQuoteAuthorName(author);
@ -37,7 +37,7 @@ export const QuoteAuthor = (props: QuoteAuthorProps) => {
}
return (
<StyledQuoteAuthor isIncoming={isIncoming} isDetailView={isDetailView}>
<StyledQuoteAuthor isIncoming={isIncoming}>
<ContactName
pubkey={PubKey.shorten(author)}
name={authorName}

@ -2,6 +2,7 @@ import React, { useCallback, useState } from 'react';
import { useDispatch } from 'react-redux';
import { useInterval, useMount } from 'react-use';
import styled from 'styled-components';
import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext';
import { Data } from '../../../../data/data';
import { useMessageExpirationPropsById } from '../../../../hooks/useParamSelector';
import { MessageModelType } from '../../../../models/messageType';
@ -9,7 +10,6 @@ import { getConversationController } from '../../../../session/conversations';
import { PropsForExpiringMessage, messagesExpired } from '../../../../state/ducks/conversations';
import { getIncrement } from '../../../../util/timer';
import { ExpireTimer } from '../../ExpireTimer';
import { hasDetailView } from './Message';
import { ReadableMessage, ReadableMessageProps } from './ReadableMessage';
const EXPIRATION_CHECK_MINIMUM = 2000;
@ -82,8 +82,7 @@ const StyledReadableMessage = styled(ReadableMessage)<{
`;
export interface ExpirableReadableMessageProps
extends hasDetailView,
Omit<ReadableMessageProps, 'receivedAt' | 'isUnread'> {
extends Omit<ReadableMessageProps, 'receivedAt' | 'isUnread'> {
messageId: string;
isControlMessage?: boolean;
}
@ -110,6 +109,7 @@ function ExpireTimerControlMessage({
export const ExpirableReadableMessage = (props: ExpirableReadableMessageProps) => {
const selected = useMessageExpirationPropsById(props.messageId);
const isDetailView = useIsDetailMessageView();
const { isControlMessage, onClick, onDoubleClickCapture, role, dataTestId } = props;
@ -136,7 +136,7 @@ export const ExpirableReadableMessage = (props: ExpirableReadableMessageProps) =
} = selected;
// NOTE we want messages on the left in the message detail view regardless of direction
const direction = props.isDetailView ? 'incoming' : _direction;
const direction = isDetailView ? 'incoming' : _direction;
const isIncoming = direction === 'incoming';
return (

@ -4,6 +4,7 @@ import React, { useCallback, useEffect, useState } from 'react';
import { contextMenu } from 'react-contexify';
import { useSelector } from 'react-redux';
import styled, { keyframes } from 'styled-components';
import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext';
import { MessageRenderingProps } from '../../../../models/messageType';
import { getConversationController } from '../../../../session/conversations';
import { StateType } from '../../../../state/reducer';
@ -14,7 +15,6 @@ import {
} from '../../../../state/selectors/conversations';
import { MessageContentWithStatuses } from '../message-content/MessageContentWithStatus';
import { StyledMessageReactionsContainer } from '../message-content/MessageReactions';
import { hasDetailView } from './Message';
export type GenericReadableMessageSelectorProps = Pick<
MessageRenderingProps,
@ -27,7 +27,7 @@ export type GenericReadableMessageSelectorProps = Pick<
| 'isDeleted'
>;
type Props = hasDetailView & {
type Props = {
messageId: string;
ctxMenuID: string;
};
@ -38,12 +38,11 @@ const highlightedMessageAnimation = keyframes`
}
`;
const StyledReadableMessage = styled.div<
hasDetailView & {
selected: boolean;
isRightClicked: boolean;
}
>`
const StyledReadableMessage = styled.div<{
selected: boolean;
isDetailView: boolean;
isRightClicked: boolean;
}>`
display: flex;
align-items: center;
width: 100%;
@ -65,7 +64,9 @@ const StyledReadableMessage = styled.div<
`;
export const GenericReadableMessage = (props: Props) => {
const { ctxMenuID, messageId, isDetailView } = props;
const isDetailView = useIsDetailMessageView();
const { ctxMenuID, messageId } = props;
const [enableReactions, setEnableReactions] = useState(true);
@ -149,7 +150,6 @@ export const GenericReadableMessage = (props: Props) => {
<MessageContentWithStatuses
ctxMenuID={ctxMenuID}
messageId={messageId}
isDetailView={isDetailView}
dataTestId={'message-content'}
enableReactions={enableReactions}
/>

@ -10,10 +10,7 @@ import { GenericReadableMessage } from './GenericReadableMessage';
// Same as MIN_WIDTH in ImageGrid.tsx
export const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = THUMBNAIL_SIDE;
/** when the message info panel is displayed for a message, we disable onClick and make some other minor UI changes */
export type hasDetailView = { isDetailView?: boolean };
type Props = hasDetailView & {
type Props = {
messageId: string;
};
@ -28,11 +25,5 @@ export const Message = (props: Props) => {
return null;
}
return (
<GenericReadableMessage
ctxMenuID={ctxMenuID}
messageId={props.messageId}
isDetailView={props.isDetailView}
/>
);
return <GenericReadableMessage ctxMenuID={ctxMenuID} messageId={props.messageId} />;
};

@ -1,14 +1,8 @@
import { debounce, noop } from 'lodash';
import React, {
AriaRole,
MouseEventHandler,
useCallback,
useContext,
useLayoutEffect,
useState,
} from 'react';
import React, { AriaRole, MouseEventHandler, useCallback, useLayoutEffect, useState } from 'react';
import { InView } from 'react-intersection-observer';
import { useDispatch, useSelector } from 'react-redux';
import { useScrollToLoadedMessage } from '../../../../contexts/ScrollToLoadedMessage';
import { Data } from '../../../../data/data';
import { useHasUnread } from '../../../../hooks/useParamSelector';
import { getConversationController } from '../../../../session/conversations';
@ -28,7 +22,6 @@ import {
} from '../../../../state/selectors/conversations';
import { getIsAppFocused } from '../../../../state/selectors/section';
import { useSelectedConversationKey } from '../../../../state/selectors/selectedConversation';
import { ScrollToLoadedMessageContext } from '../../SessionMessagesListContainer';
export type ReadableMessageProps = {
children: React.ReactNode;
@ -95,7 +88,7 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
const [didScroll, setDidScroll] = useState(false);
const quotedMessageToAnimate = useSelector(getQuotedMessageToAnimate);
const scrollToLoadedMessage = useContext(ScrollToLoadedMessageContext);
const scrollToLoadedMessage = useScrollToLoadedMessage();
// if this unread-indicator is rendered,
// we want to scroll here only if the conversation was not opened to a specific message

@ -10,6 +10,7 @@ import { getMessageInfoId } from '../../../../../state/selectors/conversations';
import { Flex } from '../../../../basic/Flex';
import { Header, HeaderTitle, StyledScrollContainer } from '../components';
import { IsDetailMessageViewContext } from '../../../../../contexts/isDetailViewContext';
import { Data } from '../../../../../data/data';
import { useRightOverlayMode } from '../../../../../hooks/useUI';
import {
@ -71,9 +72,11 @@ const MessageBody = ({
}
return (
<StyledMessageBody>
<Message messageId={messageId} isDetailView={true} />
</StyledMessageBody>
<IsDetailMessageViewContext.Provider value={true}>
<StyledMessageBody>
<Message messageId={messageId} />
</StyledMessageBody>
</IsDetailMessageViewContext.Provider>
);
};

@ -10,6 +10,10 @@ import { Avatar, AvatarSize } from '../../avatar/Avatar';
import { openConversationWithMessages } from '../../../state/ducks/conversations';
import { updateUserDetailsModal } from '../../../state/ducks/modalDialog';
import {
ContextConversationProvider,
useConvoIdFromContext,
} from '../../../contexts/ConvoIdContext';
import {
useAvatarPath,
useConversationUsername,
@ -21,7 +25,6 @@ import {
import { isSearching } from '../../../state/selectors/search';
import { useSelectedConversationKey } from '../../../state/selectors/selectedConversation';
import { MemoConversationListItemContextMenu } from '../../menu/ConversationListItemContextMenu';
import { ContextConversationProvider, useConvoIdFromContext } from './ConvoIdContext';
import { ConversationListItemHeaderItem } from './HeaderItem';
import { MessageItem } from './MessageItem';

@ -2,6 +2,7 @@ import classNames from 'classnames';
import React from 'react';
import { useSelector } from 'react-redux';
import styled from 'styled-components';
import { useConvoIdFromContext } from '../../../contexts/ConvoIdContext';
import { Data } from '../../../data/data';
import {
useActiveAt,
@ -20,7 +21,6 @@ import { isSearching } from '../../../state/selectors/search';
import { getIsMessageSection } from '../../../state/selectors/section';
import { Timestamp } from '../../conversation/Timestamp';
import { SessionIcon } from '../../icon';
import { useConvoIdFromContext } from './ConvoIdContext';
import { UserItem } from './UserItem';
const NotificationSettingIcon = () => {

@ -2,6 +2,7 @@ import classNames from 'classnames';
import { isEmpty } from 'lodash';
import React from 'react';
import { useSelector } from 'react-redux';
import { useConvoIdFromContext } from '../../../contexts/ConvoIdContext';
import {
useHasUnread,
useIsPrivate,
@ -15,7 +16,6 @@ import { assertUnreachable } from '../../../types/sqlSharedTypes';
import { TypingAnimation } from '../../conversation/TypingAnimation';
import { MessageBody } from '../../conversation/message/message-content/MessageBody';
import { SessionIcon } from '../../icon';
import { useConvoIdFromContext } from './ConvoIdContext';
import { InteractionItem } from './InteractionItem';
export const MessageItem = () => {

@ -1,5 +1,6 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { useConvoIdFromContext } from '../../../contexts/ConvoIdContext';
import {
useConversationRealName,
useConversationUsername,
@ -9,7 +10,6 @@ import {
import { PubKey } from '../../../session/types';
import { isSearching } from '../../../state/selectors/search';
import { ContactName } from '../../conversation/ContactName';
import { useConvoIdFromContext } from './ConvoIdContext';
export const UserItem = () => {
const conversationId = useConvoIdFromContext();
@ -36,15 +36,13 @@ export const UserItem = () => {
}
return (
<div className="module-conversation__user">
<ContactName
pubkey={displayedPubkey}
name={username}
profileName={displayName}
module="module-conversation__user"
boldProfileName={true}
shouldShowPubkey={shouldShowPubkey}
/>
</div>
<ContactName
pubkey={displayedPubkey}
name={username}
profileName={displayName}
module="module-conversation__user"
boldProfileName={true}
shouldShowPubkey={shouldShowPubkey}
/>
);
};

@ -2,10 +2,11 @@ import React from 'react';
import { Item, Menu } from 'react-contexify';
import { useSelector } from 'react-redux';
import { useConvoIdFromContext } from '../../contexts/ConvoIdContext';
import { useIsPinned, useIsPrivate, useIsPrivateAndFriend } from '../../hooks/useParamSelector';
import { getConversationController } from '../../session/conversations';
import { isSearching } from '../../state/selectors/search';
import { getIsMessageSection } from '../../state/selectors/section';
import { useConvoIdFromContext } from '../leftpane/conversation-list-item/ConvoIdContext';
import { SessionContextMenuContainer } from '../SessionContextMenuContainer';
import {
AcceptMsgRequestMenuItem,
@ -17,16 +18,15 @@ import {
DeclineAndBlockMsgRequestMenuItem,
DeclineMsgRequestMenuItem,
DeleteMessagesMenuItem,
DeletePrivateConversationMenuItem,
InviteContactMenuItem,
LeaveGroupOrCommunityMenuItem,
MarkAllReadMenuItem,
MarkConversationUnreadMenuItem,
NotificationForConvoMenuItem,
ShowUserDetailsMenuItem,
UnbanMenuItem,
DeletePrivateConversationMenuItem,
NotificationForConvoMenuItem,
} from './Menu';
import { isSearching } from '../../state/selectors/search';
export type PropsContextConversationItem = {
triggerId: string;

@ -2,6 +2,7 @@ import React from 'react';
import { Item, Submenu } from 'react-contexify';
import { useDispatch, useSelector } from 'react-redux';
import { useConvoIdFromContext } from '../../contexts/ConvoIdContext';
import {
useAvatarPath,
useConversationUsername,
@ -56,7 +57,6 @@ import { getIsMessageSection } from '../../state/selectors/section';
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
import { LocalizerKeys } from '../../types/LocalizerKeys';
import { SessionButtonColor } from '../basic/SessionButton';
import { useConvoIdFromContext } from '../leftpane/conversation-list-item/ConvoIdContext';
/** Menu items standardized */

@ -1,15 +1,15 @@
import React from 'react';
import styled, { CSSProperties } from 'styled-components';
import { useConversationUsername, useIsPrivate } from '../../hooks/useParamSelector';
import { MessageAttributes } from '../../models/messageType';
import { UserUtils } from '../../session/utils';
import { getOurPubKeyStrFromCache } from '../../session/utils/User';
import { openConversationToSpecificMessage } from '../../state/ducks/conversations';
import { ContactName } from '../conversation/ContactName';
import { Avatar, AvatarSize } from '../avatar/Avatar';
import { Timestamp } from '../conversation/Timestamp';
import { MessageBodyHighlight } from '../basic/MessageBodyHighlight';
import { MessageAttributes } from '../../models/messageType';
import { useConversationUsername, useIsPrivate } from '../../hooks/useParamSelector';
import { UserUtils } from '../../session/utils';
import { ContactName } from '../conversation/ContactName';
import { Timestamp } from '../conversation/Timestamp';
export type MessageResultProps = MessageAttributes & { snippet: string };
@ -58,6 +58,7 @@ const StyledResultText = styled.div`
display: inline-flex;
flex-direction: column;
align-items: stretch;
min-width: 0;
`;
const ResultsHeader = styled.div`

@ -0,0 +1,16 @@
import { createContext, useContext } from 'react';
export type ScrollToLoadedReasons =
| 'quote-or-search-result'
| 'go-to-bottom'
| 'unread-indicator'
| 'load-more-top'
| 'load-more-bottom';
export const ScrollToLoadedMessageContext = createContext(
(_loadedMessageIdToScrollTo: string, _reason: ScrollToLoadedReasons) => {}
);
export function useScrollToLoadedMessage() {
return useContext(ScrollToLoadedMessageContext);
}

@ -0,0 +1,10 @@
import { createContext, useContext } from 'react';
/**
* When the message is rendered as part of the detailView (right panel) we disable onClick and make some other minor UI changes
*/
export const IsDetailMessageViewContext = createContext<boolean>(false);
export function useIsDetailMessageView() {
return useContext(IsDetailMessageViewContext);
}

@ -0,0 +1,7 @@
import { createContext, useContext } from 'react';
export const IsMessageVisibleContext = createContext(false);
export function useIsMessageVisible() {
return useContext(IsMessageVisibleContext);
}
Loading…
Cancel
Save