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_components.cpp
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.h
history/history_inner_widget.cpp

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -95,7 +95,7 @@ void CheckForSwitchInlineButton(not_null<HistoryItem*> item) {
return;
}
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) {
using ButtonType = HistoryMessageMarkupButton::Type;
if (button.type == ButtonType::SwitchInline) {

View file

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

View file

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

View file

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

View file

@ -86,7 +86,7 @@ not_null<HistoryItem*> CreateUnsupportedMessage(
QString(),
text,
MTP_messageMediaEmpty(),
MTPReplyMarkup(),
HistoryMessageMarkupData(),
groupedId);
}
@ -233,7 +233,7 @@ void HistoryItem::setGroupId(MessageGroupId groupId) {
HistoryMessageReplyMarkup *HistoryItem::inlineReplyMarkup() {
if (const auto markup = Get<HistoryMessageReplyMarkup>()) {
if (markup->flags & ReplyMarkupFlag::Inline) {
if (markup->data.flags & ReplyMarkupFlag::Inline) {
return markup;
}
}
@ -371,7 +371,7 @@ void HistoryItem::setIsPinned(bool pinned) {
bool HistoryItem::definesReplyKeyboard() const {
if (const auto markup = Get<HistoryMessageReplyMarkup>()) {
if (markup->flags & ReplyMarkupFlag::Inline) {
if (markup->data.flags & ReplyMarkupFlag::Inline) {
return false;
}
return true;
@ -386,7 +386,7 @@ ReplyMarkupFlags HistoryItem::replyKeyboardFlags() const {
Expects(definesReplyKeyboard());
if (const auto markup = Get<HistoryMessageReplyMarkup>()) {
return markup->flags;
return markup->data.flags;
}
// optimization: don't create markup component for the case
@ -508,7 +508,7 @@ void HistoryItem::applySentMessage(const MTPDmessage &data) {
&history()->session(),
data.ventities().value_or_empty())
}, data.vmedia());
updateReplyMarkup(data.vreply_markup());
updateReplyMarkup(HistoryMessageMarkupData(data.vreply_markup()));
updateForwardedInfo(data.vfwd_from());
setViewsCount(data.vviews().value_or(-1));
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/value_ordering.h"
#include "data/data_media_types.h"
#include "history/history_item_reply_markup.h"
#include <any>
@ -73,18 +74,6 @@ struct ItemPreview {
struct HiddenSenderInfo;
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(MTPDmessageService::Flags flags);
@ -284,7 +273,7 @@ public:
const TextWithEntities &textWithEntities,
const MTPMessageMedia *media) {
}
virtual void updateReplyMarkup(const MTPReplyMarkup *markup) {
virtual void updateReplyMarkup(HistoryMessageMarkupData &&markup) {
}
virtual void updateForwardedInfo(const MTPMessageFwdHeader *fwd) {
}

View file

@ -504,10 +504,10 @@ ReplyKeyboard::ReplyKeyboard(
if (const auto markup = _item->Get<HistoryMessageReplyMarkup>()) {
const auto owner = &_item->history()->owner();
const auto context = _item->fullId();
const auto rowCount = int(markup->rows.size());
const auto rowCount = int(markup->data.rows.size());
_rows.reserve(rowCount);
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());
auto newRow = std::vector<Button>();
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);
}
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) {
void HistoryMessageReplyMarkup::createForwarded(
const HistoryMessageReplyMarkup &original) {
Expects(!inlineKeyboard);
data.fillForwardedData(original.data);
}
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->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();
void HistoryMessageReplyMarkup::updateData(
HistoryMessageMarkupData &&markup) {
data = std::move(markup);
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;

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

View file

@ -21,6 +21,7 @@ class Message;
struct HistoryMessageEdited;
struct HistoryMessageReply;
struct HistoryMessageViews;
struct HistoryMessageMarkupData;
[[nodiscard]] Fn<void(ChannelData*, MsgId)> HistoryDependentItemCallback(
not_null<HistoryItem*> item);
@ -75,7 +76,7 @@ public:
const QString &postAuthor,
const TextWithEntities &textWithEntities,
const MTPMessageMedia &media,
const MTPReplyMarkup &markup,
HistoryMessageMarkupData &&markup,
uint64 groupedId); // local message
HistoryMessage(
not_null<History*> history,
@ -88,7 +89,7 @@ public:
const QString &postAuthor,
not_null<DocumentData*> document,
const TextWithEntities &caption,
const MTPReplyMarkup &markup); // local document
HistoryMessageMarkupData &&markup); // local document
HistoryMessage(
not_null<History*> history,
MsgId id,
@ -100,7 +101,7 @@ public:
const QString &postAuthor,
not_null<PhotoData*> photo,
const TextWithEntities &caption,
const MTPReplyMarkup &markup); // local photo
HistoryMessageMarkupData &&markup); // local photo
HistoryMessage(
not_null<History*> history,
MsgId id,
@ -111,7 +112,7 @@ public:
PeerId from,
const QString &postAuthor,
not_null<GameData*> game,
const MTPReplyMarkup &markup); // local game
HistoryMessageMarkupData &&markup); // local game
void refreshMedia(const MTPMessageMedia *media);
void refreshSentMedia(const MTPMessageMedia *media);
@ -164,9 +165,7 @@ public:
void updateSentContent(
const TextWithEntities &textWithEntities,
const MTPMessageMedia *media) override;
void updateReplyMarkup(const MTPReplyMarkup *markup) override {
setReplyMarkup(markup);
}
void updateReplyMarkup(HistoryMessageMarkupData &&markup) override;
void updateForwardedInfo(const MTPMessageFwdHeader *fwd) 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.
void replaceBuyWithReceiptInMarkup();
void setReplyMarkup(const MTPReplyMarkup *markup);
void setReplyMarkup(HistoryMessageMarkupData &&markup);
struct CreateConfig;
void createComponentsHelper(
@ -248,8 +247,8 @@ private:
MsgId replyTo,
UserId viaBotId,
const QString &postAuthor,
const MTPReplyMarkup &markup);
void createComponents(const CreateConfig &config);
HistoryMessageMarkupData &&markup);
void createComponents(CreateConfig &&config);
void setupForwardedComponent(const CreateConfig &config);
void changeReplyToTopCounter(
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_photo_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_send_data.h"
#include "storage/file_download.h"
@ -267,7 +268,8 @@ std::unique_ptr<Result> Result::Create(
message->match([&](const auto &data) {
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 {
flags |= MessageFlag::FromInlineBot;
auto markup = MTPReplyMarkup();
if (_mtpKeyboard) {
auto markup = _replyMarkup ? *_replyMarkup : HistoryMessageMarkupData();
if (!markup.isNull()) {
flags |= MessageFlag::HasReplyMarkup;
markup = *_mtpKeyboard;
}
sendData->addToHistory(
this,
@ -388,7 +389,7 @@ void Result::addToHistory(
viaBotId,
replyToId,
postAuthor,
markup);
std::move(markup));
}
QString Result::getErrorOnSend(History *history) const {

View file

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

View file

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

View file

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

View file

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