diff --git a/src/components/common/File.scss b/src/components/common/File.scss index 6756fcb66..dad721a96 100644 --- a/src/components/common/File.scss +++ b/src/components/common/File.scss @@ -7,6 +7,9 @@ .content-inner & { min-width: 14rem; + @media (max-width: 340px) { + min-width: 11rem; + } } display: flex; diff --git a/src/components/common/helpers/mediaDimensions.ts b/src/components/common/helpers/mediaDimensions.ts index 578e4aff3..7877dc6da 100644 --- a/src/components/common/helpers/mediaDimensions.ts +++ b/src/components/common/helpers/mediaDimensions.ts @@ -11,34 +11,56 @@ export const AVATAR_FULL_DIMENSIONS = { width: 640, height: 640 }; const DEFAULT_MEDIA_DIMENSIONS: IDimensions = { width: 100, height: 100 }; export const LIKE_STICKER_ID = '1258816259753933'; -const MOBILE_SCREEN_MAX_MESSAGE_SCREEN_WIDTH = 0.69; +const MOBILE_SCREEN_NO_AVATARS_MESSAGE_EXTRA_WIDTH_REM = 4.5; +const MOBILE_SCREEN_MESSAGE_EXTRA_WIDTH_REM = 7; +const MESSAGE_MAX_WIDTH_REM = 29; +const MESSAGE_OWN_MAX_WIDTH_REM = 30; +let cachedMaxWidthOwn: number | undefined; let cachedMaxWidth: number | undefined; +let cachedMaxWidthNoAvatar: number | undefined; -function getMaxMessageWidthRem(fromOwnMessage: boolean) { - const regularMaxWidth = fromOwnMessage ? 30 : 29; +function getMaxMessageWidthRem(fromOwnMessage: boolean, noAvatars?: boolean) { + const regularMaxWidth = fromOwnMessage ? MESSAGE_OWN_MAX_WIDTH_REM : MESSAGE_MAX_WIDTH_REM; if (!IS_SINGLE_COLUMN_LAYOUT) { return regularMaxWidth; } + const { width: windowWidth } = windowSize.get(); + // @optimization Limitation: changing device screen width not supported + if (!cachedMaxWidthOwn) { + cachedMaxWidthOwn = Math.min( + MESSAGE_OWN_MAX_WIDTH_REM, + windowWidth / REM - MOBILE_SCREEN_NO_AVATARS_MESSAGE_EXTRA_WIDTH_REM, + ); + } if (!cachedMaxWidth) { cachedMaxWidth = Math.min( - regularMaxWidth, - Math.floor(window.innerWidth * MOBILE_SCREEN_MAX_MESSAGE_SCREEN_WIDTH) / REM, + MESSAGE_MAX_WIDTH_REM, + windowWidth / REM - MOBILE_SCREEN_MESSAGE_EXTRA_WIDTH_REM, + ); + } + if (!cachedMaxWidthNoAvatar) { + cachedMaxWidthNoAvatar = Math.min( + MESSAGE_MAX_WIDTH_REM, + windowWidth / REM - MOBILE_SCREEN_NO_AVATARS_MESSAGE_EXTRA_WIDTH_REM, ); } - return cachedMaxWidth; + return fromOwnMessage + ? cachedMaxWidthOwn + : (noAvatars ? cachedMaxWidthNoAvatar : cachedMaxWidth); } -function getAvailableWidth( +export function getAvailableWidth( fromOwnMessage: boolean, isForwarded?: boolean, isWebPagePhoto?: boolean, + noAvatars?: boolean, ) { const extraPaddingRem = isForwarded || isWebPagePhoto ? 1.625 : 0; - const availableWidthRem = getMaxMessageWidthRem(fromOwnMessage) - extraPaddingRem; + const availableWidthRem = getMaxMessageWidthRem(fromOwnMessage, noAvatars) - extraPaddingRem; return availableWidthRem * REM; } @@ -61,6 +83,7 @@ function calculateDimensionsForMessageMedia({ isForwarded, isWebPagePhoto, isGif, + noAvatars, }: { width: number; height: number; @@ -68,9 +91,10 @@ function calculateDimensionsForMessageMedia({ isForwarded?: boolean; isWebPagePhoto?: boolean; isGif?: boolean; + noAvatars?: boolean; }): IDimensions { const aspectRatio = height / width; - const availableWidth = getAvailableWidth(fromOwnMessage, isForwarded, isWebPagePhoto); + const availableWidth = getAvailableWidth(fromOwnMessage, isForwarded, isWebPagePhoto, noAvatars); const availableHeight = getAvailableHeight(isGif, aspectRatio); return calculateDimensions(availableWidth, availableHeight, width, height); @@ -95,6 +119,7 @@ export function calculateInlineImageDimensions( fromOwnMessage: boolean, isForwarded?: boolean, isWebPagePhoto?: boolean, + noAvatars?: boolean, ) { const { width, height } = getPhotoInlineDimensions(photo) || DEFAULT_MEDIA_DIMENSIONS; @@ -104,6 +129,7 @@ export function calculateInlineImageDimensions( fromOwnMessage, isForwarded, isWebPagePhoto, + noAvatars, }); } @@ -111,6 +137,7 @@ export function calculateVideoDimensions( video: ApiVideo, fromOwnMessage: boolean, isForwarded?: boolean, + noAvatars?: boolean, ) { const { width, height } = getVideoDimensions(video) || DEFAULT_MEDIA_DIMENSIONS; @@ -120,6 +147,7 @@ export function calculateVideoDimensions( fromOwnMessage, isForwarded, isGif: video.isGif, + noAvatars, }); } diff --git a/src/components/middle/MessageList.tsx b/src/components/middle/MessageList.tsx index 45e31aa4a..d79303390 100644 --- a/src/components/middle/MessageList.tsx +++ b/src/components/middle/MessageList.tsx @@ -508,11 +508,11 @@ const MessageList: FC = ({ const isPrivate = Boolean(chatId && isChatPrivate(chatId)); const withUsers = Boolean((!isPrivate && !isChannelChat) || isChatWithSelf); + const noAvatars = Boolean(!withUsers || isChannelChat); const className = buildClassName( 'MessageList custom-scroll', - !withUsers && 'no-avatars', - isChannelChat && 'no-avatars', + noAvatars && 'no-avatars', !canPost && 'no-composer', type === 'pinned' && 'type-pinned', isSelectModeActive && 'select-mode-active', @@ -551,6 +551,7 @@ const MessageList: FC = ({ observeIntersectionForMedia, observeIntersectionForAnimatedStickers, withUsers, + noAvatars, anchorIdRef, memoUnreadDividerBeforeIdRef, threadId, @@ -577,6 +578,7 @@ function renderMessages( observeIntersectionForMedia: ObserveFn, observeIntersectionForAnimatedStickers: ObserveFn, withUsers: boolean, + noAvatars: boolean, currentAnchorIdRef: { current: string | undefined }, memoFirstUnreadIdRef: { current: number | undefined }, threadId: number, @@ -676,6 +678,7 @@ function renderMessages( observeIntersectionForMedia={observeIntersectionForMedia} observeIntersectionForAnimatedStickers={observeIntersectionForAnimatedStickers} album={album} + noAvatars={noAvatars} withAvatar={position.isLastInGroup && withUsers && !isOwn && !(message.id === threadTopMessageId)} withSenderName={position.isFirstInGroup && withUsers && !isOwn} threadId={threadId} diff --git a/src/components/middle/message/Message.tsx b/src/components/middle/message/Message.tsx index 266fddd1a..7117978a8 100644 --- a/src/components/middle/message/Message.tsx +++ b/src/components/middle/message/Message.tsx @@ -71,7 +71,6 @@ import renderText from '../../common/helpers/renderText'; import calculateAuthorWidth from './helpers/calculateAuthorWidth'; import { ObserveFn, useOnIntersect } from '../../../hooks/useIntersectionObserver'; import useFocusMessage from './hooks/useFocusMessage'; -import useWindowSize from '../../../hooks/useWindowSize'; import useLang from '../../../hooks/useLang'; import useShowTransition from '../../../hooks/useShowTransition'; import useFlag from '../../../hooks/useFlag'; @@ -112,6 +111,7 @@ type OwnProps = { observeIntersectionForMedia: ObserveFn; observeIntersectionForAnimatedStickers: ObserveFn; album?: IAlbum; + noAvatars?: boolean; withAvatar?: boolean; withSenderName?: boolean; threadId: number; @@ -175,6 +175,7 @@ const Message: FC = ({ observeIntersectionForMedia, observeIntersectionForAnimatedStickers, album, + noAvatars, withAvatar, withSenderName, noComments, @@ -236,8 +237,6 @@ const Message: FC = ({ useOnIntersect(bottomMarkerRef, observeIntersectionForBottom); - const { width: windowWidth } = useWindowSize(); - const { isContextMenuOpen, contextMenuPosition, handleBeforeContextMenu, handleContextMenu, @@ -277,6 +276,24 @@ const Message: FC = ({ const customShape = getMessageCustomShape(message); const textParts = renderMessageText(message, highlight, isEmojiOnlyMessage(customShape)); const isContextMenuShown = contextMenuPosition !== undefined; + const signature = ( + (isChannel && message.adminTitle) || (forwardInfo && !asForwarded && forwardInfo.adminTitle) || undefined + ); + const metaSafeAuthorWidth = useMemo(() => { + return signature ? calculateAuthorWidth(signature) : undefined; + }, [signature]); + const canShowActionButton = ( + !(isContextMenuShown || isInSelectMode || isForwarding) + && (!isInDocumentGroup || isLastInDocumentGroup) + ); + const canForward = canShowActionButton && isChannel && !isScheduled; + const canFocus = Boolean(canShowActionButton && ( + (forwardInfo && (forwardInfo.isChannelPost || (isChatWithSelf && !isOwn)) && forwardInfo.fromMessageId) + || isPinnedList + )); + const avatarPeer = forwardInfo && (isChatWithSelf || !sender) ? originSender : sender; + const senderPeer = forwardInfo ? originSender : sender; + const containerClassName = buildClassName( 'Message message-list-item', isFirstInGroup && 'first-in-group', @@ -310,11 +327,6 @@ const Message: FC = ({ forceSenderName, hasComments: message.threadInfo && message.threadInfo.messagesCount > 0, }); - const avatarPeer = forwardInfo && (isChatWithSelf || !sender) ? originSender : sender; - const senderPeer = forwardInfo ? originSender : sender; - const signature = ( - (isChannel && message.adminTitle) || (forwardInfo && !asForwarded && forwardInfo.adminTitle) || undefined - ); const withCommentButton = message.threadInfo && (!isInDocumentGroup || isLastInDocumentGroup) && messageListType === 'thread' && !noComments; const withAppendix = contentClassName.includes('has-appendix'); @@ -470,19 +482,19 @@ const Message: FC = ({ let calculatedWidth; let noMediaCorners = false; const albumLayout = useMemo(() => { - return isAlbum ? calculateAlbumLayout(isOwn, Boolean(asForwarded), album!, windowWidth) : undefined; - }, [isAlbum, windowWidth, isOwn, asForwarded, album]); + return isAlbum ? calculateAlbumLayout(isOwn, Boolean(asForwarded), Boolean(noAvatars), album!) : undefined; + }, [isAlbum, isOwn, asForwarded, noAvatars, album]); const extraPadding = asForwarded ? 28 : 0; if (!isAlbum && (photo || video)) { let width: number | undefined; if (photo) { - width = calculateMediaDimensions(message).width; + width = calculateMediaDimensions(message, noAvatars).width; } else if (video) { if (video.isRound) { width = ROUND_VIDEO_DIMENSIONS; } else { - width = calculateMediaDimensions(message).width; + width = calculateMediaDimensions(message, noAvatars).width; } } @@ -577,6 +589,7 @@ const Message: FC = ({ = ({