Don't use MTP* for reply markup data.

This commit is contained in:
John Preston 2021-10-02 15:28:21 +04:00
parent 1790828b01
commit 21ac2b8f3a
23 changed files with 425 additions and 334 deletions

View file

@ -636,6 +636,8 @@ PRIVATE
history/history_item.h history/history_item.h
history/history_item_components.cpp history/history_item_components.cpp
history/history_item_components.h history/history_item_components.h
history/history_item_reply_markup.cpp
history/history_item_reply_markup.h
history/history_item_text.cpp history/history_item_text.cpp
history/history_item_text.h history/history_item_text.h
history/history_inner_widget.cpp history/history_inner_widget.cpp

View file

@ -128,7 +128,7 @@ void SendExistingMedia(
messagePostAuthor, messagePostAuthor,
media, media,
caption, caption,
MTPReplyMarkup()); HistoryMessageMarkupData());
auto performRequest = [=](const auto &repeatRequest) -> void { auto performRequest = [=](const auto &repeatRequest) -> void {
auto &histories = history->owner().histories(); auto &histories = history->owner().histories();
@ -288,7 +288,7 @@ bool SendDice(Api::MessageToSend &message) {
messagePostAuthor, messagePostAuthor,
TextWithEntities(), TextWithEntities(),
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)), MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
MTPReplyMarkup()); HistoryMessageMarkupData());
const auto requestType = Data::Histories::RequestType::Send; const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) { histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
@ -471,7 +471,7 @@ void SendConfirmedFile(
messagePostAuthor, messagePostAuthor,
caption, caption,
media, media,
MTPReplyMarkup(), HistoryMessageMarkupData(),
groupId); groupId);
} }

View file

@ -3839,7 +3839,7 @@ void ApiWrap::sendSharedContact(
MTP_string(lastName), MTP_string(lastName),
MTP_string(), // vcard MTP_string(), // vcard
MTP_long(userId.bare)), MTP_long(userId.bare)),
MTPReplyMarkup()); HistoryMessageMarkupData());
const auto media = MTP_inputMediaContact( const auto media = MTP_inputMediaContact(
MTP_string(phone), MTP_string(phone),
@ -4103,7 +4103,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
messagePostAuthor, messagePostAuthor,
sending, sending,
media, media,
MTPReplyMarkup()); HistoryMessageMarkupData());
histories.sendRequest(history, requestType, [=](Fn<void()> finish) { histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
history->sendRequestId = request(MTPmessages_SendMessage( history->sendRequestId = request(MTPmessages_SendMessage(
MTP_flags(sendFlags), MTP_flags(sendFlags),

View file

@ -304,7 +304,7 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
QString(), QString(),
TextWithEntities{ TextUtilities::Clean(text) }, TextWithEntities{ TextUtilities::Clean(text) },
MTP_messageMediaEmpty(), MTP_messageMediaEmpty(),
MTPReplyMarkup(), HistoryMessageMarkupData(),
groupedId); groupedId);
return AdminLog::OwnedItem(delegate, item); return AdminLog::OwnedItem(delegate, item);
} }

View file

@ -199,9 +199,9 @@ bool BotKeyboard::moderateKeyActivate(int key) {
if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) { if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) {
if (key >= Qt::Key_1 && key <= Qt::Key_2) { if (key >= Qt::Key_1 && key <= Qt::Key_2) {
const auto index = int(key - Qt::Key_1); const auto index = int(key - Qt::Key_1);
if (!markup->rows.empty() if (!markup->data.rows.empty()
&& index >= 0 && index >= 0
&& index < int(markup->rows.front().size())) { && index < int(markup->data.rows.front().size())) {
App::activateBotCommand(_controller, item, 0, index); App::activateBotCommand(_controller, item, 0, index);
return true; return true;
} }
@ -257,14 +257,14 @@ bool BotKeyboard::updateMarkup(HistoryItem *to, bool force) {
_singleUse = _forceReply || (markupFlags & ReplyMarkupFlag::SingleUse); _singleUse = _forceReply || (markupFlags & ReplyMarkupFlag::SingleUse);
if (const auto markup = to->Get<HistoryMessageReplyMarkup>()) { if (const auto markup = to->Get<HistoryMessageReplyMarkup>()) {
_placeholder = markup->placeholder; _placeholder = markup->data.placeholder;
} else { } else {
_placeholder = QString(); _placeholder = QString();
} }
_impl = nullptr; _impl = nullptr;
if (auto markup = to->Get<HistoryMessageReplyMarkup>()) { if (auto markup = to->Get<HistoryMessageReplyMarkup>()) {
if (!markup->rows.empty()) { if (!markup->data.rows.empty()) {
_impl = std::make_unique<ReplyKeyboard>( _impl = std::make_unique<ReplyKeyboard>(
to, to,
std::make_unique<Style>(this, *_st)); std::make_unique<Style>(this, *_st));

View file

@ -270,7 +270,8 @@ void ScheduledMessages::checkEntitiesAndUpdate(const MTPDmessage &data) {
qs(data.vmessage()), qs(data.vmessage()),
Api::EntitiesFromMTP(_session, data.ventities().value_or_empty()) Api::EntitiesFromMTP(_session, data.ventities().value_or_empty())
}, data.vmedia()); }, data.vmedia());
existing->updateReplyMarkup(data.vreply_markup()); existing->updateReplyMarkup(
HistoryMessageMarkupData(data.vreply_markup()));
existing->updateForwardedInfo(data.vfwd_from()); existing->updateForwardedInfo(data.vfwd_from());
_session->data().requestItemTextRefresh(existing); _session->data().requestItemTextRefresh(existing);
@ -455,7 +456,8 @@ HistoryItem *ScheduledMessages::append(
_session, _session,
data.ventities().value_or_empty()) data.ventities().value_or_empty())
}, data.vmedia()); }, data.vmedia());
existing->updateReplyMarkup(data.vreply_markup()); existing->updateReplyMarkup(
HistoryMessageMarkupData(data.vreply_markup()));
existing->updateForwardedInfo(data.vfwd_from()); existing->updateForwardedInfo(data.vfwd_from());
existing->updateDate(data.vdate().v); existing->updateDate(data.vdate().v);
history->owner().requestItemTextRefresh(existing); history->owner().requestItemTextRefresh(existing);

View file

@ -95,7 +95,7 @@ void CheckForSwitchInlineButton(not_null<HistoryItem*> item) {
return; return;
} }
if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) { if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) {
for (const auto &row : markup->rows) { for (const auto &row : markup->data.rows) {
for (const auto &button : row) { for (const auto &button : row) {
using ButtonType = HistoryMessageMarkupButton::Type; using ButtonType = HistoryMessageMarkupButton::Type;
if (button.type == ButtonType::SwitchInline) { if (button.type == ButtonType::SwitchInline) {

View file

@ -556,7 +556,7 @@ void GenerateItems(
QString(), QString(),
std::move(text), std::move(text),
MTP_messageMediaEmpty(), MTP_messageMediaEmpty(),
MTPReplyMarkup(), HistoryMessageMarkupData(),
bodyGroupedId); bodyGroupedId);
}; };

View file

@ -550,7 +550,7 @@ not_null<HistoryItem*> History::addNewLocalMessage(
const QString &postAuthor, const QString &postAuthor,
const TextWithEntities &text, const TextWithEntities &text,
const MTPMessageMedia &media, const MTPMessageMedia &media,
const MTPReplyMarkup &markup, HistoryMessageMarkupData &&markup,
uint64 groupedId) { uint64 groupedId) {
return addNewItem( return addNewItem(
makeMessage( makeMessage(
@ -563,7 +563,7 @@ not_null<HistoryItem*> History::addNewLocalMessage(
postAuthor, postAuthor,
text, text,
media, media,
markup, std::move(markup),
groupedId), groupedId),
true); true);
} }
@ -596,7 +596,7 @@ not_null<HistoryItem*> History::addNewLocalMessage(
const QString &postAuthor, const QString &postAuthor,
not_null<DocumentData*> document, not_null<DocumentData*> document,
const TextWithEntities &caption, const TextWithEntities &caption,
const MTPReplyMarkup &markup) { HistoryMessageMarkupData &&markup) {
return addNewItem( return addNewItem(
makeMessage( makeMessage(
id, id,
@ -608,7 +608,7 @@ not_null<HistoryItem*> History::addNewLocalMessage(
postAuthor, postAuthor,
document, document,
caption, caption,
markup), std::move(markup)),
true); true);
} }
@ -622,7 +622,7 @@ not_null<HistoryItem*> History::addNewLocalMessage(
const QString &postAuthor, const QString &postAuthor,
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
const TextWithEntities &caption, const TextWithEntities &caption,
const MTPReplyMarkup &markup) { HistoryMessageMarkupData &&markup) {
return addNewItem( return addNewItem(
makeMessage( makeMessage(
id, id,
@ -634,7 +634,7 @@ not_null<HistoryItem*> History::addNewLocalMessage(
postAuthor, postAuthor,
photo, photo,
caption, caption,
markup), std::move(markup)),
true); true);
} }
@ -647,7 +647,7 @@ not_null<HistoryItem*> History::addNewLocalMessage(
PeerId from, PeerId from,
const QString &postAuthor, const QString &postAuthor,
not_null<GameData*> game, not_null<GameData*> game,
const MTPReplyMarkup &markup) { HistoryMessageMarkupData &&markup) {
return addNewItem( return addNewItem(
makeMessage( makeMessage(
id, id,
@ -658,7 +658,7 @@ not_null<HistoryItem*> History::addNewLocalMessage(
from, from,
postAuthor, postAuthor,
game, game,
markup), std::move(markup)),
true); true);
} }

View file

@ -24,6 +24,7 @@ class HistoryBlock;
class HistoryItem; class HistoryItem;
class HistoryMessage; class HistoryMessage;
class HistoryService; class HistoryService;
struct HistoryMessageMarkupData;
namespace Main { namespace Main {
class Session; class Session;
@ -149,7 +150,7 @@ public:
const QString &postAuthor, const QString &postAuthor,
const TextWithEntities &text, const TextWithEntities &text,
const MTPMessageMedia &media, const MTPMessageMedia &media,
const MTPReplyMarkup &markup, HistoryMessageMarkupData &&markup,
uint64 groupedId = 0); uint64 groupedId = 0);
not_null<HistoryItem*> addNewLocalMessage( not_null<HistoryItem*> addNewLocalMessage(
MsgId id, MsgId id,
@ -168,7 +169,7 @@ public:
const QString &postAuthor, const QString &postAuthor,
not_null<DocumentData*> document, not_null<DocumentData*> document,
const TextWithEntities &caption, const TextWithEntities &caption,
const MTPReplyMarkup &markup); HistoryMessageMarkupData &&markup);
not_null<HistoryItem*> addNewLocalMessage( not_null<HistoryItem*> addNewLocalMessage(
MsgId id, MsgId id,
MessageFlags flags, MessageFlags flags,
@ -179,7 +180,7 @@ public:
const QString &postAuthor, const QString &postAuthor,
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
const TextWithEntities &caption, const TextWithEntities &caption,
const MTPReplyMarkup &markup); HistoryMessageMarkupData &&markup);
not_null<HistoryItem*> addNewLocalMessage( not_null<HistoryItem*> addNewLocalMessage(
MsgId id, MsgId id,
MessageFlags flags, MessageFlags flags,
@ -189,7 +190,7 @@ public:
PeerId from, PeerId from,
const QString &postAuthor, const QString &postAuthor,
not_null<GameData*> game, not_null<GameData*> game,
const MTPReplyMarkup &markup); HistoryMessageMarkupData &&markup);
// Used only internally and for channel admin log. // Used only internally and for channel admin log.
HistoryItem *createItem( HistoryItem *createItem(

View file

@ -86,7 +86,7 @@ not_null<HistoryItem*> CreateUnsupportedMessage(
QString(), QString(),
text, text,
MTP_messageMediaEmpty(), MTP_messageMediaEmpty(),
MTPReplyMarkup(), HistoryMessageMarkupData(),
groupedId); groupedId);
} }
@ -233,7 +233,7 @@ void HistoryItem::setGroupId(MessageGroupId groupId) {
HistoryMessageReplyMarkup *HistoryItem::inlineReplyMarkup() { HistoryMessageReplyMarkup *HistoryItem::inlineReplyMarkup() {
if (const auto markup = Get<HistoryMessageReplyMarkup>()) { if (const auto markup = Get<HistoryMessageReplyMarkup>()) {
if (markup->flags & ReplyMarkupFlag::Inline) { if (markup->data.flags & ReplyMarkupFlag::Inline) {
return markup; return markup;
} }
} }
@ -371,7 +371,7 @@ void HistoryItem::setIsPinned(bool pinned) {
bool HistoryItem::definesReplyKeyboard() const { bool HistoryItem::definesReplyKeyboard() const {
if (const auto markup = Get<HistoryMessageReplyMarkup>()) { if (const auto markup = Get<HistoryMessageReplyMarkup>()) {
if (markup->flags & ReplyMarkupFlag::Inline) { if (markup->data.flags & ReplyMarkupFlag::Inline) {
return false; return false;
} }
return true; return true;
@ -386,7 +386,7 @@ ReplyMarkupFlags HistoryItem::replyKeyboardFlags() const {
Expects(definesReplyKeyboard()); Expects(definesReplyKeyboard());
if (const auto markup = Get<HistoryMessageReplyMarkup>()) { if (const auto markup = Get<HistoryMessageReplyMarkup>()) {
return markup->flags; return markup->data.flags;
} }
// optimization: don't create markup component for the case // optimization: don't create markup component for the case
@ -508,7 +508,7 @@ void HistoryItem::applySentMessage(const MTPDmessage &data) {
&history()->session(), &history()->session(),
data.ventities().value_or_empty()) data.ventities().value_or_empty())
}, data.vmedia()); }, data.vmedia());
updateReplyMarkup(data.vreply_markup()); updateReplyMarkup(HistoryMessageMarkupData(data.vreply_markup()));
updateForwardedInfo(data.vfwd_from()); updateForwardedInfo(data.vfwd_from());
setViewsCount(data.vviews().value_or(-1)); setViewsCount(data.vviews().value_or(-1));
if (const auto replies = data.vreplies()) { if (const auto replies = data.vreplies()) {

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/flags.h" #include "base/flags.h"
#include "base/value_ordering.h" #include "base/value_ordering.h"
#include "data/data_media_types.h" #include "data/data_media_types.h"
#include "history/history_item_reply_markup.h"
#include <any> #include <any>
@ -73,18 +74,6 @@ struct ItemPreview {
struct HiddenSenderInfo; struct HiddenSenderInfo;
class History; class History;
enum class ReplyMarkupFlag : uint32 {
None = (1U << 0),
ForceReply = (1U << 1),
HasSwitchInlineButton = (1U << 2),
Inline = (1U << 3),
Resize = (1U << 4),
SingleUse = (1U << 5),
Selective = (1U << 6),
};
inline constexpr bool is_flag_type(ReplyMarkupFlag) { return true; }
using ReplyMarkupFlags = base::flags<ReplyMarkupFlag>;
[[nodiscard]] MessageFlags FlagsFromMTP(MTPDmessage::Flags flags); [[nodiscard]] MessageFlags FlagsFromMTP(MTPDmessage::Flags flags);
[[nodiscard]] MessageFlags FlagsFromMTP(MTPDmessageService::Flags flags); [[nodiscard]] MessageFlags FlagsFromMTP(MTPDmessageService::Flags flags);
@ -284,7 +273,7 @@ public:
const TextWithEntities &textWithEntities, const TextWithEntities &textWithEntities,
const MTPMessageMedia *media) { const MTPMessageMedia *media) {
} }
virtual void updateReplyMarkup(const MTPReplyMarkup *markup) { virtual void updateReplyMarkup(HistoryMessageMarkupData &&markup) {
} }
virtual void updateForwardedInfo(const MTPMessageFwdHeader *fwd) { virtual void updateForwardedInfo(const MTPMessageFwdHeader *fwd) {
} }

View file

@ -504,10 +504,10 @@ ReplyKeyboard::ReplyKeyboard(
if (const auto markup = _item->Get<HistoryMessageReplyMarkup>()) { if (const auto markup = _item->Get<HistoryMessageReplyMarkup>()) {
const auto owner = &_item->history()->owner(); const auto owner = &_item->history()->owner();
const auto context = _item->fullId(); const auto context = _item->fullId();
const auto rowCount = int(markup->rows.size()); const auto rowCount = int(markup->data.rows.size());
_rows.reserve(rowCount); _rows.reserve(rowCount);
for (auto i = 0; i != rowCount; ++i) { for (auto i = 0; i != rowCount; ++i) {
const auto &row = markup->rows.at(i); const auto &row = markup->data.rows[i];
const auto rowSize = int(row.size()); const auto rowSize = int(row.size());
auto newRow = std::vector<Button>(); auto newRow = std::vector<Button>();
newRow.reserve(rowSize); newRow.reserve(rowSize);
@ -831,174 +831,17 @@ void ReplyKeyboard::Style::paintButton(
button.text.drawElided(p, tx, rect.y() + _st->textTop + ((rect.height() - _st->height) / 2), tw, 1, style::al_top); button.text.drawElided(p, tx, rect.y() + _st->textTop + ((rect.height() - _st->height) / 2), tw, 1, style::al_top);
} }
HistoryMessageMarkupButton::HistoryMessageMarkupButton( void HistoryMessageReplyMarkup::createForwarded(
Type type, const HistoryMessageReplyMarkup &original) {
const QString &text, Expects(!inlineKeyboard);
const QByteArray &data,
const QString &forwardText, data.fillForwardedData(original.data);
int32 buttonId)
: type(type)
, text(text)
, forwardText(forwardText)
, data(data)
, buttonId(buttonId) {
} }
HistoryMessageMarkupButton *HistoryMessageMarkupButton::Get( void HistoryMessageReplyMarkup::updateData(
not_null<Data::Session*> owner, HistoryMessageMarkupData &&markup) {
FullMsgId itemId, data = std::move(markup);
int row,
int column) {
if (const auto item = owner->message(itemId)) {
if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) {
if (row < markup->rows.size()) {
auto &buttons = markup->rows[row];
if (column < buttons.size()) {
return &buttons[column];
}
}
}
}
return nullptr;
}
void HistoryMessageReplyMarkup::createFromButtonRows(
const QVector<MTPKeyboardButtonRow> &list) {
rows.clear();
if (list.isEmpty()) {
return;
}
rows.reserve(list.size());
for (const auto &row : list) {
row.match([&](const MTPDkeyboardButtonRow &data) {
auto row = std::vector<Button>();
row.reserve(data.vbuttons().v.size());
for (const auto &button : data.vbuttons().v) {
using Type = Button::Type;
button.match([&](const MTPDkeyboardButton &data) {
row.emplace_back(Type::Default, qs(data.vtext()));
}, [&](const MTPDkeyboardButtonCallback &data) {
row.emplace_back(
(data.is_requires_password()
? Type::CallbackWithPassword
: Type::Callback),
qs(data.vtext()),
qba(data.vdata()));
}, [&](const MTPDkeyboardButtonRequestGeoLocation &data) {
row.emplace_back(Type::RequestLocation, qs(data.vtext()));
}, [&](const MTPDkeyboardButtonRequestPhone &data) {
row.emplace_back(Type::RequestPhone, qs(data.vtext()));
}, [&](const MTPDkeyboardButtonUrl &data) {
row.emplace_back(
Type::Url,
qs(data.vtext()),
qba(data.vurl()));
}, [&](const MTPDkeyboardButtonSwitchInline &data) {
const auto type = data.is_same_peer()
? Type::SwitchInlineSame
: Type::SwitchInline;
row.emplace_back(type, qs(data.vtext()), qba(data.vquery()));
if (type == Type::SwitchInline) {
// Optimization flag.
// Fast check on all new messages if there is a switch button to auto-click it.
flags |= ReplyMarkupFlag::HasSwitchInlineButton;
}
}, [&](const MTPDkeyboardButtonGame &data) {
row.emplace_back(Type::Game, qs(data.vtext()));
}, [&](const MTPDkeyboardButtonBuy &data) {
row.emplace_back(Type::Buy, qs(data.vtext()));
}, [&](const MTPDkeyboardButtonUrlAuth &data) {
row.emplace_back(
Type::Auth,
qs(data.vtext()),
qba(data.vurl()),
qs(data.vfwd_text().value_or_empty()),
data.vbutton_id().v);
}, [&](const MTPDinputKeyboardButtonUrlAuth &data) {
LOG(("API Error: inputKeyboardButtonUrlAuth received."));
// Should not get those for the users.
}, [&](const MTPDkeyboardButtonRequestPoll &data) {
const auto quiz = [&] {
if (!data.vquiz()) {
return QByteArray();
}
return data.vquiz()->match([&](const MTPDboolTrue&) {
return QByteArray(1, 1);
}, [&](const MTPDboolFalse&) {
return QByteArray(1, 0);
});
}();
row.emplace_back(
Type::RequestPoll,
qs(data.vtext()),
quiz);
});
}
if (!row.empty()) {
rows.push_back(std::move(row));
}
});
}
}
void HistoryMessageReplyMarkup::create(const MTPReplyMarkup &markup) {
flags = 0;
rows.clear();
inlineKeyboard = nullptr; inlineKeyboard = nullptr;
using Flag = ReplyMarkupFlag;
markup.match([&](const MTPDreplyKeyboardMarkup &data) {
flags = (data.is_resize() ? Flag::Resize : Flag())
| (data.is_selective() ? Flag::Selective : Flag())
| (data.is_single_use() ? Flag::SingleUse : Flag());
placeholder = qs(data.vplaceholder().value_or_empty());
createFromButtonRows(data.vrows().v);
}, [&](const MTPDreplyInlineMarkup &data) {
flags = Flag::Inline;
placeholder = QString();
createFromButtonRows(data.vrows().v);
}, [&](const MTPDreplyKeyboardHide &data) {
flags = Flag::None | (data.is_selective() ? Flag::Selective : Flag());
placeholder = QString();
}, [&](const MTPDreplyKeyboardForceReply &data) {
flags = Flag::ForceReply
| (data.is_selective() ? Flag::Selective : Flag())
| (data.is_single_use() ? Flag::SingleUse : Flag());
placeholder = qs(data.vplaceholder().value_or_empty());
});
}
void HistoryMessageReplyMarkup::create(
const HistoryMessageReplyMarkup &markup) {
flags = markup.flags;
placeholder = markup.placeholder;
inlineKeyboard = nullptr;
rows.clear();
rows.reserve(markup.rows.size());
using Type = HistoryMessageMarkupButton::Type;
for (const auto &existing : markup.rows) {
auto row = std::vector<Button>();
row.reserve(existing.size());
for (const auto &button : existing) {
const auto newType = (button.type != Type::SwitchInlineSame)
? button.type
: Type::SwitchInline;
const auto text = button.forwardText.isEmpty()
? button.text
: button.forwardText;
row.emplace_back(
newType,
text,
button.data,
QString(),
button.buttonId);
}
if (!row.empty()) {
rows.push_back(std::move(row));
}
}
} }
HistoryMessageLogEntryOriginal::HistoryMessageLogEntryOriginal() = default; HistoryMessageLogEntryOriginal::HistoryMessageLogEntryOriginal() = default;

View file

@ -189,63 +189,16 @@ struct HistoryMessageReply : public RuntimeComponent<HistoryMessageReply, Histor
}; };
struct HistoryMessageMarkupButton {
enum class Type {
Default,
Url,
Callback,
CallbackWithPassword,
RequestPhone,
RequestLocation,
RequestPoll,
SwitchInline,
SwitchInlineSame,
Game,
Buy,
Auth,
};
HistoryMessageMarkupButton(
Type type,
const QString &text,
const QByteArray &data = QByteArray(),
const QString &forwardText = QString(),
int32 buttonId = 0);
static HistoryMessageMarkupButton *Get(
not_null<Data::Session*> owner,
FullMsgId itemId,
int row,
int column);
Type type;
QString text, forwardText;
QByteArray data;
int32 buttonId = 0;
mutable mtpRequestId requestId = 0;
};
struct HistoryMessageReplyMarkup struct HistoryMessageReplyMarkup
: public RuntimeComponent<HistoryMessageReplyMarkup, HistoryItem> { : public RuntimeComponent<HistoryMessageReplyMarkup, HistoryItem> {
using Button = HistoryMessageMarkupButton; using Button = HistoryMessageMarkupButton;
HistoryMessageReplyMarkup() = default; void createForwarded(const HistoryMessageReplyMarkup &original);
HistoryMessageReplyMarkup(ReplyMarkupFlags flags) : flags(flags) { void updateData(HistoryMessageMarkupData &&markup);
}
void create(const MTPReplyMarkup &markup);
void create(const HistoryMessageReplyMarkup &markup);
std::vector<std::vector<Button>> rows;
ReplyMarkupFlags flags = 0;
QString placeholder;
HistoryMessageMarkupData data;
std::unique_ptr<ReplyKeyboard> inlineKeyboard; std::unique_ptr<ReplyKeyboard> inlineKeyboard;
private:
void createFromButtonRows(const QVector<MTPKeyboardButtonRow> &v);
}; };
class ReplyMarkupClickHandler : public ClickHandler { class ReplyMarkupClickHandler : public ClickHandler {

View file

@ -0,0 +1,197 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/history_item_reply_markup.h"
#include "data/data_session.h"
#include "history/history_item.h"
#include "history/history_item_components.h"
HistoryMessageMarkupButton::HistoryMessageMarkupButton(
Type type,
const QString &text,
const QByteArray &data,
const QString &forwardText,
int32 buttonId)
: type(type)
, text(text)
, forwardText(forwardText)
, data(data)
, buttonId(buttonId) {
}
HistoryMessageMarkupButton *HistoryMessageMarkupButton::Get(
not_null<Data::Session*> owner,
FullMsgId itemId,
int row,
int column) {
if (const auto item = owner->message(itemId)) {
if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) {
if (row < markup->data.rows.size()) {
auto &buttons = markup->data.rows[row];
if (column < buttons.size()) {
return &buttons[column];
}
}
}
}
return nullptr;
}
void HistoryMessageMarkupData::fillRows(
const QVector<MTPKeyboardButtonRow> &list) {
rows.clear();
if (list.isEmpty()) {
return;
}
rows.reserve(list.size());
for (const auto &row : list) {
row.match([&](const MTPDkeyboardButtonRow &data) {
auto row = std::vector<Button>();
row.reserve(data.vbuttons().v.size());
for (const auto &button : data.vbuttons().v) {
using Type = Button::Type;
button.match([&](const MTPDkeyboardButton &data) {
row.emplace_back(Type::Default, qs(data.vtext()));
}, [&](const MTPDkeyboardButtonCallback &data) {
row.emplace_back(
(data.is_requires_password()
? Type::CallbackWithPassword
: Type::Callback),
qs(data.vtext()),
qba(data.vdata()));
}, [&](const MTPDkeyboardButtonRequestGeoLocation &data) {
row.emplace_back(Type::RequestLocation, qs(data.vtext()));
}, [&](const MTPDkeyboardButtonRequestPhone &data) {
row.emplace_back(Type::RequestPhone, qs(data.vtext()));
}, [&](const MTPDkeyboardButtonUrl &data) {
row.emplace_back(
Type::Url,
qs(data.vtext()),
qba(data.vurl()));
}, [&](const MTPDkeyboardButtonSwitchInline &data) {
const auto type = data.is_same_peer()
? Type::SwitchInlineSame
: Type::SwitchInline;
row.emplace_back(type, qs(data.vtext()), qba(data.vquery()));
if (type == Type::SwitchInline) {
// Optimization flag.
// Fast check on all new messages if there is a switch button to auto-click it.
flags |= ReplyMarkupFlag::HasSwitchInlineButton;
}
}, [&](const MTPDkeyboardButtonGame &data) {
row.emplace_back(Type::Game, qs(data.vtext()));
}, [&](const MTPDkeyboardButtonBuy &data) {
row.emplace_back(Type::Buy, qs(data.vtext()));
}, [&](const MTPDkeyboardButtonUrlAuth &data) {
row.emplace_back(
Type::Auth,
qs(data.vtext()),
qba(data.vurl()),
qs(data.vfwd_text().value_or_empty()),
data.vbutton_id().v);
}, [&](const MTPDinputKeyboardButtonUrlAuth &data) {
LOG(("API Error: inputKeyboardButtonUrlAuth received."));
// Should not get those for the users.
}, [&](const MTPDkeyboardButtonRequestPoll &data) {
const auto quiz = [&] {
if (!data.vquiz()) {
return QByteArray();
}
return data.vquiz()->match([&](const MTPDboolTrue&) {
return QByteArray(1, 1);
}, [&](const MTPDboolFalse&) {
return QByteArray(1, 0);
});
}();
row.emplace_back(
Type::RequestPoll,
qs(data.vtext()),
quiz);
});
}
if (!row.empty()) {
rows.push_back(std::move(row));
}
});
}
}
HistoryMessageMarkupData::HistoryMessageMarkupData(
const MTPReplyMarkup *data) {
if (!data) {
return;
}
using Flag = ReplyMarkupFlag;
data->match([&](const MTPDreplyKeyboardMarkup &data) {
flags = (data.is_resize() ? Flag::Resize : Flag())
| (data.is_selective() ? Flag::Selective : Flag())
| (data.is_single_use() ? Flag::SingleUse : Flag());
placeholder = qs(data.vplaceholder().value_or_empty());
fillRows(data.vrows().v);
}, [&](const MTPDreplyInlineMarkup &data) {
flags = Flag::Inline;
placeholder = QString();
fillRows(data.vrows().v);
}, [&](const MTPDreplyKeyboardHide &data) {
flags = Flag::None | (data.is_selective() ? Flag::Selective : Flag());
placeholder = QString();
}, [&](const MTPDreplyKeyboardForceReply &data) {
flags = Flag::ForceReply
| (data.is_selective() ? Flag::Selective : Flag())
| (data.is_single_use() ? Flag::SingleUse : Flag());
placeholder = qs(data.vplaceholder().value_or_empty());
});
}
void HistoryMessageMarkupData::fillForwardedData(
const HistoryMessageMarkupData &original) {
Expects(isNull());
Expects(!original.isNull());
flags = original.flags;
placeholder = original.placeholder;
rows.reserve(original.rows.size());
using Type = HistoryMessageMarkupButton::Type;
for (const auto &existing : original.rows) {
auto row = std::vector<Button>();
row.reserve(existing.size());
for (const auto &button : existing) {
const auto newType = (button.type != Type::SwitchInlineSame)
? button.type
: Type::SwitchInline;
const auto text = button.forwardText.isEmpty()
? button.text
: button.forwardText;
row.emplace_back(
newType,
text,
button.data,
QString(),
button.buttonId);
}
if (!row.empty()) {
rows.push_back(std::move(row));
}
}
}
bool HistoryMessageMarkupData::isNull() const {
if (flags & ReplyMarkupFlag::IsNull) {
Assert(isTrivial());
return true;
}
return false;
}
bool HistoryMessageMarkupData::isTrivial() const {
return rows.empty()
&& placeholder.isEmpty()
&& !(flags & ~ReplyMarkupFlag::IsNull);
}

View file

@ -0,0 +1,83 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/flags.h"
namespace Data {
class Session;
} // namespace Data
enum class ReplyMarkupFlag : uint32 {
None = (1U << 0),
ForceReply = (1U << 1),
HasSwitchInlineButton = (1U << 2),
Inline = (1U << 3),
Resize = (1U << 4),
SingleUse = (1U << 5),
Selective = (1U << 6),
IsNull = (1U << 7),
};
inline constexpr bool is_flag_type(ReplyMarkupFlag) { return true; }
using ReplyMarkupFlags = base::flags<ReplyMarkupFlag>;
struct HistoryMessageMarkupButton {
enum class Type {
Default,
Url,
Callback,
CallbackWithPassword,
RequestPhone,
RequestLocation,
RequestPoll,
SwitchInline,
SwitchInlineSame,
Game,
Buy,
Auth,
};
HistoryMessageMarkupButton(
Type type,
const QString &text,
const QByteArray &data = QByteArray(),
const QString &forwardText = QString(),
int32 buttonId = 0);
static HistoryMessageMarkupButton *Get(
not_null<Data::Session*> owner,
FullMsgId itemId,
int row,
int column);
Type type;
QString text, forwardText;
QByteArray data;
int32 buttonId = 0;
mutable mtpRequestId requestId = 0;
};
struct HistoryMessageMarkupData {
HistoryMessageMarkupData() = default;
explicit HistoryMessageMarkupData(const MTPReplyMarkup *data);
void fillForwardedData(const HistoryMessageMarkupData &original);
[[nodiscard]] bool isNull() const;
[[nodiscard]] bool isTrivial() const;
using Button = HistoryMessageMarkupButton;
std::vector<std::vector<Button>> rows;
ReplyMarkupFlags flags = ReplyMarkupFlag::IsNull;
QString placeholder;
private:
void fillRows(const QVector<MTPKeyboardButtonRow> &v);
};

View file

@ -89,7 +89,7 @@ namespace {
return false; return false;
} }
using Type = HistoryMessageMarkupButton::Type; using Type = HistoryMessageMarkupButton::Type;
for (const auto &row : markup->rows) { for (const auto &row : markup->data.rows) {
for (const auto &button : row) { for (const auto &button : row) {
const auto switchInline = (button.type == Type::SwitchInline) const auto switchInline = (button.type == Type::SwitchInline)
|| (button.type == Type::SwitchInlineSame); || (button.type == Type::SwitchInlineSame);
@ -422,10 +422,10 @@ struct HistoryMessage::CreateConfig {
TimeId originalDate = 0; TimeId originalDate = 0;
TimeId editDate = 0; TimeId editDate = 0;
bool imported = false; bool imported = false;
HistoryMessageMarkupData markup;
// For messages created from MTP structs. // For messages created from MTP structs.
const MTPMessageReplies *mtpReplies = nullptr; const MTPMessageReplies *mtpReplies = nullptr;
const MTPReplyMarkup *mtpMarkup = nullptr;
// For messages created from existing messages (forwarded). // For messages created from existing messages (forwarded).
const HistoryMessageReplyMarkup *inlineMarkup = nullptr; const HistoryMessageReplyMarkup *inlineMarkup = nullptr;
@ -484,11 +484,10 @@ HistoryMessage::HistoryMessage(
config.viaBotId = data.vvia_bot_id().value_or_empty(); config.viaBotId = data.vvia_bot_id().value_or_empty();
config.viewsCount = data.vviews().value_or(-1); config.viewsCount = data.vviews().value_or(-1);
config.mtpReplies = isScheduled() ? nullptr : data.vreplies(); config.mtpReplies = isScheduled() ? nullptr : data.vreplies();
config.mtpMarkup = data.vreply_markup(); config.markup = HistoryMessageMarkupData(data.vreply_markup());
config.editDate = data.vedit_date().value_or_empty(); config.editDate = data.vedit_date().value_or_empty();
config.author = qs(data.vpost_author().value_or_empty()); config.author = qs(data.vpost_author().value_or_empty());
createComponents(std::move(config));
createComponents(config);
if (const auto media = data.vmedia()) { if (const auto media = data.vmedia()) {
setMedia(*media); setMedia(*media);
@ -520,7 +519,6 @@ HistoryMessage::HistoryMessage(
data.vdate().v, data.vdate().v,
data.vfrom_id() ? peerFromMTP(*data.vfrom_id()) : PeerId(0)) { data.vfrom_id() ? peerFromMTP(*data.vfrom_id()) : PeerId(0)) {
auto config = CreateConfig(); auto config = CreateConfig();
if (const auto reply = data.vreply_to()) { if (const auto reply = data.vreply_to()) {
reply->match([&](const MTPDmessageReplyHeader &data) { reply->match([&](const MTPDmessageReplyHeader &data) {
const auto peer = data.vreply_to_peer_id() const auto peer = data.vreply_to_peer_id()
@ -533,8 +531,7 @@ HistoryMessage::HistoryMessage(
} }
}); });
} }
createComponents(std::move(config));
createComponents(config);
data.vaction().match([&](const MTPDmessageActionPhoneCall &data) { data.vaction().match([&](const MTPDmessageActionPhoneCall &data) {
_media = std::make_unique<Data::MediaCall>(this, data); _media = std::make_unique<Data::MediaCall>(this, data);
@ -625,8 +622,7 @@ HistoryMessage::HistoryMessage(
if (CopyMarkupToForward(original)) { if (CopyMarkupToForward(original)) {
config.inlineMarkup = original->inlineReplyMarkup(); config.inlineMarkup = original->inlineReplyMarkup();
} }
createComponents(std::move(config));
createComponents(config);
const auto ignoreMedia = [&] { const auto ignoreMedia = [&] {
if (mediaOriginal && mediaOriginal->webpage()) { if (mediaOriginal && mediaOriginal->webpage()) {
@ -653,7 +649,7 @@ HistoryMessage::HistoryMessage(
const QString &postAuthor, const QString &postAuthor,
const TextWithEntities &textWithEntities, const TextWithEntities &textWithEntities,
const MTPMessageMedia &media, const MTPMessageMedia &media,
const MTPReplyMarkup &markup, HistoryMessageMarkupData &&markup,
uint64 groupedId) uint64 groupedId)
: HistoryItem( : HistoryItem(
history, history,
@ -661,7 +657,12 @@ HistoryMessage::HistoryMessage(
flags, flags,
date, date,
(flags & MessageFlag::HasFromId) ? from : 0) { (flags & MessageFlag::HasFromId) ? from : 0) {
createComponentsHelper(flags, replyTo, viaBotId, postAuthor, markup); createComponentsHelper(
flags,
replyTo,
viaBotId,
postAuthor,
std::move(markup));
setMedia(media); setMedia(media);
setText(textWithEntities); setText(textWithEntities);
if (groupedId) { if (groupedId) {
@ -680,14 +681,19 @@ HistoryMessage::HistoryMessage(
const QString &postAuthor, const QString &postAuthor,
not_null<DocumentData*> document, not_null<DocumentData*> document,
const TextWithEntities &caption, const TextWithEntities &caption,
const MTPReplyMarkup &markup) HistoryMessageMarkupData &&markup)
: HistoryItem( : HistoryItem(
history, history,
id, id,
flags, flags,
date, date,
(flags & MessageFlag::HasFromId) ? from : 0) { (flags & MessageFlag::HasFromId) ? from : 0) {
createComponentsHelper(flags, replyTo, viaBotId, postAuthor, markup); createComponentsHelper(
flags,
replyTo,
viaBotId,
postAuthor,
std::move(markup));
_media = std::make_unique<Data::MediaFile>(this, document); _media = std::make_unique<Data::MediaFile>(this, document);
setText(caption); setText(caption);
@ -704,14 +710,19 @@ HistoryMessage::HistoryMessage(
const QString &postAuthor, const QString &postAuthor,
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
const TextWithEntities &caption, const TextWithEntities &caption,
const MTPReplyMarkup &markup) HistoryMessageMarkupData &&markup)
: HistoryItem( : HistoryItem(
history, history,
id, id,
flags, flags,
date, date,
(flags & MessageFlag::HasFromId) ? from : 0) { (flags & MessageFlag::HasFromId) ? from : 0) {
createComponentsHelper(flags, replyTo, viaBotId, postAuthor, markup); createComponentsHelper(
flags,
replyTo,
viaBotId,
postAuthor,
std::move(markup));
_media = std::make_unique<Data::MediaPhoto>(this, photo); _media = std::make_unique<Data::MediaPhoto>(this, photo);
setText(caption); setText(caption);
@ -727,14 +738,19 @@ HistoryMessage::HistoryMessage(
PeerId from, PeerId from,
const QString &postAuthor, const QString &postAuthor,
not_null<GameData*> game, not_null<GameData*> game,
const MTPReplyMarkup &markup) HistoryMessageMarkupData &&markup)
: HistoryItem( : HistoryItem(
history, history,
id, id,
flags, flags,
date, date,
(flags & MessageFlag::HasFromId) ? from : 0) { (flags & MessageFlag::HasFromId) ? from : 0) {
createComponentsHelper(flags, replyTo, viaBotId, postAuthor, markup); createComponentsHelper(
flags,
replyTo,
viaBotId,
postAuthor,
std::move(markup));
_media = std::make_unique<Data::MediaGame>(this, game); _media = std::make_unique<Data::MediaGame>(this, game);
setEmptyText(); setEmptyText();
@ -745,20 +761,19 @@ void HistoryMessage::createComponentsHelper(
MsgId replyTo, MsgId replyTo,
UserId viaBotId, UserId viaBotId,
const QString &postAuthor, const QString &postAuthor,
const MTPReplyMarkup &markup) { HistoryMessageMarkupData &&markup) {
auto config = CreateConfig(); auto config = CreateConfig();
if (flags & MessageFlag::HasViaBot) config.viaBotId = viaBotId; if (flags & MessageFlag::HasViaBot) config.viaBotId = viaBotId;
if (flags & MessageFlag::HasReplyInfo) { if (flags & MessageFlag::HasReplyInfo) {
config.replyTo = replyTo; config.replyTo = replyTo;
const auto replyToTop = LookupReplyToTop(history(), replyTo); const auto replyToTop = LookupReplyToTop(history(), replyTo);
config.replyToTop = replyToTop ? replyToTop : replyTo; config.replyToTop = replyToTop ? replyToTop : replyTo;
} }
if (flags & MessageFlag::HasReplyMarkup) config.mtpMarkup = &markup; config.markup = std::move(markup);
if (flags & MessageFlag::HasPostAuthor) config.author = postAuthor; if (flags & MessageFlag::HasPostAuthor) config.author = postAuthor;
if (flags & MessageFlag::HasViews) config.viewsCount = 1; if (flags & MessageFlag::HasViews) config.viewsCount = 1;
createComponents(config); createComponents(std::move(config));
} }
int HistoryMessage::viewsCount() const { int HistoryMessage::viewsCount() const {
@ -1033,7 +1048,7 @@ bool HistoryMessage::uploading() const {
return _media && _media->uploading(); return _media && _media->uploading();
} }
void HistoryMessage::createComponents(const CreateConfig &config) { void HistoryMessage::createComponents(CreateConfig &&config) {
uint64 mask = 0; uint64 mask = 0;
if (config.replyTo) { if (config.replyTo) {
mask |= HistoryMessageReply::Bit(); mask |= HistoryMessageReply::Bit();
@ -1064,12 +1079,8 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
if (config.originalDate != 0) { if (config.originalDate != 0) {
mask |= HistoryMessageForwarded::Bit(); mask |= HistoryMessageForwarded::Bit();
} }
if (config.mtpMarkup) { if (!config.markup.isTrivial()) {
// optimization: don't create markup component for the case mask |= HistoryMessageReplyMarkup::Bit();
// MTPDreplyKeyboardHide with flags = 0, assume it has f_zero flag
if (config.mtpMarkup->type() != mtpc_replyKeyboardHide || config.mtpMarkup->c_replyKeyboardHide().vflags().v != 0) {
mask |= HistoryMessageReplyMarkup::Bit();
}
} else if (config.inlineMarkup) { } else if (config.inlineMarkup) {
mask |= HistoryMessageReplyMarkup::Bit(); mask |= HistoryMessageReplyMarkup::Bit();
} }
@ -1097,7 +1108,7 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
setViewsCount(config.viewsCount); setViewsCount(config.viewsCount);
if (config.mtpReplies) { if (config.mtpReplies) {
setReplies(*config.mtpReplies); setReplies(*config.mtpReplies);
} else if (isSending() && !config.mtpMarkup) { } else if (isSending() && config.markup.isNull()) {
if (const auto broadcast = history()->peer->asBroadcast()) { if (const auto broadcast = history()->peer->asBroadcast()) {
if (const auto linked = broadcast->linkedChat()) { if (const auto linked = broadcast->linkedChat()) {
setReplies(MTP_messageReplies( setReplies(MTP_messageReplies(
@ -1125,14 +1136,18 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
} }
setupForwardedComponent(config); setupForwardedComponent(config);
if (const auto markup = Get<HistoryMessageReplyMarkup>()) { if (const auto markup = Get<HistoryMessageReplyMarkup>()) {
if (config.mtpMarkup) { if (!config.markup.isTrivial()) {
markup->create(*config.mtpMarkup); markup->updateData(std::move(config.markup));
} else if (config.inlineMarkup) { } else if (config.inlineMarkup) {
markup->create(*config.inlineMarkup); markup->createForwarded(*config.inlineMarkup);
} }
if (markup->flags & ReplyMarkupFlag::HasSwitchInlineButton) { if (markup->data.flags & ReplyMarkupFlag::HasSwitchInlineButton) {
_flags |= MessageFlag::HasSwitchInlineButton; _flags |= MessageFlag::HasSwitchInlineButton;
} }
} else if (!config.markup.isNull()) {
_flags |= MessageFlag::HasReplyMarkup;
} else {
_flags &= ~MessageFlag::HasReplyMarkup;
} }
const auto from = displayFrom(); const auto from = displayFrom();
_fromNameVersion = from ? from->nameVersion : 1; _fromNameVersion = from ? from->nameVersion : 1;
@ -1343,7 +1358,7 @@ std::unique_ptr<Data::Media> HistoryMessage::CreateMedia(
void HistoryMessage::replaceBuyWithReceiptInMarkup() { void HistoryMessage::replaceBuyWithReceiptInMarkup() {
if (const auto markup = inlineReplyMarkup()) { if (const auto markup = inlineReplyMarkup()) {
for (auto &row : markup->rows) { for (auto &row : markup->data.rows) {
for (auto &button : row) { for (auto &button : row) {
if (button.type == HistoryMessageMarkupButton::Type::Buy) { if (button.type == HistoryMessageMarkupButton::Type::Buy) {
const auto receipt = tr::lng_payments_receipt_button(tr::now); const auto receipt = tr::lng_payments_receipt_button(tr::now);
@ -1390,7 +1405,7 @@ void HistoryMessage::applyEdition(const MTPDmessage &message) {
&history()->session(), &history()->session(),
message.ventities().value_or_empty()) message.ventities().value_or_empty())
}; };
setReplyMarkup(message.vreply_markup()); setReplyMarkup(HistoryMessageMarkupData(message.vreply_markup()));
if (!isLocalUpdateMedia()) { if (!isLocalUpdateMedia()) {
refreshMedia(message.vmedia()); refreshMedia(message.vmedia());
} }
@ -1417,7 +1432,7 @@ void HistoryMessage::applyEdition(const MTPDmessage &message) {
void HistoryMessage::applyEdition(const MTPDmessageService &message) { void HistoryMessage::applyEdition(const MTPDmessageService &message) {
if (message.vaction().type() == mtpc_messageActionHistoryClear) { if (message.vaction().type() == mtpc_messageActionHistoryClear) {
const auto wasGrouped = history()->owner().groups().isGrouped(this); const auto wasGrouped = history()->owner().groups().isGrouped(this);
setReplyMarkup(nullptr); setReplyMarkup({});
refreshMedia(nullptr); refreshMedia(nullptr);
setEmptyText(); setEmptyText();
setViewsCount(-1); setViewsCount(-1);
@ -1466,6 +1481,10 @@ void HistoryMessage::updateForwardedInfo(const MTPMessageFwdHeader *fwd) {
}); });
} }
void HistoryMessage::updateReplyMarkup(HistoryMessageMarkupData &&markup) {
setReplyMarkup(std::move(markup));
}
void HistoryMessage::contributeToSlowmode(TimeId realDate) { void HistoryMessage::contributeToSlowmode(TimeId realDate) {
if (const auto channel = history()->peer->asChannel()) { if (const auto channel = history()->peer->asChannel()) {
if (out() && IsServerMsgId(id)) { if (out() && IsServerMsgId(id)) {
@ -1612,14 +1631,14 @@ void HistoryMessage::checkIsolatedEmoji() {
} }
} }
void HistoryMessage::setReplyMarkup(const MTPReplyMarkup *markup) { void HistoryMessage::setReplyMarkup(HistoryMessageMarkupData &&markup) {
const auto requestUpdate = [&] { const auto requestUpdate = [&] {
history()->owner().requestItemResize(this); history()->owner().requestItemResize(this);
history()->session().changes().messageUpdated( history()->session().changes().messageUpdated(
this, this,
Data::MessageUpdate::Flag::ReplyMarkup); Data::MessageUpdate::Flag::ReplyMarkup);
}; };
if (!markup) { if (markup.isNull()) {
if (_flags & MessageFlag::HasReplyMarkup) { if (_flags & MessageFlag::HasReplyMarkup) {
_flags &= ~MessageFlag::HasReplyMarkup; _flags &= ~MessageFlag::HasReplyMarkup;
if (Has<HistoryMessageReplyMarkup>()) { if (Has<HistoryMessageReplyMarkup>()) {
@ -1632,8 +1651,7 @@ void HistoryMessage::setReplyMarkup(const MTPReplyMarkup *markup) {
// optimization: don't create markup component for the case // optimization: don't create markup component for the case
// MTPDreplyKeyboardHide with flags = 0, assume it has f_zero flag // MTPDreplyKeyboardHide with flags = 0, assume it has f_zero flag
if (markup->type() == mtpc_replyKeyboardHide if (markup.isTrivial()) {
&& markup->c_replyKeyboardHide().vflags().v == 0) {
bool changed = false; bool changed = false;
if (Has<HistoryMessageReplyMarkup>()) { if (Has<HistoryMessageReplyMarkup>()) {
RemoveComponents(HistoryMessageReplyMarkup::Bit()); RemoveComponents(HistoryMessageReplyMarkup::Bit());
@ -1653,7 +1671,7 @@ void HistoryMessage::setReplyMarkup(const MTPReplyMarkup *markup) {
if (!Has<HistoryMessageReplyMarkup>()) { if (!Has<HistoryMessageReplyMarkup>()) {
AddComponents(HistoryMessageReplyMarkup::Bit()); AddComponents(HistoryMessageReplyMarkup::Bit());
} }
Get<HistoryMessageReplyMarkup>()->create(*markup); Get<HistoryMessageReplyMarkup>()->updateData(std::move(markup));
requestUpdate(); requestUpdate();
} }
} }

View file

@ -21,6 +21,7 @@ class Message;
struct HistoryMessageEdited; struct HistoryMessageEdited;
struct HistoryMessageReply; struct HistoryMessageReply;
struct HistoryMessageViews; struct HistoryMessageViews;
struct HistoryMessageMarkupData;
[[nodiscard]] Fn<void(ChannelData*, MsgId)> HistoryDependentItemCallback( [[nodiscard]] Fn<void(ChannelData*, MsgId)> HistoryDependentItemCallback(
not_null<HistoryItem*> item); not_null<HistoryItem*> item);
@ -75,7 +76,7 @@ public:
const QString &postAuthor, const QString &postAuthor,
const TextWithEntities &textWithEntities, const TextWithEntities &textWithEntities,
const MTPMessageMedia &media, const MTPMessageMedia &media,
const MTPReplyMarkup &markup, HistoryMessageMarkupData &&markup,
uint64 groupedId); // local message uint64 groupedId); // local message
HistoryMessage( HistoryMessage(
not_null<History*> history, not_null<History*> history,
@ -88,7 +89,7 @@ public:
const QString &postAuthor, const QString &postAuthor,
not_null<DocumentData*> document, not_null<DocumentData*> document,
const TextWithEntities &caption, const TextWithEntities &caption,
const MTPReplyMarkup &markup); // local document HistoryMessageMarkupData &&markup); // local document
HistoryMessage( HistoryMessage(
not_null<History*> history, not_null<History*> history,
MsgId id, MsgId id,
@ -100,7 +101,7 @@ public:
const QString &postAuthor, const QString &postAuthor,
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
const TextWithEntities &caption, const TextWithEntities &caption,
const MTPReplyMarkup &markup); // local photo HistoryMessageMarkupData &&markup); // local photo
HistoryMessage( HistoryMessage(
not_null<History*> history, not_null<History*> history,
MsgId id, MsgId id,
@ -111,7 +112,7 @@ public:
PeerId from, PeerId from,
const QString &postAuthor, const QString &postAuthor,
not_null<GameData*> game, not_null<GameData*> game,
const MTPReplyMarkup &markup); // local game HistoryMessageMarkupData &&markup); // local game
void refreshMedia(const MTPMessageMedia *media); void refreshMedia(const MTPMessageMedia *media);
void refreshSentMedia(const MTPMessageMedia *media); void refreshSentMedia(const MTPMessageMedia *media);
@ -164,9 +165,7 @@ public:
void updateSentContent( void updateSentContent(
const TextWithEntities &textWithEntities, const TextWithEntities &textWithEntities,
const MTPMessageMedia *media) override; const MTPMessageMedia *media) override;
void updateReplyMarkup(const MTPReplyMarkup *markup) override { void updateReplyMarkup(HistoryMessageMarkupData &&markup) override;
setReplyMarkup(markup);
}
void updateForwardedInfo(const MTPMessageFwdHeader *fwd) override; void updateForwardedInfo(const MTPMessageFwdHeader *fwd) override;
void contributeToSlowmode(TimeId realDate = 0) override; void contributeToSlowmode(TimeId realDate = 0) override;
@ -240,7 +239,7 @@ private:
// It should show the receipt for the payed invoice. Still let mobile apps do that. // It should show the receipt for the payed invoice. Still let mobile apps do that.
void replaceBuyWithReceiptInMarkup(); void replaceBuyWithReceiptInMarkup();
void setReplyMarkup(const MTPReplyMarkup *markup); void setReplyMarkup(HistoryMessageMarkupData &&markup);
struct CreateConfig; struct CreateConfig;
void createComponentsHelper( void createComponentsHelper(
@ -248,8 +247,8 @@ private:
MsgId replyTo, MsgId replyTo,
UserId viaBotId, UserId viaBotId,
const QString &postAuthor, const QString &postAuthor,
const MTPReplyMarkup &markup); HistoryMessageMarkupData &&markup);
void createComponents(const CreateConfig &config); void createComponents(CreateConfig &&config);
void setupForwardedComponent(const CreateConfig &config); void setupForwardedComponent(const CreateConfig &config);
void changeReplyToTopCounter( void changeReplyToTopCounter(
not_null<HistoryMessageReply*> reply, not_null<HistoryMessageReply*> reply,

View file

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_photo_media.h" #include "data/data_photo_media.h"
#include "data/data_document_media.h" #include "data/data_document_media.h"
#include "history/history_item_reply_markup.h"
#include "inline_bots/inline_bot_layout_item.h" #include "inline_bots/inline_bot_layout_item.h"
#include "inline_bots/inline_bot_send_data.h" #include "inline_bots/inline_bot_send_data.h"
#include "storage/file_download.h" #include "storage/file_download.h"
@ -267,7 +268,8 @@ std::unique_ptr<Result> Result::Create(
message->match([&](const auto &data) { message->match([&](const auto &data) {
if (const auto markup = data.vreply_markup()) { if (const auto markup = data.vreply_markup()) {
result->_mtpKeyboard = std::make_unique<MTPReplyMarkup>(*markup); result->_replyMarkup
= std::make_unique<HistoryMessageMarkupData>(markup);
} }
}); });
@ -373,10 +375,9 @@ void Result::addToHistory(
const QString &postAuthor) const { const QString &postAuthor) const {
flags |= MessageFlag::FromInlineBot; flags |= MessageFlag::FromInlineBot;
auto markup = MTPReplyMarkup(); auto markup = _replyMarkup ? *_replyMarkup : HistoryMessageMarkupData();
if (_mtpKeyboard) { if (!markup.isNull()) {
flags |= MessageFlag::HasReplyMarkup; flags |= MessageFlag::HasReplyMarkup;
markup = *_mtpKeyboard;
} }
sendData->addToHistory( sendData->addToHistory(
this, this,
@ -388,7 +389,7 @@ void Result::addToHistory(
viaBotId, viaBotId,
replyToId, replyToId,
postAuthor, postAuthor,
markup); std::move(markup));
} }
QString Result::getErrorOnSend(History *history) const { QString Result::getErrorOnSend(History *history) const {

View file

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class FileLoader; class FileLoader;
class History; class History;
class UserData; class UserData;
struct HistoryMessageMarkupData;
namespace Data { namespace Data {
class LocationPoint; class LocationPoint;
@ -118,7 +119,7 @@ private:
PhotoData *_photo = nullptr; PhotoData *_photo = nullptr;
GameData *_game = nullptr; GameData *_game = nullptr;
std::unique_ptr<MTPReplyMarkup> _mtpKeyboard; std::unique_ptr<HistoryMessageMarkupData> _replyMarkup;
Data::CloudImage _thumbnail; Data::CloudImage _thumbnail;
Data::CloudImage _locationThumbnail; Data::CloudImage _locationThumbnail;

View file

@ -38,7 +38,7 @@ void SendDataCommon::addToHistory(
UserId viaBotId, UserId viaBotId,
MsgId replyToId, MsgId replyToId,
const QString &postAuthor, const QString &postAuthor,
const MTPReplyMarkup &markup) const { HistoryMessageMarkupData &&markup) const {
auto fields = getSentMessageFields(); auto fields = getSentMessageFields();
if (replyToId) { if (replyToId) {
flags |= MessageFlag::HasReplyInfo; flags |= MessageFlag::HasReplyInfo;
@ -53,7 +53,7 @@ void SendDataCommon::addToHistory(
postAuthor, postAuthor,
std::move(fields.text), std::move(fields.text),
std::move(fields.media), std::move(fields.media),
markup); std::move(markup));
} }
QString SendDataCommon::getErrorOnSend( QString SendDataCommon::getErrorOnSend(
@ -123,7 +123,7 @@ void SendPhoto::addToHistory(
UserId viaBotId, UserId viaBotId,
MsgId replyToId, MsgId replyToId,
const QString &postAuthor, const QString &postAuthor,
const MTPReplyMarkup &markup) const { HistoryMessageMarkupData &&markup) const {
history->addNewLocalMessage( history->addNewLocalMessage(
msgId, msgId,
flags, flags,
@ -134,7 +134,7 @@ void SendPhoto::addToHistory(
postAuthor, postAuthor,
_photo, _photo,
{ _message, _entities }, { _message, _entities },
markup); std::move(markup));
} }
QString SendPhoto::getErrorOnSend( QString SendPhoto::getErrorOnSend(
@ -156,7 +156,7 @@ void SendFile::addToHistory(
UserId viaBotId, UserId viaBotId,
MsgId replyToId, MsgId replyToId,
const QString &postAuthor, const QString &postAuthor,
const MTPReplyMarkup &markup) const { HistoryMessageMarkupData &&markup) const {
history->addNewLocalMessage( history->addNewLocalMessage(
msgId, msgId,
flags, flags,
@ -167,7 +167,7 @@ void SendFile::addToHistory(
postAuthor, postAuthor,
_document, _document,
{ _message, _entities }, { _message, _entities },
markup); std::move(markup));
} }
QString SendFile::getErrorOnSend( QString SendFile::getErrorOnSend(
@ -203,7 +203,7 @@ void SendGame::addToHistory(
UserId viaBotId, UserId viaBotId,
MsgId replyToId, MsgId replyToId,
const QString &postAuthor, const QString &postAuthor,
const MTPReplyMarkup &markup) const { HistoryMessageMarkupData &&markup) const {
history->addNewLocalMessage( history->addNewLocalMessage(
msgId, msgId,
flags, flags,
@ -213,7 +213,7 @@ void SendGame::addToHistory(
fromId, fromId,
postAuthor, postAuthor,
_game, _game,
markup); std::move(markup));
} }
QString SendGame::getErrorOnSend( QString SendGame::getErrorOnSend(

View file

@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_location_manager.h" #include "history/history_location_manager.h"
struct HistoryMessageMarkupData;
namespace Main { namespace Main {
class Session; class Session;
} // namespace Main } // namespace Main
@ -48,7 +50,7 @@ public:
UserId viaBotId, UserId viaBotId,
MsgId replyToId, MsgId replyToId,
const QString &postAuthor, const QString &postAuthor,
const MTPReplyMarkup &markup) const = 0; HistoryMessageMarkupData &&markup) const = 0;
virtual QString getErrorOnSend( virtual QString getErrorOnSend(
const Result *owner, const Result *owner,
not_null<History*> history) const = 0; not_null<History*> history) const = 0;
@ -90,7 +92,7 @@ public:
UserId viaBotId, UserId viaBotId,
MsgId replyToId, MsgId replyToId,
const QString &postAuthor, const QString &postAuthor,
const MTPReplyMarkup &markup) const override; HistoryMessageMarkupData &&markup) const override;
QString getErrorOnSend( QString getErrorOnSend(
const Result *owner, const Result *owner,
@ -258,7 +260,7 @@ public:
UserId viaBotId, UserId viaBotId,
MsgId replyToId, MsgId replyToId,
const QString &postAuthor, const QString &postAuthor,
const MTPReplyMarkup &markup) const override; HistoryMessageMarkupData &&markup) const override;
QString getErrorOnSend( QString getErrorOnSend(
const Result *owner, const Result *owner,
@ -299,7 +301,7 @@ public:
UserId viaBotId, UserId viaBotId,
MsgId replyToId, MsgId replyToId,
const QString &postAuthor, const QString &postAuthor,
const MTPReplyMarkup &markup) const override; HistoryMessageMarkupData &&markup) const override;
QString getErrorOnSend( QString getErrorOnSend(
const Result *owner, const Result *owner,
@ -334,7 +336,7 @@ public:
UserId viaBotId, UserId viaBotId,
MsgId replyToId, MsgId replyToId,
const QString &postAuthor, const QString &postAuthor,
const MTPReplyMarkup &markup) const override; HistoryMessageMarkupData &&markup) const override;
QString getErrorOnSend( QString getErrorOnSend(
const Result *owner, const Result *owner,

View file

@ -289,7 +289,7 @@ AdminLog::OwnedItem GenerateCommentItem(
QString(), QString(),
TextWithEntities{ TextUtilities::Clean(data.comment) }, TextWithEntities{ TextUtilities::Clean(data.comment) },
MTP_messageMediaEmpty(), MTP_messageMediaEmpty(),
MTPReplyMarkup(), HistoryMessageMarkupData(),
groupedId); groupedId);
return AdminLog::OwnedItem(delegate, item); return AdminLog::OwnedItem(delegate, item);
} }
@ -319,7 +319,7 @@ AdminLog::OwnedItem GenerateContactItem(
MTP_string(data.lastName), MTP_string(data.lastName),
MTP_string(), // vcard MTP_string(), // vcard
MTP_long(0)), // user_id MTP_long(0)), // user_id
MTPReplyMarkup(), HistoryMessageMarkupData(),
groupedId); groupedId);
return AdminLog::OwnedItem(delegate, item); return AdminLog::OwnedItem(delegate, item);
} }