Message List: Various fixes for sending messages in empty chat

This commit is contained in:
Alexander Zinchuk 2021-08-27 21:09:03 +03:00
parent f4fad13266
commit 5a444dbb50
3 changed files with 30 additions and 24 deletions

View File

@ -4,12 +4,12 @@ import React, {
import { getGlobal, withGlobal } from '../../lib/teact/teactn';
import {
ApiAction, ApiMessage, ApiRestrictionReason, MAIN_THREAD_ID,
ApiMessage, ApiRestrictionReason, MAIN_THREAD_ID,
} from '../../api/types';
import { GlobalActions, MessageListType } from '../../global/types';
import { LoadMoreDirection } from '../../types';
import { ANIMATION_END_DELAY, MESSAGE_LIST_SLICE } from '../../config';
import { ANIMATION_END_DELAY, LOCAL_MESSAGE_ID_BASE, MESSAGE_LIST_SLICE } from '../../config';
import {
selectChatMessages,
selectIsViewportNewest,
@ -32,7 +32,7 @@ import { fastRaf, debounce, onTickEnd } from '../../util/schedulers';
import useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps';
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
import buildClassName from '../../util/buildClassName';
import { groupMessages, MessageDateGroup } from './helpers/groupMessages';
import { groupMessages } from './helpers/groupMessages';
import { preventMessageInputBlur } from './helpers/preventMessageInputBlur';
import useOnChange from '../../hooks/useOnChange';
import useStickyDates from './hooks/useStickyDates';
@ -259,7 +259,7 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
if (isReady) {
containerRef.current!.dataset.normalHeight = String(containerRef.current!.offsetHeight);
}
}, [windowHeight, isReady]);
}, [windowHeight, isReady, canPost]);
// Initial message loading
useEffect(() => {
@ -267,6 +267,12 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
return;
}
// Loading history while sending a message can return the same message and cause ambiguity
const isFirstMessageLocal = messageIds && messageIds[0] >= LOCAL_MESSAGE_ID_BASE;
if (isFirstMessageLocal) {
return;
}
const container = containerRef.current!;
if (!messageIds || (
@ -331,11 +337,13 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
}, FOCUSING_DURATION);
}
const hasFirstMessageChanged = messageIds && prevMessageIds && messageIds[0] !== prevMessageIds[0];
const hasLastMessageChanged = (
messageIds && prevMessageIds && messageIds[messageIds.length - 1] !== prevMessageIds[prevMessageIds.length - 1]
);
const wasMessageAdded = hasLastMessageChanged && !hasFirstMessageChanged;
const hasViewportShifted = (
messageIds?.[0] !== prevMessageIds?.[0] && messageIds?.length === (MESSAGE_LIST_SLICE / 2 + 1)
);
const wasMessageAdded = hasLastMessageChanged && !hasViewportShifted;
const isAlreadyFocusing = messageIds && memoFocusingIdRef.current === messageIds[messageIds.length - 1];
const { scrollTop, scrollHeight, offsetHeight } = container;
@ -442,11 +450,12 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
// Used to avoid flickering when deleting a greeting that has just been sent
&& (!listItemElementsRef.current || listItemElementsRef.current.length === 0)
)
|| checkSingleMessageActionByType('contactSignUp', messageGroups)
|| (lastMessage?.content.action && lastMessage.content.action.type === 'contactSignUp')
|| (messageIds?.length === 1 && messagesById?.[messageIds[0]]?.content.action?.type === 'contactSignUp')
|| (lastMessage?.content?.action?.type === 'contactSignUp')
);
const isGroupChatJustCreated = isGroupChat && isCreator
&& checkSingleMessageActionByType('chatCreate', messageGroups);
&& messageIds?.length === 1 && messagesById?.[messageIds[0]]?.content.action?.type === 'chatCreate';
const className = buildClassName(
'MessageList custom-scroll',
@ -512,16 +521,6 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
);
};
function checkSingleMessageActionByType(type: ApiAction['type'], messageGroups?: MessageDateGroup[]) {
return messageGroups
&& messageGroups.length === 1
&& messageGroups[0].senderGroups.length === 1
&& messageGroups[0].senderGroups[0].length === 1
&& 'content' in messageGroups[0].senderGroups[0][0]
&& messageGroups[0].senderGroups[0][0].content.action
&& messageGroups[0].senderGroups[0][0].content.action.type === type;
}
export default memo(withGlobal<OwnProps>(
(global, { chatId, threadId, type }): StateProps => {
const chat = selectChat(global, chatId);

View File

@ -1,13 +1,13 @@
import { RefObject } from 'react';
import { getDispatch } from '../../../lib/teact/teactn';
import { useCallback, useMemo, useRef } from '../../../lib/teact/teact';
import { useMemo, useRef } from '../../../lib/teact/teact';
import { LoadMoreDirection } from '../../../types';
import { MessageListType } from '../../../global/types';
import { debounce } from '../../../util/schedulers';
import { useIntersectionObserver, useOnIntersect } from '../../../hooks/useIntersectionObserver';
import { MESSAGE_LIST_SENSITIVE_AREA } from '../../../config';
import { LOCAL_MESSAGE_ID_BASE, MESSAGE_LIST_SENSITIVE_AREA } from '../../../config';
import resetScroll from '../../../util/resetScroll';
import useOnChange from '../../../hooks/useOnChange';
@ -42,7 +42,7 @@ export default function useScrollHooks(
// eslint-disable-next-line no-null/no-null
const fabTriggerRef = useRef<HTMLDivElement>(null);
const toggleScrollTools = useCallback(() => {
function toggleScrollTools() {
if (!isActive) return;
if (!messageIds || !messageIds.length) {
@ -64,7 +64,7 @@ export default function useScrollHooks(
onFabToggle(isUnread ? !isAtBottom : !isNearBottom);
onNotchToggle(!isAtBottom);
}, [isActive, messageIds, isViewportNewest, containerRef, onFabToggle, isUnread, onNotchToggle]);
}
const {
observe: observeIntersection,
@ -76,6 +76,12 @@ export default function useScrollHooks(
return;
}
// Loading history while sending a message can return the same message and cause ambiguity
const isFirstMessageLocal = messageIds[0] >= LOCAL_MESSAGE_ID_BASE;
if (isFirstMessageLocal) {
return;
}
const triggerEntry = entries.find(({ isIntersecting }) => isIntersecting);
if (!triggerEntry) {
return;

View File

@ -671,6 +671,7 @@ async function loadViewportMessages(
global = isOutlying
? updateOutlyingIds(global, chatId, threadId, ids)
: updateListedIds(global, chatId, threadId, ids);
global = addUsers(global, buildCollectionByKey(users, 'id'));
global = addChats(global, buildCollectionByKey(chats, 'id'));
global = updateThreadInfos(global, chatId, threadInfos);
@ -679,7 +680,7 @@ async function loadViewportMessages(
const outlyingIds = selectOutlyingIds(global, chatId, threadId);
if (isOutlying && listedIds && outlyingIds) {
if (areSortedArraysIntersecting(listedIds, outlyingIds)) {
if (!outlyingIds.length || areSortedArraysIntersecting(listedIds, outlyingIds)) {
global = updateListedIds(global, chatId, threadId, outlyingIds);
listedIds = selectListedIds(global, chatId, threadId);
global = replaceThreadParam(global, chatId, threadId, 'outlyingIds', undefined);