diff --git a/src/api/gramjs/apiBuilders/messages.ts b/src/api/gramjs/apiBuilders/messages.ts index 2e6766e40..2af1ee897 100644 --- a/src/api/gramjs/apiBuilders/messages.ts +++ b/src/api/gramjs/apiBuilders/messages.ts @@ -16,7 +16,7 @@ import { ApiWebPage, ApiMessageEntity, ApiFormattedText, - ApiKeyboardButtons, + ApiReplyKeyboard, ApiKeyboardButton, ApiChat, ApiThreadInfo, @@ -138,7 +138,9 @@ export function buildApiMessageWithChatId(chatId: number, mtpMessage: UniversalM const { replyToMsgId, replyToTopId } = mtpMessage.replyTo || {}; const isEdited = mtpMessage.editDate && !mtpMessage.editHide; - const { inlineButtons, keyboardButtons } = buildReplyButtons(mtpMessage) || {}; + const { + inlineButtons, keyboardButtons, keyboardPlaceholder, isKeyboardSingleUse, + } = buildReplyButtons(mtpMessage) || {}; const forwardInfo = mtpMessage.fwdFrom && buildApiMessageForwardInfo(mtpMessage.fwdFrom, isChatWithSelf); const { replies, mediaUnread: isMediaUnread, postAuthor } = mtpMessage; const groupedId = mtpMessage.groupedId && mtpMessage.groupedId.toString(); @@ -165,7 +167,7 @@ export function buildApiMessageWithChatId(chatId: number, mtpMessage: UniversalM isInAlbum, }), inlineButtons, - ...(keyboardButtons && { keyboardButtons }), + ...(keyboardButtons && { keyboardButtons, keyboardPlaceholder, isKeyboardSingleUse }), ...(shouldHideKeyboardButtons && { shouldHideKeyboardButtons }), ...(mtpMessage.viaBotId && { viaBotId: mtpMessage.viaBotId }), ...(replies && replies.comments && { threadInfo: buildThreadInfo(replies, mtpMessage.id, chatId) }), @@ -693,9 +695,7 @@ function buildAction( }; } -function buildReplyButtons(message: UniversalMessage): { - [K in 'inlineButtons' | 'keyboardButtons']?: ApiKeyboardButtons -} | undefined { +function buildReplyButtons(message: UniversalMessage): ApiReplyKeyboard | undefined { const { id: messageId, replyMarkup, media } = message; if (!replyMarkup) { @@ -756,7 +756,13 @@ function buildReplyButtons(message: UniversalMessage): { }); }); - return { [replyMarkup instanceof GramJs.ReplyKeyboardMarkup ? 'keyboardButtons' : 'inlineButtons']: markup }; + return { + [replyMarkup instanceof GramJs.ReplyKeyboardMarkup ? 'keyboardButtons' : 'inlineButtons']: markup, + ...(replyMarkup instanceof GramJs.ReplyKeyboardMarkup && { + keyboardPlaceholder: replyMarkup.placeholder, + isKeyboardSingleUse: replyMarkup.singleUse, + }), + }; } function getFilenameFromDocument(document: GramJs.Document, defaultBase = 'file') { diff --git a/src/api/types/messages.ts b/src/api/types/messages.ts index 8e52cf1c8..0e3b08a3c 100644 --- a/src/api/types/messages.ts +++ b/src/api/types/messages.ts @@ -243,6 +243,8 @@ export interface ApiMessage { hasUnreadMention?: boolean; inlineButtons?: ApiKeyboardButtons; keyboardButtons?: ApiKeyboardButtons; + keyboardPlaceholder?: string; + isKeyboardSingleUse?: boolean; viaBotId?: number; threadInfo?: ApiThreadInfo; adminTitle?: string; @@ -272,6 +274,12 @@ export interface ApiKeyboardButton { } export type ApiKeyboardButtons = ApiKeyboardButton[][]; +export type ApiReplyKeyboard = { + keyboardPlaceholder?: string; + isKeyboardSingleUse?: boolean; +} & { + [K in 'inlineButtons' | 'keyboardButtons']?: ApiKeyboardButtons; +}; export type ApiMessageSearchType = 'text' | 'media' | 'documents' | 'links' | 'audio' | 'profilePhoto'; export type ApiGlobalMessageSearchType = 'text' | 'media' | 'documents' | 'links' | 'audio' | 'voice'; diff --git a/src/bundles/extra.ts b/src/bundles/extra.ts index f5bef6936..617187af4 100644 --- a/src/bundles/extra.ts +++ b/src/bundles/extra.ts @@ -31,7 +31,6 @@ export { default as SymbolMenu } from '../components/middle/composer/SymbolMenu' export { default as AttachMenu } from '../components/middle/composer/AttachMenu'; export { default as MentionTooltip } from '../components/middle/composer/MentionTooltip'; export { default as StickerTooltip } from '../components/middle/composer/StickerTooltip'; -export { default as BotKeyboardMenu } from '../components/middle/composer/BotKeyboardMenu'; export { default as CustomSendMenu } from '../components/middle/composer/CustomSendMenu'; export { default as DropArea } from '../components/middle/composer/DropArea'; export { default as TextFormatter } from '../components/middle/composer/TextFormatter'; diff --git a/src/components/middle/composer/BotKeyboardMenu.async.tsx b/src/components/middle/composer/BotKeyboardMenu.async.tsx deleted file mode 100644 index e2fb202e6..000000000 --- a/src/components/middle/composer/BotKeyboardMenu.async.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React, { FC, memo } from '../../../lib/teact/teact'; -import { OwnProps } from './BotKeyboardMenu'; -import { Bundles } from '../../../util/moduleLoader'; - -import useModuleLoader from '../../../hooks/useModuleLoader'; - -const BotKeyboardMenuAsync: FC = (props) => { - const { isOpen } = props; - const BotKeyboardMenu = useModuleLoader(Bundles.Extra, 'BotKeyboardMenu', !isOpen); - - // eslint-disable-next-line react/jsx-props-no-spreading - return BotKeyboardMenu ? : undefined; -}; - -export default memo(BotKeyboardMenuAsync); diff --git a/src/components/middle/composer/BotKeyboardMenu.scss b/src/components/middle/composer/BotKeyboardMenu.scss index 000cbf8ac..50d63c542 100644 --- a/src/components/middle/composer/BotKeyboardMenu.scss +++ b/src/components/middle/composer/BotKeyboardMenu.scss @@ -1,4 +1,4 @@ -.KeyboardMenu { +.BotKeyboardMenu { .bubble { width: 100% !important; max-width: 27rem; @@ -40,6 +40,7 @@ &:hover { color: #fff; border-color: var(--color-primary-shade); + background: var(--color-primary-shade); } } diff --git a/src/components/middle/composer/BotKeyboardMenu.tsx b/src/components/middle/composer/BotKeyboardMenu.tsx index b17a69373..b9c72fa35 100644 --- a/src/components/middle/composer/BotKeyboardMenu.tsx +++ b/src/components/middle/composer/BotKeyboardMenu.tsx @@ -1,4 +1,4 @@ -import React, { FC, memo } from '../../../lib/teact/teact'; +import React, { FC, memo, useEffect } from '../../../lib/teact/teact'; import { withGlobal } from '../../../lib/teact/teactn'; import { GlobalActions } from '../../../global/types'; @@ -8,6 +8,7 @@ import { IS_TOUCH_ENV } from '../../../util/environment'; import { pick } from '../../../util/iteratees'; import { selectChatMessage, selectCurrentMessageList } from '../../../modules/selectors'; import useMouseInside from '../../../hooks/useMouseInside'; +import useFlag from '../../../hooks/useFlag'; import Menu from '../../ui/Menu'; import Button from '../../ui/Button'; @@ -30,6 +31,17 @@ const BotKeyboardMenu: FC = ({ isOpen, message, onClose, clickInlineButton, }) => { const [handleMouseEnter, handleMouseLeave] = useMouseInside(isOpen, onClose); + const { isKeyboardSingleUse } = message || {}; + const [forceOpen, markForceOpen, unmarkForceOpen] = useFlag(true); + + const handleClose = () => { + unmarkForceOpen(); + onClose(); + }; + + useEffect(() => { + markForceOpen(); + }, [markForceOpen, message]); if (!message || !message.keyboardButtons) { return undefined; @@ -37,16 +49,15 @@ const BotKeyboardMenu: FC = ({ return (
{message.keyboardButtons.map((row) => ( diff --git a/src/components/middle/composer/Composer.tsx b/src/components/middle/composer/Composer.tsx index 6d135c8d6..5844228dd 100644 --- a/src/components/middle/composer/Composer.tsx +++ b/src/components/middle/composer/Composer.tsx @@ -33,6 +33,7 @@ import { selectEditingMessage, selectIsChatWithSelf, selectChatUser, + selectChatMessage, } from '../../../modules/selectors'; import { getAllowedAttachmentOptions, @@ -77,7 +78,7 @@ import MentionTooltip from './MentionTooltip.async'; import CustomSendMenu from './CustomSendMenu.async'; import StickerTooltip from './StickerTooltip.async'; import EmojiTooltip from './EmojiTooltip.async'; -import BotKeyboardMenu from './BotKeyboardMenu.async'; +import BotKeyboardMenu from './BotKeyboardMenu'; import MessageInput from './MessageInput'; import ComposerEmbeddedMessage from './ComposerEmbeddedMessage'; import AttachmentModal from './AttachmentModal.async'; @@ -113,6 +114,7 @@ type StateProps = { isPaymentModalOpen?: boolean; isReceiptModalOpen?: boolean; botKeyboardMessageId?: number; + botKeyboardPlaceholder?: string; withScheduledButton?: boolean; shouldSchedule?: boolean; canScheduleUntilOnline?: boolean; @@ -178,6 +180,7 @@ const Composer: FC = ({ isPaymentModalOpen, isReceiptModalOpen, botKeyboardMessageId, + botKeyboardPlaceholder, withScheduledButton, stickersForEmoji, groupChatMembers, @@ -851,7 +854,9 @@ const Composer: FC = ({ id="message-input-text" html={!attachments.length ? html : ''} placeholder={ - activeVoiceRecording && windowWidth <= SCREEN_WIDTH_TO_HIDE_PLACEHOLDER ? '' : lang('Message') + activeVoiceRecording && windowWidth <= SCREEN_WIDTH_TO_HIDE_PLACEHOLDER + ? '' + : botKeyboardPlaceholder || lang('Message') } forcedPlaceholder={inlineBotHelp} shouldSetFocus={isSymbolMenuOpen} @@ -1006,6 +1011,8 @@ export default memo(withGlobal( const { language } = global.settings.byKey; const baseEmojiKeywords = global.emojiKeywords[BASE_EMOJI_KEYWORD_LANG]; const emojiKeywords = language !== BASE_EMOJI_KEYWORD_LANG ? global.emojiKeywords[language] : undefined; + const botKeyboardMessageId = messageWithActualBotKeyboard ? messageWithActualBotKeyboard.id : undefined; + const keyboardMessage = botKeyboardMessageId ? selectChatMessage(global, chatId, botKeyboardMessageId) : undefined; return { editingMessage: selectEditingMessage(global, chatId, threadId, messageListType), @@ -1026,7 +1033,8 @@ export default memo(withGlobal( && Boolean(scheduledIds && scheduledIds.length) ), shouldSchedule: messageListType === 'scheduled', - botKeyboardMessageId: messageWithActualBotKeyboard ? messageWithActualBotKeyboard.id : undefined, + botKeyboardMessageId, + botKeyboardPlaceholder: keyboardMessage ? keyboardMessage.keyboardPlaceholder : undefined, isForwarding: chatId === global.forwardMessages.toChatId, isPollModalOpen: global.isPollModalOpen, stickersForEmoji: global.stickers.forEmoji.stickers,