Inline Buttons: Support "Request Contact" (#1635)

This commit is contained in:
Alexander Zinchuk 2022-01-13 01:11:54 +01:00
parent 23d1dc6d48
commit 9e8ebe8b1c
6 changed files with 69 additions and 9 deletions

View File

@ -820,6 +820,8 @@ function buildReplyButtons(message: UniversalMessage): ApiReplyKeyboard | undefi
value = serializeBytes(button.data); value = serializeBytes(button.data);
} else if (button instanceof GramJs.KeyboardButtonRequestPoll) { } else if (button instanceof GramJs.KeyboardButtonRequestPoll) {
type = 'requestPoll'; type = 'requestPoll';
} else if (button instanceof GramJs.KeyboardButtonRequestPhone) {
type = 'requestSelfContact';
} else if (button instanceof GramJs.KeyboardButtonBuy) { } else if (button instanceof GramJs.KeyboardButtonBuy) {
if (media instanceof GramJs.MessageMediaInvoice && media.receiptMsgId) { if (media instanceof GramJs.MessageMediaInvoice && media.receiptMsgId) {
text = 'PaymentReceipt'; text = 'PaymentReceipt';
@ -871,6 +873,7 @@ export function buildLocalMessage(
sticker?: ApiSticker, sticker?: ApiSticker,
gif?: ApiVideo, gif?: ApiVideo,
poll?: ApiNewPoll, poll?: ApiNewPoll,
contact?: ApiContact,
groupedId?: string, groupedId?: string,
scheduledAt?: number, scheduledAt?: number,
sendAs?: ApiChat | ApiUser, sendAs?: ApiChat | ApiUser,
@ -894,6 +897,7 @@ export function buildLocalMessage(
...(sticker && { sticker }), ...(sticker && { sticker }),
...(gif && { video: gif }), ...(gif && { video: gif }),
...(poll && buildNewPoll(poll, localId)), ...(poll && buildNewPoll(poll, localId)),
...(contact && { contact }),
}, },
date: scheduledAt || Math.round(Date.now() / 1000) + serverTimeOffset, date: scheduledAt || Math.round(Date.now() / 1000) + serverTimeOffset,
isOutgoing: !isChannel, isOutgoing: !isChannel,

View File

@ -18,6 +18,7 @@ import {
ApiReportReason, ApiReportReason,
ApiSponsoredMessage, ApiSponsoredMessage,
ApiSendMessageAction, ApiSendMessageAction,
ApiContact,
} from '../../types'; } from '../../types';
import { import {
@ -201,6 +202,7 @@ export function sendMessage(
sticker, sticker,
gif, gif,
poll, poll,
contact,
isSilent, isSilent,
scheduledAt, scheduledAt,
groupedId, groupedId,
@ -216,6 +218,7 @@ export function sendMessage(
sticker?: ApiSticker; sticker?: ApiSticker;
gif?: ApiVideo; gif?: ApiVideo;
poll?: ApiNewPoll; poll?: ApiNewPoll;
contact?: ApiContact;
isSilent?: boolean; isSilent?: boolean;
scheduledAt?: number; scheduledAt?: number;
groupedId?: string; groupedId?: string;
@ -226,7 +229,7 @@ export function sendMessage(
onProgress?: ApiOnProgress, onProgress?: ApiOnProgress,
) { ) {
const localMessage = buildLocalMessage( 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, sendAs, serverTimeOffset,
); );
onUpdate({ onUpdate({
@ -280,6 +283,13 @@ export function sendMessage(
media = buildInputMediaDocument(gif); media = buildInputMediaDocument(gif);
} else if (poll) { } else if (poll) {
media = buildInputPoll(poll, randomId); media = buildInputPoll(poll, randomId);
} else if (contact) {
media = new GramJs.InputMediaContact({
phoneNumber: contact.phoneNumber,
firstName: contact.firstName,
lastName: contact.lastName,
vcard: '',
});
} }
await prevQueue; await prevQueue;

View File

@ -296,7 +296,7 @@ export type ApiSponsoredMessage = {
}; };
export interface ApiKeyboardButton { export interface ApiKeyboardButton {
type: 'command' | 'url' | 'callback' | 'requestPoll' | 'buy' | 'NOT_SUPPORTED'; type: 'command' | 'url' | 'callback' | 'requestPoll' | 'requestSelfContact' | 'buy' | 'NOT_SUPPORTED';
text: string; text: string;
messageId: number; messageId: number;
value?: string; value?: string;

View File

@ -1,7 +1,9 @@
import React, { FC, memo, useEffect } from '../../lib/teact/teact'; import React, { FC, memo, useEffect } from '../../lib/teact/teact';
import { getDispatch, withGlobal } from '../../lib/teact/teactn'; 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 getReadableErrorText from '../../util/getReadableErrorText';
import { pick } from '../../util/iteratees'; import { pick } from '../../util/iteratees';
@ -20,7 +22,7 @@ type StateProps = {
}; };
const Dialogs: FC<StateProps> = ({ dialogs }) => { const Dialogs: FC<StateProps> = ({ dialogs }) => {
const { dismissDialog, acceptInviteConfirmation } = getDispatch(); const { dismissDialog, acceptInviteConfirmation, sendMessage } = getDispatch();
const [isModalOpen, openModal, closeModal] = useFlag(); const [isModalOpen, openModal, closeModal] = useFlag();
const lang = useLang(); const lang = useLang();
@ -94,6 +96,31 @@ const Dialogs: FC<StateProps> = ({ dialogs }) => {
); );
}; };
const renderContactRequest = (contactRequest: ApiContact) => {
const handleConfirm = () => {
sendMessage({
contact: pick(contactRequest, ['firstName', 'lastName', 'phoneNumber']),
});
closeModal();
};
return (
<Modal
isOpen={isModalOpen}
onClose={closeModal}
className="confirm"
title={lang('ShareYouPhoneNumberTitle')}
onCloseAnimationEnd={dismissDialog}
>
{lang('AreYouSureShareMyContactInfoBot')}
<div>
<Button className="confirm-dialog-button" isText onClick={handleConfirm}>{lang('OK')}</Button>
<Button className="confirm-dialog-button" isText onClick={closeModal}>{lang('Cancel')}</Button>
</div>
</Modal>
);
};
const renderError = (error: ApiError) => { const renderError = (error: ApiError) => {
return ( return (
<Modal <Modal
@ -111,11 +138,15 @@ const Dialogs: FC<StateProps> = ({ dialogs }) => {
); );
}; };
const renderDialog = (dialog: ApiError | ApiInviteInfo) => { const renderDialog = (dialog: ApiError | ApiInviteInfo | ApiContact) => {
if ('hash' in dialog) { if ('hash' in dialog) {
return renderInvite(dialog); return renderInvite(dialog);
} }
if ('phoneNumber' in dialog) {
return renderContactRequest(dialog);
}
return renderError(dialog); return renderError(dialog);
}; };

View File

@ -2,7 +2,7 @@ import {
addReducer, getDispatch, getGlobal, setGlobal, addReducer, getDispatch, getGlobal, setGlobal,
} from '../../../lib/teact/teactn'; } from '../../../lib/teact/teactn';
import { ApiChat, ApiUser } from '../../../api/types'; import { ApiChat, ApiContact, ApiUser } from '../../../api/types';
import { InlineBotSettings } from '../../../types'; import { InlineBotSettings } from '../../../types';
import { import {
@ -48,6 +48,21 @@ addReducer('clickInlineButton', (global, actions, payload) => {
case 'requestPoll': case 'requestPoll':
actions.openPollModal(); actions.openPollModal();
break; 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': { case 'buy': {
const chat = selectCurrentChat(global); const chat = selectCurrentChat(global);
const { messageId, value } = button; const { messageId, value } = button;

View File

@ -199,9 +199,6 @@ addReducer('sendMessage', (global, actions, payload) => {
const chat = selectChat(global, chatId)!; const chat = selectChat(global, chatId)!;
actions.setReplyingToId({ messageId: undefined });
actions.clearWebPagePreview({ chatId, threadId, value: false });
const params = { const params = {
...payload, ...payload,
chat, chat,
@ -210,6 +207,9 @@ addReducer('sendMessage', (global, actions, payload) => {
sendAs: selectSendAs(global, chatId), sendAs: selectSendAs(global, chatId),
}; };
actions.setReplyingToId({ messageId: undefined });
actions.clearWebPagePreview({ chatId, threadId, value: false });
const isSingle = !payload.attachments || payload.attachments.length <= 1; const isSingle = !payload.attachments || payload.attachments.length <= 1;
const isGrouped = !isSingle && payload.attachments && payload.attachments.length > 1; const isGrouped = !isSingle && payload.attachments && payload.attachments.length > 1;