Composer: Fix race conditions when sending messages (#3279)

This commit is contained in:
Alexander Zinchuk 2023-06-12 11:56:00 +02:00
parent e5ad070a27
commit 85bdbd5fa5
9 changed files with 133 additions and 66 deletions

View File

@ -5,15 +5,18 @@ import { getActions, withGlobal } from '../../global';
import type { FC } from '../../lib/teact/teact'; import type { FC } from '../../lib/teact/teact';
import type { ApiSticker, ApiStickerSet } from '../../api/types'; import type { ApiSticker, ApiStickerSet } from '../../api/types';
import type { MessageList } from '../../global/types';
import { EMOJI_SIZE_MODAL, STICKER_SIZE_MODAL, TME_LINK_PREFIX } from '../../config'; import { EMOJI_SIZE_MODAL, STICKER_SIZE_MODAL, TME_LINK_PREFIX } from '../../config';
import { import {
selectCanScheduleUntilOnline, selectCanScheduleUntilOnline,
selectChat, selectChat,
selectCurrentMessageList, selectCurrentMessageList,
selectIsChatWithSelf, selectIsCurrentUserPremium, selectIsChatWithSelf,
selectIsCurrentUserPremium,
selectShouldSchedule, selectShouldSchedule,
selectStickerSet, selectThreadInfo, selectStickerSet,
selectThreadInfo,
} from '../../global/selectors'; } from '../../global/selectors';
import renderText from './helpers/renderText'; import renderText from './helpers/renderText';
import { copyTextToClipboard } from '../../util/clipboard'; import { copyTextToClipboard } from '../../util/clipboard';
@ -44,6 +47,7 @@ export type OwnProps = {
}; };
type StateProps = { type StateProps = {
currentMessageList?: MessageList;
canSendStickers?: boolean; canSendStickers?: boolean;
stickerSet?: ApiStickerSet; stickerSet?: ApiStickerSet;
canScheduleUntilOnline?: boolean; canScheduleUntilOnline?: boolean;
@ -66,6 +70,7 @@ const StickerSetModal: FC<OwnProps & StateProps> = ({
isSavedMessages, isSavedMessages,
isCurrentUserPremium, isCurrentUserPremium,
shouldUpdateStickerSetOrder, shouldUpdateStickerSetOrder,
currentMessageList,
onClose, onClose,
}) => { }) => {
const { const {
@ -109,6 +114,9 @@ const StickerSetModal: FC<OwnProps & StateProps> = ({
}, [isOpen, fromSticker, loadStickers, stickerSetShortName, renderingStickerSet]); }, [isOpen, fromSticker, loadStickers, stickerSetShortName, renderingStickerSet]);
const handleSelect = useCallback((sticker: ApiSticker, isSilent?: boolean, isScheduleRequested?: boolean) => { const handleSelect = useCallback((sticker: ApiSticker, isSilent?: boolean, isScheduleRequested?: boolean) => {
if (!currentMessageList) {
return;
}
sticker = { sticker = {
...sticker, ...sticker,
isPreloadedGlobally: true, isPreloadedGlobally: true,
@ -117,19 +125,20 @@ const StickerSetModal: FC<OwnProps & StateProps> = ({
if (shouldSchedule || isScheduleRequested) { if (shouldSchedule || isScheduleRequested) {
requestCalendar((scheduledAt) => { requestCalendar((scheduledAt) => {
sendMessage({ sendMessage({
sticker, isSilent, scheduledAt, messageList: currentMessageList, sticker, isSilent, scheduledAt,
}); });
onClose(); onClose();
}); });
} else { } else {
sendMessage({ sendMessage({
messageList: currentMessageList,
sticker, sticker,
isSilent, isSilent,
shouldUpdateStickerSetOrder: shouldUpdateStickerSetOrder && isAdded, shouldUpdateStickerSetOrder: shouldUpdateStickerSetOrder && isAdded,
}); });
onClose(); onClose();
} }
}, [onClose, requestCalendar, sendMessage, shouldSchedule, isAdded, shouldUpdateStickerSetOrder]); }, [currentMessageList, shouldSchedule, requestCalendar, onClose, shouldUpdateStickerSetOrder, isAdded]);
const handleButtonClick = useCallback(() => { const handleButtonClick = useCallback(() => {
if (renderingStickerSet) { if (renderingStickerSet) {
@ -270,6 +279,7 @@ export default memo(withGlobal<OwnProps>(
stickerSet, stickerSet,
isCurrentUserPremium: selectIsCurrentUserPremium(global), isCurrentUserPremium: selectIsCurrentUserPremium(global),
shouldUpdateStickerSetOrder: global.settings.byKey.shouldUpdateStickerSetOrder, shouldUpdateStickerSetOrder: global.settings.byKey.shouldUpdateStickerSetOrder,
currentMessageList,
}; };
}, },
)(StickerSetModal)); )(StickerSetModal));

View File

@ -5,8 +5,9 @@ import { getActions, withGlobal } from '../../global';
import type { import type {
ApiContact, ApiError, ApiInviteInfo, ApiPhoto, ApiContact, ApiError, ApiInviteInfo, ApiPhoto,
} from '../../api/types'; } from '../../api/types';
import type { MessageList } from '../../global/types';
import { selectTabState } from '../../global/selectors'; import { selectCurrentMessageList, selectTabState } from '../../global/selectors';
import getReadableErrorText from '../../util/getReadableErrorText'; import getReadableErrorText from '../../util/getReadableErrorText';
import { pick } from '../../util/iteratees'; import { pick } from '../../util/iteratees';
import renderText from '../common/helpers/renderText'; import renderText from '../common/helpers/renderText';
@ -18,10 +19,11 @@ import Button from '../ui/Button';
import Avatar from '../common/Avatar'; import Avatar from '../common/Avatar';
type StateProps = { type StateProps = {
currentMessageList?: MessageList;
dialogs: (ApiError | ApiInviteInfo | ApiContact)[]; dialogs: (ApiError | ApiInviteInfo | ApiContact)[];
}; };
const Dialogs: FC<StateProps> = ({ dialogs }) => { const Dialogs: FC<StateProps> = ({ dialogs, currentMessageList }) => {
const { const {
dismissDialog, dismissDialog,
acceptInviteConfirmation, acceptInviteConfirmation,
@ -115,8 +117,13 @@ const Dialogs: FC<StateProps> = ({ dialogs }) => {
const renderContactRequest = (contactRequest: ApiContact) => { const renderContactRequest = (contactRequest: ApiContact) => {
const handleConfirm = () => { const handleConfirm = () => {
if (!currentMessageList) {
return;
}
sendMessage({ sendMessage({
contact: pick(contactRequest, ['firstName', 'lastName', 'phoneNumber']), contact: pick(contactRequest, ['firstName', 'lastName', 'phoneNumber']),
messageList: currentMessageList,
}); });
closeModal(); closeModal();
}; };
@ -194,6 +201,7 @@ export default memo(withGlobal(
(global): StateProps => { (global): StateProps => {
return { return {
dialogs: selectTabState(global).dialogs, dialogs: selectTabState(global).dialogs,
currentMessageList: selectCurrentMessageList(global),
}; };
}, },
)(Dialogs)); )(Dialogs));

View File

@ -3,8 +3,9 @@ import React, { memo, useEffect, useRef } from '../../lib/teact/teact';
import { getActions, withGlobal } from '../../global'; import { getActions, withGlobal } from '../../global';
import type { ApiSticker, ApiUpdateConnectionStateType } from '../../api/types'; import type { ApiSticker, ApiUpdateConnectionStateType } from '../../api/types';
import type { MessageList } from '../../global/types';
import { selectChat } from '../../global/selectors'; import { selectChat, selectCurrentMessageList } from '../../global/selectors';
import { getUserIdDividend } from '../../global/helpers'; import { getUserIdDividend } from '../../global/helpers';
import useLastCallback from '../../hooks/useLastCallback'; import useLastCallback from '../../hooks/useLastCallback';
@ -23,6 +24,7 @@ type StateProps = {
sticker?: ApiSticker; sticker?: ApiSticker;
lastUnreadMessageId?: number; lastUnreadMessageId?: number;
connectionState?: ApiUpdateConnectionStateType; connectionState?: ApiUpdateConnectionStateType;
currentMessageList?: MessageList;
}; };
const INTERSECTION_DEBOUNCE_MS = 200; const INTERSECTION_DEBOUNCE_MS = 200;
@ -31,6 +33,7 @@ const ContactGreeting: FC<OwnProps & StateProps> = ({
sticker, sticker,
connectionState, connectionState,
lastUnreadMessageId, lastUnreadMessageId,
currentMessageList,
}) => { }) => {
const { const {
loadGreetingStickers, loadGreetingStickers,
@ -62,11 +65,15 @@ const ContactGreeting: FC<OwnProps & StateProps> = ({
}, [connectionState, markMessageListRead, lastUnreadMessageId]); }, [connectionState, markMessageListRead, lastUnreadMessageId]);
const handleStickerSelect = useLastCallback((selectedSticker: ApiSticker) => { const handleStickerSelect = useLastCallback((selectedSticker: ApiSticker) => {
if (!currentMessageList) {
return;
}
selectedSticker = { selectedSticker = {
...selectedSticker, ...selectedSticker,
isPreloadedGlobally: true, isPreloadedGlobally: true,
}; };
sendMessage({ sticker: selectedSticker }); sendMessage({ sticker: selectedSticker, messageList: currentMessageList });
}); });
return ( return (
@ -110,6 +117,7 @@ export default memo(withGlobal<OwnProps>(
? chat.lastMessage.id ? chat.lastMessage.id
: undefined, : undefined,
connectionState: global.connectionState, connectionState: global.connectionState,
currentMessageList: selectCurrentMessageList(global),
}; };
}, },
)(ContactGreeting)); )(ContactGreeting));

View File

@ -6,7 +6,7 @@ import { requestMeasure, requestNextMutation } from '../../../lib/fasterdom/fast
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { import type {
TabState, MessageListType, GlobalState, ApiDraft, TabState, MessageListType, GlobalState, ApiDraft, MessageList,
} from '../../../global/types'; } from '../../../global/types';
import type { import type {
ApiAttachment, ApiAttachment,
@ -159,6 +159,7 @@ type StateProps =
editingMessage?: ApiMessage; editingMessage?: ApiMessage;
chat?: ApiChat; chat?: ApiChat;
draft?: ApiDraft; draft?: ApiDraft;
currentMessageList?: MessageList;
isChatWithBot?: boolean; isChatWithBot?: boolean;
isChatWithSelf?: boolean; isChatWithSelf?: boolean;
isChannel?: boolean; isChannel?: boolean;
@ -243,6 +244,7 @@ const Composer: FC<OwnProps & StateProps> = ({
editingMessage, editingMessage,
chatId, chatId,
threadId, threadId,
currentMessageList,
messageListType, messageListType,
draft, draft,
chat, chat,
@ -740,7 +742,7 @@ const Composer: FC<OwnProps & StateProps> = ({
isSilent?: boolean; isSilent?: boolean;
scheduledAt?: number; scheduledAt?: number;
}) => { }) => {
if (connectionState !== 'connectionStateReady') { if (connectionState !== 'connectionStateReady' || !currentMessageList) {
return; return;
} }
@ -752,6 +754,7 @@ const Composer: FC<OwnProps & StateProps> = ({
if (!checkSlowMode()) return; if (!checkSlowMode()) return;
sendMessage({ sendMessage({
messageList: currentMessageList,
text, text,
entities, entities,
scheduledAt, scheduledAt,
@ -787,7 +790,7 @@ const Composer: FC<OwnProps & StateProps> = ({
}); });
const handleSend = useLastCallback(async (isSilent = false, scheduledAt?: number) => { const handleSend = useLastCallback(async (isSilent = false, scheduledAt?: number) => {
if (connectionState !== 'connectionStateReady') { if (connectionState !== 'connectionStateReady' || !currentMessageList) {
return; return;
} }
@ -826,6 +829,7 @@ const Composer: FC<OwnProps & StateProps> = ({
if (!checkSlowMode()) return; if (!checkSlowMode()) return;
sendMessage({ sendMessage({
messageList: currentMessageList,
text, text,
entities, entities,
scheduledAt, scheduledAt,
@ -871,7 +875,7 @@ const Composer: FC<OwnProps & StateProps> = ({
}); });
const handleMessageSchedule = useLastCallback(( const handleMessageSchedule = useLastCallback((
args: ScheduledMessageArgs, scheduledAt: number, args: ScheduledMessageArgs, scheduledAt: number, messageList: MessageList,
) => { ) => {
if (args && 'queryId' in args) { if (args && 'queryId' in args) {
const { id, queryId, isSilent } = args; const { id, queryId, isSilent } = args;
@ -880,6 +884,7 @@ const Composer: FC<OwnProps & StateProps> = ({
queryId, queryId,
scheduledAt, scheduledAt,
isSilent, isSilent,
messageList,
}); });
return; return;
} }
@ -894,18 +899,19 @@ const Composer: FC<OwnProps & StateProps> = ({
} else { } else {
sendMessage({ sendMessage({
...args, ...args,
messageList,
scheduledAt, scheduledAt,
}); });
} }
}); });
useEffectWithPrevDeps(([prevContentToBeScheduled]) => { useEffectWithPrevDeps(([prevContentToBeScheduled]) => {
if (contentToBeScheduled && contentToBeScheduled !== prevContentToBeScheduled) { if (currentMessageList && contentToBeScheduled && contentToBeScheduled !== prevContentToBeScheduled) {
requestCalendar((scheduledAt) => { requestCalendar((scheduledAt) => {
handleMessageSchedule(contentToBeScheduled, scheduledAt); handleMessageSchedule(contentToBeScheduled, scheduledAt, currentMessageList);
}); });
} }
}, [contentToBeScheduled, handleMessageSchedule, requestCalendar]); }, [contentToBeScheduled, currentMessageList, handleMessageSchedule, requestCalendar]);
useEffect(() => { useEffect(() => {
if (requestedDraftText) { if (requestedDraftText) {
@ -940,17 +946,21 @@ const Composer: FC<OwnProps & StateProps> = ({
}); });
const handleGifSelect = useLastCallback((gif: ApiVideo, isSilent?: boolean, isScheduleRequested?: boolean) => { const handleGifSelect = useLastCallback((gif: ApiVideo, isSilent?: boolean, isScheduleRequested?: boolean) => {
if (!currentMessageList) {
return;
}
if (shouldSchedule || isScheduleRequested) { if (shouldSchedule || isScheduleRequested) {
forceShowSymbolMenu(); forceShowSymbolMenu();
requestCalendar((scheduledAt) => { requestCalendar((scheduledAt) => {
cancelForceShowSymbolMenu(); cancelForceShowSymbolMenu();
handleMessageSchedule({ gif, isSilent }, scheduledAt); handleMessageSchedule({ gif, isSilent }, scheduledAt, currentMessageList);
requestMeasure(() => { requestMeasure(() => {
resetComposer(true); resetComposer(true);
}); });
}); });
} else { } else {
sendMessage({ gif, isSilent }); sendMessage({ messageList: currentMessageList, gif, isSilent });
requestMeasure(() => { requestMeasure(() => {
resetComposer(true); resetComposer(true);
}); });
@ -964,6 +974,10 @@ const Composer: FC<OwnProps & StateProps> = ({
shouldPreserveInput = false, shouldPreserveInput = false,
canUpdateStickerSetsOrder?: boolean, canUpdateStickerSetsOrder?: boolean,
) => { ) => {
if (!currentMessageList) {
return;
}
sticker = { sticker = {
...sticker, ...sticker,
isPreloadedGlobally: true, isPreloadedGlobally: true,
@ -973,13 +987,14 @@ const Composer: FC<OwnProps & StateProps> = ({
forceShowSymbolMenu(); forceShowSymbolMenu();
requestCalendar((scheduledAt) => { requestCalendar((scheduledAt) => {
cancelForceShowSymbolMenu(); cancelForceShowSymbolMenu();
handleMessageSchedule({ sticker, isSilent }, scheduledAt); handleMessageSchedule({ sticker, isSilent }, scheduledAt, currentMessageList);
requestMeasure(() => { requestMeasure(() => {
resetComposer(shouldPreserveInput); resetComposer(shouldPreserveInput);
}); });
}); });
} else { } else {
sendMessage({ sendMessage({
messageList: currentMessageList,
sticker, sticker,
isSilent, isSilent,
shouldUpdateStickerSetOrder: shouldUpdateStickerSetOrder && canUpdateStickerSetsOrder, shouldUpdateStickerSetOrder: shouldUpdateStickerSetOrder && canUpdateStickerSetsOrder,
@ -993,7 +1008,7 @@ const Composer: FC<OwnProps & StateProps> = ({
const handleInlineBotSelect = useLastCallback(( const handleInlineBotSelect = useLastCallback((
inlineResult: ApiBotInlineResult | ApiBotInlineMediaResult, isSilent?: boolean, isScheduleRequested?: boolean, inlineResult: ApiBotInlineResult | ApiBotInlineMediaResult, isSilent?: boolean, isScheduleRequested?: boolean,
) => { ) => {
if (connectionState !== 'connectionStateReady') { if (connectionState !== 'connectionStateReady' || !currentMessageList) {
return; return;
} }
@ -1003,13 +1018,14 @@ const Composer: FC<OwnProps & StateProps> = ({
id: inlineResult.id, id: inlineResult.id,
queryId: inlineResult.queryId, queryId: inlineResult.queryId,
isSilent, isSilent,
}, scheduledAt); }, scheduledAt, currentMessageList);
}); });
} else { } else {
sendInlineBotResult({ sendInlineBotResult({
id: inlineResult.id, id: inlineResult.id,
queryId: inlineResult.queryId, queryId: inlineResult.queryId,
isSilent, isSilent,
messageList: currentMessageList,
}); });
} }
@ -1032,13 +1048,17 @@ const Composer: FC<OwnProps & StateProps> = ({
}); });
const handlePollSend = useLastCallback((poll: ApiNewPoll) => { const handlePollSend = useLastCallback((poll: ApiNewPoll) => {
if (!currentMessageList) {
return;
}
if (shouldSchedule) { if (shouldSchedule) {
requestCalendar((scheduledAt) => { requestCalendar((scheduledAt) => {
handleMessageSchedule({ poll }, scheduledAt); handleMessageSchedule({ poll }, scheduledAt, currentMessageList);
}); });
closePollModal(); closePollModal();
} else { } else {
sendMessage({ poll }); sendMessage({ messageList: currentMessageList, poll });
closePollModal(); closePollModal();
} }
}); });
@ -1046,7 +1066,7 @@ const Composer: FC<OwnProps & StateProps> = ({
const sendSilent = useLastCallback((additionalArgs?: ScheduledMessageArgs) => { const sendSilent = useLastCallback((additionalArgs?: ScheduledMessageArgs) => {
if (shouldSchedule) { if (shouldSchedule) {
requestCalendar((scheduledAt) => { requestCalendar((scheduledAt) => {
handleMessageSchedule({ ...additionalArgs, isSilent: true }, scheduledAt); handleMessageSchedule({ ...additionalArgs, isSilent: true }, scheduledAt, currentMessageList!);
}); });
} else if (additionalArgs && ('sendCompressed' in additionalArgs || 'sendGrouped' in additionalArgs)) { } else if (additionalArgs && ('sendCompressed' in additionalArgs || 'sendGrouped' in additionalArgs)) {
const { sendCompressed = false, sendGrouped = false } = additionalArgs; const { sendCompressed = false, sendGrouped = false } = additionalArgs;
@ -1162,8 +1182,12 @@ const Composer: FC<OwnProps & StateProps> = ({
if (activeVoiceRecording) { if (activeVoiceRecording) {
pauseRecordingVoice(); pauseRecordingVoice();
} }
if (!currentMessageList) {
return;
}
requestCalendar((scheduledAt) => { requestCalendar((scheduledAt) => {
handleMessageSchedule({}, scheduledAt); handleMessageSchedule({}, scheduledAt, currentMessageList!);
}); });
break; break;
default: default:
@ -1201,7 +1225,7 @@ const Composer: FC<OwnProps & StateProps> = ({
const handleSendScheduled = useLastCallback(() => { const handleSendScheduled = useLastCallback(() => {
requestCalendar((scheduledAt) => { requestCalendar((scheduledAt) => {
handleMessageSchedule({}, scheduledAt); handleMessageSchedule({}, scheduledAt, currentMessageList!);
}); });
}); });
@ -1210,12 +1234,12 @@ const Composer: FC<OwnProps & StateProps> = ({
}); });
const handleSendWhenOnline = useLastCallback(() => { const handleSendWhenOnline = useLastCallback(() => {
handleMessageSchedule({}, SCHEDULED_WHEN_ONLINE); handleMessageSchedule({}, SCHEDULED_WHEN_ONLINE, currentMessageList!);
}); });
const handleSendScheduledAttachments = useLastCallback((sendCompressed: boolean, sendGrouped: boolean) => { const handleSendScheduledAttachments = useLastCallback((sendCompressed: boolean, sendGrouped: boolean) => {
requestCalendar((scheduledAt) => { requestCalendar((scheduledAt) => {
handleMessageSchedule({ sendCompressed, sendGrouped }, scheduledAt); handleMessageSchedule({ sendCompressed, sendGrouped }, scheduledAt, currentMessageList!);
}); });
}); });
@ -1656,6 +1680,7 @@ export default memo(withGlobal<OwnProps>(
canSendVoiceByPrivacy, canSendVoiceByPrivacy,
attachmentSettings: global.attachmentSettings, attachmentSettings: global.attachmentSettings,
slowMode, slowMode,
currentMessageList,
}; };
}, },
)(Composer)); )(Composer));

View File

@ -155,6 +155,7 @@ const useEditing = (
} }
editMessage({ editMessage({
messageList: { chatId, threadId, type },
text, text,
entities, entities,
}); });

View File

@ -3,6 +3,7 @@ import React, { memo, useRef, useCallback } from '../../lib/teact/teact';
import { getActions, withGlobal } from '../../global'; import { getActions, withGlobal } from '../../global';
import type { ApiChat, ApiVideo } from '../../api/types'; import type { ApiChat, ApiVideo } from '../../api/types';
import type { MessageList } from '../../global/types';
import { IS_TOUCH_ENV } from '../../util/windowEnvironment'; import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
import { import {
@ -39,6 +40,7 @@ type StateProps = {
canScheduleUntilOnline?: boolean; canScheduleUntilOnline?: boolean;
isSavedMessages?: boolean; isSavedMessages?: boolean;
canPostInChat?: boolean; canPostInChat?: boolean;
currentMessageList?: MessageList;
}; };
const PRELOAD_BACKWARDS = 96; // GIF Search bot results are multiplied by 24 const PRELOAD_BACKWARDS = 96; // GIF Search bot results are multiplied by 24
@ -53,6 +55,7 @@ const GifSearch: FC<OwnProps & StateProps> = ({
canScheduleUntilOnline, canScheduleUntilOnline,
isSavedMessages, isSavedMessages,
canPostInChat, canPostInChat,
currentMessageList,
onClose, onClose,
}) => { }) => {
const { const {
@ -74,19 +77,28 @@ const GifSearch: FC<OwnProps & StateProps> = ({
const handleGifClick = useCallback((gif: ApiVideo, isSilent?: boolean, shouldSchedule?: boolean) => { const handleGifClick = useCallback((gif: ApiVideo, isSilent?: boolean, shouldSchedule?: boolean) => {
if (canSendGifs) { if (canSendGifs) {
if (!currentMessageList) {
return;
}
if (shouldSchedule) { if (shouldSchedule) {
requestCalendar((scheduledAt) => { requestCalendar((scheduledAt) => {
sendMessage({ gif, scheduledAt, isSilent }); sendMessage({
messageList: currentMessageList,
gif,
scheduledAt,
isSilent,
});
}); });
} else { } else {
sendMessage({ gif, isSilent }); sendMessage({ messageList: currentMessageList, gif, isSilent });
} }
} }
if (IS_TOUCH_ENV) { if (IS_TOUCH_ENV) {
setGifSearchQuery({ query: undefined }); setGifSearchQuery({ query: undefined });
} }
}, [canSendGifs, requestCalendar, sendMessage, setGifSearchQuery]); }, [canSendGifs, currentMessageList, requestCalendar]);
const handleSearchMoreGifs = useCallback(() => { const handleSearchMoreGifs = useCallback(() => {
searchMoreGifs(); searchMoreGifs();
@ -167,6 +179,7 @@ export default memo(withGlobal(
isSavedMessages, isSavedMessages,
canPostInChat, canPostInChat,
canScheduleUntilOnline: Boolean(chatId) && selectCanScheduleUntilOnline(global, chatId), canScheduleUntilOnline: Boolean(chatId) && selectCanScheduleUntilOnline(global, chatId),
currentMessageList: selectCurrentMessageList(global),
}; };
}, },
)(GifSearch)); )(GifSearch));

View File

@ -329,23 +329,20 @@ addActionHandler('switchBotInline', (global, actions, payload): ActionReturnType
addActionHandler('sendInlineBotResult', (global, actions, payload): ActionReturnType => { addActionHandler('sendInlineBotResult', (global, actions, payload): ActionReturnType => {
const { const {
id, queryId, isSilent, scheduledAt, id, queryId, isSilent, scheduledAt, messageList,
tabId = getCurrentTabId(), tabId = getCurrentTabId(),
} = payload; } = payload;
const currentMessageList = selectCurrentMessageList(global, tabId); if (!id) {
if (!currentMessageList || !id) {
return; return;
} }
const { chatId, threadId } = currentMessageList; const { chatId, threadId } = messageList;
const chat = selectChat(global, chatId)!; const chat = selectChat(global, chatId)!;
const replyingTo = selectReplyingToId(global, chatId, threadId); const replyingToId = selectReplyingToId(global, chatId, threadId);
let replyingToTopId: number | undefined; const replyingToMessage = replyingToId ? selectChatMessage(global, chatId, replyingToId) : undefined;
const replyingToTopId = (chat.isForum || threadId !== MAIN_THREAD_ID)
if (replyingTo && threadId !== MAIN_THREAD_ID) { ? selectThreadTopMessageId(global, chatId, threadId)
replyingToTopId = selectThreadTopMessageId(global, chatId, threadId)!; : replyingToMessage?.replyToTopMessageId || replyingToMessage?.replyToMessageId;
}
actions.setReplyingToId({ messageId: undefined, tabId }); actions.setReplyingToId({ messageId: undefined, tabId });
actions.clearWebPagePreview({ tabId }); actions.clearWebPagePreview({ tabId });
@ -354,7 +351,7 @@ addActionHandler('sendInlineBotResult', (global, actions, payload): ActionReturn
chat, chat,
resultId: id, resultId: id,
queryId, queryId,
replyingTo, replyingTo: replyingToId || replyingToTopId,
replyingToTopId, replyingToTopId,
sendAs: selectSendAs(global, chatId), sendAs: selectSendAs(global, chatId),
isSilent, isSilent,

View File

@ -235,14 +235,13 @@ addActionHandler('loadMessage', async (global, actions, payload): Promise<void>
}); });
addActionHandler('sendMessage', (global, actions, payload): ActionReturnType => { addActionHandler('sendMessage', (global, actions, payload): ActionReturnType => {
const { tabId = getCurrentTabId() } = payload; const { messageList, tabId = getCurrentTabId() } = payload;
const currentMessageList = selectCurrentMessageList(global, tabId);
if (!currentMessageList) { if (!messageList) {
return undefined; return undefined;
} }
const { chatId, threadId, type } = currentMessageList; const { chatId, threadId, type } = messageList;
payload = omit(payload, ['tabId']); payload = omit(payload, ['tabId']);
@ -263,6 +262,7 @@ addActionHandler('sendMessage', (global, actions, payload): ActionReturnType =>
const params = { const params = {
...payload, ...payload,
chat, chat,
currentThreadId: messageList.threadId,
replyingTo: replyingToId, replyingTo: replyingToId,
replyingToTopId, replyingToTopId,
noWebPage: selectNoWebPage(global, chatId, threadId), noWebPage: selectNoWebPage(global, chatId, threadId),
@ -280,7 +280,7 @@ addActionHandler('sendMessage', (global, actions, payload): ActionReturnType =>
sendMessage(global, { sendMessage(global, {
...restParams, ...restParams,
attachment: attachments ? attachments[0] : undefined, attachment: attachments ? attachments[0] : undefined,
}, tabId); });
} else if (isGrouped) { } else if (isGrouped) {
const { const {
text, entities, attachments, ...commonParams text, entities, attachments, ...commonParams
@ -301,14 +301,14 @@ addActionHandler('sendMessage', (global, actions, payload): ActionReturnType =>
entities: isFirst ? entities : undefined, entities: isFirst ? entities : undefined,
attachment: firstAttachment, attachment: firstAttachment,
groupedId: restAttachments.length > 0 ? groupedId : undefined, groupedId: restAttachments.length > 0 ? groupedId : undefined,
}, tabId); });
restAttachments.forEach((attachment: ApiAttachment) => { restAttachments.forEach((attachment: ApiAttachment) => {
sendMessage(global, { sendMessage(global, {
...commonParams, ...commonParams,
attachment, attachment,
groupedId, groupedId,
}, tabId); });
}); });
} }
}); });
@ -323,14 +323,14 @@ addActionHandler('sendMessage', (global, actions, payload): ActionReturnType =>
text, text,
entities, entities,
replyingTo, replyingTo,
}, tabId); });
} }
attachments?.forEach((attachment: ApiAttachment) => { attachments?.forEach((attachment: ApiAttachment) => {
sendMessage(global, { sendMessage(global, {
...commonParams, ...commonParams,
attachment, attachment,
}, tabId); });
}); });
} }
@ -338,14 +338,15 @@ addActionHandler('sendMessage', (global, actions, payload): ActionReturnType =>
}); });
addActionHandler('editMessage', (global, actions, payload): ActionReturnType => { addActionHandler('editMessage', (global, actions, payload): ActionReturnType => {
const { text, entities, tabId = getCurrentTabId() } = payload; const {
messageList, text, entities, tabId = getCurrentTabId(),
} = payload;
const currentMessageList = selectCurrentMessageList(global, tabId); if (!messageList) {
if (!currentMessageList) {
return; return;
} }
const { chatId, threadId, type: messageListType } = currentMessageList; const { chatId, threadId, type: messageListType } = messageList;
const chat = selectChat(global, chatId); const chat = selectChat(global, chatId);
const message = selectEditingMessage(global, chatId, threadId, messageListType); const message = selectEditingMessage(global, chatId, threadId, messageListType);
if (!chat || !message) { if (!chat || !message) {
@ -760,7 +761,9 @@ addActionHandler('loadExtendedMedia', (global, actions, payload): ActionReturnTy
}); });
addActionHandler('forwardMessages', (global, actions, payload): ActionReturnType => { addActionHandler('forwardMessages', (global, actions, payload): ActionReturnType => {
const { isSilent, scheduledAt, tabId = getCurrentTabId() } = payload; const {
isSilent, scheduledAt, tabId = getCurrentTabId(),
} = payload;
const { const {
fromChatId, messageIds, toChatId, withMyScore, noAuthors, noCaptions, toThreadId, fromChatId, messageIds, toChatId, withMyScore, noAuthors, noCaptions, toThreadId,
@ -806,6 +809,7 @@ addActionHandler('forwardMessages', (global, actions, payload): ActionReturnType
void sendMessage(global, { void sendMessage(global, {
chat: toChat, chat: toChat,
replyingToTopId: toThreadId, replyingToTopId: toThreadId,
currentThreadId: toThreadId || MAIN_THREAD_ID,
text, text,
entities, entities,
sticker, sticker,
@ -813,7 +817,7 @@ addActionHandler('forwardMessages', (global, actions, payload): ActionReturnType
isSilent, isSilent,
scheduledAt, scheduledAt,
sendAs, sendAs,
}, tabId); });
}); });
global = getGlobal(); global = getGlobal();
@ -1140,10 +1144,10 @@ async function sendMessage<T extends GlobalState>(global: T, params: {
isSilent?: boolean; isSilent?: boolean;
scheduledAt?: number; scheduledAt?: number;
sendAs?: ApiChat | ApiUser; sendAs?: ApiChat | ApiUser;
currentThreadId: number;
replyingToTopId?: number; replyingToTopId?: number;
groupedId?: string; groupedId?: string;
}, }) {
...[tabId = getCurrentTabId()]: TabArgs<T>) {
let localId: number | undefined; let localId: number | undefined;
const progressCallback = params.attachment ? (progress: number, messageLocalId: number) => { const progressCallback = params.attachment ? (progress: number, messageLocalId: number) => {
if (!uploadProgressCallbacks.has(messageLocalId)) { if (!uploadProgressCallbacks.has(messageLocalId)) {
@ -1171,18 +1175,16 @@ async function sendMessage<T extends GlobalState>(global: T, params: {
} }
global = getGlobal(); global = getGlobal();
const currentMessageList = selectCurrentMessageList(global, tabId); if (params.currentThreadId === undefined) {
if (!currentMessageList) {
return; return;
} }
const { threadId } = currentMessageList;
if (!params.replyingTo && threadId !== MAIN_THREAD_ID) { if (!params.replyingTo && params.currentThreadId !== MAIN_THREAD_ID) {
params.replyingTo = selectThreadTopMessageId(global, params.chat.id, threadId)!; params.replyingTo = selectThreadTopMessageId(global, params.chat.id, params.currentThreadId)!;
} }
if (params.replyingTo && !params.replyingToTopId && threadId !== MAIN_THREAD_ID) { if (params.replyingTo && !params.replyingToTopId && params.currentThreadId !== MAIN_THREAD_ID) {
params.replyingToTopId = selectThreadTopMessageId(global, params.chat.id, threadId)!; params.replyingToTopId = selectThreadTopMessageId(global, params.chat.id, params.currentThreadId)!;
} }
await callApi('sendMessage', params, progressCallback); await callApi('sendMessage', params, progressCallback);

View File

@ -1185,6 +1185,7 @@ export interface ActionPayloads {
contact?: Partial<ApiContact>; contact?: Partial<ApiContact>;
shouldUpdateStickerSetOrder?: boolean; shouldUpdateStickerSetOrder?: boolean;
shouldGroupMessages?: boolean; shouldGroupMessages?: boolean;
messageList: MessageList;
} & WithTabId; } & WithTabId;
cancelSendingMessage: { cancelSendingMessage: {
chatId: string; chatId: string;
@ -1216,6 +1217,7 @@ export interface ActionPayloads {
}; };
}; };
editMessage: { editMessage: {
messageList: MessageList;
text: string; text: string;
entities?: ApiMessageEntity[]; entities?: ApiMessageEntity[];
} & WithTabId; } & WithTabId;
@ -2067,6 +2069,7 @@ export interface ActionPayloads {
sendInlineBotResult: { sendInlineBotResult: {
id: string; id: string;
queryId: string; queryId: string;
messageList: MessageList;
isSilent?: boolean; isSilent?: boolean;
scheduledAt?: number; scheduledAt?: number;
} & WithTabId; } & WithTabId;