diff --git a/src/api/gramjs/apiBuilders/messages.ts b/src/api/gramjs/apiBuilders/messages.ts index 0d4dd6260..de934b855 100644 --- a/src/api/gramjs/apiBuilders/messages.ts +++ b/src/api/gramjs/apiBuilders/messages.ts @@ -820,6 +820,8 @@ function buildReplyButtons(message: UniversalMessage): ApiReplyKeyboard | undefi value = serializeBytes(button.data); } else if (button instanceof GramJs.KeyboardButtonRequestPoll) { type = 'requestPoll'; + } else if (button instanceof GramJs.KeyboardButtonRequestPhone) { + type = 'requestSelfContact'; } else if (button instanceof GramJs.KeyboardButtonBuy) { if (media instanceof GramJs.MessageMediaInvoice && media.receiptMsgId) { text = 'PaymentReceipt'; @@ -871,6 +873,7 @@ export function buildLocalMessage( sticker?: ApiSticker, gif?: ApiVideo, poll?: ApiNewPoll, + contact?: ApiContact, groupedId?: string, scheduledAt?: number, sendAs?: ApiChat | ApiUser, @@ -894,6 +897,7 @@ export function buildLocalMessage( ...(sticker && { sticker }), ...(gif && { video: gif }), ...(poll && buildNewPoll(poll, localId)), + ...(contact && { contact }), }, date: scheduledAt || Math.round(Date.now() / 1000) + serverTimeOffset, isOutgoing: !isChannel, diff --git a/src/api/gramjs/methods/messages.ts b/src/api/gramjs/methods/messages.ts index ec9c73f46..36b400525 100644 --- a/src/api/gramjs/methods/messages.ts +++ b/src/api/gramjs/methods/messages.ts @@ -18,6 +18,7 @@ import { ApiReportReason, ApiSponsoredMessage, ApiSendMessageAction, + ApiContact, } from '../../types'; import { @@ -201,6 +202,7 @@ export function sendMessage( sticker, gif, poll, + contact, isSilent, scheduledAt, groupedId, @@ -216,6 +218,7 @@ export function sendMessage( sticker?: ApiSticker; gif?: ApiVideo; poll?: ApiNewPoll; + contact?: ApiContact; isSilent?: boolean; scheduledAt?: number; groupedId?: string; @@ -226,7 +229,7 @@ export function sendMessage( onProgress?: ApiOnProgress, ) { const localMessage = buildLocalMessage( - chat, text, entities, replyingTo, attachment, sticker, gif, poll, groupedId, scheduledAt, + chat, text, entities, replyingTo, attachment, sticker, gif, poll, contact, groupedId, scheduledAt, sendAs, serverTimeOffset, ); onUpdate({ @@ -280,6 +283,13 @@ export function sendMessage( media = buildInputMediaDocument(gif); } else if (poll) { media = buildInputPoll(poll, randomId); + } else if (contact) { + media = new GramJs.InputMediaContact({ + phoneNumber: contact.phoneNumber, + firstName: contact.firstName, + lastName: contact.lastName, + vcard: '', + }); } await prevQueue; diff --git a/src/api/types/messages.ts b/src/api/types/messages.ts index b5bd43fcb..ca6ddccf7 100644 --- a/src/api/types/messages.ts +++ b/src/api/types/messages.ts @@ -296,7 +296,7 @@ export type ApiSponsoredMessage = { }; export interface ApiKeyboardButton { - type: 'command' | 'url' | 'callback' | 'requestPoll' | 'buy' | 'NOT_SUPPORTED'; + type: 'command' | 'url' | 'callback' | 'requestPoll' | 'requestSelfContact' | 'buy' | 'NOT_SUPPORTED'; text: string; messageId: number; value?: string; diff --git a/src/components/main/Dialogs.tsx b/src/components/main/Dialogs.tsx index 87b4c5ff1..2dca2e163 100644 --- a/src/components/main/Dialogs.tsx +++ b/src/components/main/Dialogs.tsx @@ -1,7 +1,9 @@ import React, { FC, memo, useEffect } from '../../lib/teact/teact'; import { getDispatch, withGlobal } from '../../lib/teact/teactn'; -import { ApiError, ApiInviteInfo, ApiPhoto } from '../../api/types'; +import { + ApiContact, ApiError, ApiInviteInfo, ApiPhoto, +} from '../../api/types'; import getReadableErrorText from '../../util/getReadableErrorText'; import { pick } from '../../util/iteratees'; @@ -20,7 +22,7 @@ type StateProps = { }; const Dialogs: FC = ({ dialogs }) => { - const { dismissDialog, acceptInviteConfirmation } = getDispatch(); + const { dismissDialog, acceptInviteConfirmation, sendMessage } = getDispatch(); const [isModalOpen, openModal, closeModal] = useFlag(); const lang = useLang(); @@ -94,6 +96,31 @@ const Dialogs: FC = ({ dialogs }) => { ); }; + const renderContactRequest = (contactRequest: ApiContact) => { + const handleConfirm = () => { + sendMessage({ + contact: pick(contactRequest, ['firstName', 'lastName', 'phoneNumber']), + }); + closeModal(); + }; + + return ( + + {lang('AreYouSureShareMyContactInfoBot')} +
+ + +
+
+ ); + }; + const renderError = (error: ApiError) => { return ( = ({ dialogs }) => { ); }; - const renderDialog = (dialog: ApiError | ApiInviteInfo) => { + const renderDialog = (dialog: ApiError | ApiInviteInfo | ApiContact) => { if ('hash' in dialog) { return renderInvite(dialog); } + if ('phoneNumber' in dialog) { + return renderContactRequest(dialog); + } + return renderError(dialog); }; diff --git a/src/modules/actions/api/bots.ts b/src/modules/actions/api/bots.ts index 1cc7fdfb1..faceb0cd8 100644 --- a/src/modules/actions/api/bots.ts +++ b/src/modules/actions/api/bots.ts @@ -2,7 +2,7 @@ import { addReducer, getDispatch, getGlobal, setGlobal, } from '../../../lib/teact/teactn'; -import { ApiChat, ApiUser } from '../../../api/types'; +import { ApiChat, ApiContact, ApiUser } from '../../../api/types'; import { InlineBotSettings } from '../../../types'; import { @@ -48,6 +48,21 @@ addReducer('clickInlineButton', (global, actions, payload) => { case 'requestPoll': actions.openPollModal(); break; + case 'requestSelfContact': { + const user = global.currentUserId ? selectUser(global, global.currentUserId) : undefined; + if (!user) { + return; + } + actions.showDialog({ + data: { + phoneNumber: user.phoneNumber, + firstName: user.firstName, + lastName: user.lastName, + userId: user.id, + } as ApiContact, + }); + break; + } case 'buy': { const chat = selectCurrentChat(global); const { messageId, value } = button; diff --git a/src/modules/actions/api/messages.ts b/src/modules/actions/api/messages.ts index ababbf360..8f9a1208b 100644 --- a/src/modules/actions/api/messages.ts +++ b/src/modules/actions/api/messages.ts @@ -199,9 +199,6 @@ addReducer('sendMessage', (global, actions, payload) => { const chat = selectChat(global, chatId)!; - actions.setReplyingToId({ messageId: undefined }); - actions.clearWebPagePreview({ chatId, threadId, value: false }); - const params = { ...payload, chat, @@ -210,6 +207,9 @@ addReducer('sendMessage', (global, actions, payload) => { sendAs: selectSendAs(global, chatId), }; + actions.setReplyingToId({ messageId: undefined }); + actions.clearWebPagePreview({ chatId, threadId, value: false }); + const isSingle = !payload.attachments || payload.attachments.length <= 1; const isGrouped = !isSingle && payload.attachments && payload.attachments.length > 1;