From daa5016c2341069e4676b5ff4eb9fdf8f9073b38 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 28 Mar 2016 15:51:22 +0300 Subject: [PATCH] Components are now almost plain structs Moved reply markups to history items which hold them --- Telegram/Resources/style.txt | 10 ++ Telegram/SourceFiles/apiwrap.h | 4 +- Telegram/SourceFiles/app.cpp | 116 ------------ Telegram/SourceFiles/app.h | 12 -- Telegram/SourceFiles/facades.cpp | 5 + Telegram/SourceFiles/facades.h | 1 + Telegram/SourceFiles/gui/animation.h | 4 +- Telegram/SourceFiles/history.cpp | 200 +++++++++++++++------ Telegram/SourceFiles/history.h | 131 +++++++++----- Telegram/SourceFiles/historywidget.cpp | 45 ++--- Telegram/SourceFiles/historywidget.h | 16 +- Telegram/SourceFiles/layout.h | 16 +- Telegram/SourceFiles/mtproto/core_types.h | 2 +- Telegram/SourceFiles/mtproto/generate.py | 1 + Telegram/SourceFiles/mtproto/scheme_auto.h | 8 + Telegram/SourceFiles/overviewwidget.cpp | 28 +-- Telegram/SourceFiles/shortcuts.cpp | 2 +- Telegram/SourceFiles/types.h | 143 ++++++++++----- 18 files changed, 409 insertions(+), 335 deletions(-) diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index 5ada019a8..196059ae5 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1085,6 +1085,16 @@ msgInReplyBarColor: #2fa9e2; msgOutReplyBarSelColor: #4da79f; msgInReplyBarSelColor: #2fa9e2; +msgBotKbDuration: 200; +msgBotKbFont: semiboldFont; +msgBotKbButton: botKeyboardButton { + margin: 5px; + padding: 10px; + height: 36px; + textTop: 8px; + downTextTop: 9px; +} + msgServiceBg: #89a0b47f; msgServiceSelectBg: #bbc8d4a2; msgServiceColor: #FFF; diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 3ea5eca0f..8845d90bd 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -28,7 +28,7 @@ public: ApiWrap(QObject *parent); void init(); - typedef SharedCallback2 RequestMessageDataCallback; + typedef SharedCallback RequestMessageDataCallback; void requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback *callback); void requestFullPeer(PeerData *peer); @@ -69,7 +69,7 @@ private: struct MessageDataRequest { MessageDataRequest() : req(0) { } - typedef SharedCallback2::Ptr CallbackPtr; + typedef SharedCallback::Ptr CallbackPtr; typedef QList Callbacks; mtpRequestId req; Callbacks callbacks; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 29cb00368..1edee0a39 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -55,12 +55,6 @@ namespace { typedef QHash WebPagesData; WebPagesData webPagesData; - typedef QMap ReplyMarkups; - ReplyMarkups replyMarkups; - ReplyMarkup zeroMarkup(qFlags(MTPDreplyKeyboardMarkup_ClientFlag::f_zero)); - typedef QMap ChannelReplyMarkups; - ChannelReplyMarkups channelReplyMarkups; - PhotoItems photoItems; DocumentItems documentItems; WebPageItems webPageItems; @@ -1851,8 +1845,6 @@ namespace App { } ::hoveredItem = ::pressedItem = ::hoveredLinkItem = ::pressedLinkItem = ::contextItem = 0; - replyMarkups.clear(); - channelReplyMarkups.clear(); } void historyClearItems() { @@ -2396,114 +2388,6 @@ namespace App { ::inlineResultLoaders.remove(loader); } - InlineResult *inlineResultFromLoader(FileLoader *loader) { - InlineResultLoaders::const_iterator i = ::inlineResultLoaders.find(loader); - return (i == ::inlineResultLoaders.cend()) ? 0 : i.value(); - } - - inline void insertReplyMarkup(ChannelId channelId, MsgId msgId, const ReplyMarkup &markup) { - if (channelId == NoChannel) { - replyMarkups.insert(msgId, markup); - } else { - channelReplyMarkups[channelId].insert(msgId, markup); - } - } - - void feedReplyMarkup(ChannelId channelId, MsgId msgId, const MTPReplyMarkup &markup) { - ReplyMarkup data; - ReplyMarkup::Commands &commands(data.commands); - switch (markup.type()) { - case mtpc_replyKeyboardMarkup: { - const MTPDreplyKeyboardMarkup &d(markup.c_replyKeyboardMarkup()); - data.flags = d.vflags.v; - - const QVector &v(d.vrows.c_vector().v); - if (!v.isEmpty()) { - commands.reserve(v.size()); - for (int32 i = 0, l = v.size(); i < l; ++i) { - switch (v.at(i).type()) { - case mtpc_keyboardButtonRow: { - const MTPDkeyboardButtonRow &r(v.at(i).c_keyboardButtonRow()); - const QVector &b(r.vbuttons.c_vector().v); - if (!b.isEmpty()) { - QList btns; - btns.reserve(b.size()); - for (int32 j = 0, s = b.size(); j < s; ++j) { - switch (b.at(j).type()) { - case mtpc_keyboardButton: { - btns.push_back(qs(b.at(j).c_keyboardButton().vtext)); - } break; - - case mtpc_keyboardButtonCallback: { - - } break; - - case mtpc_keyboardButtonRequestGeoLocation: { - - } break; - - case mtpc_keyboardButtonRequestPhone: { - - } break; - - case mtpc_keyboardButtonUrl: { - - } break; - } - } - if (!btns.isEmpty()) commands.push_back(btns); - } - } break; - } - } - if (!commands.isEmpty()) { - insertReplyMarkup(channelId, msgId, data); - } - } - } break; - - case mtpc_replyKeyboardHide: { - const MTPDreplyKeyboardHide &d(markup.c_replyKeyboardHide()); - if (d.vflags.v) { - insertReplyMarkup(channelId, msgId, ReplyMarkup(mtpCastFlags(d.vflags.v) | MTPDreplyKeyboardMarkup_ClientFlag::f_zero)); - } - } break; - - case mtpc_replyKeyboardForceReply: { - const MTPDreplyKeyboardForceReply &d(markup.c_replyKeyboardForceReply()); - insertReplyMarkup(channelId, msgId, ReplyMarkup(mtpCastFlags(d.vflags.v) | MTPDreplyKeyboardMarkup_ClientFlag::f_force_reply)); - } break; - } - } - - void clearReplyMarkup(ChannelId channelId, MsgId msgId) { - if (channelId == NoChannel) { - replyMarkups.remove(msgId); - } else { - ChannelReplyMarkups::iterator i = channelReplyMarkups.find(channelId); - if (i != channelReplyMarkups.cend()) { - i->remove(msgId); - if (i->isEmpty()) { - channelReplyMarkups.erase(i); - } - } - } - } - - inline const ReplyMarkup &replyMarkup(const ReplyMarkups &markups, MsgId msgId) { - ReplyMarkups::const_iterator i = markups.constFind(msgId); - if (i == markups.cend()) return zeroMarkup; - return i.value(); - } - const ReplyMarkup &replyMarkup(ChannelId channelId, MsgId msgId) { - if (channelId == NoChannel) { - return replyMarkup(replyMarkups, msgId); - } - ChannelReplyMarkups::const_iterator j = channelReplyMarkups.constFind(channelId); - if (j == channelReplyMarkups.cend()) return zeroMarkup; - return replyMarkup(*j, msgId); - } - void setProxySettings(QNetworkAccessManager &manager) { #ifndef TDESKTOP_DISABLE_NETWORK_PROXY manager.setProxy(getHttpProxySettings()); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index ebe1711e5..a4039571e 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -44,14 +44,6 @@ typedef QHash GifItems; typedef QHash PhotosData; typedef QHash DocumentsData; -struct ReplyMarkup { - ReplyMarkup(MTPDreplyKeyboardMarkup::Flags flags = 0) : flags(flags) { - } - typedef QList > Commands; - Commands commands; - MTPDreplyKeyboardMarkup::Flags flags; -}; - class LayeredWidget; namespace App { @@ -272,10 +264,6 @@ namespace App { void unregInlineResultLoader(FileLoader *loader); InlineResult *inlineResultFromLoader(FileLoader *loader); - void feedReplyMarkup(ChannelId channelId, MsgId msgId, const MTPReplyMarkup &markup); - void clearReplyMarkup(ChannelId channelId, MsgId msgId); - const ReplyMarkup &replyMarkup(ChannelId channelId, MsgId msgId); - void setProxySettings(QNetworkAccessManager &manager); #ifndef TDESKTOP_DISABLE_NETWORK_PROXY QNetworkProxy getHttpProxySettings(); diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 0b9557e3d..9e955b272 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -41,6 +41,11 @@ namespace App { return false; } + void activateBotCommand(const HistoryMessageReplyMarkup::Button &button, MsgId replyTo) { + QString cmd(button.text); + App::sendBotCommand(cmd, replyTo); + } + void searchByHashtag(const QString &tag, PeerData *inPeer) { if (MainWidget *m = main()) m->searchMessages(tag + ' ', (inPeer && inPeer->isChannel()) ? inPeer : 0); } diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index ba77a20a2..462299987 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -26,6 +26,7 @@ namespace App { void sendBotCommand(const QString &cmd, MsgId replyTo = 0); bool insertBotCommand(const QString &cmd, bool specialGif = false); + void activateBotCommand(const HistoryMessageReplyMarkup::Button &button, MsgId replyTo = 0); void searchByHashtag(const QString &tag, PeerData *inPeer); void openPeerByName(const QString &username, MsgId msgId = ShowAtUnreadMsgId, const QString &startToken = QString()); void joinGroupByHash(const QString &hash); diff --git a/Telegram/SourceFiles/gui/animation.h b/Telegram/SourceFiles/gui/animation.h index cb61a09e0..e31c08d29 100644 --- a/Telegram/SourceFiles/gui/animation.h +++ b/Telegram/SourceFiles/gui/animation.h @@ -211,7 +211,7 @@ public: AnimationImplementation *create() const { return getPointerAndReset(_ptr); } ~AnimationCreator() { deleteAndMark(_ptr); } private: - AnimationCreator &operator=(const AnimationCreator &other); + AnimationCreator &operator=(const AnimationCreator &other) = delete; mutable AnimationImplementation *_ptr; }; class AnimationCallbacks { @@ -222,7 +222,7 @@ public: ~AnimationCallbacks() { deleteAndMark(_implementation); } private: AnimationCallbacks(const AnimationCallbacks &other); - AnimationCallbacks &operator=(const AnimationCallbacks &other); + AnimationCallbacks &operator=(const AnimationCallbacks &other) = delete; AnimationImplementation *_implementation; }; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 1478fe97c..155081491 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -1291,9 +1291,6 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, result = HistoryService::create(this, m.vid.v, date(m.vdate), lang(lng_message_empty), m.vflags.v, nullptr, m.has_from_id() ? m.vfrom_id.v : 0); } else { result = HistoryMessage::create(this, m); - if (m.has_reply_markup()) { - App::feedReplyMarkup(channelId(), msgId, m.vreply_markup); - } } } break; @@ -1589,8 +1586,8 @@ HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) { } } } - if (adding->hasReplyMarkup()) { - MTPDreplyKeyboardMarkup::Flags markupFlags = App::replyMarkup(channelId(), adding->id).flags; + if (adding->definesReplyKeyboard()) { + MTPDreplyKeyboardMarkup::Flags markupFlags = adding->replyKeyboardFlags(); if (!(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_selective) || adding->mentionsMe()) { OrderedSet *markupSenders = 0; if (peer->isChat()) { @@ -1759,8 +1756,8 @@ void History::addOlderSlice(const QVector &slice, const QVectorauthor()->id) { if (markupSenders) { // chats with bots - if (!lastKeyboardInited && item->hasReplyMarkup() && !item->out()) { - MTPDreplyKeyboardMarkup::Flags markupFlags = App::replyMarkup(channelId(), item->id).flags; + if (!lastKeyboardInited && item->definesReplyKeyboard() && !item->out()) { + MTPDreplyKeyboardMarkup::Flags markupFlags = item->replyKeyboardFlags(); if (!(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_selective) || item->mentionsMe()) { bool wasKeyboardHide = markupSenders->contains(item->author()); if (!wasKeyboardHide) { @@ -1786,8 +1783,8 @@ void History::addOlderSlice(const QVector &slice, const QVectorhasReplyMarkup() && !item->out()) { // conversations with bots - MTPDreplyKeyboardMarkup::Flags markupFlags = App::replyMarkup(channelId(), item->id).flags; + } else if (!lastKeyboardInited && item->definesReplyKeyboard() && !item->out()) { // conversations with bots + MTPDreplyKeyboardMarkup::Flags markupFlags = item->replyKeyboardFlags(); if (!(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_selective) || item->mentionsMe()) { if (markupFlags & MTPDreplyKeyboardMarkup_ClientFlag::f_zero) { clearLastKeyboard(); @@ -2708,6 +2705,63 @@ void HistoryBlock::removeItem(HistoryItem *item) { } } +void HistoryMessageReplyMarkup::create(const MTPReplyMarkup &markup) { + switch (markup.type()) { + case mtpc_replyKeyboardMarkup: { + const MTPDreplyKeyboardMarkup &d(markup.c_replyKeyboardMarkup()); + flags = d.vflags.v; + + const QVector &v(d.vrows.c_vector().v); + if (!v.isEmpty()) { + rows.reserve(v.size()); + for_const (const MTPKeyboardButtonRow &row, v) { + switch (row.type()) { + case mtpc_keyboardButtonRow: { + const MTPDkeyboardButtonRow &r(row.c_keyboardButtonRow()); + const QVector &b(r.vbuttons.c_vector().v); + if (!b.isEmpty()) { + ButtonRow buttonRow; + buttonRow.reserve(b.size()); + for_const (const MTPKeyboardButton &button, b) { + switch (button.type()) { + case mtpc_keyboardButton: { + buttonRow.push_back({ Button::Default, qs(button.c_keyboardButton().vtext), QString() }); + } break; + case mtpc_keyboardButtonCallback: { + buttonRow.push_back({ Button::Callback, qs(button.c_keyboardButtonCallback().vtext), QString() }); + } break; + case mtpc_keyboardButtonRequestGeoLocation: { + buttonRow.push_back({ Button::RequestLocation, qs(button.c_keyboardButtonRequestGeoLocation().vtext), QString() }); + } break; + case mtpc_keyboardButtonRequestPhone: { + buttonRow.push_back({ Button::RequestPhone, qs(button.c_keyboardButtonRequestPhone().vtext), QString() }); + } break; + case mtpc_keyboardButtonUrl: { + const MTPDkeyboardButtonUrl &u(button.c_keyboardButtonUrl()); + buttonRow.push_back({ Button::Url, qs(u.vtext), qs(u.vurl) }); + } break; + } + } + if (!buttonRow.isEmpty()) rows.push_back(buttonRow); + } + } break; + } + } + } + } break; + + case mtpc_replyKeyboardHide: { + const MTPDreplyKeyboardHide &d(markup.c_replyKeyboardHide()); + flags = mtpCastFlags(d.vflags) | MTPDreplyKeyboardMarkup_ClientFlag::f_zero; + } break; + + case mtpc_replyKeyboardForceReply: { + const MTPDreplyKeyboardForceReply &d(markup.c_replyKeyboardForceReply()); + flags = mtpCastFlags(d.vflags) | MTPDreplyKeyboardMarkup_ClientFlag::f_force_reply; + } break; + } +} + void HistoryDependentItemCallback::call(ChannelData *channel, MsgId msgId) const { if (HistoryItem *item = App::histItemById(_dependent)) { item->updateDependencyItem(); @@ -3789,7 +3843,7 @@ void HistoryDocumentVoice::checkPlaybackFinished() const { HistoryDocument::HistoryDocument(DocumentData *document, const QString &caption, const HistoryItem *parent) : HistoryFileMedia() , _parent(nullptr) , _data(document) { - createInterfaces(!caption.isEmpty()); + createComponents(!caption.isEmpty()); if (auto *named = Get()) { named->_name = documentName(_data); named->_namew = st::semiboldFont->width(named->_name); @@ -3809,7 +3863,7 @@ HistoryDocument::HistoryDocument(const HistoryDocument &other) : HistoryFileMedi , _parent(nullptr) , _data(other._data) { auto *captioned = other.Get(); - createInterfaces(captioned != 0); + createComponents(captioned != 0); if (auto *named = Get()) { if (auto *othernamed = other.Get()) { named->_name = othernamed->_name; @@ -3829,7 +3883,7 @@ HistoryDocument::HistoryDocument(const HistoryDocument &other) : HistoryFileMedi } } -void HistoryDocument::createInterfaces(bool caption) { +void HistoryDocument::createComponents(bool caption) { uint64 mask = 0; if (_data->voice()) { mask |= HistoryDocumentVoice::Bit(); @@ -6041,7 +6095,7 @@ bool HistoryMessageReply::updateData(HistoryMessage *holder, bool force) { replyToLnk = TextLinkPtr(new MessageLink(replyToMsg->history()->peer->id, replyToMsg->id)); if (!replyToMsg->Has()) { if (UserData *bot = replyToMsg->viaBot()) { - _replyToVia = new HistoryMessageVia(0); + _replyToVia.reset(new HistoryMessageVia()); _replyToVia->create(peerToUser(bot->id)); } } @@ -6055,8 +6109,7 @@ bool HistoryMessageReply::updateData(HistoryMessage *holder, bool force) { } void HistoryMessageReply::clearData(HistoryMessage *holder) { - delete _replyToVia; - _replyToVia = nullptr; + _replyToVia.clear(); if (replyToMsg) { App::historyUnregDependency(holder, replyToMsg); replyToMsg = nullptr; @@ -6164,20 +6217,22 @@ void HistoryMessageReply::paint(Painter &p, const HistoryItem *holder, int x, in HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg) : HistoryItem(history, msg.vid.v, msg.vflags.v, ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) { - PeerId authorOriginalId = 0, fromOriginalId = 0; - MsgId originalId = 0; + CreateConfig config; + if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) { const MTPDmessageFwdHeader &f(msg.vfwd_from.c_messageFwdHeader()); if (f.has_from_id() || f.has_channel_id()) { - authorOriginalId = f.has_channel_id() ? peerFromChannel(f.vchannel_id) : peerFromUser(f.vfrom_id); - fromOriginalId = f.has_from_id() ? peerFromUser(f.vfrom_id) : peerFromChannel(f.vchannel_id); - if (f.has_channel_post()) originalId = f.vchannel_post.v; + config.authorIdOriginal = f.has_channel_id() ? peerFromChannel(f.vchannel_id) : peerFromUser(f.vfrom_id); + config.fromIdOriginal = f.has_from_id() ? peerFromUser(f.vfrom_id) : peerFromChannel(f.vchannel_id); + if (f.has_channel_post()) config.originalId = f.vchannel_post.v; } } - MsgId replyTo = msg.has_reply_to_msg_id() ? msg.vreply_to_msg_id.v : 0; - int32 viaBotId = msg.has_via_bot_id() ? msg.vvia_bot_id.v : 0; - int views = msg.has_views() ? msg.vviews.v : -1; - createInterfaces(replyTo, viaBotId, views, authorOriginalId, fromOriginalId, originalId); + if (msg.has_reply_to_msg_id()) config.replyTo = msg.vreply_to_msg_id.v; + if (msg.has_via_bot_id()) config.viaBotId = msg.vvia_bot_id.v; + if (msg.has_views()) config.viewsCount = msg.vviews.v; + if (msg.has_reply_markup()) config.markup = &msg.vreply_markup; + + createComponents(config); QString text(textClean(qs(msg.vmessage))); initMedia(msg.has_media() ? (&msg.vmedia) : 0, text); @@ -6186,11 +6241,18 @@ HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg) HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd) : HistoryItem(history, id, newForwardedFlags(history->peer, from, fwd) | flags, date, from) { + CreateConfig config; + UserData *fwdViaBot = fwd->viaBot(); - int32 viaBotId = fwdViaBot ? peerToUser(fwdViaBot->id) : 0; - int fwdViewsCount = fwd->viewsCount(), views = (fwdViewsCount > 0) ? fwdViewsCount : (isPost() ? 1 : -1); - MsgId replyTo = 0; - createInterfaces(replyTo, viaBotId, views, fwd->authorOriginal()->id, fwd->fromOriginal()->id, fwd->authorOriginal()->isChannel() ? fwd->id : 0); + if (fwdViaBot) config.viaBotId = peerToUser(fwdViaBot->id); + int fwdViewsCount = fwd->viewsCount(); + if (fwdViewsCount > 0) { + config.viewsCount = fwdViewsCount; + } else if (isPost()) { + config.viewsCount = 1; + } + + createComponents(config); if (HistoryMedia *mediaOriginal = fwd->getMedia()) { _media = mediaOriginal->clone(); @@ -6201,14 +6263,14 @@ HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags fl HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities) : HistoryItem(history, id, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { - createInterfacesHelper(flags, replyTo, viaBotId); + createComponentsHelper(flags, replyTo, viaBotId); setText(msg, entities); } HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption) : HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { - createInterfacesHelper(flags, replyTo, viaBotId); + createComponentsHelper(flags, replyTo, viaBotId); initMediaFromDocument(doc, caption); setText(QString(), EntitiesInText()); @@ -6216,56 +6278,70 @@ HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption) : HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { - createInterfacesHelper(flags, replyTo, viaBotId); + createComponentsHelper(flags, replyTo, viaBotId); _media = new HistoryPhoto(photo, caption, this); _media->attachToItem(this); setText(QString(), EntitiesInText()); } -void HistoryMessage::createInterfacesHelper(MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId) { - if (!(flags & MTPDmessage::Flag::f_via_bot_id)) viaBotId = 0; - if (!(flags & MTPDmessage::Flag::f_reply_to_msg_id)) replyTo = 0; - createInterfaces(replyTo, viaBotId, isPost() ? 1 : -1); +void HistoryMessage::createComponentsHelper(MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId) { + CreateConfig config; + + if (flags & MTPDmessage::Flag::f_via_bot_id) config.viaBotId = viaBotId; + if (flags & MTPDmessage::Flag::f_reply_to_msg_id) config.replyTo = replyTo; + if (isPost()) config.viewsCount = 1; + + createComponents(config); } -void HistoryMessage::createInterfaces(MsgId replyTo, int32 viaBotId, int32 viewsCount, const PeerId &authorIdOriginal, const PeerId &fromIdOriginal, MsgId originalId) { +void HistoryMessage::createComponents(const CreateConfig &config) { uint64 mask = 0; - if (replyTo) { + if (config.replyTo) { mask |= HistoryMessageReply::Bit(); } - if (viaBotId) { + if (config.viaBotId) { mask |= HistoryMessageVia::Bit(); } - if (viewsCount >= 0) { + if (config.viewsCount >= 0) { mask |= HistoryMessageViews::Bit(); } if (isPost() && _from->isUser()) { mask |= HistoryMessageSigned::Bit(); } - if (authorIdOriginal && fromIdOriginal) { + if (config.authorIdOriginal && config.fromIdOriginal) { mask |= HistoryMessageForwarded::Bit(); } + if (config.markup) { + // optimization: don't create markup component for the case + // MTPDreplyKeyboardHide with flags = 0, assume it has f_zero flag + if (config.markup->type() != mtpc_replyKeyboardHide || config.markup->c_replyKeyboardHide().vflags.v != 0) { + mask |= HistoryMessageReplyMarkup::Bit(); + } + } UpdateComponents(mask); if (auto *reply = Get()) { - reply->replyToMsgId = replyTo; + reply->replyToMsgId = config.replyTo; if (!reply->updateData(this) && App::api()) { - App::api()->requestMessageData(history()->peer->asChannel(), replyTo, new HistoryDependentItemCallback(fullId())); + App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, new HistoryDependentItemCallback(fullId())); } } if (auto *via = Get()) { - via->create(viaBotId); + via->create(config.viaBotId); } if (auto *views = Get()) { - views->_views = viewsCount; + views->_views = config.viewsCount; } if (auto *msgsigned = Get()) { msgsigned->create(_from->asUser(), date); } if (auto *fwd = Get()) { - fwd->_authorOriginal = App::peer(authorIdOriginal); - fwd->_fromOriginal = App::peer(fromIdOriginal); - fwd->_originalId = originalId; + fwd->_authorOriginal = App::peer(config.authorIdOriginal); + fwd->_fromOriginal = App::peer(config.fromIdOriginal); + fwd->_originalId = config.originalId; + } + if (auto *markup = Get()) { + markup->create(*config.markup); } initTime(); } @@ -6368,7 +6444,6 @@ int32 HistoryMessage::plainMaxWidth() const { } void HistoryMessage::initDimensions() { - auto *reply = Get(); if (drawBubble()) { auto fwd = Get(); auto via = Get(); @@ -6427,7 +6502,7 @@ void HistoryMessage::initDimensions() { _maxw = _media->maxWidth(); _minh = _media->minHeight(); } - if (reply) { + if (auto *reply = Get()) { reply->updateName(); if (!_media) { int replyw = st::msgPadding.left() + reply->_maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right(); @@ -6437,6 +6512,8 @@ void HistoryMessage::initDimensions() { if (replyw > _maxw) _maxw = replyw; } } + if (HistoryMessageReplyMarkup *markup = inlineReplyMarkup()) { + } } void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const { @@ -6741,11 +6818,15 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m textstyleSet(&(outbg ? st::outTextStyle : st::inTextStyle)); - //if (displayFromPhoto()) { - // int photoleft = left + ((outbg && !Adaptive::Wide()) ? (width + (st::msgPhotoSkip - st::msgPhotoSize)) : (-st::msgPhotoSkip)); - // int phototop = marginTop(); - // author()->paintUserpic(p, st::msgPhotoSize, photoleft, phototop); - //} + if (auto *markup = inlineReplyMarkup()) { + height -= markup->rows.size() * (st::msgBotKbButton.margin + st::msgBotKbButton.height); + int y = marginTop() + height + st::msgBotKbButton.margin; + for_const (const HistoryMessageReplyMarkup::ButtonRow &row, markup->rows) { + for_const (const HistoryMessageReplyMarkup::Button &button, row) { + + } + } + } auto *reply = Get(); if (reply) { @@ -6945,6 +7026,10 @@ int HistoryMessage::resizeGetHeight_(int width) { } else { _height = _media->resize(width, this); } + if (HistoryMessageReplyMarkup *markup = inlineReplyMarkup()) { + _height += (st::msgBotKbButton.margin + st::msgBotKbButton.height) * markup->rows.size(); + } + _height += marginTop() + marginBottom(); return _height; } @@ -6996,6 +7081,10 @@ void HistoryMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 //} if (width < 1) return; + if (const HistoryMessageReplyMarkup *markup = inlineReplyMarkup()) { + height -= (st::msgBotKbButton.margin + st::msgBotKbButton.height) * markup->rows.size(); + } + if (drawBubble()) { auto *fwd = Get(); auto *via = Get(); @@ -7172,9 +7261,6 @@ HistoryMessage::~HistoryMessage() { if (auto *reply = Get()) { reply->clearData(this); } - if (_flags & MTPDmessage::Flag::f_reply_markup) { - App::clearReplyMarkup(channelId(), id); - } } void HistoryService::setMessageByAction(const MTPmessageAction &action) { diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 497dd1060..5f617c80e 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -966,8 +966,6 @@ enum HistoryItemType { }; struct HistoryMessageVia : public BaseComponent { - HistoryMessageVia(Composer*) { - } void create(int32 userId); void resize(int32 availw) const; @@ -979,18 +977,12 @@ struct HistoryMessageVia : public BaseComponent { }; struct HistoryMessageViews : public BaseComponent { - HistoryMessageViews(Composer*) { - } - QString _viewsText; int _views = 0; int _viewsWidth = 0; }; struct HistoryMessageSigned : public BaseComponent { - HistoryMessageSigned(Composer*) { - } - void create(UserData *from, const QDateTime &date); int maxWidth() const; @@ -998,8 +990,6 @@ struct HistoryMessageSigned : public BaseComponent { }; struct HistoryMessageForwarded : public BaseComponent { - HistoryMessageForwarded(Composer*) { - } void create(const HistoryMessageVia *via) const; PeerData *_authorOriginal = nullptr; @@ -1009,24 +999,23 @@ struct HistoryMessageForwarded : public BaseComponent { }; struct HistoryMessageReply : public BaseComponent { - HistoryMessageReply(Composer*) { - } HistoryMessageReply &operator=(HistoryMessageReply &&other) { replyToMsgId = other.replyToMsgId; std::swap(replyToMsg, other.replyToMsg); - replyToLnk = std11::move(other.replyToLnk); - replyToName = std11::move(other.replyToName); - replyToText = std11::move(other.replyToText); + replyToLnk = std_::move(other.replyToLnk); + replyToName = std_::move(other.replyToName); + replyToText = std_::move(other.replyToText); replyToVersion = other.replyToVersion; _maxReplyWidth = other._maxReplyWidth; - std::swap(_replyToVia, other._replyToVia); + _replyToVia = std_::move(other._replyToVia); return *this; } ~HistoryMessageReply() { // clearData() should be called by holder t_assert(replyToMsg == nullptr); - t_assert(_replyToVia == nullptr); + t_assert(_replyToVia.data() == nullptr); } + bool updateData(HistoryMessage *holder, bool force = false); void clearData(HistoryMessage *holder); // must be called before destructor @@ -1058,12 +1047,45 @@ struct HistoryMessageReply : public BaseComponent { mutable Text replyToName, replyToText; mutable int replyToVersion = 0; mutable int _maxReplyWidth = 0; - HistoryMessageVia *_replyToVia = nullptr; + UniquePointer _replyToVia; int toWidth = 0; }; Q_DECLARE_OPERATORS_FOR_FLAGS(HistoryMessageReply::PaintFlags); -class HistoryDependentItemCallback : public SharedCallback2 { +class ReplyKeyboard { +public: + ReplyKeyboard(HistoryItem *item); + +}; + +struct HistoryMessageReplyMarkup : public BaseComponent { + HistoryMessageReplyMarkup() = default; + HistoryMessageReplyMarkup(MTPDreplyKeyboardMarkup::Flags f) : flags(f) { + } + + void create(const MTPReplyMarkup &markup); + + struct Button { + enum Type { + Default, + Url, + Callback, + RequestPhone, + RequestLocation, + }; + Type type; + QString text, url; + }; + using ButtonRow = QVector