Message List: Simplify pinned navigation check (#6649)
This commit is contained in:
parent
0142b6ac55
commit
6908e40e0f
@ -135,7 +135,16 @@ const MessageListContent = ({
|
|||||||
observeIntersectionForReading,
|
observeIntersectionForReading,
|
||||||
observeIntersectionForLoading,
|
observeIntersectionForLoading,
|
||||||
observeIntersectionForPlaying,
|
observeIntersectionForPlaying,
|
||||||
} = useMessageObservers(type, containerRef, memoFirstUnreadIdRef, onIntersectPinnedMessage, chatId, isQuickPreview);
|
onMessageUnmount,
|
||||||
|
} = useMessageObservers({
|
||||||
|
type,
|
||||||
|
containerRef,
|
||||||
|
memoFirstUnreadIdRef,
|
||||||
|
chatId,
|
||||||
|
threadId,
|
||||||
|
isQuickPreview,
|
||||||
|
onIntersectPinnedMessage,
|
||||||
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
withHistoryTriggers,
|
withHistoryTriggers,
|
||||||
@ -304,7 +313,7 @@ const MessageListContent = ({
|
|||||||
isJustAdded={isLastInList && isNewMessage}
|
isJustAdded={isLastInList && isNewMessage}
|
||||||
isLastInList={isLastInList}
|
isLastInList={isLastInList}
|
||||||
getIsMessageListReady={getIsReady}
|
getIsMessageListReady={getIsReady}
|
||||||
onIntersectPinnedMessage={onIntersectPinnedMessage}
|
onMessageUnmount={onMessageUnmount}
|
||||||
/>,
|
/>,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -375,8 +384,8 @@ const MessageListContent = ({
|
|||||||
isLastInDocumentGroup={position.isLastInDocumentGroup}
|
isLastInDocumentGroup={position.isLastInDocumentGroup}
|
||||||
isLastInList={position.isLastInList}
|
isLastInList={position.isLastInList}
|
||||||
memoFirstUnreadIdRef={memoFirstUnreadIdRef}
|
memoFirstUnreadIdRef={memoFirstUnreadIdRef}
|
||||||
onIntersectPinnedMessage={onIntersectPinnedMessage}
|
|
||||||
getIsMessageListReady={getIsReady}
|
getIsMessageListReady={getIsReady}
|
||||||
|
onMessageUnmount={onMessageUnmount}
|
||||||
/>,
|
/>,
|
||||||
]);
|
]);
|
||||||
}).flat();
|
}).flat();
|
||||||
|
|||||||
@ -1,26 +1,37 @@
|
|||||||
import type { ElementRef } from '../../../lib/teact/teact';
|
import { type ElementRef, useEffect, useRef } from '../../../lib/teact/teact';
|
||||||
import { getActions } from '../../../global';
|
import { getActions } from '../../../global';
|
||||||
|
|
||||||
import type { MessageListType } from '../../../types';
|
import type { MessageListType, ThreadId } from '../../../types';
|
||||||
import type { OnIntersectPinnedMessage } from './usePinnedMessage';
|
import type { OnIntersectPinnedMessage } from './usePinnedMessage';
|
||||||
|
|
||||||
import { IS_ANDROID } from '../../../util/browser/windowEnvironment';
|
import { IS_ANDROID } from '../../../util/browser/windowEnvironment';
|
||||||
|
import { unique } from '../../../util/iteratees';
|
||||||
|
|
||||||
import useAppLayout from '../../../hooks/useAppLayout';
|
import useAppLayout from '../../../hooks/useAppLayout';
|
||||||
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
|
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
|
||||||
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
import useBackgroundMode, { isBackgroundModeActive } from '../../../hooks/window/useBackgroundMode';
|
import useBackgroundMode, { isBackgroundModeActive } from '../../../hooks/window/useBackgroundMode';
|
||||||
|
|
||||||
const INTERSECTION_THROTTLE_FOR_READING = 150;
|
const INTERSECTION_THROTTLE_FOR_READING = 150;
|
||||||
const INTERSECTION_THROTTLE_FOR_MEDIA = IS_ANDROID ? 1000 : 350;
|
const INTERSECTION_THROTTLE_FOR_MEDIA = IS_ANDROID ? 1000 : 350;
|
||||||
|
|
||||||
export default function useMessageObservers(
|
export default function useMessageObservers({
|
||||||
type: MessageListType,
|
type,
|
||||||
containerRef: ElementRef<HTMLDivElement>,
|
containerRef,
|
||||||
memoFirstUnreadIdRef: { current: number | undefined },
|
memoFirstUnreadIdRef,
|
||||||
onIntersectPinnedMessage: OnIntersectPinnedMessage | undefined,
|
chatId,
|
||||||
chatId: string,
|
threadId,
|
||||||
isQuickPreview?: boolean,
|
isQuickPreview,
|
||||||
) {
|
onIntersectPinnedMessage,
|
||||||
|
}: {
|
||||||
|
containerRef: ElementRef<HTMLDivElement>;
|
||||||
|
memoFirstUnreadIdRef: { current: number | undefined };
|
||||||
|
chatId: string;
|
||||||
|
threadId: ThreadId;
|
||||||
|
type: MessageListType;
|
||||||
|
isQuickPreview?: boolean;
|
||||||
|
onIntersectPinnedMessage: OnIntersectPinnedMessage | undefined;
|
||||||
|
}) {
|
||||||
const {
|
const {
|
||||||
markMessageListRead, markMentionsRead, animateUnreadReaction,
|
markMessageListRead, markMentionsRead, animateUnreadReaction,
|
||||||
scheduleForViewsIncrement,
|
scheduleForViewsIncrement,
|
||||||
@ -29,11 +40,18 @@ export default function useMessageObservers(
|
|||||||
const { isMobile } = useAppLayout();
|
const { isMobile } = useAppLayout();
|
||||||
const INTERSECTION_MARGIN_FOR_LOADING = isMobile ? 300 : 500;
|
const INTERSECTION_MARGIN_FOR_LOADING = isMobile ? 300 : 500;
|
||||||
|
|
||||||
|
const visibleViewportIdsRef = useRef<number[]>([]);
|
||||||
|
useEffect(() => {
|
||||||
|
visibleViewportIdsRef.current = [];
|
||||||
|
}, [threadId, chatId, type]);
|
||||||
|
|
||||||
|
// Note: Targets bottom marker, not the message itself
|
||||||
const {
|
const {
|
||||||
observe: observeIntersectionForReading, freeze: freezeForReading, unfreeze: unfreezeForReading,
|
observe: observeIntersectionForReading, freeze: freezeForReading, unfreeze: unfreezeForReading,
|
||||||
} = useIntersectionObserver({
|
} = useIntersectionObserver({
|
||||||
rootRef: containerRef,
|
rootRef: containerRef,
|
||||||
throttleMs: INTERSECTION_THROTTLE_FOR_READING,
|
throttleMs: INTERSECTION_THROTTLE_FOR_READING,
|
||||||
|
threshold: 0,
|
||||||
// `memoFirstUnreadIdRef` is set after the first render, firing callback before that can skip some entries, like the last message
|
// `memoFirstUnreadIdRef` is set after the first render, firing callback before that can skip some entries, like the last message
|
||||||
shouldSkipFirst: true,
|
shouldSkipFirst: true,
|
||||||
}, (entries) => {
|
}, (entries) => {
|
||||||
@ -44,10 +62,12 @@ export default function useMessageObservers(
|
|||||||
let maxId = 0;
|
let maxId = 0;
|
||||||
const mentionIds: number[] = [];
|
const mentionIds: number[] = [];
|
||||||
const reactionIds: number[] = [];
|
const reactionIds: number[] = [];
|
||||||
const viewportPinnedIdsToAdd: number[] = [];
|
|
||||||
const viewportPinnedIdsToRemove: number[] = [];
|
|
||||||
const scheduledToUpdateViews: number[] = [];
|
const scheduledToUpdateViews: number[] = [];
|
||||||
|
|
||||||
|
const currentVisibleViewportIds = visibleViewportIdsRef.current;
|
||||||
|
const hiddenViewportIds = new Set<number>();
|
||||||
|
const newVisibleViewportIds: number[] = [];
|
||||||
|
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
const { isIntersecting, target } = entry;
|
const { isIntersecting, target } = entry;
|
||||||
|
|
||||||
@ -57,12 +77,12 @@ export default function useMessageObservers(
|
|||||||
const albumMainId = dataset.albumMainId ? Number(dataset.albumMainId) : undefined;
|
const albumMainId = dataset.albumMainId ? Number(dataset.albumMainId) : undefined;
|
||||||
|
|
||||||
if (!isIntersecting) {
|
if (!isIntersecting) {
|
||||||
if (dataset.isPinned) {
|
hiddenViewportIds.add(messageId);
|
||||||
viewportPinnedIdsToRemove.push(albumMainId || messageId);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newVisibleViewportIds.push(messageId);
|
||||||
|
|
||||||
if (messageId > maxId) {
|
if (messageId > maxId) {
|
||||||
maxId = messageId;
|
maxId = messageId;
|
||||||
}
|
}
|
||||||
@ -75,15 +95,15 @@ export default function useMessageObservers(
|
|||||||
reactionIds.push(messageId);
|
reactionIds.push(messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataset.isPinned) {
|
|
||||||
viewportPinnedIdsToAdd.push(albumMainId || messageId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldUpdateViews) {
|
if (shouldUpdateViews) {
|
||||||
scheduledToUpdateViews.push(albumMainId || messageId);
|
scheduledToUpdateViews.push(albumMainId || messageId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
visibleViewportIdsRef.current = unique(currentVisibleViewportIds.concat(newVisibleViewportIds))
|
||||||
|
.filter((id) => !hiddenViewportIds.has(id))
|
||||||
|
.sort((a, b) => a - b);
|
||||||
|
|
||||||
if (!isQuickPreview) {
|
if (!isQuickPreview) {
|
||||||
if (memoFirstUnreadIdRef.current && maxId && maxId >= memoFirstUnreadIdRef.current) {
|
if (memoFirstUnreadIdRef.current && maxId && maxId >= memoFirstUnreadIdRef.current) {
|
||||||
markMessageListRead({ maxId });
|
markMessageListRead({ maxId });
|
||||||
@ -102,8 +122,8 @@ export default function useMessageObservers(
|
|||||||
animateUnreadReaction({ chatId, messageIds: reactionIds });
|
animateUnreadReaction({ chatId, messageIds: reactionIds });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewportPinnedIdsToAdd.length || viewportPinnedIdsToRemove.length) {
|
if (visibleViewportIdsRef.current.length) {
|
||||||
onIntersectPinnedMessage?.({ viewportPinnedIdsToAdd, viewportPinnedIdsToRemove });
|
onIntersectPinnedMessage?.({ firstViewportId: visibleViewportIdsRef.current[0] });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -122,9 +142,14 @@ export default function useMessageObservers(
|
|||||||
throttleMs: INTERSECTION_THROTTLE_FOR_MEDIA,
|
throttleMs: INTERSECTION_THROTTLE_FOR_MEDIA,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const onMessageUnmount = useLastCallback((messageId: number) => {
|
||||||
|
visibleViewportIdsRef.current = visibleViewportIdsRef.current.filter((id) => id !== messageId);
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
observeIntersectionForReading,
|
observeIntersectionForReading,
|
||||||
observeIntersectionForLoading,
|
observeIntersectionForLoading,
|
||||||
observeIntersectionForPlaying,
|
observeIntersectionForPlaying,
|
||||||
|
onMessageUnmount,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,22 +3,17 @@ import { getGlobal } from '../../../global';
|
|||||||
|
|
||||||
import type { ThreadId } from '../../../types';
|
import type { ThreadId } from '../../../types';
|
||||||
|
|
||||||
import { selectFocusedMessageId, selectListedIds, selectOutlyingListByMessageId } from '../../../global/selectors';
|
import { selectListedIds, selectOutlyingListByMessageId } from '../../../global/selectors';
|
||||||
import cycleRestrict from '../../../util/cycleRestrict';
|
import cycleRestrict from '../../../util/cycleRestrict';
|
||||||
import { unique } from '../../../util/iteratees';
|
|
||||||
|
|
||||||
import useDerivedSignal from '../../../hooks/useDerivedSignal';
|
import useDerivedSignal from '../../../hooks/useDerivedSignal';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|
||||||
export type OnIntersectPinnedMessage = (params: {
|
export type OnIntersectPinnedMessage = (params: {
|
||||||
viewportPinnedIdsToAdd?: number[];
|
firstViewportId?: number;
|
||||||
viewportPinnedIdsToRemove?: number[];
|
|
||||||
shouldCancelWaiting?: boolean;
|
shouldCancelWaiting?: boolean;
|
||||||
}) => void;
|
}) => void;
|
||||||
|
|
||||||
let viewportPinnedIds: number[] | undefined;
|
|
||||||
let lastFocusedId: number | undefined;
|
|
||||||
|
|
||||||
export default function usePinnedMessage(
|
export default function usePinnedMessage(
|
||||||
chatId?: string, threadId?: ThreadId, pinnedIds?: number[],
|
chatId?: string, threadId?: ThreadId, pinnedIds?: number[],
|
||||||
) {
|
) {
|
||||||
@ -32,10 +27,9 @@ export default function usePinnedMessage(
|
|||||||
|
|
||||||
// Reset when switching chat
|
// Reset when switching chat
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
viewportPinnedIds = undefined;
|
|
||||||
setLoadingPinnedId(undefined);
|
setLoadingPinnedId(undefined);
|
||||||
}, [
|
}, [
|
||||||
chatId, setPinnedIndexByKey, setLoadingPinnedId, threadId,
|
chatId, threadId, setPinnedIndexByKey, setLoadingPinnedId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -51,14 +45,12 @@ export default function usePinnedMessage(
|
|||||||
}, [getPinnedIndexByKey, key, pinnedIds?.length, setPinnedIndexByKey]);
|
}, [getPinnedIndexByKey, key, pinnedIds?.length, setPinnedIndexByKey]);
|
||||||
|
|
||||||
const handleIntersectPinnedMessage: OnIntersectPinnedMessage = useLastCallback(({
|
const handleIntersectPinnedMessage: OnIntersectPinnedMessage = useLastCallback(({
|
||||||
viewportPinnedIdsToAdd = [],
|
firstViewportId,
|
||||||
viewportPinnedIdsToRemove = [],
|
|
||||||
shouldCancelWaiting,
|
shouldCancelWaiting,
|
||||||
}) => {
|
}) => {
|
||||||
if (!chatId || !threadId || !key || !pinnedIds?.length) return;
|
if (!chatId || !threadId || !key || !pinnedIds?.length) return;
|
||||||
|
|
||||||
if (shouldCancelWaiting) {
|
if (shouldCancelWaiting) {
|
||||||
lastFocusedId = undefined;
|
|
||||||
setLoadingPinnedId(undefined);
|
setLoadingPinnedId(undefined);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -71,36 +63,22 @@ export default function usePinnedMessage(
|
|||||||
[key]: clampIndex(newPinnedIndex),
|
[key]: clampIndex(newPinnedIndex),
|
||||||
});
|
});
|
||||||
setLoadingPinnedId(undefined);
|
setLoadingPinnedId(undefined);
|
||||||
|
|
||||||
|
// We're still scrolling, prevent updating the index
|
||||||
|
if (loadingPinnedId < (firstViewportId || 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewportPinnedIds = unique(
|
let newIndex = pinnedIds.findIndex((id) => id < (firstViewportId || 0));
|
||||||
(viewportPinnedIds?.filter((id) => !viewportPinnedIdsToRemove.includes(id)) ?? [])
|
if (newIndex === -1) {
|
||||||
.concat(viewportPinnedIdsToAdd),
|
newIndex = 0; // Pinned are sorted from newest to oldest
|
||||||
);
|
|
||||||
|
|
||||||
// Sometimes this callback is called after focus has been reset in global, so we leverage `lastFocusedId`
|
|
||||||
const focusedMessageId = selectFocusedMessageId(getGlobal(), chatId) || lastFocusedId;
|
|
||||||
|
|
||||||
if (lastFocusedId && viewportPinnedIds.includes(lastFocusedId)) {
|
|
||||||
lastFocusedId = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (focusedMessageId) {
|
setPinnedIndexByKey({
|
||||||
const pinnedIndexAboveFocused = pinnedIds.findIndex((id) => id < focusedMessageId);
|
...getPinnedIndexByKey(),
|
||||||
|
[key]: clampIndex(newIndex),
|
||||||
setPinnedIndexByKey({
|
});
|
||||||
...getPinnedIndexByKey(),
|
|
||||||
[key]: clampIndex(pinnedIndexAboveFocused),
|
|
||||||
});
|
|
||||||
} else if (viewportPinnedIds.length) {
|
|
||||||
const maxViewportPinnedId = Math.max(...viewportPinnedIds);
|
|
||||||
const newIndex = pinnedIds.indexOf(maxViewportPinnedId);
|
|
||||||
|
|
||||||
setPinnedIndexByKey({
|
|
||||||
...getPinnedIndexByKey(),
|
|
||||||
[key]: clampIndex(newIndex),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleFocusPinnedMessage = useLastCallback((messageId: number) => {
|
const handleFocusPinnedMessage = useLastCallback((messageId: number) => {
|
||||||
@ -109,8 +87,6 @@ export default function usePinnedMessage(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastFocusedId = messageId;
|
|
||||||
|
|
||||||
const global = getGlobal();
|
const global = getGlobal();
|
||||||
const listedIds = selectListedIds(global, chatId, threadId);
|
const listedIds = selectListedIds(global, chatId, threadId);
|
||||||
const isMessageLoaded = listedIds?.includes(messageId)
|
const isMessageLoaded = listedIds?.includes(messageId)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
memo, useEffect, useMemo, useRef, useUnmountCleanup,
|
memo, useEffect, useMemo, useRef,
|
||||||
|
useUnmountCleanup,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
@ -51,7 +52,6 @@ import { type ObserveFn, useOnIntersect } from '../../../hooks/useIntersectionOb
|
|||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
import useShowTransition from '../../../hooks/useShowTransition';
|
import useShowTransition from '../../../hooks/useShowTransition';
|
||||||
import { type OnIntersectPinnedMessage } from '../hooks/usePinnedMessage';
|
|
||||||
import useFluidBackgroundFilter from './hooks/useFluidBackgroundFilter';
|
import useFluidBackgroundFilter from './hooks/useFluidBackgroundFilter';
|
||||||
import useFocusMessageListElement from './hooks/useFocusMessageListElement';
|
import useFocusMessageListElement from './hooks/useFocusMessageListElement';
|
||||||
|
|
||||||
@ -82,10 +82,10 @@ type OwnProps = {
|
|||||||
isLastInList?: boolean;
|
isLastInList?: boolean;
|
||||||
memoFirstUnreadIdRef?: { current: number | undefined };
|
memoFirstUnreadIdRef?: { current: number | undefined };
|
||||||
getIsMessageListReady?: Signal<boolean>;
|
getIsMessageListReady?: Signal<boolean>;
|
||||||
onIntersectPinnedMessage?: OnIntersectPinnedMessage;
|
|
||||||
observeIntersectionForBottom?: ObserveFn;
|
observeIntersectionForBottom?: ObserveFn;
|
||||||
observeIntersectionForLoading?: ObserveFn;
|
observeIntersectionForLoading?: ObserveFn;
|
||||||
observeIntersectionForPlaying?: ObserveFn;
|
observeIntersectionForPlaying?: ObserveFn;
|
||||||
|
onMessageUnmount?: (messageId: number) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
@ -138,10 +138,10 @@ const ActionMessage = ({
|
|||||||
isResizingContainer,
|
isResizingContainer,
|
||||||
scrollTargetPosition,
|
scrollTargetPosition,
|
||||||
isAccountFrozen,
|
isAccountFrozen,
|
||||||
onIntersectPinnedMessage,
|
|
||||||
observeIntersectionForBottom,
|
observeIntersectionForBottom,
|
||||||
observeIntersectionForLoading,
|
observeIntersectionForLoading,
|
||||||
observeIntersectionForPlaying,
|
observeIntersectionForPlaying,
|
||||||
|
onMessageUnmount,
|
||||||
}: OwnProps & StateProps) => {
|
}: OwnProps & StateProps) => {
|
||||||
const {
|
const {
|
||||||
requestConfetti,
|
requestConfetti,
|
||||||
@ -249,12 +249,6 @@ const ActionMessage = ({
|
|||||||
scrollTargetPosition,
|
scrollTargetPosition,
|
||||||
});
|
});
|
||||||
|
|
||||||
useUnmountCleanup(() => {
|
|
||||||
if (message.isPinned) {
|
|
||||||
onIntersectPinnedMessage?.({ viewportPinnedIdsToRemove: [message.id] });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isContextMenuOpen, contextMenuAnchor,
|
isContextMenuOpen, contextMenuAnchor,
|
||||||
handleBeforeContextMenu, handleContextMenu,
|
handleBeforeContextMenu, handleContextMenu,
|
||||||
@ -291,6 +285,10 @@ const ActionMessage = ({
|
|||||||
ref,
|
ref,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useUnmountCleanup(() => {
|
||||||
|
onMessageUnmount?.(id);
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const bottomMarker = ref.current;
|
const bottomMarker = ref.current;
|
||||||
if (!bottomMarker || !isElementInViewport(bottomMarker)) return;
|
if (!bottomMarker || !isElementInViewport(bottomMarker)) return;
|
||||||
|
|||||||
@ -42,7 +42,6 @@ import type {
|
|||||||
ThreadReadState,
|
ThreadReadState,
|
||||||
} from '../../../types';
|
} from '../../../types';
|
||||||
import type { Signal } from '../../../util/signals';
|
import type { Signal } from '../../../util/signals';
|
||||||
import type { OnIntersectPinnedMessage } from '../hooks/usePinnedMessage';
|
|
||||||
import { MAIN_THREAD_ID } from '../../../api/types';
|
import { MAIN_THREAD_ID } from '../../../api/types';
|
||||||
import { AudioOrigin } from '../../../types';
|
import { AudioOrigin } from '../../../types';
|
||||||
|
|
||||||
@ -238,7 +237,7 @@ type OwnProps = {
|
|||||||
observeIntersectionForBottom?: ObserveFn;
|
observeIntersectionForBottom?: ObserveFn;
|
||||||
observeIntersectionForLoading?: ObserveFn;
|
observeIntersectionForLoading?: ObserveFn;
|
||||||
observeIntersectionForPlaying?: ObserveFn;
|
observeIntersectionForPlaying?: ObserveFn;
|
||||||
onIntersectPinnedMessage?: OnIntersectPinnedMessage;
|
onMessageUnmount?: (messageId: number) => void;
|
||||||
} & MessagePositionProperties;
|
} & MessagePositionProperties;
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
@ -353,9 +352,6 @@ const MAX_REASON_LENGTH = 200;
|
|||||||
|
|
||||||
const Message = ({
|
const Message = ({
|
||||||
message,
|
message,
|
||||||
observeIntersectionForBottom,
|
|
||||||
observeIntersectionForLoading,
|
|
||||||
observeIntersectionForPlaying,
|
|
||||||
album,
|
album,
|
||||||
noAvatars,
|
noAvatars,
|
||||||
withAvatar,
|
withAvatar,
|
||||||
@ -462,7 +458,10 @@ const Message = ({
|
|||||||
minFutureTime,
|
minFutureTime,
|
||||||
webPage,
|
webPage,
|
||||||
summary,
|
summary,
|
||||||
onIntersectPinnedMessage,
|
observeIntersectionForBottom,
|
||||||
|
observeIntersectionForLoading,
|
||||||
|
observeIntersectionForPlaying,
|
||||||
|
onMessageUnmount,
|
||||||
}: OwnProps & StateProps) => {
|
}: OwnProps & StateProps) => {
|
||||||
const {
|
const {
|
||||||
toggleMessageSelection,
|
toggleMessageSelection,
|
||||||
@ -536,19 +535,16 @@ const Message = ({
|
|||||||
className: false,
|
className: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useUnmountCleanup(() => {
|
||||||
|
onMessageUnmount?.(messageId);
|
||||||
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
id: messageId, chatId, forwardInfo, viaBotId, isTranscriptionError, factCheck,
|
id: messageId, chatId, forwardInfo, viaBotId, isTranscriptionError, factCheck,
|
||||||
isTypingDraft,
|
isTypingDraft,
|
||||||
} = message;
|
} = message;
|
||||||
const hasSummary = Boolean(message.summaryLanguageCode);
|
const hasSummary = Boolean(message.summaryLanguageCode);
|
||||||
|
|
||||||
useUnmountCleanup(() => {
|
|
||||||
if (message.isPinned) {
|
|
||||||
const id = album ? album.mainMessage.id : messageId;
|
|
||||||
onIntersectPinnedMessage?.({ viewportPinnedIdsToRemove: [id] });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const isLocal = isMessageLocal(message);
|
const isLocal = isMessageLocal(message);
|
||||||
const isOwn = isOwnMessage(message);
|
const isOwn = isOwnMessage(message);
|
||||||
const isScheduled = messageListType === 'scheduled' || message.isScheduled;
|
const isScheduled = messageListType === 'scheduled' || message.isScheduled;
|
||||||
|
|||||||
@ -364,6 +364,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.tiny {
|
&.tiny {
|
||||||
|
--emoji-size: 1rem;
|
||||||
|
|
||||||
height: 2.25rem;
|
height: 2.25rem;
|
||||||
padding: 0.4375rem;
|
padding: 0.4375rem;
|
||||||
border-radius: var(--border-radius-button-tiny);
|
border-radius: var(--border-radius-button-tiny);
|
||||||
@ -380,6 +382,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.pill {
|
&.pill {
|
||||||
|
--emoji-size: 1.25rem;
|
||||||
|
|
||||||
height: 1.75rem;
|
height: 1.75rem;
|
||||||
padding: 0.25rem 0.5rem;
|
padding: 0.25rem 0.5rem;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user