Message: Click on "via" bot username should prepend it into Message Input

This commit is contained in:
Alexander Zinchuk 2025-09-09 20:26:15 +02:00
parent 98212de7aa
commit 77449ad407
2 changed files with 47 additions and 30 deletions

View File

@ -1,7 +1,5 @@
import type { FC, TeactNode } from '../../lib/teact/teact';
import {
memo, useEffect, useMemo, useRef, useSignal, useState,
} from '../../lib/teact/teact';
import { memo, useEffect, useMemo, useRef, useSignal, useState } from '../../lib/teact/teact';
import { getActions, getGlobal, withGlobal } from '../../global';
import type {
@ -32,9 +30,7 @@ import type {
ApiVideo,
ApiWebPage,
} from '../../api/types';
import type {
GlobalState, TabState,
} from '../../global/types';
import type { GlobalState, TabState } from '../../global/types';
import type {
IAnchorPosition,
InlineBotSettings,
@ -559,13 +555,15 @@ const Composer: FC<OwnProps & StateProps> = ({
canSendStickers, canSendGifs, canAttachMedia, canAttachPolls, canAttachEmbedLinks, canAttachToDoLists,
canSendVoices, canSendPlainText, canSendAudios, canSendVideos, canSendPhotos, canSendDocuments,
} = useMemo(
() => getAllowedAttachmentOptions(chat,
() => getAllowedAttachmentOptions(
chat,
chatFullInfo,
isChatWithBot,
isChatWithSelf,
isInStoryViewer,
paidMessagesStars,
isInScheduledList),
isInScheduledList,
),
[chat, chatFullInfo, isChatWithBot, isChatWithSelf, isInStoryViewer, paidMessagesStars, isInScheduledList],
);
@ -597,7 +595,9 @@ const Composer: FC<OwnProps & StateProps> = ({
}
}, [hasWebPagePreview]);
const insertHtmlAndUpdateCursor = useLastCallback((newHtml: string, inInputId: string = editableInputId) => {
const insertHtmlAndUpdateCursor = useLastCallback((
newHtml: string, inInputId: string = editableInputId, shouldPrepend = false,
) => {
if (inInputId === editableInputId && isComposerBlocked) return;
const selection = window.getSelection()!;
let messageInput: HTMLDivElement;
@ -607,7 +607,7 @@ const Composer: FC<OwnProps & StateProps> = ({
messageInput = document.getElementById(inInputId) as HTMLDivElement;
}
if (selection.rangeCount) {
if (selection.rangeCount && !shouldPrepend) {
const selectionRange = selection.getRangeAt(0);
if (isSelectionInsideInput(selectionRange, inInputId)) {
insertHtmlInSelection(newHtml);
@ -616,7 +616,7 @@ const Composer: FC<OwnProps & StateProps> = ({
}
}
setHtml(`${getHtml()}${newHtml}`);
setHtml(!shouldPrepend ? `${getHtml()}${newHtml}` : `${newHtml}${getHtml()}`);
// If selection is outside of input, set cursor at the end of input
requestNextMutation(() => {
@ -634,10 +634,10 @@ const Composer: FC<OwnProps & StateProps> = ({
});
const insertFormattedTextAndUpdateCursor = useLastCallback((
text: ApiFormattedText, inInputId: string = editableInputId,
text: ApiFormattedText, inInputId: string = editableInputId, shouldPrepend = false,
) => {
const newHtml = getTextWithEntitiesAsHtml(text);
insertHtmlAndUpdateCursor(newHtml, inInputId);
insertHtmlAndUpdateCursor(newHtml, inInputId, shouldPrepend);
});
const insertCustomEmojiAndUpdateCursor = useLastCallback((emoji: ApiSticker, inInputId: string = editableInputId) => {
@ -1320,7 +1320,7 @@ const Composer: FC<OwnProps & StateProps> = ({
useEffect(() => {
if (requestedDraft) {
insertFormattedTextAndUpdateCursor(requestedDraft);
insertFormattedTextAndUpdateCursor(requestedDraft, undefined, true);
resetOpenChatWithDraft();
requestNextMutation(() => {
@ -1433,24 +1433,28 @@ const Composer: FC<OwnProps & StateProps> = ({
if (isInScheduledList || isScheduleRequested) {
requestCalendar((scheduledAt) => {
handleActionWithPaymentConfirmation(handleMessageSchedule,
handleActionWithPaymentConfirmation(
handleMessageSchedule,
{
id: inlineResult.id,
queryId: inlineResult.queryId,
isSilent,
},
scheduledAt,
currentMessageList!);
currentMessageList!,
);
});
} else {
handleActionWithPaymentConfirmation(sendInlineBotResult,
handleActionWithPaymentConfirmation(
sendInlineBotResult,
{
id: inlineResult.id,
queryId: inlineResult.queryId,
threadId,
chatId,
isSilent,
});
},
);
}
const messageInput = document.querySelector<HTMLDivElement>(editableInputCssSelector);
@ -1846,10 +1850,12 @@ const Composer: FC<OwnProps & StateProps> = ({
const handleSendScheduledAttachments = useLastCallback(
(sendCompressed: boolean, sendGrouped: boolean, isInvertedMedia?: true) => {
requestCalendar((scheduledAt) => {
handleActionWithPaymentConfirmation(handleMessageSchedule,
handleActionWithPaymentConfirmation(
handleMessageSchedule,
{ sendCompressed, sendGrouped, isInvertedMedia },
scheduledAt,
currentMessageList!);
currentMessageList!,
);
});
},
);
@ -1865,7 +1871,7 @@ const Composer: FC<OwnProps & StateProps> = ({
});
const handleStopEffect = useLastCallback(() => {
hideEffectInComposer({ });
hideEffectInComposer({});
});
const onSend = useMemo(() => {
@ -2006,8 +2012,16 @@ const Composer: FC<OwnProps & StateProps> = ({
</filter>
</defs>
<g fill="none" fill-rule="evenodd">
<path d="M6 17H0V0c.193 2.84.876 5.767 2.05 8.782.904 2.325 2.446 4.485 4.625 6.48A1 1 0 016 17z" fill="#000" filter="url(#composerAppendix)" />
<path d="M6 17H0V0c.193 2.84.876 5.767 2.05 8.782.904 2.325 2.446 4.485 4.625 6.48A1 1 0 016 17z" fill="#FFF" className="corner" />
<path
d="M6 17H0V0c.193 2.84.876 5.767 2.05 8.782.904 2.325 2.446 4.485 4.625 6.48A1 1 0 016 17z"
fill="#000"
filter="url(#composerAppendix)"
/>
<path
d="M6 17H0V0c.193 2.84.876 5.767 2.05 8.782.904 2.325 2.446 4.485 4.625 6.48A1 1 0 016 17z"
fill="#FFF"
className="corner"
/>
</g>
</svg>
)}

View File

@ -1,15 +1,12 @@
import { getActions } from '../../../../global';
import type {
ApiMessage, ApiPeer, ApiStory, ApiTopic, ApiUser,
ApiWebPage,
} from '../../../../api/types';
import type { ApiMessage, ApiPeer, ApiStory, ApiTopic, ApiUser, ApiWebPage } from '../../../../api/types';
import type { OldLangFn } from '../../../../hooks/useOldLang';
import type { IAlbum, ThreadId } from '../../../../types';
import { MAIN_THREAD_ID } from '../../../../api/types';
import { MediaViewerOrigin } from '../../../../types';
import { getMessagePhoto, getWebPagePhoto, getWebPageVideo } from '../../../../global/helpers';
import { getMainUsername, getMessagePhoto, getWebPagePhoto, getWebPageVideo } from '../../../../global/helpers';
import { getMessageReplyInfo } from '../../../../global/helpers/replies';
import { tryParseDeepLink } from '../../../../util/deepLinkParser';
@ -58,7 +55,7 @@ export default function useInnerHandlers({
lastPlaybackTimestamp?: number;
}) {
const {
openChat, showNotification, focusMessage, openMediaViewer, openAudioPlayer,
openChat, openChatWithDraft, showNotification, focusMessage, openMediaViewer, openAudioPlayer,
markMessagesRead, cancelUploadMedia, sendPollVote, openForwardMenu,
openChatLanguageModal, openThread, openStoryViewer, searchChatMediaMessages,
} = getActions();
@ -90,7 +87,13 @@ export default function useInnerHandlers({
return;
}
openChat({ id: botSender.id });
openChatWithDraft({
chatId,
threadId,
text: {
text: `@${getMainUsername(botSender)} `,
},
});
});
const handleReplyClick = useLastCallback((): void => {