Message: Auto-scroll when last message height changes (#2323)
This commit is contained in:
parent
964a5001ab
commit
d8661e223e
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import {
|
||||
|
||||
import { round } from '../util/math';
|
||||
|
||||
import { useResizeObserver } from './useResizeObserver';
|
||||
import useResizeObserver from './useResizeObserver';
|
||||
|
||||
const ANIMATION_END_TIMEOUT = 500;
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user