Composer: Bot keyboard should open automatically (#1372)

This commit is contained in:
Alexander Zinchuk 2021-08-11 01:28:04 +03:00
parent 3635d312ce
commit fbb401dac9
7 changed files with 52 additions and 34 deletions

View File

@ -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') {

View File

@ -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';

View File

@ -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';

View File

@ -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<OwnProps> = (props) => {
const { isOpen } = props;
const BotKeyboardMenu = useModuleLoader(Bundles.Extra, 'BotKeyboardMenu', !isOpen);
// eslint-disable-next-line react/jsx-props-no-spreading
return BotKeyboardMenu ? <BotKeyboardMenu {...props} /> : undefined;
};
export default memo(BotKeyboardMenuAsync);

View File

@ -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);
}
}

View File

@ -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<OwnProps & StateProps & DispatchProps> = ({
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<OwnProps & StateProps & DispatchProps> = ({
return (
<Menu
isOpen={isOpen}
autoClose
isOpen={isOpen || forceOpen}
autoClose={isKeyboardSingleUse}
positionX="right"
positionY="bottom"
onClose={onClose}
className="KeyboardMenu"
onCloseAnimationEnd={onClose}
onClose={handleClose}
className="BotKeyboardMenu"
onCloseAnimationEnd={handleClose}
onMouseEnter={!IS_TOUCH_ENV ? handleMouseEnter : undefined}
onMouseLeave={!IS_TOUCH_ENV ? handleMouseLeave : undefined}
noCloseOnBackdrop={!IS_TOUCH_ENV}
>
<div className="content">
{message.keyboardButtons.map((row) => (

View File

@ -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<OwnProps & StateProps & DispatchProps> = ({
isPaymentModalOpen,
isReceiptModalOpen,
botKeyboardMessageId,
botKeyboardPlaceholder,
withScheduledButton,
stickersForEmoji,
groupChatMembers,
@ -851,7 +854,9 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
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<OwnProps>(
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<OwnProps>(
&& 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,