Message: Auto-scroll when last message height changes (#2323)

This commit is contained in:
Alexander Zinchuk 2023-01-24 00:17:57 +01:00
parent 964a5001ab
commit d8661e223e
7 changed files with 35 additions and 20 deletions

View File

@ -60,7 +60,7 @@ import useNativeCopySelectedMessages from '../../hooks/useNativeCopySelectedMess
import useMedia from '../../hooks/useMedia';
import useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps';
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
import { useResizeObserver } from '../../hooks/useResizeObserver';
import useResizeObserver from '../../hooks/useResizeObserver';
import Loading from '../ui/Loading';
import MessageListContent from './MessageListContent';

View File

@ -19,7 +19,7 @@ import { selectIsAlwaysHighPriorityEmoji, selectIsSetPremium } from '../../../gl
import useLang from '../../../hooks/useLang';
import useFlag from '../../../hooks/useFlag';
import useMediaTransition from '../../../hooks/useMediaTransition';
import { useResizeObserver } from '../../../hooks/useResizeObserver';
import useResizeObserver from '../../../hooks/useResizeObserver';
import { useIsIntersecting } from '../../../hooks/useIntersectionObserver';
import StickerButton from '../../common/StickerButton';

View File

@ -17,7 +17,7 @@ import { fastRaf } from '../../../../util/schedulers';
import AbsoluteVideo from '../../../../util/AbsoluteVideo';
import { REM } from '../../../common/helpers/mediaDimensions';
import { useResizeObserver } from '../../../../hooks/useResizeObserver';
import useResizeObserver from '../../../../hooks/useResizeObserver';
import useBackgroundMode from '../../../../hooks/useBackgroundMode';
const SIZE = 1.25 * REM;

View File

@ -101,6 +101,8 @@ import { calculateAlbumLayout } from './helpers/calculateAlbumLayout';
import renderText from '../../common/helpers/renderText';
import calculateAuthorWidth from './helpers/calculateAuthorWidth';
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
import { isAnimatingScroll } from '../../../util/fastSmoothScroll';
import { useOnIntersect } from '../../../hooks/useIntersectionObserver';
import useLang from '../../../hooks/useLang';
import useShowTransition from '../../../hooks/useShowTransition';
@ -111,6 +113,7 @@ import useInnerHandlers from './hooks/useInnerHandlers';
import { getServerTime } from '../../../util/serverTime';
import { isElementInViewport } from '../../../util/isElementInViewport';
import { getCustomEmojiSize } from '../composer/helpers/customEmoji';
import useResizeObserver from '../../../hooks/useResizeObserver';
import Button from '../../ui/Button';
import Avatar from '../../common/Avatar';
@ -249,6 +252,7 @@ const APPENDIX_NOT_OWN = { __html: '<svg width="9" height="20" xmlns="http://www
const APPEARANCE_DELAY = 10;
const NO_MEDIA_CORNERS_THRESHOLD = 18;
const QUICK_REACTION_SIZE = 1.75 * REM;
const BOTTOM_FOCUS_SCROLL_THRESHOLD = 5;
const Message: FC<OwnProps & StateProps> = ({
message,
@ -339,6 +343,8 @@ const Message: FC<OwnProps & StateProps> = ({
// eslint-disable-next-line no-null/no-null
const contentRef = useRef<HTMLDivElement>(null);
const messageHeightRef = useRef(0);
const lang = useLang();
const [isTranscriptionHidden, setTranscriptionHidden] = useState(false);
@ -585,6 +591,30 @@ const Message: FC<OwnProps & StateProps> = ({
);
useFocusMessage(ref, chatId, isFocused, focusDirection, noFocusHighlight, isResizingContainer);
const shouldFocusOnResize = isLastInGroup;
const handleResize = useCallback((entry: ResizeObserverEntry) => {
const lastHeight = messageHeightRef.current;
const newHeight = entry.target.clientHeight;
messageHeightRef.current = newHeight;
if (isAnimatingScroll() || !lastHeight || newHeight <= lastHeight) return;
const container = entry.target.closest<HTMLDivElement>('.MessageList');
if (!container) return;
const resizeDiff = newHeight - lastHeight;
const { offsetHeight, scrollHeight, scrollTop } = container;
const currentScrollBottom = Math.round(scrollHeight - scrollTop - offsetHeight);
const previousScrollBottom = currentScrollBottom - resizeDiff;
if (previousScrollBottom <= BOTTOM_FOCUS_SCROLL_THRESHOLD) {
focusLastMessage();
}
}, [focusLastMessage]);
useResizeObserver(shouldFocusOnResize ? ref : undefined, handleResize, true);
useEffect(() => {
const bottomMarker = bottomMarkerRef.current;
if (hasUnreadReaction && bottomMarker && isElementInViewport(bottomMarker)) {

View File

@ -44,7 +44,6 @@ import {
selectViewportIds,
selectFirstUnreadId,
selectChat,
selectIsChatWithBot,
selectIsServiceChatReady,
selectLocalAnimatedEmojiEffect,
selectLocalAnimatedEmoji,
@ -205,20 +204,6 @@ addActionHandler('apiUpdate', (global, actions, update) => {
setGlobal(global);
// Scroll down if bot message height is changed with an updated inline keyboard.
// A drawback: this will scroll down even if the previous scroll was not at bottom.
if (
currentMessage
&& chat
&& !message.isOutgoing
&& chat.lastMessage?.id === message.id
&& selectIsChatWithBot(global, chat)
&& selectIsMessageInCurrentMessageList(global, chatId, message as ApiMessage)
&& selectIsViewportNewest(global, chatId, message.repliesThreadInfo?.threadId || MAIN_THREAD_ID)
) {
actions.focusLastMessage();
}
break;
}

View File

@ -4,7 +4,7 @@ import {
import { round } from '../util/math';
import { useResizeObserver } from './useResizeObserver';
import useResizeObserver from './useResizeObserver';
const ANIMATION_END_TIMEOUT = 500;

View File

@ -3,7 +3,7 @@ import { throttle } from '../util/schedulers';
const THROTTLE = 300;
export function useResizeObserver(
export default function useResizeObserver(
ref: React.RefObject<HTMLElement> | undefined,
onResize: (entry: ResizeObserverEntry) => void,
withThrottle = false,