Thread Message: Add comments button for document group (#6779)
This commit is contained in:
parent
6f29b81ae7
commit
a44ecb0113
@ -3,7 +3,7 @@ import { getIsHeavyAnimating, memo } from '../../lib/teact/teact';
|
|||||||
import { getActions, getGlobal } from '../../global';
|
import { getActions, getGlobal } from '../../global';
|
||||||
|
|
||||||
import type { ApiMessage } from '../../api/types';
|
import type { ApiMessage } from '../../api/types';
|
||||||
import type { IAlbum, MessageListType, ThreadId } from '../../types';
|
import type { IAlbum, IDocumentGroup, MessageListType, ThreadId } from '../../types';
|
||||||
import type { Signal } from '../../util/signals';
|
import type { Signal } from '../../util/signals';
|
||||||
import type { MessageDateGroup } from './helpers/groupMessages';
|
import type { MessageDateGroup } from './helpers/groupMessages';
|
||||||
import type { OnIntersectPinnedMessage } from './hooks/usePinnedMessage';
|
import type { OnIntersectPinnedMessage } from './hooks/usePinnedMessage';
|
||||||
@ -26,7 +26,7 @@ import { formatHumanDate, formatScheduledDateTime } from '../../util/dates/oldDa
|
|||||||
import { convertTonFromNanos } from '../../util/formatCurrency';
|
import { convertTonFromNanos } from '../../util/formatCurrency';
|
||||||
import { compact } from '../../util/iteratees';
|
import { compact } from '../../util/iteratees';
|
||||||
import { formatStarsAsText, formatTonAsText } from '../../util/localization/format';
|
import { formatStarsAsText, formatTonAsText } from '../../util/localization/format';
|
||||||
import { isAlbum } from './helpers/groupMessages';
|
import { isAlbum, isDocumentGroup } from './helpers/groupMessages';
|
||||||
import { preventMessageInputBlur } from './helpers/preventMessageInputBlur';
|
import { preventMessageInputBlur } from './helpers/preventMessageInputBlur';
|
||||||
import { renderPeerLink } from './message/helpers/messageActions';
|
import { renderPeerLink } from './message/helpers/messageActions';
|
||||||
|
|
||||||
@ -130,6 +130,7 @@ const MessageListContent = ({
|
|||||||
|
|
||||||
const areDatesClickable = !isSavedDialog && !isSchedule;
|
const areDatesClickable = !isSavedDialog && !isSchedule;
|
||||||
const shouldRenderSponsoredMessage = canShowAds && isViewportNewest;
|
const shouldRenderSponsoredMessage = canShowAds && isViewportNewest;
|
||||||
|
const shouldHideComments = hasLinkedChat === false || !isChannelChat || Boolean(isChatMonoforum);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
observeIntersectionForReading,
|
observeIntersectionForReading,
|
||||||
@ -270,7 +271,9 @@ const MessageListContent = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const messageCountToAnimate = noAppearanceAnimation ? 0 : messageGroups.reduce((acc, messageGroup) => {
|
const messageCountToAnimate = noAppearanceAnimation ? 0 : messageGroups.reduce((acc, messageGroup) => {
|
||||||
return acc + messageGroup.senderGroups.flat().length;
|
return acc + messageGroup.senderGroups.flat().reduce((innerAcc, messageOrAlbum) => {
|
||||||
|
return innerAcc + (isDocumentGroup(messageOrAlbum) ? messageOrAlbum.messages.length : 1);
|
||||||
|
}, 0);
|
||||||
}, 0);
|
}, 0);
|
||||||
let appearanceIndex = 0;
|
let appearanceIndex = 0;
|
||||||
|
|
||||||
@ -290,6 +293,7 @@ const MessageListContent = ({
|
|||||||
if (
|
if (
|
||||||
senderGroup.length === 1
|
senderGroup.length === 1
|
||||||
&& !isAlbum(senderGroup[0])
|
&& !isAlbum(senderGroup[0])
|
||||||
|
&& !isDocumentGroup(senderGroup[0])
|
||||||
&& isActionMessage(senderGroup[0])
|
&& isActionMessage(senderGroup[0])
|
||||||
&& senderGroup[0].content.action?.type !== 'phoneCall'
|
&& senderGroup[0].content.action?.type !== 'phoneCall'
|
||||||
) {
|
) {
|
||||||
@ -318,31 +322,115 @@ const MessageListContent = ({
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentDocumentGroupId: string | undefined;
|
let currentDocumentGroupHasThreadTop = false;
|
||||||
|
|
||||||
const senderGroupElements = senderGroup.map((
|
const senderGroupElements = senderGroup.map((
|
||||||
messageOrAlbum,
|
messageOrAlbum,
|
||||||
messageIndex,
|
messageIndex,
|
||||||
) => {
|
) => {
|
||||||
|
function renderMessageElement(
|
||||||
|
message: ApiMessage,
|
||||||
|
position: {
|
||||||
|
isFirstInGroup: boolean;
|
||||||
|
isLastInGroup: boolean;
|
||||||
|
isFirstInDocumentGroup: boolean;
|
||||||
|
isLastInDocumentGroup: boolean;
|
||||||
|
isLastInList: boolean;
|
||||||
|
},
|
||||||
|
isThreadTopMessage: boolean,
|
||||||
|
album?: IAlbum,
|
||||||
|
documentGroup?: IDocumentGroup,
|
||||||
|
) {
|
||||||
|
const isOwn = isOwnMessage(message);
|
||||||
|
const originalId = getMessageOriginalId(message);
|
||||||
|
const key = isServiceNotificationMessage(message)
|
||||||
|
? `${message.date}_${originalId}` : originalId;
|
||||||
|
|
||||||
|
return compact([
|
||||||
|
message.id === memoUnreadDividerBeforeIdRef.current && unreadDivider,
|
||||||
|
message.paidMessageStars && !withUsers && renderPaidMessageAction(message, album),
|
||||||
|
message.suggestedPostInfo && renderSuggestedPostInfoAction(message),
|
||||||
|
<Message
|
||||||
|
key={key}
|
||||||
|
message={message}
|
||||||
|
observeIntersectionForBottom={observeIntersectionForReading}
|
||||||
|
observeIntersectionForLoading={observeIntersectionForLoading}
|
||||||
|
observeIntersectionForPlaying={observeIntersectionForPlaying}
|
||||||
|
album={album}
|
||||||
|
documentGroup={documentGroup}
|
||||||
|
noAvatars={noAvatars}
|
||||||
|
withAvatar={position.isLastInGroup && withUsers && !isOwn && (!isThreadTopMessage || !isComments)}
|
||||||
|
withSenderName={position.isFirstInGroup && withUsers && !isOwn}
|
||||||
|
threadId={threadId}
|
||||||
|
messageListType={type}
|
||||||
|
noComments={shouldHideComments}
|
||||||
|
noReplies={!shouldHideComments || threadId !== MAIN_THREAD_ID || type === 'scheduled'}
|
||||||
|
appearanceOrder={messageCountToAnimate - ++appearanceIndex}
|
||||||
|
isJustAdded={position.isLastInList && isNewMessage}
|
||||||
|
isThreadTop={isThreadTopMessage}
|
||||||
|
isFirstInGroup={position.isFirstInGroup}
|
||||||
|
isLastInGroup={position.isLastInGroup}
|
||||||
|
isFirstInDocumentGroup={position.isFirstInDocumentGroup}
|
||||||
|
isLastInDocumentGroup={position.isLastInDocumentGroup}
|
||||||
|
isLastInList={position.isLastInList}
|
||||||
|
memoFirstUnreadIdRef={memoFirstUnreadIdRef}
|
||||||
|
getIsMessageListReady={getIsReady}
|
||||||
|
onMessageUnmount={onMessageUnmount}
|
||||||
|
/>,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDocumentGroup(messageOrAlbum)) {
|
||||||
|
const documentGroup = messageOrAlbum;
|
||||||
|
return documentGroup.messages.map((docMessage, docIndex) => {
|
||||||
|
const isFirstInDocGroup = docIndex === 0;
|
||||||
|
const isLastInDocGroup = docIndex === documentGroup.messages.length - 1;
|
||||||
|
|
||||||
|
if (docMessage.previousLocalId && anchorIdRef.current === getMessageHtmlId(docMessage.previousLocalId)) {
|
||||||
|
anchorIdRef.current = getMessageHtmlId(docMessage.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFirstInDocGroup && docMessage.id === threadId) {
|
||||||
|
currentDocumentGroupHasThreadTop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isThreadTopMessage = docMessage.id === threadId || currentDocumentGroupHasThreadTop;
|
||||||
|
|
||||||
|
if (isLastInDocGroup) {
|
||||||
|
currentDocumentGroupHasThreadTop = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const position = {
|
||||||
|
isFirstInGroup: messageIndex === 0 && isFirstInDocGroup,
|
||||||
|
isLastInGroup: messageIndex === senderGroup.length - 1 && isLastInDocGroup,
|
||||||
|
isFirstInDocumentGroup: isFirstInDocGroup,
|
||||||
|
isLastInDocumentGroup: isLastInDocGroup,
|
||||||
|
isLastInList: (
|
||||||
|
messageIndex === senderGroup.length - 1
|
||||||
|
&& isLastInDocGroup
|
||||||
|
&& senderGroupIndex === senderGroupsArray.length - 1
|
||||||
|
&& dateGroupIndex === dateGroupsArray.length - 1
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
return renderMessageElement(docMessage, position, isThreadTopMessage, undefined, documentGroup);
|
||||||
|
}).flat();
|
||||||
|
}
|
||||||
|
|
||||||
const message = isAlbum(messageOrAlbum) ? messageOrAlbum.mainMessage : messageOrAlbum;
|
const message = isAlbum(messageOrAlbum) ? messageOrAlbum.mainMessage : messageOrAlbum;
|
||||||
const album = isAlbum(messageOrAlbum) ? messageOrAlbum : undefined;
|
const album = isAlbum(messageOrAlbum) ? messageOrAlbum : undefined;
|
||||||
const isOwn = isOwnMessage(message);
|
|
||||||
const isMessageAlbum = isAlbum(messageOrAlbum);
|
|
||||||
const nextMessage = senderGroup[messageIndex + 1];
|
|
||||||
|
|
||||||
if (message.previousLocalId && anchorIdRef.current === getMessageHtmlId(message.previousLocalId)) {
|
if (message.previousLocalId && anchorIdRef.current === getMessageHtmlId(message.previousLocalId)) {
|
||||||
anchorIdRef.current = getMessageHtmlId(message.id);
|
anchorIdRef.current = getMessageHtmlId(message.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const documentGroupId = !isMessageAlbum && message.groupedId ? message.groupedId : undefined;
|
|
||||||
const nextDocumentGroupId = nextMessage && !isAlbum(nextMessage) ? nextMessage.groupedId : undefined;
|
|
||||||
const isThreadTopMessage = message.id === threadId;
|
const isThreadTopMessage = message.id === threadId;
|
||||||
|
|
||||||
const position = {
|
const position = {
|
||||||
isFirstInGroup: messageIndex === 0,
|
isFirstInGroup: messageIndex === 0,
|
||||||
isLastInGroup: messageIndex === senderGroup.length - 1,
|
isLastInGroup: messageIndex === senderGroup.length - 1,
|
||||||
isFirstInDocumentGroup: Boolean(documentGroupId && documentGroupId !== currentDocumentGroupId),
|
isFirstInDocumentGroup: false,
|
||||||
isLastInDocumentGroup: Boolean(documentGroupId && documentGroupId !== nextDocumentGroupId),
|
isLastInDocumentGroup: false,
|
||||||
isLastInList: (
|
isLastInList: (
|
||||||
messageIndex === senderGroup.length - 1
|
messageIndex === senderGroup.length - 1
|
||||||
&& senderGroupIndex === senderGroupsArray.length - 1
|
&& senderGroupIndex === senderGroupsArray.length - 1
|
||||||
@ -350,60 +438,33 @@ const MessageListContent = ({
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
currentDocumentGroupId = documentGroupId;
|
return renderMessageElement(message, position, isThreadTopMessage, album);
|
||||||
|
|
||||||
const originalId = getMessageOriginalId(message);
|
|
||||||
// Service notifications saved in cache in previous versions may share the same `previousLocalId`
|
|
||||||
const key = isServiceNotificationMessage(message) ? `${message.date}_${originalId}` : originalId;
|
|
||||||
|
|
||||||
const noComments = hasLinkedChat === false || !isChannelChat || Boolean(isChatMonoforum);
|
|
||||||
|
|
||||||
return compact([
|
|
||||||
message.id === memoUnreadDividerBeforeIdRef.current && unreadDivider,
|
|
||||||
message.paidMessageStars && !withUsers && renderPaidMessageAction(message, album),
|
|
||||||
message.suggestedPostInfo && renderSuggestedPostInfoAction(message),
|
|
||||||
<Message
|
|
||||||
key={key}
|
|
||||||
message={message}
|
|
||||||
observeIntersectionForBottom={observeIntersectionForReading}
|
|
||||||
observeIntersectionForLoading={observeIntersectionForLoading}
|
|
||||||
observeIntersectionForPlaying={observeIntersectionForPlaying}
|
|
||||||
album={album}
|
|
||||||
noAvatars={noAvatars}
|
|
||||||
withAvatar={position.isLastInGroup && withUsers && !isOwn && (!isThreadTopMessage || !isComments)}
|
|
||||||
withSenderName={position.isFirstInGroup && withUsers && !isOwn}
|
|
||||||
threadId={threadId}
|
|
||||||
messageListType={type}
|
|
||||||
noComments={noComments}
|
|
||||||
noReplies={!noComments || threadId !== MAIN_THREAD_ID || type === 'scheduled'}
|
|
||||||
appearanceOrder={messageCountToAnimate - ++appearanceIndex}
|
|
||||||
isJustAdded={position.isLastInList && isNewMessage}
|
|
||||||
isFirstInGroup={position.isFirstInGroup}
|
|
||||||
isLastInGroup={position.isLastInGroup}
|
|
||||||
isFirstInDocumentGroup={position.isFirstInDocumentGroup}
|
|
||||||
isLastInDocumentGroup={position.isLastInDocumentGroup}
|
|
||||||
isLastInList={position.isLastInList}
|
|
||||||
memoFirstUnreadIdRef={memoFirstUnreadIdRef}
|
|
||||||
getIsMessageListReady={getIsReady}
|
|
||||||
onMessageUnmount={onMessageUnmount}
|
|
||||||
/>,
|
|
||||||
]);
|
|
||||||
}).flat();
|
}).flat();
|
||||||
|
|
||||||
if (!withUsers) return senderGroupElements;
|
if (!withUsers) return senderGroupElements;
|
||||||
|
|
||||||
const lastMessageOrAlbum = senderGroup[senderGroup.length - 1];
|
const lastItem = senderGroup[senderGroup.length - 1];
|
||||||
const lastMessage = isAlbum(lastMessageOrAlbum) ? lastMessageOrAlbum.mainMessage : lastMessageOrAlbum;
|
const lastMessage = isAlbum(lastItem)
|
||||||
|
? lastItem.mainMessage
|
||||||
|
: isDocumentGroup(lastItem)
|
||||||
|
? lastItem.messages[lastItem.messages.length - 1]
|
||||||
|
: lastItem;
|
||||||
const lastMessageId = getMessageOriginalId(lastMessage);
|
const lastMessageId = getMessageOriginalId(lastMessage);
|
||||||
const lastAppearanceOrder = messageCountToAnimate - appearanceIndex;
|
const lastAppearanceOrder = messageCountToAnimate - appearanceIndex;
|
||||||
|
|
||||||
const isThreadTopMessage = lastMessage.id === threadId;
|
|
||||||
const isOwn = isOwnMessage(lastMessage);
|
const isOwn = isOwnMessage(lastMessage);
|
||||||
|
|
||||||
const firstMessageOrAlbum = senderGroup[0];
|
const firstItem = senderGroup[0];
|
||||||
const firstMessage = isAlbum(firstMessageOrAlbum) ? firstMessageOrAlbum.mainMessage : firstMessageOrAlbum;
|
const firstMessage = isAlbum(firstItem)
|
||||||
|
? firstItem.mainMessage
|
||||||
|
: isDocumentGroup(firstItem)
|
||||||
|
? firstItem.messages[0]
|
||||||
|
: firstItem;
|
||||||
const firstMessageId = getMessageOriginalId(firstMessage);
|
const firstMessageId = getMessageOriginalId(firstMessage);
|
||||||
|
|
||||||
|
const isThreadTopMessage = lastMessage.id === threadId
|
||||||
|
|| (firstMessage.id === threadId && Boolean(firstMessage.groupedId));
|
||||||
|
|
||||||
const key = `${firstMessageId}-${lastMessageId}`;
|
const key = `${firstMessageId}-${lastMessageId}`;
|
||||||
const id = (firstMessageId === lastMessageId) ? `message-group-${firstMessageId}`
|
const id = (firstMessageId === lastMessageId) ? `message-group-${firstMessageId}`
|
||||||
: `message-group-${firstMessageId}-${lastMessageId}`;
|
: `message-group-${firstMessageId}-${lastMessageId}`;
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import type { ApiMessage } from '../../../api/types';
|
import type { ApiMessage } from '../../../api/types';
|
||||||
import type { IAlbum } from '../../../types';
|
import type { IAlbum, IDocumentGroup } from '../../../types';
|
||||||
|
|
||||||
import { isActionMessage } from '../../../global/helpers';
|
import { isActionMessage } from '../../../global/helpers';
|
||||||
import { getDayStartAt } from '../../../util/dates/oldDateFormat';
|
import { getDayStartAt } from '../../../util/dates/oldDateFormat';
|
||||||
|
|
||||||
type SenderGroup = (ApiMessage | IAlbum)[];
|
type SenderGroup = (ApiMessage | IAlbum | IDocumentGroup)[];
|
||||||
|
|
||||||
const GROUP_INTERVAL_SECONDS = 600; // 10 minutes
|
const GROUP_INTERVAL_SECONDS = 600; // 10 minutes
|
||||||
|
|
||||||
@ -14,10 +14,16 @@ export type MessageDateGroup = {
|
|||||||
senderGroups: SenderGroup[];
|
senderGroups: SenderGroup[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function isAlbum(messageOrAlbum: ApiMessage | IAlbum): messageOrAlbum is IAlbum {
|
export function isAlbum(messageOrAlbum: ApiMessage | IAlbum | IDocumentGroup): messageOrAlbum is IAlbum {
|
||||||
return 'albumId' in messageOrAlbum;
|
return 'albumId' in messageOrAlbum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isDocumentGroup(
|
||||||
|
messageOrAlbum: ApiMessage | IAlbum | IDocumentGroup,
|
||||||
|
): messageOrAlbum is IDocumentGroup {
|
||||||
|
return 'documentGroupId' in messageOrAlbum;
|
||||||
|
}
|
||||||
|
|
||||||
export function groupMessages(
|
export function groupMessages(
|
||||||
messages: ApiMessage[], firstUnreadId?: number, topMessageId?: number, isChatWithSelf?: boolean, withUsers?: boolean,
|
messages: ApiMessage[], firstUnreadId?: number, topMessageId?: number, isChatWithSelf?: boolean, withUsers?: boolean,
|
||||||
) {
|
) {
|
||||||
@ -27,6 +33,7 @@ export function groupMessages(
|
|||||||
senderGroups: [[]],
|
senderGroups: [[]],
|
||||||
};
|
};
|
||||||
let currentAlbum: IAlbum | undefined;
|
let currentAlbum: IAlbum | undefined;
|
||||||
|
let currentDocumentGroup: IDocumentGroup | undefined;
|
||||||
|
|
||||||
const dateGroups: MessageDateGroup[] = [initDateGroup];
|
const dateGroups: MessageDateGroup[] = [initDateGroup];
|
||||||
|
|
||||||
@ -40,6 +47,8 @@ export function groupMessages(
|
|||||||
messages: [message],
|
messages: [message],
|
||||||
mainMessage: message,
|
mainMessage: message,
|
||||||
hasMultipleCaptions: false,
|
hasMultipleCaptions: false,
|
||||||
|
commentsMessage: message.hasComments ? message : undefined,
|
||||||
|
captionMessage: message.content.text ? message : undefined,
|
||||||
} satisfies IAlbum;
|
} satisfies IAlbum;
|
||||||
} else {
|
} else {
|
||||||
currentAlbum.messages.push(message);
|
currentAlbum.messages.push(message);
|
||||||
@ -63,6 +72,20 @@ export function groupMessages(
|
|||||||
hasMultipleCaptions: false,
|
hasMultipleCaptions: false,
|
||||||
isPaidMedia: true,
|
isPaidMedia: true,
|
||||||
} satisfies IAlbum);
|
} satisfies IAlbum);
|
||||||
|
} else if (message.groupedId) {
|
||||||
|
if (!currentDocumentGroup) {
|
||||||
|
currentDocumentGroup = {
|
||||||
|
documentGroupId: message.groupedId,
|
||||||
|
messages: [message],
|
||||||
|
firstMessageId: message.id,
|
||||||
|
commentsMessage: message.hasComments ? message : undefined,
|
||||||
|
} satisfies IDocumentGroup;
|
||||||
|
} else {
|
||||||
|
currentDocumentGroup.messages.push(message);
|
||||||
|
if (message.hasComments) {
|
||||||
|
currentDocumentGroup.commentsMessage = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
currentSenderGroup.push(message);
|
currentSenderGroup.push(message);
|
||||||
}
|
}
|
||||||
@ -77,8 +100,16 @@ export function groupMessages(
|
|||||||
currentAlbum = undefined;
|
currentAlbum = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
currentDocumentGroup
|
||||||
|
&& (!nextMessage || !nextMessage.groupedId || nextMessage.groupedId !== currentDocumentGroup.documentGroupId)
|
||||||
|
) {
|
||||||
|
currentSenderGroup.push(currentDocumentGroup);
|
||||||
|
currentDocumentGroup = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const lastMessageInSenderGroup = currentSenderGroup[currentSenderGroup.length - 1];
|
const lastMessageInSenderGroup = currentSenderGroup[currentSenderGroup.length - 1];
|
||||||
if (nextMessage && !currentAlbum) {
|
if (nextMessage && !currentAlbum && !currentDocumentGroup) {
|
||||||
const nextMessageDayStartsAt = getDayStartAt(nextMessage.date * 1000);
|
const nextMessageDayStartsAt = getDayStartAt(nextMessage.date * 1000);
|
||||||
if (currentDateGroup.datetime !== nextMessageDayStartsAt) {
|
if (currentDateGroup.datetime !== nextMessageDayStartsAt) {
|
||||||
const newDateGroup: MessageDateGroup = {
|
const newDateGroup: MessageDateGroup = {
|
||||||
@ -101,10 +132,12 @@ export function groupMessages(
|
|||||||
|| (nextMessage.date - message.date) > GROUP_INTERVAL_SECONDS
|
|| (nextMessage.date - message.date) > GROUP_INTERVAL_SECONDS
|
||||||
|| (topMessageId
|
|| (topMessageId
|
||||||
&& (message.id === topMessageId
|
&& (message.id === topMessageId
|
||||||
|| (lastMessageInSenderGroup
|
|| (lastMessageInSenderGroup && (
|
||||||
&& 'mainMessage' in lastMessageInSenderGroup
|
(isAlbum(lastMessageInSenderGroup) && lastMessageInSenderGroup.mainMessage.id === topMessageId)
|
||||||
&& lastMessageInSenderGroup.mainMessage?.id === topMessageId))
|
|| (isDocumentGroup(lastMessageInSenderGroup) && lastMessageInSenderGroup.firstMessageId === topMessageId)
|
||||||
&& nextMessage.id !== topMessageId)
|
)))
|
||||||
|
&& nextMessage.id !== topMessageId
|
||||||
|
&& !(message.groupedId && message.groupedId === nextMessage.groupedId))
|
||||||
|| (isChatWithSelf && message.forwardInfo?.fromId !== nextMessage.forwardInfo?.fromId)
|
|| (isChatWithSelf && message.forwardInfo?.fromId !== nextMessage.forwardInfo?.fromId)
|
||||||
) {
|
) {
|
||||||
currentDateGroup.senderGroups.push([]);
|
currentDateGroup.senderGroups.push([]);
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import type {
|
|||||||
ChatTranslatedMessages,
|
ChatTranslatedMessages,
|
||||||
FocusDirection,
|
FocusDirection,
|
||||||
IAlbum,
|
IAlbum,
|
||||||
|
IDocumentGroup,
|
||||||
MessageListType,
|
MessageListType,
|
||||||
ScrollTargetPosition,
|
ScrollTargetPosition,
|
||||||
TextSummary,
|
TextSummary,
|
||||||
@ -97,7 +98,6 @@ import {
|
|||||||
selectIsMessageFocused,
|
selectIsMessageFocused,
|
||||||
selectIsMessageProtected,
|
selectIsMessageProtected,
|
||||||
selectIsMessageSelected,
|
selectIsMessageSelected,
|
||||||
selectMessageIdsByGroupId,
|
|
||||||
selectMessageSummary,
|
selectMessageSummary,
|
||||||
selectOutgoingStatus,
|
selectOutgoingStatus,
|
||||||
selectPeer,
|
selectPeer,
|
||||||
@ -225,6 +225,7 @@ type MessagePositionProperties = {
|
|||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
message: ApiMessage;
|
message: ApiMessage;
|
||||||
album?: IAlbum;
|
album?: IAlbum;
|
||||||
|
documentGroup?: IDocumentGroup;
|
||||||
noAvatars?: boolean;
|
noAvatars?: boolean;
|
||||||
withAvatar?: boolean;
|
withAvatar?: boolean;
|
||||||
withSenderName?: boolean;
|
withSenderName?: boolean;
|
||||||
@ -234,6 +235,7 @@ type OwnProps = {
|
|||||||
noReplies: boolean;
|
noReplies: boolean;
|
||||||
appearanceOrder: number;
|
appearanceOrder: number;
|
||||||
isJustAdded: boolean;
|
isJustAdded: boolean;
|
||||||
|
isThreadTop?: boolean;
|
||||||
memoFirstUnreadIdRef?: { current: number | undefined };
|
memoFirstUnreadIdRef?: { current: number | undefined };
|
||||||
getIsMessageListReady?: Signal<boolean>;
|
getIsMessageListReady?: Signal<boolean>;
|
||||||
observeIntersectionForBottom?: ObserveFn;
|
observeIntersectionForBottom?: ObserveFn;
|
||||||
@ -249,7 +251,6 @@ type StateProps = {
|
|||||||
canShowSender: boolean;
|
canShowSender: boolean;
|
||||||
originSender?: ApiPeer;
|
originSender?: ApiPeer;
|
||||||
botSender?: ApiUser;
|
botSender?: ApiUser;
|
||||||
isThreadTop?: boolean;
|
|
||||||
shouldHideReply?: boolean;
|
shouldHideReply?: boolean;
|
||||||
replyMessage?: ApiMessage;
|
replyMessage?: ApiMessage;
|
||||||
replyMessageSender?: ApiPeer;
|
replyMessageSender?: ApiPeer;
|
||||||
@ -2004,7 +2005,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
loadingThread,
|
loadingThread,
|
||||||
} = selectTabState(global);
|
} = selectTabState(global);
|
||||||
const {
|
const {
|
||||||
message, album, withSenderName, withAvatar, threadId, messageListType, isLastInDocumentGroup, isFirstInGroup,
|
message, album, documentGroup, withSenderName, withAvatar, threadId, messageListType,
|
||||||
|
isLastInDocumentGroup, isFirstInGroup,
|
||||||
} = ownProps;
|
} = ownProps;
|
||||||
const {
|
const {
|
||||||
id, chatId, viaBotId, isOutgoing, forwardInfo, transcriptionId, isPinned, viaBusinessBotId, effectId,
|
id, chatId, viaBotId, isOutgoing, forwardInfo, transcriptionId, isPinned, viaBusinessBotId, effectId,
|
||||||
@ -2040,8 +2042,6 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
? (adminMembersById?.[sender?.id] || members?.find((member) => member.userId === sender?.id))
|
? (adminMembersById?.[sender?.id] || members?.find((member) => member.userId === sender?.id))
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const isThreadTop = message.id === threadId;
|
|
||||||
|
|
||||||
const { replyToMsgId, replyToPeerId, replyFrom } = getMessageReplyInfo(message) || {};
|
const { replyToMsgId, replyToPeerId, replyFrom } = getMessageReplyInfo(message) || {};
|
||||||
const { peerId: storyReplyPeerId, storyId: storyReplyId } = getStoryReplyInfo(message) || {};
|
const { peerId: storyReplyPeerId, storyId: storyReplyId } = getStoryReplyInfo(message) || {};
|
||||||
|
|
||||||
@ -2094,14 +2094,15 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const downloadableMedia = selectMessageDownloadableMedia(global, message);
|
const downloadableMedia = selectMessageDownloadableMedia(global, message);
|
||||||
const isDownloading = downloadableMedia && getIsDownloading(activeDownloads, downloadableMedia);
|
const isDownloading = downloadableMedia && getIsDownloading(activeDownloads, downloadableMedia);
|
||||||
|
|
||||||
const repliesThreadInfo = selectThreadInfo(global, chatId, album?.commentsMessage?.id || id);
|
|
||||||
|
|
||||||
const isInDocumentGroup = Boolean(message.groupedId) && !message.isInAlbum;
|
const isInDocumentGroup = Boolean(message.groupedId) && !message.isInAlbum;
|
||||||
const documentGroupFirstMessageId = isInDocumentGroup
|
|
||||||
? selectMessageIdsByGroupId(global, chatId, message.groupedId!)![0]
|
const repliesThreadInfo = selectThreadInfo(
|
||||||
: undefined;
|
global, chatId, album?.commentsMessage?.id || documentGroup?.commentsMessage?.id || id,
|
||||||
|
);
|
||||||
const reactionMessage = isInDocumentGroup ? (
|
const reactionMessage = isInDocumentGroup ? (
|
||||||
isLastInDocumentGroup ? selectChatMessage(global, chatId, documentGroupFirstMessageId!) : undefined
|
isLastInDocumentGroup && documentGroup?.firstMessageId
|
||||||
|
? selectChatMessage(global, chatId, documentGroup.firstMessageId)
|
||||||
|
: undefined
|
||||||
) : message;
|
) : message;
|
||||||
|
|
||||||
const readState = selectThreadReadState(global, chatId, threadId);
|
const readState = selectThreadReadState(global, chatId, threadId);
|
||||||
@ -2158,7 +2159,6 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
originSender,
|
originSender,
|
||||||
botSender,
|
botSender,
|
||||||
shouldHideReply: shouldHideReply || isReplyToTopicStart,
|
shouldHideReply: shouldHideReply || isReplyToTopicStart,
|
||||||
isThreadTop,
|
|
||||||
replyMessage,
|
replyMessage,
|
||||||
replyMessageSender,
|
replyMessageSender,
|
||||||
replyMessageForwardSender,
|
replyMessageForwardSender,
|
||||||
|
|||||||
@ -141,6 +141,7 @@ import {
|
|||||||
selectIsMonoforumAdmin,
|
selectIsMonoforumAdmin,
|
||||||
selectLanguageCode,
|
selectLanguageCode,
|
||||||
selectListedIds,
|
selectListedIds,
|
||||||
|
selectMessageIdsByGroupId,
|
||||||
selectMessageReplyInfo,
|
selectMessageReplyInfo,
|
||||||
selectOutlyingListByMessageId,
|
selectOutlyingListByMessageId,
|
||||||
selectPeer,
|
selectPeer,
|
||||||
@ -1809,7 +1810,16 @@ async function loadViewportMessages<T extends GlobalState>(
|
|||||||
if (threadId !== MAIN_THREAD_ID && !getIsSavedDialog(chatId, threadId, global.currentUserId)) {
|
if (threadId !== MAIN_THREAD_ID && !getIsSavedDialog(chatId, threadId, global.currentUserId)) {
|
||||||
const threadFirstMessageId = selectFirstMessageId(global, chatId, threadId);
|
const threadFirstMessageId = selectFirstMessageId(global, chatId, threadId);
|
||||||
if ((!ids[0] || threadFirstMessageId === ids[0]) && threadFirstMessageId !== threadId) {
|
if ((!ids[0] || threadFirstMessageId === ids[0]) && threadFirstMessageId !== threadId) {
|
||||||
ids.unshift(Number(threadId));
|
const threadTopMessage = selectChatMessage(global, chatId, Number(threadId));
|
||||||
|
const groupedIds = threadTopMessage?.groupedId
|
||||||
|
? selectMessageIdsByGroupId(global, chatId, threadTopMessage.groupedId)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (groupedIds && groupedIds.length > 1) {
|
||||||
|
ids.unshift(...groupedIds);
|
||||||
|
} else {
|
||||||
|
ids.unshift(Number(threadId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -96,6 +96,13 @@ export interface IAlbum {
|
|||||||
commentsMessage?: ApiMessage;
|
commentsMessage?: ApiMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IDocumentGroup {
|
||||||
|
documentGroupId: string;
|
||||||
|
messages: ApiMessage[];
|
||||||
|
firstMessageId: number;
|
||||||
|
commentsMessage?: ApiMessage;
|
||||||
|
}
|
||||||
|
|
||||||
export type ThreadId = string | number;
|
export type ThreadId = string | number;
|
||||||
|
|
||||||
export type ThemeKey = 'light' | 'dark';
|
export type ThemeKey = 'light' | 'dark';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user