fix: ellipsis on name rather than pubkey

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

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

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

@ -1,4 +1,4 @@
import React, { useContext } from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { import {
@ -10,10 +10,10 @@ import {
isVideoAttachment, isVideoAttachment,
} from '../../types/Attachment'; } from '../../types/Attachment';
import { useIsMessageVisible } from '../../contexts/isMessageVisibleContext';
import { useMessageSelected } from '../../state/selectors'; import { useMessageSelected } from '../../state/selectors';
import { THUMBNAIL_SIDE } from '../../types/attachments/VisualAttachment'; import { THUMBNAIL_SIDE } from '../../types/attachments/VisualAttachment';
import { Image } from './Image'; import { Image } from './Image';
import { IsMessageVisibleContext } from './message/message-content/MessageContent';
type Props = { type Props = {
attachments: Array<AttachmentTypeWithPath>; attachments: Array<AttachmentTypeWithPath>;
@ -46,7 +46,7 @@ const Row = (
totalAttachmentsCount, totalAttachmentsCount,
selected, selected,
} = props; } = props;
const isMessageVisible = useContext(IsMessageVisibleContext); const isMessageVisible = useIsMessageVisible();
const moreMessagesOverlay = totalAttachmentsCount > 3; const moreMessagesOverlay = totalAttachmentsCount > 3;
const moreMessagesOverlayText = moreMessagesOverlay ? `+${totalAttachmentsCount - 3}` : undefined; 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 { useSelector } from 'react-redux';
import styled from 'styled-components'; import styled from 'styled-components';
import { useScrollToLoadedMessage } from '../../contexts/ScrollToLoadedMessage';
import { getQuotedMessageToAnimate } from '../../state/selectors/conversations'; import { getQuotedMessageToAnimate } from '../../state/selectors/conversations';
import { isDarkTheme } from '../../state/selectors/theme'; import { isDarkTheme } from '../../state/selectors/theme';
import { ScrollToLoadedMessageContext } from './SessionMessagesListContainer';
const LastSeenBar = styled.div` const LastSeenBar = styled.div`
height: 2px; height: 2px;
@ -52,7 +52,7 @@ export const SessionLastSeenIndicator = (props: {
const darkMode = useSelector(isDarkTheme); const darkMode = useSelector(isDarkTheme);
// if this unread-indicator is not unique it's going to cause issues // if this unread-indicator is not unique it's going to cause issues
const quotedMessageToAnimate = useSelector(getQuotedMessageToAnimate); const quotedMessageToAnimate = useSelector(getQuotedMessageToAnimate);
const scrollToLoadedMessage = useContext(ScrollToLoadedMessageContext); const scrollToLoadedMessage = useScrollToLoadedMessage();
const { messageId, didScroll, setDidScroll } = props; const { messageId, didScroll, setDidScroll } = props;

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

@ -15,6 +15,10 @@ import {
} from '../../state/ducks/conversations'; } from '../../state/ducks/conversations';
import { SessionScrollButton } from '../SessionScrollButton'; import { SessionScrollButton } from '../SessionScrollButton';
import {
ScrollToLoadedMessageContext,
ScrollToLoadedReasons,
} from '../../contexts/ScrollToLoadedMessage';
import { StateType } from '../../state/reducer'; import { StateType } from '../../state/reducer';
import { import {
getQuotedMessageToAnimate, getQuotedMessageToAnimate,
@ -31,17 +35,6 @@ export type SessionMessageListProps = {
}; };
export const messageContainerDomID = 'messages-container'; 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 & { type Props = SessionMessageListProps & {
conversationKey?: string; conversationKey?: string;
messagesProps: Array<SortedMessageModelProps>; messagesProps: Array<SortedMessageModelProps>;

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

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

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

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

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

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

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

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

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

@ -10,10 +10,7 @@ import { GenericReadableMessage } from './GenericReadableMessage';
// Same as MIN_WIDTH in ImageGrid.tsx // Same as MIN_WIDTH in ImageGrid.tsx
export const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = THUMBNAIL_SIDE; 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 */ type Props = {
export type hasDetailView = { isDetailView?: boolean };
type Props = hasDetailView & {
messageId: string; messageId: string;
}; };
@ -28,11 +25,5 @@ export const Message = (props: Props) => {
return null; return null;
} }
return ( return <GenericReadableMessage ctxMenuID={ctxMenuID} messageId={props.messageId} />;
<GenericReadableMessage
ctxMenuID={ctxMenuID}
messageId={props.messageId}
isDetailView={props.isDetailView}
/>
);
}; };

@ -1,14 +1,8 @@
import { debounce, noop } from 'lodash'; import { debounce, noop } from 'lodash';
import React, { import React, { AriaRole, MouseEventHandler, useCallback, useLayoutEffect, useState } from 'react';
AriaRole,
MouseEventHandler,
useCallback,
useContext,
useLayoutEffect,
useState,
} from 'react';
import { InView } from 'react-intersection-observer'; import { InView } from 'react-intersection-observer';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { useScrollToLoadedMessage } from '../../../../contexts/ScrollToLoadedMessage';
import { Data } from '../../../../data/data'; import { Data } from '../../../../data/data';
import { useHasUnread } from '../../../../hooks/useParamSelector'; import { useHasUnread } from '../../../../hooks/useParamSelector';
import { getConversationController } from '../../../../session/conversations'; import { getConversationController } from '../../../../session/conversations';
@ -28,7 +22,6 @@ import {
} from '../../../../state/selectors/conversations'; } from '../../../../state/selectors/conversations';
import { getIsAppFocused } from '../../../../state/selectors/section'; import { getIsAppFocused } from '../../../../state/selectors/section';
import { useSelectedConversationKey } from '../../../../state/selectors/selectedConversation'; import { useSelectedConversationKey } from '../../../../state/selectors/selectedConversation';
import { ScrollToLoadedMessageContext } from '../../SessionMessagesListContainer';
export type ReadableMessageProps = { export type ReadableMessageProps = {
children: React.ReactNode; children: React.ReactNode;
@ -95,7 +88,7 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
const [didScroll, setDidScroll] = useState(false); const [didScroll, setDidScroll] = useState(false);
const quotedMessageToAnimate = useSelector(getQuotedMessageToAnimate); const quotedMessageToAnimate = useSelector(getQuotedMessageToAnimate);
const scrollToLoadedMessage = useContext(ScrollToLoadedMessageContext); const scrollToLoadedMessage = useScrollToLoadedMessage();
// if this unread-indicator is rendered, // if this unread-indicator is rendered,
// we want to scroll here only if the conversation was not opened to a specific message // 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 { Flex } from '../../../../basic/Flex';
import { Header, HeaderTitle, StyledScrollContainer } from '../components'; import { Header, HeaderTitle, StyledScrollContainer } from '../components';
import { IsDetailMessageViewContext } from '../../../../../contexts/isDetailViewContext';
import { Data } from '../../../../../data/data'; import { Data } from '../../../../../data/data';
import { useRightOverlayMode } from '../../../../../hooks/useUI'; import { useRightOverlayMode } from '../../../../../hooks/useUI';
import { import {
@ -71,9 +72,11 @@ const MessageBody = ({
} }
return ( return (
<StyledMessageBody> <IsDetailMessageViewContext.Provider value={true}>
<Message messageId={messageId} isDetailView={true} /> <StyledMessageBody>
</StyledMessageBody> <Message messageId={messageId} />
</StyledMessageBody>
</IsDetailMessageViewContext.Provider>
); );
}; };

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

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

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

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

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

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

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