Message List: Various fixes for local message IDs
This commit is contained in:
parent
2647c561a9
commit
ea0da789ce
@ -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,
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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];
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user