mirror of
https://github.com/danog/telegram-tt.git
synced 2024-11-27 12:55:11 +01:00
[Perf] Optimistically mark messages read
This commit is contained in:
parent
13b62d0199
commit
5a7bbb19b1
@ -140,6 +140,7 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
const anchorIdRef = useRef<string>();
|
||||
const anchorTopRef = useRef<number>();
|
||||
const listItemElementsRef = useRef<HTMLDivElement[]>();
|
||||
// Not updated (as we want the unread divider to keep its position)
|
||||
const memoUnreadDividerBeforeIdRef = useRef<number | undefined>(firstUnreadId);
|
||||
// Updated every time (to be used from intersection callback closure)
|
||||
const memoFirstUnreadIdRef = useRef<number>();
|
||||
@ -485,7 +486,8 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
noAvatars={noAvatars}
|
||||
containerRef={containerRef}
|
||||
anchorIdRef={anchorIdRef}
|
||||
memoFirstUnreadIdRef={memoUnreadDividerBeforeIdRef}
|
||||
memoUnreadDividerBeforeIdRef={memoUnreadDividerBeforeIdRef}
|
||||
memoFirstUnreadIdRef={memoFirstUnreadIdRef}
|
||||
threadId={threadId}
|
||||
type={type}
|
||||
threadTopMessageId={threadTopMessageId}
|
||||
|
@ -26,6 +26,7 @@ interface OwnProps {
|
||||
noAvatars: boolean;
|
||||
containerRef: RefObject<HTMLDivElement>;
|
||||
anchorIdRef: { current: string | undefined };
|
||||
memoUnreadDividerBeforeIdRef: { current: number | undefined };
|
||||
memoFirstUnreadIdRef: { current: number | undefined };
|
||||
threadId: number;
|
||||
type: MessageListType;
|
||||
@ -49,6 +50,7 @@ const MessageListContent: FC<OwnProps> = ({
|
||||
noAvatars,
|
||||
containerRef,
|
||||
anchorIdRef,
|
||||
memoUnreadDividerBeforeIdRef,
|
||||
memoFirstUnreadIdRef,
|
||||
threadId,
|
||||
type,
|
||||
@ -111,7 +113,7 @@ const MessageListContent: FC<OwnProps> = ({
|
||||
);
|
||||
|
||||
return compact([
|
||||
message.id === memoFirstUnreadIdRef.current && unreadDivider,
|
||||
message.id === memoUnreadDividerBeforeIdRef.current && unreadDivider,
|
||||
<ActionMessage
|
||||
key={message.id}
|
||||
message={message}
|
||||
@ -162,7 +164,7 @@ const MessageListContent: FC<OwnProps> = ({
|
||||
const key = type !== 'scheduled' ? originalId : `${message.date}_${originalId}`;
|
||||
|
||||
return compact([
|
||||
message.id === memoFirstUnreadIdRef.current ? unreadDivider : undefined,
|
||||
message.id === memoUnreadDividerBeforeIdRef.current && unreadDivider,
|
||||
<Message
|
||||
key={key}
|
||||
message={message}
|
||||
|
@ -9,6 +9,7 @@ import useBackgroundMode from '../../../hooks/useBackgroundMode';
|
||||
|
||||
const INTERSECTION_THROTTLE_FOR_MEDIA = IS_ANDROID ? 1000 : 350;
|
||||
const INTERSECTION_MARGIN_FOR_MEDIA = IS_SINGLE_COLUMN_LAYOUT ? 300 : 500;
|
||||
const INTERSECTION_THROTTLE_FOR_READING = 150;
|
||||
|
||||
export default function useMessageObservers(
|
||||
type: MessageListType,
|
||||
@ -29,6 +30,7 @@ export default function useMessageObservers(
|
||||
observe: observeIntersectionForReading, freeze: freezeForReading, unfreeze: unfreezeForReading,
|
||||
} = useIntersectionObserver({
|
||||
rootRef: containerRef,
|
||||
throttleMs: INTERSECTION_THROTTLE_FOR_READING,
|
||||
}, (entries) => {
|
||||
if (type !== 'thread') {
|
||||
return;
|
||||
|
@ -50,13 +50,14 @@ import {
|
||||
selectEditingMessage,
|
||||
selectScheduledMessage,
|
||||
selectNoWebPage,
|
||||
selectFirstUnreadId,
|
||||
} from '../../selectors';
|
||||
import { rafPromise, throttle } from '../../../util/schedulers';
|
||||
import { debounce, rafPromise } from '../../../util/schedulers';
|
||||
import { IS_IOS } from '../../../util/environment';
|
||||
|
||||
const uploadProgressCallbacks = new Map<number, ApiOnProgress>();
|
||||
|
||||
const runThrottledForMarkRead = throttle((cb) => cb(), 1000, true);
|
||||
const runDebouncedForMarkRead = debounce((cb) => cb(), 1000, false);
|
||||
|
||||
addReducer('loadViewportMessages', (global, actions, payload) => {
|
||||
const {
|
||||
@ -443,22 +444,43 @@ addReducer('markMessageListRead', (global, actions, payload) => {
|
||||
const { serverTimeOffset } = global;
|
||||
const currentMessageList = selectCurrentMessageList(global);
|
||||
if (!currentMessageList) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { chatId, threadId } = currentMessageList;
|
||||
const chat = selectThreadOriginChat(global, chatId, threadId);
|
||||
if (!chat) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { maxId } = payload!;
|
||||
|
||||
runThrottledForMarkRead(() => {
|
||||
runDebouncedForMarkRead(() => {
|
||||
void callApi('markMessageListRead', {
|
||||
serverTimeOffset, chat, threadId, maxId,
|
||||
});
|
||||
});
|
||||
|
||||
// TODO Support local marking read for threads
|
||||
if (threadId !== MAIN_THREAD_ID) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const viewportIds = selectViewportIds(global, chatId, threadId);
|
||||
const minId = selectFirstUnreadId(global, chatId, threadId);
|
||||
if (!viewportIds || !minId || !chat.unreadCount) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const readCount = countSortedIds(viewportIds!, minId, maxId);
|
||||
if (!readCount) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return updateChat(global, chatId, {
|
||||
lastReadInboxMessageId: maxId,
|
||||
unreadCount: Math.max(0, chat.unreadCount - readCount),
|
||||
});
|
||||
});
|
||||
|
||||
addReducer('markMessagesRead', (global, actions, payload) => {
|
||||
@ -892,3 +914,19 @@ async function loadScheduledHistory(chat: ApiChat, historyHash?: number) {
|
||||
global = replaceThreadParam(global, chat.id, MAIN_THREAD_ID, 'scheduledIds', ids);
|
||||
setGlobal(global);
|
||||
}
|
||||
|
||||
function countSortedIds(ids: number[], from: number, to: number) {
|
||||
let count = 0;
|
||||
|
||||
for (let i = 0, l = ids.length; i < l; i++) {
|
||||
if (ids[i] >= from && ids[i] <= to) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (ids[i] >= to) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user