Message List: Various fixes for local message IDs

This commit is contained in:
Alexander Zinchuk 2022-05-31 22:30:52 +04:00
parent 2647c561a9
commit ea0da789ce
10 changed files with 27 additions and 27 deletions

View File

@ -35,7 +35,6 @@ import type {
import { import {
DELETED_COMMENTS_CHANNEL_ID, DELETED_COMMENTS_CHANNEL_ID,
LOCAL_MESSAGE_ID_BASE,
SERVICE_NOTIFICATIONS_USER_ID, SERVICE_NOTIFICATIONS_USER_ID,
SPONSORED_MESSAGE_CACHE_MS, SPONSORED_MESSAGE_CACHE_MS,
SUPPORTED_AUDIO_CONTENT_TYPES, SUPPORTED_AUDIO_CONTENT_TYPES,
@ -56,7 +55,9 @@ import { buildApiCallDiscardReason } from './calls';
const LOCAL_MEDIA_UPLOADING_TEMP_ID = 'temp'; const LOCAL_MEDIA_UPLOADING_TEMP_ID = 'temp';
const INPUT_WAVEFORM_LENGTH = 63; const INPUT_WAVEFORM_LENGTH = 63;
let localMessageCounter = LOCAL_MESSAGE_ID_BASE; let localMessageCounter = 0;
const getNextLocalMessageId = () => parseFloat(`${Date.now()}.${localMessageCounter++}`);
let currentUserId!: string; let currentUserId!: string;
export function setMessageBuilderCurrentUserId(_currentUserId: string) { export function setMessageBuilderCurrentUserId(_currentUserId: string) {
@ -120,7 +121,7 @@ export function buildApiMessageFromNotification(
notification: GramJs.UpdateServiceNotification, notification: GramJs.UpdateServiceNotification,
currentDate: number, currentDate: number,
): ApiMessage { ): ApiMessage {
const localId = localMessageCounter++; const localId = getNextLocalMessageId();
const content = buildMessageContent(notification); const content = buildMessageContent(notification);
return { return {
@ -1148,7 +1149,7 @@ export function buildLocalMessage(
sendAs?: ApiChat | ApiUser, sendAs?: ApiChat | ApiUser,
serverTimeOffset = 0, serverTimeOffset = 0,
): ApiMessage { ): ApiMessage {
const localId = localMessageCounter++; const localId = getNextLocalMessageId();
const media = attachment && buildUploadingMedia(attachment); const media = attachment && buildUploadingMedia(attachment);
const isChannel = chat.type === 'chatTypeChannel'; const isChannel = chat.type === 'chatTypeChannel';
@ -1186,7 +1187,7 @@ export function buildLocalForwardedMessage(
serverTimeOffset: number, serverTimeOffset: number,
scheduledAt?: number, scheduledAt?: number,
): ApiMessage { ): ApiMessage {
const localId = localMessageCounter++; const localId = getNextLocalMessageId();
const { const {
content, content,
chatId: fromChatId, chatId: fromChatId,

View File

@ -9,7 +9,7 @@ import { MAIN_THREAD_ID } from '../../api/types';
import type { MessageListType } from '../../global/types'; import type { MessageListType } from '../../global/types';
import { LoadMoreDirection } from '../../types'; import { LoadMoreDirection } from '../../types';
import { ANIMATION_END_DELAY, LOCAL_MESSAGE_ID_BASE, MESSAGE_LIST_SLICE } from '../../config'; import { ANIMATION_END_DELAY, LOCAL_MESSAGE_MIN_ID, MESSAGE_LIST_SLICE } from '../../config';
import { import {
selectChatMessages, selectChatMessages,
selectIsViewportNewest, selectIsViewportNewest,
@ -303,7 +303,7 @@ const MessageList: FC<OwnProps & StateProps> = ({
} }
// Loading history while sending a message can return the same message and cause ambiguity // Loading history while sending a message can return the same message and cause ambiguity
const isLastMessageLocal = messageIds && messageIds[messageIds.length - 1] >= LOCAL_MESSAGE_ID_BASE; const isLastMessageLocal = messageIds && messageIds[messageIds.length - 1] > LOCAL_MESSAGE_MIN_ID;
if (isLastMessageLocal) { if (isLastMessageLocal) {
return; return;
} }

View File

@ -9,7 +9,7 @@ import buildClassName from '../../util/buildClassName';
import { compact } from '../../util/iteratees'; import { compact } from '../../util/iteratees';
import { formatHumanDate } from '../../util/dateFormat'; import { formatHumanDate } from '../../util/dateFormat';
import { import {
getMessageHtmlId, getMessageOriginalId, isActionMessage, isOwnMessage, getMessageHtmlId, getMessageOriginalId, isActionMessage, isOwnMessage, isServiceNotificationMessage,
} from '../../global/helpers'; } from '../../global/helpers';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
import type { MessageDateGroup } from './helpers/groupMessages'; import type { MessageDateGroup } from './helpers/groupMessages';
@ -182,10 +182,8 @@ const MessageListContent: FC<OwnProps> = ({
currentDocumentGroupId = documentGroupId; currentDocumentGroupId = documentGroupId;
const originalId = getMessageOriginalId(message); const originalId = getMessageOriginalId(message);
// Scheduled messages can have local IDs in the middle of the list, // Service notifications saved in cache in previous versions may share the same `previousLocalId`
// and keys should be ordered, so we prefix it with a date. const key = isServiceNotificationMessage(message) ? `${message.date}_${originalId}` : originalId;
// However, this may lead to issues if server date is not synchronized with the local one.
const key = type !== 'scheduled' ? originalId : `${message.date}_${originalId}`;
return compact([ return compact([
message.id === memoUnreadDividerBeforeIdRef.current && unreadDivider, message.id === memoUnreadDividerBeforeIdRef.current && unreadDivider,

View File

@ -5,7 +5,7 @@ import { useMemo, useRef } from '../../../lib/teact/teact';
import { LoadMoreDirection } from '../../../types'; import { LoadMoreDirection } from '../../../types';
import type { MessageListType } from '../../../global/types'; import type { MessageListType } from '../../../global/types';
import { LOCAL_MESSAGE_ID_BASE, MESSAGE_LIST_SLICE } from '../../../config'; import { LOCAL_MESSAGE_MIN_ID, MESSAGE_LIST_SLICE } from '../../../config';
import { IS_SCROLL_PATCH_NEEDED, MESSAGE_LIST_SENSITIVE_AREA } from '../../../util/environment'; import { IS_SCROLL_PATCH_NEEDED, MESSAGE_LIST_SENSITIVE_AREA } from '../../../util/environment';
import { debounce } from '../../../util/schedulers'; import { debounce } from '../../../util/schedulers';
import { useIntersectionObserver, useOnIntersect } from '../../../hooks/useIntersectionObserver'; import { useIntersectionObserver, useOnIntersect } from '../../../hooks/useIntersectionObserver';
@ -84,7 +84,7 @@ export default function useScrollHooks(
} }
// Loading history while sending a message can return the same message and cause ambiguity // Loading history while sending a message can return the same message and cause ambiguity
const isFirstMessageLocal = messageIds[0] >= LOCAL_MESSAGE_ID_BASE; const isFirstMessageLocal = messageIds[0] > LOCAL_MESSAGE_MIN_ID;
if (isFirstMessageLocal) { if (isFirstMessageLocal) {
return; return;
} }

View File

@ -7,7 +7,7 @@ import type { IAlbum, ISettings } from '../../../types';
import type { IAlbumLayout } from './helpers/calculateAlbumLayout'; import type { IAlbumLayout } from './helpers/calculateAlbumLayout';
import { AlbumRectPart } from './helpers/calculateAlbumLayout'; import { AlbumRectPart } from './helpers/calculateAlbumLayout';
import { getMessageContent, getMessageHtmlId } from '../../../global/helpers'; import { getMessageContent, getMessageHtmlId, getMessageOriginalId } from '../../../global/helpers';
import { getActions, getGlobal, withGlobal } from '../../../global'; import { getActions, getGlobal, withGlobal } from '../../../global';
import withSelectControl from './hocs/withSelectControl'; import withSelectControl from './hocs/withSelectControl';
import type { ObserveFn } from '../../../hooks/useIntersectionObserver'; import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
@ -66,7 +66,7 @@ const Album: FC<OwnProps & StateProps> = ({
function renderAlbumMessage(message: ApiMessage, index: number) { function renderAlbumMessage(message: ApiMessage, index: number) {
const { photo, video } = getMessageContent(message); const { photo, video } = getMessageContent(message);
const fileUpload = uploadsById[message.previousLocalId || message.id]; const fileUpload = uploadsById[getMessageOriginalId(message)];
const uploadProgress = fileUpload?.progress; const uploadProgress = fileUpload?.progress;
const { dimensions, sides } = albumLayout.layout[index]; const { dimensions, sides } = albumLayout.layout[index];

View File

@ -107,7 +107,7 @@ export const MOBILE_SCREEN_MAX_WIDTH = 600; // px
export const MOBILE_SCREEN_LANDSCAPE_MAX_WIDTH = 950; // px export const MOBILE_SCREEN_LANDSCAPE_MAX_WIDTH = 950; // px
export const MOBILE_SCREEN_LANDSCAPE_MAX_HEIGHT = 450; // px export const MOBILE_SCREEN_LANDSCAPE_MAX_HEIGHT = 450; // px
export const LOCAL_MESSAGE_ID_BASE = 1e9; export const LOCAL_MESSAGE_MIN_ID = 1e11; // `Date.now()` is always used as base
export const TMP_CHAT_ID = '0'; export const TMP_CHAT_ID = '0';
export const ANIMATION_END_DELAY = 100; export const ANIMATION_END_DELAY = 100;

View File

@ -68,7 +68,7 @@ import {
selectSponsoredMessage, selectSponsoredMessage,
} from '../../selectors'; } from '../../selectors';
import { debounce, onTickEnd, rafPromise } from '../../../util/schedulers'; import { debounce, onTickEnd, rafPromise } from '../../../util/schedulers';
import { isServiceNotificationMessage } from '../../helpers'; import { getMessageOriginalId, isServiceNotificationMessage } from '../../helpers';
import { getTranslation } from '../../../util/langProvider'; import { getTranslation } from '../../../util/langProvider';
const uploadProgressCallbacks = new Map<number, ApiOnProgress>(); const uploadProgressCallbacks = new Map<number, ApiOnProgress>();
@ -302,7 +302,7 @@ addActionHandler('editMessage', (global, actions, payload) => {
addActionHandler('cancelSendingMessage', (global, actions, payload) => { addActionHandler('cancelSendingMessage', (global, actions, payload) => {
const { chatId, messageId } = payload!; const { chatId, messageId } = payload!;
const message = selectChatMessage(global, chatId, messageId); const message = selectChatMessage(global, chatId, messageId);
const progressCallback = message && uploadProgressCallbacks.get(message.previousLocalId || message.id); const progressCallback = message && uploadProgressCallbacks.get(getMessageOriginalId(message));
if (progressCallback) { if (progressCallback) {
cancelApiProgress(progressCallback); cancelApiProgress(progressCallback);
} }

View File

@ -47,7 +47,7 @@ import {
selectLocalAnimatedEmoji, selectLocalAnimatedEmoji,
} from '../../selectors'; } from '../../selectors';
import { import {
getMessageContent, isUserId, isMessageLocal, getMessageText, checkIfHasUnreadReactions, getMessageContent, isUserId, isMessageLocal, getMessageText, checkIfHasUnreadReactions, getMessageOriginalId,
} from '../../helpers'; } from '../../helpers';
import { onTickEnd } from '../../../util/schedulers'; import { onTickEnd } from '../../../util/schedulers';
import { updateUnreadReactions } from '../../reducers/reactions'; import { updateUnreadReactions } from '../../reducers/reactions';
@ -665,7 +665,7 @@ function updateChatLastMessage(
if (currentLastMessage && !force) { if (currentLastMessage && !force) {
const isSameOrNewer = ( const isSameOrNewer = (
currentLastMessage.id === message.id || currentLastMessage.id === message.previousLocalId currentLastMessage.id === getMessageOriginalId(message)
) || message.id > currentLastMessage.id; ) || message.id > currentLastMessage.id;
if (!isSameOrNewer) { if (!isSameOrNewer) {

View File

@ -6,7 +6,7 @@ import type { LangFn } from '../../hooks/useLang';
import { import {
CONTENT_NOT_SUPPORTED, CONTENT_NOT_SUPPORTED,
LOCAL_MESSAGE_ID_BASE, LOCAL_MESSAGE_MIN_ID,
RE_LINK_TEMPLATE, RE_LINK_TEMPLATE,
SERVICE_NOTIFICATIONS_USER_ID, SERVICE_NOTIFICATIONS_USER_ID,
} from '../../config'; } from '../../config';
@ -175,7 +175,7 @@ export function getSendingState(message: ApiMessage) {
} }
export function isMessageLocal(message: ApiMessage) { export function isMessageLocal(message: ApiMessage) {
return message.id >= LOCAL_MESSAGE_ID_BASE; return message.id > LOCAL_MESSAGE_MIN_ID;
} }
export function isHistoryClearMessage(message: ApiMessage) { export function isHistoryClearMessage(message: ApiMessage) {

View File

@ -9,7 +9,7 @@ import {
MAIN_THREAD_ID, MAIN_THREAD_ID,
} from '../../api/types'; } from '../../api/types';
import { LOCAL_MESSAGE_ID_BASE, REPLIES_USER_ID, SERVICE_NOTIFICATIONS_USER_ID } from '../../config'; import { LOCAL_MESSAGE_MIN_ID, REPLIES_USER_ID, SERVICE_NOTIFICATIONS_USER_ID } from '../../config';
import { import {
selectChat, selectChatBot, selectIsChatWithBot, selectIsChatWithSelf, selectChat, selectChatBot, selectIsChatWithBot, selectIsChatWithSelf,
} from './chats'; } from './chats';
@ -37,6 +37,7 @@ import {
getMessageVoice, getMessageVoice,
getMessageDocument, getMessageDocument,
getMessageWebPagePhoto, getMessageWebPagePhoto,
getMessageOriginalId,
} from '../helpers'; } from '../helpers';
import { findLast } from '../../util/iteratees'; import { findLast } from '../../util/iteratees';
import { selectIsStickerFavorite } from './symbols'; import { selectIsStickerFavorite } from './symbols';
@ -253,7 +254,7 @@ export function selectIsViewportNewest(global: GlobalState, chatId: string, thre
} }
// Edge case: outgoing `lastMessage` is updated with a delay to optimize animation // Edge case: outgoing `lastMessage` is updated with a delay to optimize animation
if (lastMessageId >= LOCAL_MESSAGE_ID_BASE && !selectChatMessage(global, chatId, lastMessageId)) { if (lastMessageId > LOCAL_MESSAGE_MIN_ID && !selectChatMessage(global, chatId, lastMessageId)) {
return true; return true;
} }
@ -310,7 +311,7 @@ export function selectFocusedMessageId(global: GlobalState, chatId: string) {
export function selectIsMessageFocused(global: GlobalState, message: ApiMessage) { export function selectIsMessageFocused(global: GlobalState, message: ApiMessage) {
const focusedId = selectFocusedMessageId(global, message.chatId); const focusedId = selectFocusedMessageId(global, message.chatId);
return focusedId ? focusedId === message.id || focusedId === message.previousLocalId : false; return focusedId ? focusedId === getMessageOriginalId(message) : false;
} }
export function selectIsMessageUnread(global: GlobalState, message: ApiMessage) { export function selectIsMessageUnread(global: GlobalState, message: ApiMessage) {
@ -554,7 +555,7 @@ export function selectActiveDownloadIds(global: GlobalState, chatId: string) {
} }
export function selectUploadProgress(global: GlobalState, message: ApiMessage) { export function selectUploadProgress(global: GlobalState, message: ApiMessage) {
return global.fileUploads.byMessageLocalId[message.previousLocalId || message.id]?.progress; return global.fileUploads.byMessageLocalId[getMessageOriginalId(message)]?.progress;
} }
export function selectRealLastReadId(global: GlobalState, chatId: string, threadId: number) { export function selectRealLastReadId(global: GlobalState, chatId: string, threadId: number) {