fix: drop shadow renders correctly

moved to individual text and image attachments, need to check the other attachment types
pull/3020/head
William Grant 4 months ago
parent b34bf1380a
commit 0ecdcd93a0

@ -134,7 +134,6 @@ textarea {
.module-message__container { .module-message__container {
position: relative; position: relative;
display: inline-block; display: inline-block;
overflow: hidden;
min-width: 30px; min-width: 30px;
// To limit messages with things forcing them wider, like long attachment names. // To limit messages with things forcing them wider, like long attachment names.
width: 100%; width: 100%;

@ -24,6 +24,7 @@ type Props = {
playIconOverlay?: boolean; playIconOverlay?: boolean;
softCorners: boolean; softCorners: boolean;
forceSquare?: boolean; forceSquare?: boolean;
dropShadow?: boolean;
attachmentIndex?: number; attachmentIndex?: number;
onClick?: (attachment: AttachmentTypeWithPath | AttachmentType) => void; onClick?: (attachment: AttachmentTypeWithPath | AttachmentType) => void;
@ -55,6 +56,7 @@ export const Image = (props: Props) => {
playIconOverlay, playIconOverlay,
softCorners, softCorners,
forceSquare, forceSquare,
dropShadow,
attachmentIndex, attachmentIndex,
url, url,
width: _width, width: _width,
@ -101,6 +103,7 @@ export const Image = (props: Props) => {
maxWidth: width, maxWidth: width,
minHeight: height, minHeight: height,
minWidth: width, minWidth: width,
boxShadow: dropShadow ? 'var(--drop-shadow)' : undefined,
}} }}
data-attachmentindex={attachmentIndex} data-attachmentindex={attachmentIndex}
> >

@ -10,14 +10,16 @@ import {
isVideoAttachment, isVideoAttachment,
} from '../../types/Attachment'; } from '../../types/Attachment';
import { useMessageSelected } from '../../state/selectors';
import { THUMBNAIL_SIDE } from '../../types/attachments/VisualAttachment';
import { Image } from './Image'; import { Image } from './Image';
import { IsMessageVisibleContext } from './message/message-content/MessageContent'; import { IsMessageVisibleContext } from './message/message-content/MessageContent';
import { THUMBNAIL_SIDE } from '../../types/attachments/VisualAttachment';
type Props = { type Props = {
attachments: Array<AttachmentTypeWithPath>; attachments: Array<AttachmentTypeWithPath>;
onError: () => void; onError: () => void;
onClickAttachment?: (attachment: AttachmentTypeWithPath | AttachmentType) => void; onClickAttachment?: (attachment: AttachmentTypeWithPath | AttachmentType) => void;
messageId?: string;
}; };
const StyledImageGrid = styled.div<{ flexDirection: 'row' | 'column' }>` const StyledImageGrid = styled.div<{ flexDirection: 'row' | 'column' }>`
@ -28,7 +30,12 @@ const StyledImageGrid = styled.div<{ flexDirection: 'row' | 'column' }>`
`; `;
const Row = ( const Row = (
props: Props & { renderedSize: number; startIndex: number; totalAttachmentsCount: number } props: Props & {
renderedSize: number;
startIndex: number;
totalAttachmentsCount: number;
selected: boolean;
}
) => { ) => {
const { const {
attachments, attachments,
@ -37,6 +44,7 @@ const Row = (
startIndex, startIndex,
onClickAttachment, onClickAttachment,
totalAttachmentsCount, totalAttachmentsCount,
selected,
} = props; } = props;
const isMessageVisible = useContext(IsMessageVisibleContext); const isMessageVisible = useContext(IsMessageVisibleContext);
const moreMessagesOverlay = totalAttachmentsCount > 3; const moreMessagesOverlay = totalAttachmentsCount > 3;
@ -61,6 +69,7 @@ const Row = (
softCorners={true} softCorners={true}
darkOverlay={showOverlay} darkOverlay={showOverlay}
overlayText={showOverlay ? moreMessagesOverlayText : undefined} overlayText={showOverlay ? moreMessagesOverlayText : undefined}
dropShadow={selected}
/> />
); );
})} })}
@ -69,7 +78,9 @@ const Row = (
}; };
export const ImageGrid = (props: Props) => { export const ImageGrid = (props: Props) => {
const { attachments, onError, onClickAttachment } = props; const { attachments, onError, onClickAttachment, messageId } = props;
const selected = useMessageSelected(messageId);
if (!attachments || !attachments.length) { if (!attachments || !attachments.length) {
return null; return null;
@ -85,6 +96,7 @@ export const ImageGrid = (props: Props) => {
renderedSize={THUMBNAIL_SIDE} renderedSize={THUMBNAIL_SIDE}
startIndex={0} startIndex={0}
totalAttachmentsCount={attachments.length} totalAttachmentsCount={attachments.length}
selected={selected}
/> />
</StyledImageGrid> </StyledImageGrid>
); );
@ -101,6 +113,7 @@ export const ImageGrid = (props: Props) => {
renderedSize={THUMBNAIL_SIDE} renderedSize={THUMBNAIL_SIDE}
startIndex={0} startIndex={0}
totalAttachmentsCount={attachments.length} totalAttachmentsCount={attachments.length}
selected={selected}
/> />
</StyledImageGrid> </StyledImageGrid>
); );
@ -118,6 +131,7 @@ export const ImageGrid = (props: Props) => {
renderedSize={THUMBNAIL_SIDE} renderedSize={THUMBNAIL_SIDE}
startIndex={0} startIndex={0}
totalAttachmentsCount={attachments.length} totalAttachmentsCount={attachments.length}
selected={selected}
/> />
<StyledImageGrid flexDirection={'column'}> <StyledImageGrid flexDirection={'column'}>
@ -128,6 +142,7 @@ export const ImageGrid = (props: Props) => {
renderedSize={columnImageSide} renderedSize={columnImageSide}
startIndex={1} startIndex={1}
totalAttachmentsCount={attachments.length} totalAttachmentsCount={attachments.length}
selected={selected}
/> />
</StyledImageGrid> </StyledImageGrid>
</StyledImageGrid> </StyledImageGrid>

@ -51,8 +51,7 @@ type Props = SessionMessageListProps & {
scrollToNow: () => Promise<void>; scrollToNow: () => Promise<void>;
}; };
// isGroup is used to align the ExpireTimer with the member avatars const StyledMessagesContainer = styled.div`
const StyledMessagesContainer = styled.div<{ isGroup: boolean }>`
display: flex; display: flex;
flex-grow: 1; flex-grow: 1;
gap: var(--margins-sm); gap: var(--margins-sm);
@ -61,12 +60,8 @@ const StyledMessagesContainer = styled.div<{ isGroup: boolean }>`
overflow-x: hidden; overflow-x: hidden;
min-width: 370px; min-width: 370px;
scrollbar-width: 4px; scrollbar-width: 4px;
padding-top: var(--margins-sm);
// TODO fixing spacing around messages when in multi-select mode
/* padding-top: var(--margins-sm);
padding-right: var(--margins-lg);
padding-bottom: var(--margins-xl); padding-bottom: var(--margins-xl);
padding-left: ${props => (props.isGroup ? 'var(--margins-xs)' : 'var(--margins-lg)')}; */
.session-icon-button { .session-icon-button {
display: flex; display: flex;
@ -127,7 +122,6 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
<StyledMessagesContainer <StyledMessagesContainer
className="messages-container" className="messages-container"
id={messageContainerDomID} id={messageContainerDomID}
isGroup={!conversation.isPrivate}
onScroll={this.handleScroll} onScroll={this.handleScroll}
ref={this.props.messageContainerRef} ref={this.props.messageContainerRef}
data-testid="messages-container" data-testid="messages-container"

@ -32,7 +32,7 @@ import { AudioPlayerWithEncryptedFile } from '../../H5AudioPlayer';
import { ImageGrid } from '../../ImageGrid'; import { ImageGrid } from '../../ImageGrid';
import { LightBoxOptions } from '../../SessionConversation'; import { LightBoxOptions } from '../../SessionConversation';
import { ClickToTrustSender } from './ClickToTrustSender'; import { ClickToTrustSender } from './ClickToTrustSender';
import { StyledMessageHighlighter } from './MessageContent'; import { MessageHighlighter } from './MessageHighlighter';
export type MessageAttachmentSelectorProps = Pick< export type MessageAttachmentSelectorProps = Pick<
MessageRenderingProps, MessageRenderingProps,
@ -138,21 +138,22 @@ export const MessageAttachment = (props: Props) => {
(isVideo(attachments) && hasVideoScreenshot(attachments))) (isVideo(attachments) && hasVideoScreenshot(attachments)))
) { ) {
return ( return (
<StyledMessageHighlighter highlight={highlight}> <MessageHighlighter highlight={highlight}>
<StyledAttachmentContainer messageDirection={direction}> <StyledAttachmentContainer messageDirection={direction}>
<ImageGrid <ImageGrid
messageId={messageId}
attachments={attachments} attachments={attachments}
onError={handleImageError} onError={handleImageError}
onClickAttachment={onClickOnImageGrid} onClickAttachment={onClickOnImageGrid}
/> />
</StyledAttachmentContainer> </StyledAttachmentContainer>
</StyledMessageHighlighter> </MessageHighlighter>
); );
} }
if (!firstAttachment.pending && !firstAttachment.error && isAudio(attachments)) { if (!firstAttachment.pending && !firstAttachment.error && isAudio(attachments)) {
return ( return (
<StyledMessageHighlighter <MessageHighlighter
highlight={highlight} highlight={highlight}
role="main" role="main"
onClick={(e: any) => { onClick={(e: any) => {
@ -168,14 +169,14 @@ export const MessageAttachment = (props: Props) => {
contentType={firstAttachment.contentType} contentType={firstAttachment.contentType}
messageId={messageId} messageId={messageId}
/> />
</StyledMessageHighlighter> </MessageHighlighter>
); );
} }
const { pending, fileName, fileSize, contentType } = firstAttachment; const { pending, fileName, fileSize, contentType } = firstAttachment;
const extension = getExtensionForDisplay({ contentType, fileName }); const extension = getExtensionForDisplay({ contentType, fileName });
return ( return (
<StyledMessageHighlighter highlight={highlight} className="module-message__generic-attachment"> <MessageHighlighter highlight={highlight} className="module-message__generic-attachment">
{pending ? ( {pending ? (
<div className="module-message__generic-attachment__spinner-container"> <div className="module-message__generic-attachment__spinner-container">
<Spinner size="small" /> <Spinner size="small" />
@ -211,7 +212,7 @@ export const MessageAttachment = (props: Props) => {
{fileSize} {fileSize}
</div> </div>
</div> </div>
</StyledMessageHighlighter> </MessageHighlighter>
); );
}; };

@ -4,10 +4,14 @@ import moment from 'moment';
import React, { createContext, useCallback, useContext, useLayoutEffect, useState } from 'react'; import React, { createContext, useCallback, useContext, 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, { css, keyframes } from 'styled-components'; import styled from 'styled-components';
import { MessageModelType, MessageRenderingProps } from '../../../../models/messageType'; import { MessageModelType, MessageRenderingProps } from '../../../../models/messageType';
import { StateType } from '../../../../state/reducer'; import { StateType } from '../../../../state/reducer';
import { useHideAvatarInMsgList, useMessageIsDeleted } from '../../../../state/selectors'; import {
useHideAvatarInMsgList,
useMessageIsDeleted,
useMessageSelected,
} from '../../../../state/selectors';
import { import {
getMessageContentSelectorProps, getMessageContentSelectorProps,
getQuotedMessageToAnimate, getQuotedMessageToAnimate,
@ -21,6 +25,7 @@ import { canDisplayImage } from '../../../../types/Attachment';
import { ScrollToLoadedMessageContext } from '../../SessionMessagesListContainer'; import { ScrollToLoadedMessageContext } from '../../SessionMessagesListContainer';
import { MessageAttachment } from './MessageAttachment'; import { MessageAttachment } from './MessageAttachment';
import { MessageAvatar } from './MessageAvatar'; import { MessageAvatar } from './MessageAvatar';
import { MessageHighlighter } from './MessageHighlighter';
import { MessageLinkPreview } from './MessageLinkPreview'; import { MessageLinkPreview } from './MessageLinkPreview';
import { MessageQuote } from './MessageQuote'; import { MessageQuote } from './MessageQuote';
import { MessageText } from './MessageText'; import { MessageText } from './MessageText';
@ -58,37 +63,10 @@ const StyledMessageContent = styled.div<{ msgDirection: MessageModelType }>`
align-self: ${props => (props.msgDirection === 'incoming' ? 'flex-start' : 'flex-end')}; align-self: ${props => (props.msgDirection === 'incoming' ? 'flex-start' : 'flex-end')};
`; `;
const opacityAnimation = keyframes` const StyledMessageOpaqueContent = styled(MessageHighlighter)<{
0% {
opacity: 1;
}
25% {
opacity: 0.2;
}
50% {
opacity: 1;
}
75% {
opacity: 0.2;
}
100% {
opacity: 1;
}
`;
export const StyledMessageHighlighter = styled.div<{
highlight: boolean;
}>`
${props =>
props.highlight &&
css`
animation: ${opacityAnimation} 1s linear;
`}
`;
const StyledMessageOpaqueContent = styled(StyledMessageHighlighter)<{
isIncoming: boolean; isIncoming: boolean;
highlight: boolean; highlight: boolean;
selected: boolean;
}>` }>`
background: ${props => background: ${props =>
props.isIncoming props.isIncoming
@ -98,6 +76,8 @@ const StyledMessageOpaqueContent = styled(StyledMessageHighlighter)<{
padding: var(--padding-message-content); padding: var(--padding-message-content);
border-radius: var(--border-radius-message-box); border-radius: var(--border-radius-message-box);
width: 100%; width: 100%;
${props => props.selected && `box-shadow: var(--drop-shadow);`}
`; `;
export const IsMessageVisibleContext = createContext(false); export const IsMessageVisibleContext = createContext(false);
@ -125,7 +105,7 @@ export const MessageContent = (props: Props) => {
const [imageBroken, setImageBroken] = useState(false); const [imageBroken, setImageBroken] = useState(false);
const onVisible = (inView: boolean, _: IntersectionObserverEntry) => { const onVisible = (inView: boolean, _: IntersectionObserverEntry) => {
// TODO check if there is no issue with focus after simplifiying the check // TODO[epic=ses-1409] check if there is no issue with focus after simplifiying the check
if (inView) { if (inView) {
if (isMessageVisible !== true) { if (isMessageVisible !== true) {
setMessageIsVisible(true); setMessageIsVisible(true);
@ -140,7 +120,7 @@ export const MessageContent = (props: Props) => {
const quotedMessageToAnimate = useSelector(getQuotedMessageToAnimate); const quotedMessageToAnimate = useSelector(getQuotedMessageToAnimate);
const shouldHighlightMessage = useSelector(getShouldHighlightMessage); const shouldHighlightMessage = useSelector(getShouldHighlightMessage);
const isQuotedMessageToAnimate = quotedMessageToAnimate === props.messageId; const isQuotedMessageToAnimate = quotedMessageToAnimate === props.messageId;
// const selected = useMessageSelected(props.messageId); const selected = useMessageSelected(props.messageId);
useLayoutEffect(() => { useLayoutEffect(() => {
if (isQuotedMessageToAnimate) { if (isQuotedMessageToAnimate) {
@ -222,7 +202,11 @@ export const MessageContent = (props: Props) => {
> >
<IsMessageVisibleContext.Provider value={isMessageVisible}> <IsMessageVisibleContext.Provider value={isMessageVisible}>
{hasContentBeforeAttachment && ( {hasContentBeforeAttachment && (
<StyledMessageOpaqueContent isIncoming={direction === 'incoming'} highlight={highlight}> <StyledMessageOpaqueContent
isIncoming={direction === 'incoming'}
highlight={highlight}
selected={selected}
>
{!isDeleted && ( {!isDeleted && (
<> <>
<MessageQuote messageId={props.messageId} /> <MessageQuote messageId={props.messageId} />

@ -0,0 +1,29 @@
import styled, { css, keyframes } from 'styled-components';
const opacityAnimation = keyframes`
0% {
opacity: 1;
}
25% {
opacity: 0.2;
}
50% {
opacity: 1;
}
75% {
opacity: 0.2;
}
100% {
opacity: 1;
}
`;
export const MessageHighlighter = styled.div<{
highlight: boolean;
}>`
${props =>
props.highlight &&
css`
animation: ${opacityAnimation} 1s linear;
`}
`;
Loading…
Cancel
Save